Release leveldb 1.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.
This commit is contained in:
parent
514c943a8e
commit
28dad918f2
1
.gitignore
vendored
1
.gitignore
vendored
@ -6,3 +6,4 @@ build_config.mk
|
|||||||
*.so.*
|
*.so.*
|
||||||
*_test
|
*_test
|
||||||
db_bench
|
db_bench
|
||||||
|
leveldbutil
|
||||||
|
4
Makefile
4
Makefile
@ -12,7 +12,7 @@ OPT ?= -O2 -DNDEBUG # (A) Production use (optimized mode)
|
|||||||
#-----------------------------------------------
|
#-----------------------------------------------
|
||||||
|
|
||||||
# detect what platform we're building on
|
# detect what platform we're building on
|
||||||
$(shell CC=$(CC) CXX=$(CXX) TARGET_OS=$(TARGET_OS) \
|
$(shell CC="$(CC)" CXX="$(CXX)" TARGET_OS="$(TARGET_OS)" \
|
||||||
./build_detect_platform build_config.mk ./)
|
./build_detect_platform build_config.mk ./)
|
||||||
# this file is generated by the previous line to set build flags and sources
|
# this file is generated by the previous line to set build flags and sources
|
||||||
include build_config.mk
|
include build_config.mk
|
||||||
@ -69,7 +69,7 @@ SHARED = $(SHARED1)
|
|||||||
else
|
else
|
||||||
# Update db.h if you change these.
|
# Update db.h if you change these.
|
||||||
SHARED_MAJOR = 1
|
SHARED_MAJOR = 1
|
||||||
SHARED_MINOR = 9
|
SHARED_MINOR = 10
|
||||||
SHARED1 = libleveldb.$(PLATFORM_SHARED_EXT)
|
SHARED1 = libleveldb.$(PLATFORM_SHARED_EXT)
|
||||||
SHARED2 = $(SHARED1).$(SHARED_MAJOR)
|
SHARED2 = $(SHARED1).$(SHARED_MAJOR)
|
||||||
SHARED3 = $(SHARED1).$(SHARED_MAJOR).$(SHARED_MINOR)
|
SHARED3 = $(SHARED1).$(SHARED_MAJOR).$(SHARED_MINOR)
|
||||||
|
@ -44,6 +44,10 @@ if test -z "$CXX"; then
|
|||||||
CXX=g++
|
CXX=g++
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if test -z "$TMPDIR"; then
|
||||||
|
TMPDIR=/tmp
|
||||||
|
fi
|
||||||
|
|
||||||
# Detect OS
|
# Detect OS
|
||||||
if test -z "$TARGET_OS"; then
|
if test -z "$TARGET_OS"; then
|
||||||
TARGET_OS=`uname -s`
|
TARGET_OS=`uname -s`
|
||||||
@ -155,8 +159,10 @@ if [ "$CROSS_COMPILE" = "true" ]; then
|
|||||||
# Cross-compiling; do not try any compilation tests.
|
# Cross-compiling; do not try any compilation tests.
|
||||||
true
|
true
|
||||||
else
|
else
|
||||||
|
CXXOUTPUT="${TMPDIR}/leveldb_build_detect_platform-cxx.$$"
|
||||||
|
|
||||||
# If -std=c++0x works, use <cstdatomic>. Otherwise use port_posix.h.
|
# If -std=c++0x works, use <cstdatomic>. Otherwise use port_posix.h.
|
||||||
$CXX $CXXFLAGS -std=c++0x -x c++ - -o /dev/null 2>/dev/null <<EOF
|
$CXX $CXXFLAGS -std=c++0x -x c++ - -o $CXXOUTPUT 2>/dev/null <<EOF
|
||||||
#include <cstdatomic>
|
#include <cstdatomic>
|
||||||
int main() {}
|
int main() {}
|
||||||
EOF
|
EOF
|
||||||
@ -169,7 +175,7 @@ EOF
|
|||||||
|
|
||||||
# Test whether Snappy library is installed
|
# Test whether Snappy library is installed
|
||||||
# http://code.google.com/p/snappy/
|
# http://code.google.com/p/snappy/
|
||||||
$CXX $CXXFLAGS -x c++ - -o /dev/null 2>/dev/null <<EOF
|
$CXX $CXXFLAGS -x c++ - -o $CXXOUTPUT 2>/dev/null <<EOF
|
||||||
#include <snappy.h>
|
#include <snappy.h>
|
||||||
int main() {}
|
int main() {}
|
||||||
EOF
|
EOF
|
||||||
@ -179,12 +185,14 @@ EOF
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# Test whether tcmalloc is available
|
# Test whether tcmalloc is available
|
||||||
$CXX $CXXFLAGS -x c++ - -o /dev/null -ltcmalloc 2>/dev/null <<EOF
|
$CXX $CXXFLAGS -x c++ - -o $CXXOUTPUT -ltcmalloc 2>/dev/null <<EOF
|
||||||
int main() {}
|
int main() {}
|
||||||
EOF
|
EOF
|
||||||
if [ "$?" = 0 ]; then
|
if [ "$?" = 0 ]; then
|
||||||
PLATFORM_LIBS="$PLATFORM_LIBS -ltcmalloc"
|
PLATFORM_LIBS="$PLATFORM_LIBS -ltcmalloc"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
rm -f $CXXOUTPUT 2>/dev/null
|
||||||
fi
|
fi
|
||||||
|
|
||||||
PLATFORM_CCFLAGS="$PLATFORM_CCFLAGS $COMMON_FLAGS"
|
PLATFORM_CCFLAGS="$PLATFORM_CCFLAGS $COMMON_FLAGS"
|
||||||
|
@ -1276,10 +1276,11 @@ Status DBImpl::MakeRoomForWrite(bool force) {
|
|||||||
} else if (imm_ != NULL) {
|
} else if (imm_ != NULL) {
|
||||||
// We have filled up the current memtable, but the previous
|
// We have filled up the current memtable, but the previous
|
||||||
// one is still being compacted, so we wait.
|
// one is still being compacted, so we wait.
|
||||||
|
Log(options_.info_log, "Current memtable full; waiting...\n");
|
||||||
bg_cv_.Wait();
|
bg_cv_.Wait();
|
||||||
} else if (versions_->NumLevelFiles(0) >= config::kL0_StopWritesTrigger) {
|
} else if (versions_->NumLevelFiles(0) >= config::kL0_StopWritesTrigger) {
|
||||||
// There are too many level-0 files.
|
// There are too many level-0 files.
|
||||||
Log(options_.info_log, "waiting...\n");
|
Log(options_.info_log, "Too many L0 files; waiting...\n");
|
||||||
bg_cv_.Wait();
|
bg_cv_.Wait();
|
||||||
} else {
|
} else {
|
||||||
// Attempt to switch to a new memtable and trigger compaction of old
|
// Attempt to switch to a new memtable and trigger compaction of old
|
||||||
|
@ -26,7 +26,7 @@ std::string ParsedInternalKey::DebugString() const {
|
|||||||
(unsigned long long) sequence,
|
(unsigned long long) sequence,
|
||||||
int(type));
|
int(type));
|
||||||
std::string result = "'";
|
std::string result = "'";
|
||||||
result += user_key.ToString();
|
result += EscapeString(user_key.ToString());
|
||||||
result += buf;
|
result += buf;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,7 @@ namespace leveldb {
|
|||||||
|
|
||||||
// Update Makefile if you change these
|
// Update Makefile if you change these
|
||||||
static const int kMajorVersion = 1;
|
static const int kMajorVersion = 1;
|
||||||
static const int kMinorVersion = 9;
|
static const int kMinorVersion = 10;
|
||||||
|
|
||||||
struct Options;
|
struct Options;
|
||||||
struct ReadOptions;
|
struct ReadOptions;
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
namespace leveldb {
|
namespace leveldb {
|
||||||
|
|
||||||
inline uint32_t Block::NumRestarts() const {
|
inline uint32_t Block::NumRestarts() const {
|
||||||
assert(size_ >= 2*sizeof(uint32_t));
|
assert(size_ >= sizeof(uint32_t));
|
||||||
return DecodeFixed32(data_ + 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)) {
|
if (size_ < sizeof(uint32_t)) {
|
||||||
size_ = 0; // Error marker
|
size_ = 0; // Error marker
|
||||||
} else {
|
} else {
|
||||||
restart_offset_ = size_ - (1 + NumRestarts()) * sizeof(uint32_t);
|
size_t max_restarts_allowed = (size_-sizeof(uint32_t)) / sizeof(uint32_t);
|
||||||
if (restart_offset_ > size_ - sizeof(uint32_t)) {
|
if (NumRestarts() > max_restarts_allowed) {
|
||||||
// The size is too small for NumRestarts() and therefore
|
// The size is too small for NumRestarts()
|
||||||
// restart_offset_ wrapped around.
|
|
||||||
size_ = 0;
|
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) {
|
Iterator* Block::NewIterator(const Comparator* cmp) {
|
||||||
if (size_ < 2*sizeof(uint32_t)) {
|
if (size_ < sizeof(uint32_t)) {
|
||||||
return NewErrorIterator(Status::Corruption("bad block contents"));
|
return NewErrorIterator(Status::Corruption("bad block contents"));
|
||||||
}
|
}
|
||||||
const uint32_t num_restarts = NumRestarts();
|
const uint32_t num_restarts = NumRestarts();
|
||||||
|
@ -228,7 +228,6 @@ Status Table::InternalGet(const ReadOptions& options, const Slice& k,
|
|||||||
!filter->KeyMayMatch(handle.offset(), k)) {
|
!filter->KeyMayMatch(handle.offset(), k)) {
|
||||||
// Not found
|
// Not found
|
||||||
} else {
|
} else {
|
||||||
Slice handle = iiter->value();
|
|
||||||
Iterator* block_iter = BlockReader(this, options, iiter->value());
|
Iterator* block_iter = BlockReader(this, options, iiter->value());
|
||||||
block_iter->Seek(k);
|
block_iter->Seek(k);
|
||||||
if (block_iter->Valid()) {
|
if (block_iter->Valid()) {
|
||||||
|
@ -644,6 +644,36 @@ class Harness {
|
|||||||
Constructor* constructor_;
|
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 the empty key
|
||||||
TEST(Harness, SimpleEmptyKey) {
|
TEST(Harness, SimpleEmptyKey) {
|
||||||
for (int i = 0; i < kNumTestArgs; i++) {
|
for (int i = 0; i < kNumTestArgs; i++) {
|
||||||
|
@ -116,7 +116,6 @@ class HandleTable {
|
|||||||
LRUHandle* h = list_[i];
|
LRUHandle* h = list_[i];
|
||||||
while (h != NULL) {
|
while (h != NULL) {
|
||||||
LRUHandle* next = h->next_hash;
|
LRUHandle* next = h->next_hash;
|
||||||
Slice key = h->key();
|
|
||||||
uint32_t hash = h->hash;
|
uint32_t hash = h->hash;
|
||||||
LRUHandle** ptr = &new_list[hash & (new_length - 1)];
|
LRUHandle** ptr = &new_list[hash & (new_length - 1)];
|
||||||
h->next_hash = *ptr;
|
h->next_hash = *ptr;
|
||||||
@ -160,7 +159,6 @@ class LRUCache {
|
|||||||
// mutex_ protects the following state.
|
// mutex_ protects the following state.
|
||||||
port::Mutex mutex_;
|
port::Mutex mutex_;
|
||||||
size_t usage_;
|
size_t usage_;
|
||||||
uint64_t last_id_;
|
|
||||||
|
|
||||||
// Dummy head of LRU list.
|
// Dummy head of LRU list.
|
||||||
// lru.prev is newest entry, lru.next is oldest entry.
|
// lru.prev is newest entry, lru.next is oldest entry.
|
||||||
@ -170,8 +168,7 @@ class LRUCache {
|
|||||||
};
|
};
|
||||||
|
|
||||||
LRUCache::LRUCache()
|
LRUCache::LRUCache()
|
||||||
: usage_(0),
|
: usage_(0) {
|
||||||
last_id_(0) {
|
|
||||||
// Make empty circular linked list
|
// Make empty circular linked list
|
||||||
lru_.next = &lru_;
|
lru_.next = &lru_;
|
||||||
lru_.prev = &lru_;
|
lru_.prev = &lru_;
|
||||||
|
@ -385,7 +385,7 @@ class PosixEnv : public Env {
|
|||||||
PosixEnv();
|
PosixEnv();
|
||||||
virtual ~PosixEnv() {
|
virtual ~PosixEnv() {
|
||||||
fprintf(stderr, "Destroying Env::Default()\n");
|
fprintf(stderr, "Destroying Env::Default()\n");
|
||||||
exit(1);
|
abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual Status NewSequentialFile(const std::string& fname,
|
virtual Status NewSequentialFile(const std::string& fname,
|
||||||
@ -588,7 +588,7 @@ class PosixEnv : public Env {
|
|||||||
void PthreadCall(const char* label, int result) {
|
void PthreadCall(const char* label, int result) {
|
||||||
if (result != 0) {
|
if (result != 0) {
|
||||||
fprintf(stderr, "pthread %s: %s\n", label, strerror(result));
|
fprintf(stderr, "pthread %s: %s\n", label, strerror(result));
|
||||||
exit(1);
|
abort();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user