aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorsanjay@google.com <sanjay@google.com@62dab493-f737-651d-591e-8d6aee1b9529>2012-05-30 16:53:11 +0000
committersanjay@google.com <sanjay@google.com@62dab493-f737-651d-591e-8d6aee1b9529>2012-05-30 16:53:11 +0000
commit158f767acaed4c39cbb3ee8128fe896e155ec40c (patch)
tree8a669f037e1a75ff34b30fda28ab1184fdcb6946
parent99a7585544fc162a5f8dd39a6add00776a981efe (diff)
downloadsrc-158f767acaed4c39cbb3ee8128fe896e155ec40c.tar.gz
Remove static initializer; fix endian-ness detection; fix build on various platforms; improve android port speed
git-svn-id: http://leveldb.googlecode.com/svn/trunk@66 62dab493-f737-651d-591e-8d6aee1b9529
-rw-r--r--Makefile27
-rw-r--r--build_detect_platform37
-rw-r--r--db/c_test.c11
-rw-r--r--db/db_bench.cc10
-rw-r--r--db/db_impl.cc23
-rw-r--r--db/db_impl.h2
-rw-r--r--db/db_test.cc63
-rw-r--r--db/version_set.cc4
-rw-r--r--db/version_set.h9
-rw-r--r--doc/bench/db_bench_sqlite3.cc28
-rw-r--r--doc/bench/db_bench_tree_db.cc30
-rw-r--r--port/atomic_pointer.h18
-rw-r--r--port/port.h2
-rw-r--r--port/port_android.cc64
-rw-r--r--port/port_android.h159
-rw-r--r--port/port_example.h10
-rw-r--r--port/port_posix.cc4
-rw-r--r--port/port_posix.h33
-rw-r--r--util/coding_test.cc23
-rw-r--r--util/comparator.cc11
20 files changed, 283 insertions, 285 deletions
diff --git a/Makefile b/Makefile
index b961ba1..5cd9d37 100644
--- a/Makefile
+++ b/Makefile
@@ -3,8 +3,6 @@
# found in the LICENSE file. See the AUTHORS file for names of contributors.
# Inherit some settings from environment variables, if available
-CXX ?= g++
-CC ?= gcc
INSTALL_PATH ?= $(CURDIR)
#-----------------------------------------------
@@ -63,6 +61,13 @@ default: all
# Should we build shared libraries?
ifneq ($(PLATFORM_SHARED_EXT),)
+
+ifneq ($(PLATFORM_SHARED_VERSIONED),true)
+SHARED1 = libleveldb.$(PLATFORM_SHARED_EXT)
+SHARED2 = $(SHARED1)
+SHARED3 = $(SHARED1)
+SHARED = $(SHARED1)
+else
# Update db.h if you change these.
SHARED_MAJOR = 1
SHARED_MINOR = 4
@@ -70,14 +75,17 @@ SHARED1 = libleveldb.$(PLATFORM_SHARED_EXT)
SHARED2 = $(SHARED1).$(SHARED_MAJOR)
SHARED3 = $(SHARED1).$(SHARED_MAJOR).$(SHARED_MINOR)
SHARED = $(SHARED1) $(SHARED2) $(SHARED3)
-$(SHARED3):
- $(CXX) $(LDFLAGS) $(PLATFORM_SHARED_LDFLAGS)$(INSTALL_PATH)/$(SHARED2) $(CXXFLAGS) $(PLATFORM_SHARED_CFLAGS) $(SOURCES) -o $(SHARED3)
-$(SHARED2): $(SHARED3)
- ln -fs $(SHARED3) $(SHARED2)
$(SHARED1): $(SHARED3)
ln -fs $(SHARED3) $(SHARED1)
+$(SHARED2): $(SHARED3)
+ ln -fs $(SHARED3) $(SHARED2)
endif
+$(SHARED3):
+ $(CXX) $(LDFLAGS) $(PLATFORM_SHARED_LDFLAGS)$(SHARED2) $(CXXFLAGS) $(PLATFORM_SHARED_CFLAGS) $(SOURCES) -o $(SHARED3)
+
+endif # PLATFORM_SHARED_EXT
+
all: $(SHARED) $(LIBRARY)
check: all $(PROGRAMS) $(TESTS)
@@ -164,9 +172,10 @@ memenv_test : helpers/memenv/memenv_test.o $(MEMENVLIBRARY) $(LIBRARY) $(TESTHAR
ifeq ($(PLATFORM), IOS)
# For iOS, create universal object files to be used on both the simulator and
# a device.
-SIMULATORROOT=/Developer/Platforms/iPhoneSimulator.platform/Developer
-DEVICEROOT=/Developer/Platforms/iPhoneOS.platform/Developer
-IOSVERSION=$(shell defaults read /Developer/Platforms/iPhoneOS.platform/version CFBundleShortVersionString)
+PLATFORMSROOT=/Applications/Xcode.app/Contents/Developer/Platforms
+SIMULATORROOT=$(PLATFORMSROOT)/iPhoneSimulator.platform/Developer
+DEVICEROOT=$(PLATFORMSROOT)/iPhoneOS.platform/Developer
+IOSVERSION=$(shell defaults read $(PLATFORMSROOT)/iPhoneOS.platform/version CFBundleShortVersionString)
.cc.o:
mkdir -p ios-x86/$(dir $@)
diff --git a/build_detect_platform b/build_detect_platform
index b71bf02..959a7d6 100644
--- a/build_detect_platform
+++ b/build_detect_platform
@@ -4,18 +4,27 @@
# argument, which in turn gets read while processing Makefile.
#
# The output will set the following variables:
+# CC C Compiler path
+# CXX C++ Compiler path
# PLATFORM_LDFLAGS Linker flags
# PLATFORM_SHARED_EXT Extension for shared libraries
# PLATFORM_SHARED_LDFLAGS Flags for building shared library
# PLATFORM_SHARED_CFLAGS Flags for compiling objects for shared library
# PLATFORM_CCFLAGS C compiler flags
# PLATFORM_CXXFLAGS C++ compiler flags. Will contain:
-# -DLEVELDB_PLATFORM_POSIX if cstdatomic is present
-# -DLEVELDB_PLATFORM_NOATOMIC if it is not
+# PLATFORM_SHARED_VERSIONED Set to 'true' if platform supports versioned
+# shared libraries, empty otherwise.
+#
+# The PLATFORM_CCFLAGS and PLATFORM_CXXFLAGS might include the following:
+#
+# -DLEVELDB_CSTDATOMIC_PRESENT if <cstdatomic> is present
+# -DLEVELDB_PLATFORM_POSIX for Posix-based platforms
+# -DSNAPPY if the Snappy library is present
+#
OUTPUT=$1
if test -z "$OUTPUT"; then
- echo "usage: $0 <output-filename>"
+ echo "usage: $0 <output-filename>" >&2
exit 1
fi
@@ -23,6 +32,10 @@ fi
rm -f $OUTPUT
touch $OUTPUT
+if test -z "$CC"; then
+ CC=cc
+fi
+
if test -z "$CXX"; then
CXX=g++
fi
@@ -33,12 +46,14 @@ if test -z "$TARGET_OS"; then
fi
COMMON_FLAGS=
+CROSS_COMPILE=
PLATFORM_CCFLAGS=
PLATFORM_CXXFLAGS=
PLATFORM_LDFLAGS=
PLATFORM_SHARED_EXT="so"
PLATFORM_SHARED_LDFLAGS="-shared -Wl,-soname -Wl,"
PLATFORM_SHARED_CFLAGS="-fPIC"
+PLATFORM_SHARED_VERSIONED=true
# On GCC, we pick libc's memcmp over GCC's memcmp via -fno-builtin-memcmp
case "$TARGET_OS" in
@@ -86,13 +101,14 @@ case "$TARGET_OS" in
PORT_FILE=port/port_posix.cc
;;
OS_ANDROID_CROSSCOMPILE)
- PLATFORM="$TARGET_OS"
- COMMON_FLAGS=""
- PLATFORM_LDFLAGS=""
- PORT_FILE=port/port_android.cc
+ PLATFORM=OS_ANDROID
+ COMMON_FLAGS="-fno-builtin-memcmp -D_REENTRANT -DOS_ANDROID -DLEVELDB_PLATFORM_POSIX"
+ PLATFORM_LDFLAGS="" # All pthread features are in the Android C library
+ PORT_FILE=port/port_posix.cc
+ CROSS_COMPILE=true
;;
*)
- echo "Unknown platform!"
+ echo "Unknown platform!" >&2
exit 1
esac
@@ -112,7 +128,7 @@ set +f # re-enable globbing
echo "SOURCES=$PORTABLE_FILES $PORT_FILE" >> $OUTPUT
echo "MEMENV_SOURCES=helpers/memenv/memenv.cc" >> $OUTPUT
-if [ "$PLATFORM" = "OS_ANDROID_CROSSCOMPILE" ]; then
+if [ "$CROSS_COMPILE" = "true" ]; then
# Cross-compiling; do not try any compilation tests.
true
else
@@ -151,6 +167,8 @@ fi
PLATFORM_CCFLAGS="$PLATFORM_CCFLAGS $COMMON_FLAGS"
PLATFORM_CXXFLAGS="$PLATFORM_CXXFLAGS $COMMON_FLAGS"
+echo "CC=$CC" >> $OUTPUT
+echo "CXX=$CXX" >> $OUTPUT
echo "PLATFORM=$PLATFORM" >> $OUTPUT
echo "PLATFORM_LDFLAGS=$PLATFORM_LDFLAGS" >> $OUTPUT
echo "PLATFORM_CCFLAGS=$PLATFORM_CCFLAGS" >> $OUTPUT
@@ -158,3 +176,4 @@ echo "PLATFORM_CXXFLAGS=$PLATFORM_CXXFLAGS" >> $OUTPUT
echo "PLATFORM_SHARED_CFLAGS=$PLATFORM_SHARED_CFLAGS" >> $OUTPUT
echo "PLATFORM_SHARED_EXT=$PLATFORM_SHARED_EXT" >> $OUTPUT
echo "PLATFORM_SHARED_LDFLAGS=$PLATFORM_SHARED_LDFLAGS" >> $OUTPUT
+echo "PLATFORM_SHARED_VERSIONED=$PLATFORM_SHARED_VERSIONED" >> $OUTPUT
diff --git a/db/c_test.c b/db/c_test.c
index 12b4424..9792447 100644
--- a/db/c_test.c
+++ b/db/c_test.c
@@ -19,6 +19,13 @@ static void StartPhase(const char* name) {
phase = name;
}
+static const char* GetTempDir(void) {
+ const char* ret = getenv("TEST_TMPDIR");
+ if (ret == NULL || ret[0] == '\0')
+ ret = "/tmp";
+ return ret;
+}
+
#define CheckNoError(err) \
if ((err) != NULL) { \
fprintf(stderr, "%s:%d: %s: %s\n", __FILE__, __LINE__, phase, (err)); \
@@ -158,7 +165,9 @@ int main(int argc, char** argv) {
char* err = NULL;
int run = -1;
- snprintf(dbname, sizeof(dbname), "/tmp/leveldb_c_test-%d",
+ snprintf(dbname, sizeof(dbname),
+ "%s/leveldb_c_test-%d",
+ GetTempDir(),
((int) geteuid()));
StartPhase("create_objects");
diff --git a/db/db_bench.cc b/db/db_bench.cc
index b0c3995..21d3e25 100644
--- a/db/db_bench.cc
+++ b/db/db_bench.cc
@@ -100,7 +100,7 @@ static int FLAGS_bloom_bits = -1;
static bool FLAGS_use_existing_db = false;
// Use the db with the following name.
-static const char* FLAGS_db = "/tmp/dbbench";
+static const char* FLAGS_db = NULL;
namespace leveldb {
@@ -925,6 +925,7 @@ class Benchmark {
int main(int argc, char** argv) {
FLAGS_write_buffer_size = leveldb::Options().write_buffer_size;
FLAGS_open_files = leveldb::Options().max_open_files;
+ std::string default_db_path;
for (int i = 1; i < argc; i++) {
double d;
@@ -964,6 +965,13 @@ int main(int argc, char** argv) {
}
}
+ // Choose a location for the test database if none given with --db=<path>
+ if (FLAGS_db == NULL) {
+ leveldb::Env::Default()->GetTestDirectory(&default_db_path);
+ default_db_path += "/dbbench";
+ FLAGS_db = default_db_path.c_str();
+ }
+
leveldb::Benchmark benchmark;
benchmark.Run();
return 0;
diff --git a/db/db_impl.cc b/db/db_impl.cc
index c9c9023..90c1c81 100644
--- a/db/db_impl.cc
+++ b/db/db_impl.cc
@@ -608,8 +608,21 @@ void DBImpl::BackgroundCall() {
MutexLock l(&mutex_);
assert(bg_compaction_scheduled_);
if (!shutting_down_.Acquire_Load()) {
- BackgroundCompaction();
+ Status s = BackgroundCompaction();
+ if (!s.ok()) {
+ // Wait a little bit before retrying background compaction in
+ // case this is an environmental problem and we do not want to
+ // chew up resources for failed compactions for the duration of
+ // the problem.
+ bg_cv_.SignalAll(); // In case a waiter can proceed despite the error
+ Log(options_.info_log, "Waiting after background compaction error: %s",
+ s.ToString().c_str());
+ mutex_.Unlock();
+ env_->SleepForMicroseconds(1000000);
+ mutex_.Lock();
+ }
}
+
bg_compaction_scheduled_ = false;
// Previous compaction may have produced too many files in a level,
@@ -618,12 +631,11 @@ void DBImpl::BackgroundCall() {
bg_cv_.SignalAll();
}
-void DBImpl::BackgroundCompaction() {
+Status DBImpl::BackgroundCompaction() {
mutex_.AssertHeld();
if (imm_ != NULL) {
- CompactMemTable();
- return;
+ return CompactMemTable();
}
Compaction* c;
@@ -698,6 +710,7 @@ void DBImpl::BackgroundCompaction() {
}
manual_compaction_ = NULL;
}
+ return status;
}
void DBImpl::CleanupCompaction(CompactionState* compact) {
@@ -1263,6 +1276,8 @@ Status DBImpl::MakeRoomForWrite(bool force) {
WritableFile* lfile = NULL;
s = env_->NewWritableFile(LogFileName(dbname_, new_log_number), &lfile);
if (!s.ok()) {
+ // Avoid chewing through file number space in a tight loop.
+ versions_->ReuseFileNumber(new_log_number);
break;
}
delete log_;
diff --git a/db/db_impl.h b/db/db_impl.h
index 2f8b523..8d2bb34 100644
--- a/db/db_impl.h
+++ b/db/db_impl.h
@@ -94,7 +94,7 @@ class DBImpl : public DB {
void MaybeScheduleCompaction();
static void BGWork(void* db);
void BackgroundCall();
- void BackgroundCompaction();
+ Status BackgroundCompaction();
void CleanupCompaction(CompactionState* compact);
Status DoCompactionWork(CompactionState* compact);
diff --git a/db/db_test.cc b/db/db_test.cc
index ee10807..3744d0e 100644
--- a/db/db_test.cc
+++ b/db/db_test.cc
@@ -56,12 +56,18 @@ class SpecialEnv : public EnvWrapper {
// Simulate no-space errors while this pointer is non-NULL.
port::AtomicPointer no_space_;
+ // Simulate non-writable file system while this pointer is non-NULL
+ port::AtomicPointer non_writable_;
+
bool count_random_reads_;
AtomicCounter random_read_counter_;
+ AtomicCounter sleep_counter_;
+
explicit SpecialEnv(Env* base) : EnvWrapper(base) {
delay_sstable_sync_.Release_Store(NULL);
no_space_.Release_Store(NULL);
+ non_writable_.Release_Store(NULL);
count_random_reads_ = false;
}
@@ -95,6 +101,10 @@ class SpecialEnv : public EnvWrapper {
}
};
+ if (non_writable_.Acquire_Load() != NULL) {
+ return Status::IOError("simulated write error");
+ }
+
Status s = target()->NewWritableFile(f, r);
if (s.ok()) {
if (strstr(f.c_str(), ".sst") != NULL) {
@@ -127,6 +137,11 @@ class SpecialEnv : public EnvWrapper {
}
return s;
}
+
+ virtual void SleepForMicroseconds(int micros) {
+ sleep_counter_.Increment();
+ target()->SleepForMicroseconds(micros);
+ }
};
class DBTest {
@@ -137,6 +152,7 @@ class DBTest {
enum OptionConfig {
kDefault,
kFilter,
+ kUncompressed,
kEnd
};
int option_config_;
@@ -167,10 +183,10 @@ class DBTest {
// Switch to a fresh database with the next option configuration to
// test. Return false if there are no more configurations to test.
bool ChangeOptions() {
- if (option_config_ == kEnd) {
+ option_config_++;
+ if (option_config_ >= kEnd) {
return false;
} else {
- option_config_++;
DestroyAndReopen();
return true;
}
@@ -183,6 +199,9 @@ class DBTest {
case kFilter:
options.filter_policy = filter_policy_;
break;
+ case kUncompressed:
+ options.compression = kNoCompression;
+ break;
default:
break;
}
@@ -552,13 +571,15 @@ TEST(DBTest, GetEncountersEmptyLevel) {
ASSERT_EQ(NumTableFilesAtLevel(1), 0);
ASSERT_EQ(NumTableFilesAtLevel(2), 1);
- // Step 3: read until level 0 compaction disappears.
- int read_count = 0;
- while (NumTableFilesAtLevel(0) > 0) {
- ASSERT_LE(read_count, 10000) << "did not trigger level 0 compaction";
- read_count++;
+ // Step 3: read a bunch of times
+ for (int i = 0; i < 1000; i++) {
ASSERT_EQ("NOT_FOUND", Get("missing"));
}
+
+ // Step 4: Wait for compaction to finish
+ env_->SleepForMicroseconds(1000000);
+
+ ASSERT_EQ(NumTableFilesAtLevel(0), 0);
} while (ChangeOptions());
}
@@ -1432,13 +1453,37 @@ TEST(DBTest, NoSpace) {
Compact("a", "z");
const int num_files = CountFiles();
env_->no_space_.Release_Store(env_); // Force out-of-space errors
- for (int i = 0; i < 10; i++) {
+ env_->sleep_counter_.Reset();
+ for (int i = 0; i < 5; i++) {
for (int level = 0; level < config::kNumLevels-1; level++) {
dbfull()->TEST_CompactRange(level, NULL, NULL);
}
}
env_->no_space_.Release_Store(NULL);
- ASSERT_LT(CountFiles(), num_files + 5);
+ ASSERT_LT(CountFiles(), num_files + 3);
+
+ // Check that compaction attempts slept after errors
+ ASSERT_GE(env_->sleep_counter_.Read(), 5);
+}
+
+TEST(DBTest, NonWritableFileSystem) {
+ Options options = CurrentOptions();
+ options.write_buffer_size = 1000;
+ options.env = env_;
+ Reopen(&options);
+ ASSERT_OK(Put("foo", "v1"));
+ env_->non_writable_.Release_Store(env_); // Force errors for new files
+ std::string big(100000, 'x');
+ int errors = 0;
+ for (int i = 0; i < 20; i++) {
+ fprintf(stderr, "iter %d; errors %d\n", i, errors);
+ if (!Put("foo", big).ok()) {
+ errors++;
+ env_->SleepForMicroseconds(100000);
+ }
+ }
+ ASSERT_GT(errors, 0);
+ env_->non_writable_.Release_Store(NULL);
}
TEST(DBTest, FilesDeletedAfterCompaction) {
diff --git a/db/version_set.cc b/db/version_set.cc
index 1f48419..cf976b4 100644
--- a/db/version_set.cc
+++ b/db/version_set.cc
@@ -132,7 +132,7 @@ bool SomeFileOverlapsRange(
const Comparator* ucmp = icmp.user_comparator();
if (!disjoint_sorted_files) {
// Need to check against all files
- for (int i = 0; i < files.size(); i++) {
+ for (size_t i = 0; i < files.size(); i++) {
const FileMetaData* f = files[i];
if (AfterFile(ucmp, smallest_user_key, f) ||
BeforeFile(ucmp, largest_user_key, f)) {
@@ -1297,7 +1297,7 @@ Compaction* VersionSet::CompactRange(
// Avoid compacting too much in one shot in case the range is large.
const uint64_t limit = MaxFileSizeForLevel(level);
uint64_t total = 0;
- for (int i = 0; i < inputs.size(); i++) {
+ for (size_t i = 0; i < inputs.size(); i++) {
uint64_t s = inputs[i]->file_size;
total += s;
if (total >= limit) {
diff --git a/db/version_set.h b/db/version_set.h
index 572602e..61c4c99 100644
--- a/db/version_set.h
+++ b/db/version_set.h
@@ -173,6 +173,15 @@ class VersionSet {
// Allocate and return a new file number
uint64_t NewFileNumber() { return next_file_number_++; }
+ // Arrange to reuse "file_number" unless a newer file number has
+ // already been allocated.
+ // REQUIRES: "file_number" was returned by a call to NewFileNumber().
+ void ReuseFileNumber(uint64_t file_number) {
+ if (next_file_number_ == file_number + 1) {
+ next_file_number_ = file_number;
+ }
+ }
+
// Return the number of Table files at the specified level.
int NumLevelFiles(int level) const;
diff --git a/doc/bench/db_bench_sqlite3.cc b/doc/bench/db_bench_sqlite3.cc
index 6951a14..256793a 100644
--- a/doc/bench/db_bench_sqlite3.cc
+++ b/doc/bench/db_bench_sqlite3.cc
@@ -75,6 +75,9 @@ static bool FLAGS_transaction = true;
// If true, we enable Write-Ahead Logging
static bool FLAGS_WAL_enabled = true;
+// Use the db with the following name.
+static const char* FLAGS_db = NULL;
+
inline
static void ExecErrorCheck(int status, char *err_msg) {
if (status != SQLITE_OK) {
@@ -317,11 +320,16 @@ class Benchmark {
bytes_(0),
rand_(301) {
std::vector<std::string> files;
- Env::Default()->GetChildren("/tmp", &files);
+ std::string test_dir;
+ Env::Default()->GetTestDirectory(&test_dir);
+ Env::Default()->GetChildren(test_dir, &files);
if (!FLAGS_use_existing_db) {
for (int i = 0; i < files.size(); i++) {
if (Slice(files[i]).starts_with("dbbench_sqlite3")) {
- Env::Default()->DeleteFile("/tmp/" + files[i]);
+ std::string file_name(test_dir);
+ file_name += "/";
+ file_name += files[i];
+ Env::Default()->DeleteFile(file_name.c_str());
}
}
}
@@ -415,7 +423,11 @@ class Benchmark {
db_num_++;
// Open database
- snprintf(file_name, sizeof(file_name), "/tmp/dbbench_sqlite3-%d.db",
+ std::string tmp_dir;
+ Env::Default()->GetTestDirectory(&tmp_dir);
+ snprintf(file_name, sizeof(file_name),
+ "%s/dbbench_sqlite3-%d.db",
+ tmp_dir.c_str(),
db_num_);
status = sqlite3_open(file_name, &db_);
if (status) {
@@ -655,6 +667,7 @@ class Benchmark {
} // namespace leveldb
int main(int argc, char** argv) {
+ std::string default_db_path;
for (int i = 1; i < argc; i++) {
double d;
int n;
@@ -684,12 +697,21 @@ int main(int argc, char** argv) {
} else if (sscanf(argv[i], "--WAL_enabled=%d%c", &n, &junk) == 1 &&
(n == 0 || n == 1)) {
FLAGS_WAL_enabled = n;
+ } else if (strncmp(argv[i], "--db=", 5) == 0) {
+ FLAGS_db = argv[i] + 5;
} else {
fprintf(stderr, "Invalid flag '%s'\n", argv[i]);
exit(1);
}
}
+ // Choose a location for the test database if none given with --db=<path>
+ if (FLAGS_db == NULL) {
+ leveldb::Env::Default()->GetTestDirectory(&default_db_path);
+ default_db_path += "/dbbench";
+ FLAGS_db = default_db_path.c_str();
+ }
+
leveldb::Benchmark benchmark;
benchmark.Run();
return 0;
diff --git a/doc/bench/db_bench_tree_db.cc b/doc/bench/db_bench_tree_db.cc
index 214d9b7..ed86f03 100644
--- a/doc/bench/db_bench_tree_db.cc
+++ b/doc/bench/db_bench_tree_db.cc
@@ -68,6 +68,9 @@ static bool FLAGS_use_existing_db = false;
// is off.
static bool FLAGS_compression = true;
+// Use the db with the following name.
+static const char* FLAGS_db = NULL;
+
inline
static void DBSynchronize(kyotocabinet::TreeDB* db_)
{
@@ -292,11 +295,16 @@ class Benchmark {
bytes_(0),
rand_(301) {
std::vector<std::string> files;
- Env::Default()->GetChildren("/tmp", &files);
+ std::string test_dir;
+ Env::Default()->GetTestDirectory(&test_dir);
+ Env::Default()->GetChildren(test_dir.c_str(), &files);
if (!FLAGS_use_existing_db) {
for (int i = 0; i < files.size(); i++) {
if (Slice(files[i]).starts_with("dbbench_polyDB")) {
- Env::Default()->DeleteFile("/tmp/" + files[i]);
+ std::string file_name(test_dir);
+ file_name += "/";
+ file_name += files[i];
+ Env::Default()->DeleteFile(file_name.c_str());
}
}
}
@@ -385,8 +393,12 @@ class Benchmark {
db_ = new kyotocabinet::TreeDB();
char file_name[100];
db_num_++;
- snprintf(file_name, sizeof(file_name), "/tmp/dbbench_polyDB-%d.kct",
- db_num_);
+ std::string test_dir;
+ Env::Default()->GetTestDirectory(&test_dir);
+ snprintf(file_name, sizeof(file_name),
+ "%s/dbbench_polyDB-%d.kct",
+ test_dir.c_str(),
+ db_num_);
// Create tuning options and open the database
int open_options = kyotocabinet::PolyDB::OWRITER |
@@ -470,6 +482,7 @@ class Benchmark {
} // namespace leveldb
int main(int argc, char** argv) {
+ std::string default_db_path;
for (int i = 1; i < argc; i++) {
double d;
int n;
@@ -494,12 +507,21 @@ int main(int argc, char** argv) {
} else if (sscanf(argv[i], "--compression=%d%c", &n, &junk) == 1 &&
(n == 0 || n == 1)) {
FLAGS_compression = (n == 1) ? true : false;
+ } else if (strncmp(argv[i], "--db=", 5) == 0) {
+ FLAGS_db = argv[i] + 5;
} else {
fprintf(stderr, "Invalid flag '%s'\n", argv[i]);
exit(1);
}
}
+ // Choose a location for the test database if none given with --db=<path>
+ if (FLAGS_db == NULL) {
+ leveldb::Env::Default()->GetTestDirectory(&default_db_path);
+ default_db_path += "/dbbench";
+ FLAGS_db = default_db_path.c_str();
+ }
+
leveldb::Benchmark benchmark;
benchmark.Run();
return 0;
diff --git a/port/atomic_pointer.h b/port/atomic_pointer.h
index 35ae550..c58bffb 100644
--- a/port/atomic_pointer.h
+++ b/port/atomic_pointer.h
@@ -73,13 +73,21 @@ inline void MemoryBarrier() {
}
#define LEVELDB_HAVE_MEMORY_BARRIER
-// ARM
-#elif defined(ARCH_CPU_ARM_FAMILY)
+// ARM Linux
+#elif defined(ARCH_CPU_ARM_FAMILY) && defined(__linux__)
typedef void (*LinuxKernelMemoryBarrierFunc)(void);
-LinuxKernelMemoryBarrierFunc pLinuxKernelMemoryBarrier __attribute__((weak)) =
- (LinuxKernelMemoryBarrierFunc) 0xffff0fa0;
+// The Linux ARM kernel provides a highly optimized device-specific memory
+// barrier function at a fixed memory address that is mapped in every
+// user-level process.
+//
+// This beats using CPU-specific instructions which are, on single-core
+// devices, un-necessary and very costly (e.g. ARMv7-A "dmb" takes more
+// than 180ns on a Cortex-A8 like the one on a Nexus One). Benchmarking
+// shows that the extra function call cost is completely negligible on
+// multi-core devices.
+//
inline void MemoryBarrier() {
- pLinuxKernelMemoryBarrier();
+ (*(LinuxKernelMemoryBarrierFunc)0xffff0fa0)();
}
#define LEVELDB_HAVE_MEMORY_BARRIER
diff --git a/port/port.h b/port/port.h
index 816826b..e667db4 100644
--- a/port/port.h
+++ b/port/port.h
@@ -14,8 +14,6 @@
# include "port/port_posix.h"
#elif defined(LEVELDB_PLATFORM_CHROMIUM)
# include "port/port_chromium.h"
-#elif defined(LEVELDB_PLATFORM_ANDROID)
-# include "port/port_android.h"
#endif
#endif // STORAGE_LEVELDB_PORT_PORT_H_
diff --git a/port/port_android.cc b/port/port_android.cc
deleted file mode 100644
index 815abf2..0000000
--- a/port/port_android.cc
+++ /dev/null
@@ -1,64 +0,0 @@
-// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file. See the AUTHORS file for names of contributors.
-
-#include "port/port_android.h"
-
-#include <cstdlib>
-
-extern "C" {
-size_t fread_unlocked(void *a, size_t b, size_t c, FILE *d) {
- return fread(a, b, c, d);
-}
-
-size_t fwrite_unlocked(const void *a, size_t b, size_t c, FILE *d) {
- return fwrite(a, b, c, d);
-}
-
-int fflush_unlocked(FILE *f) {
- return fflush(f);
-}
-
-int fdatasync(int fd) {
- return fsync(fd);
-}
-}
-
-namespace leveldb {
-namespace port {
-
-static void PthreadCall(const char* label, int result) {
- if (result != 0) {
- fprintf(stderr, "pthread %s: %s\n", label, strerror(result));
- abort();
- }
-}
-
-Mutex::Mutex() { PthreadCall("init mutex", pthread_mutex_init(&mu_, NULL)); }
-Mutex::~Mutex() { PthreadCall("destroy mutex", pthread_mutex_destroy(&mu_)); }
-void Mutex::Lock() { PthreadCall("lock", pthread_mutex_lock(&mu_)); }
-void Mutex::Unlock() { PthreadCall("unlock", pthread_mutex_unlock(&mu_)); }
-
-CondVar::CondVar(Mutex* mu)
- : mu_(mu) {
- PthreadCall("init cv", pthread_cond_init(&cv_, NULL));
-}
-
-CondVar::~CondVar() {
- PthreadCall("destroy cv", pthread_cond_destroy(&cv_));
-}
-
-void CondVar::Wait() {
- PthreadCall("wait", pthread_cond_wait(&cv_, &mu_->mu_));
-}
-
-void CondVar::Signal(){
- PthreadCall("signal", pthread_cond_signal(&cv_));
-}
-
-void CondVar::SignalAll() {
- PthreadCall("broadcast", pthread_cond_broadcast(&cv_));
-}
-
-} // namespace port
-} // namespace leveldb
diff --git a/port/port_android.h b/port/port_android.h
deleted file mode 100644
index b733388..0000000
--- a/port/port_android.h
+++ /dev/null
@@ -1,159 +0,0 @@
-// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file. See the AUTHORS file for names of contributors.
-//
-// See port_example.h for documentation for the following types/functions.
-
-#ifndef STORAGE_LEVELDB_PORT_PORT_ANDROID_H_
-#define STORAGE_LEVELDB_PORT_PORT_ANDROID_H_
-
-#include <endian.h>
-#include <pthread.h>
-#include <stdint.h>
-#include <unistd.h>
-#include <string>
-#include <cctype>
-
-// Collapse the plethora of ARM flavors available to an easier to manage set
-// Defs reference is at https://wiki.edubuntu.org/ARM/Thumb2PortingHowto
-#if defined(__ARM_ARCH_6__) || \
- defined(__ARM_ARCH_6J__) || \
- defined(__ARM_ARCH_6K__) || \
- defined(__ARM_ARCH_6Z__) || \
- defined(__ARM_ARCH_6T2__) || \
- defined(__ARM_ARCH_6ZK__) || \
- defined(__ARM_ARCH_7__) || \
- defined(__ARM_ARCH_7R__) || \
- defined(__ARM_ARCH_7A__)
-#define ARMV6_OR_7 1
-#endif
-
-extern "C" {
- size_t fread_unlocked(void *a, size_t b, size_t c, FILE *d);
- size_t fwrite_unlocked(const void *a, size_t b, size_t c, FILE *d);
- int fflush_unlocked(FILE *f);
- int fdatasync (int fd);
-}
-
-namespace leveldb {
-namespace port {
-
-static const bool kLittleEndian = __BYTE_ORDER == __LITTLE_ENDIAN;
-
-class CondVar;
-
-class Mutex {
- public:
- Mutex();
- ~Mutex();
-
- void Lock();
- void Unlock();
- void AssertHeld() {
- //TODO(gabor): How can I implement this?
- }
-
- private:
- friend class CondVar;
- pthread_mutex_t mu_;
-
- // No copying
- Mutex(const Mutex&);
- void operator=(const Mutex&);
-};
-
-class CondVar {
- public:
- explicit CondVar(Mutex* mu);
- ~CondVar();
- void Wait();
- void Signal();
- void SignalAll();
- private:
- Mutex* mu_;
- pthread_cond_t cv_;
-};
-
-#ifndef ARMV6_OR_7
-// On ARM chipsets <V6, 0xffff0fa0 is the hard coded address of a
-// memory barrier function provided by the kernel.
-typedef void (*LinuxKernelMemoryBarrierFunc)(void);
-// TODO(user): ATTRIBUTE_WEAK is undefined, so this fails to build on
-// non-ARMV6_OR_7. We may be able to replace it with __attribute__((weak)) for
-// older ARM builds, but x86 builds will require a different memory barrier.
-LinuxKernelMemoryBarrierFunc pLinuxKernelMemoryBarrier ATTRIBUTE_WEAK =
- (LinuxKernelMemoryBarrierFunc) 0xffff0fa0;
-#endif
-
-// Storage for a lock-free pointer
-class AtomicPointer {
- private:
- void* rep_;
-
- inline void MemoryBarrier() const {
- // TODO(gabor): This only works on Android instruction sets >= V6
-#ifdef ARMV6_OR_7
- __asm__ __volatile__("dmb" : : : "memory");
-#else
- pLinuxKernelMemoryBarrier();
-#endif
- }
-
- public:
- AtomicPointer() { }
- explicit AtomicPointer(void* v) : rep_(v) { }
- inline void* Acquire_Load() const {
- void* r = rep_;
- MemoryBarrier();
- return r;
- }
- inline void Release_Store(void* v) {
- MemoryBarrier();
- rep_ = v;
- }
- inline void* NoBarrier_Load() const {
- void* r = rep_;
- return r;
- }
- inline void NoBarrier_Store(void* v) {
- rep_ = v;
- }
-};
-
-// TODO(gabor): Implement compress
-inline bool Snappy_Compress(
- const char* input,
- size_t input_length,
- std::string* output) {
- return false;
-}
-
-// TODO(gabor): Implement uncompress
-inline bool Snappy_GetUncompressedLength(const char* input, size_t length,
- size_t* result) {
- return false;
-}
-
-// TODO(gabor): Implement uncompress
-inline bool Snappy_Uncompress(
- const char* input_data,
- size_t input_length,
- char* output) {
- return false;
-}
-
-inline uint64_t ThreadIdentifier() {
- pthread_t tid = pthread_self();
- uint64_t r = 0;
- memcpy(&r, &tid, sizeof(r) < sizeof(tid) ? sizeof(r) : sizeof(tid));
- return r;
-}
-
-inline bool GetHeapProfile(void (*func)(void*, const char*, int), void* arg) {
- return false;
-}
-
-} // namespace port
-} // namespace leveldb
-
-#endif // STORAGE_LEVELDB_PORT_PORT_ANDROID_H_
diff --git a/port/port_example.h b/port/port_example.h
index 036c7d1..ab9e489 100644
--- a/port/port_example.h
+++ b/port/port_example.h
@@ -60,6 +60,16 @@ class CondVar {
void SignallAll();
};
+// Thread-safe initialization.
+// Used as follows:
+// static port::OnceType init_control = LEVELDB_ONCE_INIT;
+// static void Initializer() { ... do something ...; }
+// ...
+// port::InitOnce(&init_control, &Initializer);
+typedef intptr_t OnceType;
+#define LEVELDB_ONCE_INIT 0
+extern void InitOnce(port::OnceType*, void (*initializer)());
+
// A type that holds a pointer that can be read or written atomically
// (i.e., without word-tearing.)
class AtomicPointer {
diff --git a/port/port_posix.cc b/port/port_posix.cc
index c44cc99..5ba127a 100644
--- a/port/port_posix.cc
+++ b/port/port_posix.cc
@@ -46,5 +46,9 @@ void CondVar::SignalAll() {
PthreadCall("broadcast", pthread_cond_broadcast(&cv_));
}
+void InitOnce(OnceType* once, void (*initializer)()) {
+ PthreadCall("once", pthread_once(once, initializer));
+}
+
} // namespace port
} // namespace leveldb
diff --git a/port/port_posix.h b/port/port_posix.h
index 485ad10..654a4b9 100644
--- a/port/port_posix.h
+++ b/port/port_posix.h
@@ -7,17 +7,22 @@
#ifndef STORAGE_LEVELDB_PORT_PORT_POSIX_H_
#define STORAGE_LEVELDB_PORT_PORT_POSIX_H_
+#undef PLATFORM_IS_LITTLE_ENDIAN
#if defined(OS_MACOSX)
#include <machine/endian.h>
+ #if defined(__DARWIN_LITTLE_ENDIAN) && defined(__DARWIN_BYTE_ORDER)
+ #define PLATFORM_IS_LITTLE_ENDIAN \
+ (__DARWIN_BYTE_ORDER == __DARWIN_LITTLE_ENDIAN)
+ #endif
#elif defined(OS_SOLARIS)
#include <sys/isa_defs.h>
#ifdef _LITTLE_ENDIAN
- #define LITTLE_ENDIAN
+ #define PLATFORM_IS_LITTLE_ENDIAN true
#else
- #define BIG_ENDIAN
+ #define PLATFORM_IS_LITTLE_ENDIAN false
#endif
#elif defined(OS_FREEBSD) || defined(OS_OPENBSD) || defined(OS_NETBSD) ||\
- defined(OS_DRAGONFLYBSD)
+ defined(OS_DRAGONFLYBSD) || defined(OS_ANDROID)
#include <sys/types.h>
#include <sys/endian.h>
#else
@@ -31,14 +36,13 @@
#include <string>
#include "port/atomic_pointer.h"
-#ifdef LITTLE_ENDIAN
-#define IS_LITTLE_ENDIAN true
-#else
-#define IS_LITTLE_ENDIAN (__BYTE_ORDER == __LITTLE_ENDIAN)
+#ifndef PLATFORM_IS_LITTLE_ENDIAN
+#define PLATFORM_IS_LITTLE_ENDIAN (__BYTE_ORDER == __LITTLE_ENDIAN)
#endif
#if defined(OS_MACOSX) || defined(OS_SOLARIS) || defined(OS_FREEBSD) ||\
- defined(OS_NETBSD) || defined(OS_OPENBSD) || defined(OS_DRAGONFLYBSD)
+ defined(OS_NETBSD) || defined(OS_OPENBSD) || defined(OS_DRAGONFLYBSD) ||\
+ defined(OS_ANDROID)
// Use fread/fwrite/fflush on platforms without _unlocked variants
#define fread_unlocked fread
#define fwrite_unlocked fwrite
@@ -51,10 +55,17 @@
#define fdatasync fsync
#endif
+#if defined(OS_ANDROID) && __ANDROID_API__ < 9
+// fdatasync() was only introduced in API level 9 on Android. Use fsync()
+// when targetting older platforms.
+#define fdatasync fsync
+#endif
+
namespace leveldb {
namespace port {
-static const bool kLittleEndian = IS_LITTLE_ENDIAN;
+static const bool kLittleEndian = PLATFORM_IS_LITTLE_ENDIAN;
+#undef PLATFORM_IS_LITTLE_ENDIAN
class CondVar;
@@ -88,6 +99,10 @@ class CondVar {
Mutex* mu_;
};
+typedef pthread_once_t OnceType;
+#define LEVELDB_ONCE_INIT PTHREAD_ONCE_INIT
+extern void InitOnce(OnceType* once, void (*initializer)());
+
inline bool Snappy_Compress(const char* input, size_t length,
::std::string* output) {
#ifdef SNAPPY
diff --git a/util/coding_test.cc b/util/coding_test.cc
index 4cc856c..2c52b17 100644
--- a/util/coding_test.cc
+++ b/util/coding_test.cc
@@ -51,6 +51,29 @@ TEST(Coding, Fixed64) {
}
}
+// Test that encoding routines generate little-endian encodings
+TEST(Coding, EncodingOutput) {
+ std::string dst;
+ PutFixed32(&dst, 0x04030201);
+ ASSERT_EQ(4, dst.size());
+ ASSERT_EQ(0x01, static_cast<int>(dst[0]));
+ ASSERT_EQ(0x02, static_cast<int>(dst[1]));
+ ASSERT_EQ(0x03, static_cast<int>(dst[2]));
+ ASSERT_EQ(0x04, static_cast<int>(dst[3]));
+
+ dst.clear();
+ PutFixed64(&dst, 0x0807060504030201ull);
+ ASSERT_EQ(8, dst.size());
+ ASSERT_EQ(0x01, static_cast<int>(dst[0]));
+ ASSERT_EQ(0x02, static_cast<int>(dst[1]));
+ ASSERT_EQ(0x03, static_cast<int>(dst[2]));
+ ASSERT_EQ(0x04, static_cast<int>(dst[3]));
+ ASSERT_EQ(0x05, static_cast<int>(dst[4]));
+ ASSERT_EQ(0x06, static_cast<int>(dst[5]));
+ ASSERT_EQ(0x07, static_cast<int>(dst[6]));
+ ASSERT_EQ(0x08, static_cast<int>(dst[7]));
+}
+
TEST(Coding, Varint32) {
std::string s;
for (uint32_t i = 0; i < (32 * 32); i++) {
diff --git a/util/comparator.cc b/util/comparator.cc
index eed9d2f..4b7b572 100644
--- a/util/comparator.cc
+++ b/util/comparator.cc
@@ -6,6 +6,7 @@
#include <stdint.h>
#include "leveldb/comparator.h"
#include "leveldb/slice.h"
+#include "port/port.h"
#include "util/logging.h"
namespace leveldb {
@@ -65,11 +66,15 @@ class BytewiseComparatorImpl : public Comparator {
};
} // namespace
-// Intentionally not destroyed to prevent destructor racing
-// with background threads.
-static const Comparator* bytewise = new BytewiseComparatorImpl;
+static port::OnceType once = LEVELDB_ONCE_INIT;
+static const Comparator* bytewise;
+
+static void InitModule() {
+ bytewise = new BytewiseComparatorImpl;
+}
const Comparator* BytewiseComparator() {
+ port::InitOnce(&once, InitModule);
return bytewise;
}