summaryrefslogtreecommitdiff
path: root/table
diff options
context:
space:
mode:
authorDavid Grogan <dgrogan@chromium.org>2013-05-14 16:52:56 -0700
committerDavid Grogan <dgrogan@chromium.org>2013-05-14 17:03:07 -0700
commit28dad918f2ffb80fd70110ed5cd47744339649f2 (patch)
treec2ce59adbce3e461e9f3e6d7d984f93f07d7eb33 /table
parent514c943a8e9ce1b06c55ae5e47008f6b0854b36c (diff)
downloadleveldb-28dad918f2ffb80fd70110ed5cd47744339649f2.tar.gz
Release leveldb 1.10v1.10
Fixes issues 147 - thanks feniksgordonfreeman 153 156 166 Additionally, * Remove calls to exit(1). * Fix unused-variable warnings from clang. * Fix possible overflow error related to num_restart value >= (2^32/4). * Add leveldbutil to .gitignore. * Add better log messages when Write is stalled on a compaction.
Diffstat (limited to 'table')
-rw-r--r--table/block.cc13
-rw-r--r--table/table.cc1
-rw-r--r--table/table_test.cc30
3 files changed, 37 insertions, 7 deletions
diff --git a/table/block.cc b/table/block.cc
index ab83c11..79ea9d9 100644
--- a/table/block.cc
+++ b/table/block.cc
@@ -16,7 +16,7 @@
namespace leveldb {
inline uint32_t Block::NumRestarts() const {
- assert(size_ >= 2*sizeof(uint32_t));
+ assert(size_ >= sizeof(uint32_t));
return DecodeFixed32(data_ + size_ - sizeof(uint32_t));
}
@@ -27,11 +27,12 @@ Block::Block(const BlockContents& contents)
if (size_ < sizeof(uint32_t)) {
size_ = 0; // Error marker
} else {
- restart_offset_ = size_ - (1 + NumRestarts()) * sizeof(uint32_t);
- if (restart_offset_ > size_ - sizeof(uint32_t)) {
- // The size is too small for NumRestarts() and therefore
- // restart_offset_ wrapped around.
+ size_t max_restarts_allowed = (size_-sizeof(uint32_t)) / sizeof(uint32_t);
+ if (NumRestarts() > max_restarts_allowed) {
+ // The size is too small for NumRestarts()
size_ = 0;
+ } else {
+ restart_offset_ = size_ - (1 + NumRestarts()) * sizeof(uint32_t);
}
}
}
@@ -253,7 +254,7 @@ class Block::Iter : public Iterator {
};
Iterator* Block::NewIterator(const Comparator* cmp) {
- if (size_ < 2*sizeof(uint32_t)) {
+ if (size_ < sizeof(uint32_t)) {
return NewErrorIterator(Status::Corruption("bad block contents"));
}
const uint32_t num_restarts = NumRestarts();
diff --git a/table/table.cc b/table/table.cc
index dbd6d3a..71c1756 100644
--- a/table/table.cc
+++ b/table/table.cc
@@ -228,7 +228,6 @@ Status Table::InternalGet(const ReadOptions& options, const Slice& k,
!filter->KeyMayMatch(handle.offset(), k)) {
// Not found
} else {
- Slice handle = iiter->value();
Iterator* block_iter = BlockReader(this, options, iiter->value());
block_iter->Seek(k);
if (block_iter->Valid()) {
diff --git a/table/table_test.cc b/table/table_test.cc
index 57cea25..c723bf8 100644
--- a/table/table_test.cc
+++ b/table/table_test.cc
@@ -644,6 +644,36 @@ class Harness {
Constructor* constructor_;
};
+// Test empty table/block.
+TEST(Harness, Empty) {
+ for (int i = 0; i < kNumTestArgs; i++) {
+ Init(kTestArgList[i]);
+ Random rnd(test::RandomSeed() + 1);
+ Test(&rnd);
+ }
+}
+
+// Special test for a block with no restart entries. The C++ leveldb
+// code never generates such blocks, but the Java version of leveldb
+// seems to.
+TEST(Harness, ZeroRestartPointsInBlock) {
+ char data[sizeof(uint32_t)];
+ memset(data, 0, sizeof(data));
+ BlockContents contents;
+ contents.data = Slice(data, sizeof(data));
+ contents.cachable = false;
+ contents.heap_allocated = false;
+ Block block(contents);
+ Iterator* iter = block.NewIterator(BytewiseComparator());
+ iter->SeekToFirst();
+ ASSERT_TRUE(!iter->Valid());
+ iter->SeekToLast();
+ ASSERT_TRUE(!iter->Valid());
+ iter->Seek("foo");
+ ASSERT_TRUE(!iter->Valid());
+ delete iter;
+}
+
// Test the empty key
TEST(Harness, SimpleEmptyKey) {
for (int i = 0; i < kNumTestArgs; i++) {