From ab323f7e1ec53749653967e7d6a2fa1c922334f2 Mon Sep 17 00:00:00 2001 From: "gabor@google.com" Date: Tue, 16 Aug 2011 01:21:01 +0000 Subject: [PATCH] Bugfixes for iterator and documentation. - Fix bug in Iterator::Prev where it would return the wrong key. Fixes issues 29 and 30. - Added a tweak to testharness to allow running just some tests. - Fixing two minor documentation errors based on issues 28 and 25. - Cleanup; fix namespaces of export-to-C code. Also fix one "const char*" vs "char*" mismatch. git-svn-id: https://leveldb.googlecode.com/svn/trunk@48 62dab493-f737-651d-591e-8d6aee1b9529 --- db/c.cc | 25 +++++++++++++++++++++---- db/db_iter.cc | 3 ++- db/db_test.cc | 15 +++++++++++++++ doc/index.html | 10 +++++----- util/testharness.cc | 12 ++++++++++++ util/testharness.h | 11 ++++++++++- 6 files changed, 65 insertions(+), 11 deletions(-) diff --git a/db/c.cc b/db/c.cc index ee8a4722b..366dd2d40 100644 --- a/db/c.cc +++ b/db/c.cc @@ -15,7 +15,26 @@ #include "leveldb/status.h" #include "leveldb/write_batch.h" -namespace leveldb { +using leveldb::Cache; +using leveldb::Comparator; +using leveldb::CompressionType; +using leveldb::DB; +using leveldb::Env; +using leveldb::FileLock; +using leveldb::Iterator; +using leveldb::Logger; +using leveldb::NewLRUCache; +using leveldb::Options; +using leveldb::RandomAccessFile; +using leveldb::Range; +using leveldb::ReadOptions; +using leveldb::SequentialFile; +using leveldb::Slice; +using leveldb::Snapshot; +using leveldb::Status; +using leveldb::WritableFile; +using leveldb::WriteBatch; +using leveldb::WriteOptions; extern "C" { @@ -172,7 +191,7 @@ void leveldb_release_snapshot( delete snapshot; } -const char* leveldb_property_value( +char* leveldb_property_value( leveldb_t* db, const char* propname) { std::string tmp; @@ -449,5 +468,3 @@ void leveldb_env_destroy(leveldb_env_t* env) { } } // end extern "C" - -} diff --git a/db/db_iter.cc b/db/db_iter.cc index 0be18fffa..8849f928c 100644 --- a/db/db_iter.cc +++ b/db/db_iter.cc @@ -216,7 +216,6 @@ void DBIter::FindPrevUserEntry() { ValueType value_type = kTypeDeletion; if (iter_->Valid()) { - SaveKey(ExtractUserKey(iter_->key()), &saved_key_); do { ParsedInternalKey ikey; if (ParseKey(&ikey) && ikey.sequence <= sequence_) { @@ -227,6 +226,7 @@ void DBIter::FindPrevUserEntry() { } value_type = ikey.type; if (value_type == kTypeDeletion) { + saved_key_.clear(); ClearSavedValue(); } else { Slice raw_value = iter_->value(); @@ -234,6 +234,7 @@ void DBIter::FindPrevUserEntry() { std::string empty; swap(empty, saved_value_); } + SaveKey(ExtractUserKey(iter_->key()), &saved_key_); saved_value_.assign(raw_value.data(), raw_value.size()); } } diff --git a/db/db_test.cc b/db/db_test.cc index 22fa70ce7..14eb44d7b 100644 --- a/db/db_test.cc +++ b/db/db_test.cc @@ -519,6 +519,21 @@ TEST(DBTest, IterSmallAndLargeMix) { delete iter; } +TEST(DBTest, IterMultiWithDelete) { + ASSERT_OK(Put("a", "va")); + ASSERT_OK(Put("b", "vb")); + ASSERT_OK(Put("c", "vc")); + ASSERT_OK(Delete("b")); + ASSERT_EQ("NOT_FOUND", Get("b")); + + Iterator* iter = db_->NewIterator(ReadOptions()); + iter->Seek("c"); + ASSERT_EQ(IterStatus(iter), "c->vc"); + iter->Prev(); + ASSERT_EQ(IterStatus(iter), "a->va"); + delete iter; +} + TEST(DBTest, Recover) { ASSERT_OK(Put("foo", "v1")); ASSERT_OK(Put("baz", "v5")); diff --git a/doc/index.html b/doc/index.html index 58442e898..8d03c45d9 100644 --- a/doc/index.html +++ b/doc/index.html @@ -23,7 +23,7 @@ creating it if necessary:

   #include <assert>
-  #include "leveldb/include/db.h"
+  #include "leveldb/db.h"
 
   leveldb::DB* db;
   leveldb::Options options;
@@ -78,7 +78,7 @@ Such problems can be avoided by using the WriteBatch class to
 atomically apply a set of updates:
 

-  #include "leveldb/include/write_batch.h"
+  #include "leveldb/write_batch.h"
   ...
   std::string value;
   leveldb::Status s = db->Get(leveldb::ReadOptions(), key1, &value);
@@ -296,7 +296,7 @@ subclass of leveldb::Comparator that expresses these rules:
     }
 
     // Ignore the following methods for now:
-    const char* Name() { return "TwoPartComparator"; }
+    const char* Name() const { return "TwoPartComparator"; }
     void FindShortestSeparator(std::string*, const leveldb::Slice&) const { }
     void FindShortSuccessor(std::string*) const { }
   };
@@ -333,7 +333,7 @@ version numbers found in the keys to decide how to interpret them.
 

Performance

Performance can be tuned by changing the default values of the -types defined in leveldb/include/options.h. +types defined in include/leveldb/options.h.

Block size

@@ -371,7 +371,7 @@ filesystem and each file stores a sequence of compressed blocks. If uncompressed block contents.

-  #include "leveldb/include/cache.h"
+  #include "leveldb/cache.h"
 
   leveldb::Options options;
   options.cache = leveldb::NewLRUCache(100 * 1048576);  // 100MB cache
diff --git a/util/testharness.cc b/util/testharness.cc
index b686ac3ec..6f4270024 100644
--- a/util/testharness.cc
+++ b/util/testharness.cc
@@ -4,6 +4,8 @@
 
 #include "util/testharness.h"
 
+#include 
+#include 
 #include 
 #include 
 
@@ -32,10 +34,20 @@ bool RegisterTest(const char* base, const char* name, void (*func)()) {
 }
 
 int RunAllTests() {
+  const char* matcher = getenv("LEVELDB_TESTS");
+
   int num = 0;
   if (tests != NULL) {
     for (int i = 0; i < tests->size(); i++) {
       const Test& t = (*tests)[i];
+      if (matcher != NULL) {
+        std::string name = t.base;
+        name.push_back('.');
+        name.append(t.name);
+        if (strstr(name.c_str(), matcher) == NULL) {
+          continue;
+        }
+      }
       fprintf(stderr, "==== Test %s.%s\n", t.base, t.name);
       (*t.func)();
       ++num;
diff --git a/util/testharness.h b/util/testharness.h
index 13ab914aa..6f1a9c328 100644
--- a/util/testharness.h
+++ b/util/testharness.h
@@ -15,7 +15,16 @@
 namespace leveldb {
 namespace test {
 
-// Run all tests registered by the TEST() macro.
+// Run some of the tests registered by the TEST() macro.  If the
+// environment variable "LEVELDB_TESTS" is not set, runs all tests.
+// Otherwise, runs only the tests whose name contains the value of
+// "LEVELDB_TESTS" as a substring.  E.g., suppose the tests are:
+//    TEST(Foo, Hello) { ... }
+//    TEST(Foo, World) { ... }
+// LEVELDB_TESTS=Hello will run the first test
+// LEVELDB_TESTS=o     will run both tests
+// LEVELDB_TESTS=Junk  will run no tests
+//
 // Returns 0 if all tests pass.
 // Dies or returns a non-zero value if some test fails.
 extern int RunAllTests();