Imported Upstream version 1.5 66/118866/1
authorDongHun Kwak <dh0128.kwak@samsung.com>
Tue, 14 Mar 2017 09:50:47 +0000 (18:50 +0900)
committerDongHun Kwak <dh0128.kwak@samsung.com>
Tue, 14 Mar 2017 09:50:47 +0000 (18:50 +0900)
Change-Id: Iff3c40e1c4822d63ec1d15926e1b9c9d385fb817
Signed-off-by: DongHun Kwak <dh0128.kwak@samsung.com>
21 files changed:
Makefile
build_detect_platform
db/c_test.c
db/db_bench.cc
db/db_impl.cc
db/db_impl.h
db/db_test.cc
db/version_set.cc
db/version_set.h
doc/bench/db_bench_sqlite3.cc
doc/bench/db_bench_tree_db.cc
include/leveldb/db.h
port/atomic_pointer.h
port/port.h
port/port_android.cc [deleted file]
port/port_android.h [deleted file]
port/port_example.h
port/port_posix.cc
port/port_posix.h
util/coding_test.cc
util/comparator.cc

index b961ba1..c648a28 100644 (file)
--- 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,21 +61,31 @@ 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
+SHARED_MINOR = 5
 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 $@)
index b71bf02..959a7d6 100755 (executable)
@@ -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
index 12b4424..9792447 100644 (file)
@@ -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");
index b0c3995..21d3e25 100644 (file)
@@ -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;
index c9c9023..90c1c81 100644 (file)
@@ -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_;
index 2f8b523..8d2bb34 100644 (file)
@@ -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);
 
index ee10807..3744d0e 100644 (file)
@@ -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) {
index 1f48419..cf976b4 100644 (file)
@@ -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) {
index 572602e..61c4c99 100644 (file)
@@ -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;
 
index 6951a14..256793a 100644 (file)
@@ -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;
index 214d9b7..ed86f03 100644 (file)
@@ -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;
index 481aad6..ed56b87 100644 (file)
@@ -14,7 +14,7 @@ namespace leveldb {
 
 // Update Makefile if you change these
 static const int kMajorVersion = 1;
-static const int kMinorVersion = 4;
+static const int kMinorVersion = 5;
 
 struct Options;
 struct ReadOptions;
index 35ae550..c58bffb 100644 (file)
@@ -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
 
index 816826b..e667db4 100644 (file)
@@ -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 (file)
index 815abf2..0000000
+++ /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 (file)
index b733388..0000000
+++ /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_
index 036c7d1..ab9e489 100644 (file)
@@ -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 {
index c44cc99..5ba127a 100644 (file)
@@ -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
index 485ad10..654a4b9 100644 (file)
@@ -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
 #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
 #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
index 4cc856c..2c52b17 100644 (file)
@@ -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++) {
index eed9d2f..4b7b572 100644 (file)
@@ -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;
 }