aboutsummaryrefslogtreecommitdiff
path: root/issues
diff options
context:
space:
mode:
Diffstat (limited to 'issues')
-rw-r--r--issues/issue178_test.cc90
-rw-r--r--issues/issue200_test.cc59
-rw-r--r--issues/issue320_test.cc131
3 files changed, 280 insertions, 0 deletions
diff --git a/issues/issue178_test.cc b/issues/issue178_test.cc
new file mode 100644
index 0000000..8fa5bb9
--- /dev/null
+++ b/issues/issue178_test.cc
@@ -0,0 +1,90 @@
+// Copyright (c) 2013 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.
+
+// Test for issue 178: a manual compaction causes deleted data to reappear.
+#include <cstdlib>
+#include <iostream>
+#include <sstream>
+
+#include "gtest/gtest.h"
+#include "leveldb/db.h"
+#include "leveldb/write_batch.h"
+#include "util/testutil.h"
+
+namespace {
+
+const int kNumKeys = 1100000;
+
+std::string Key1(int i) {
+ char buf[100];
+ std::snprintf(buf, sizeof(buf), "my_key_%d", i);
+ return buf;
+}
+
+std::string Key2(int i) { return Key1(i) + "_xxx"; }
+
+TEST(Issue178, Test) {
+ // Get rid of any state from an old run.
+ std::string dbpath = testing::TempDir() + "leveldb_cbug_test";
+ DestroyDB(dbpath, leveldb::Options());
+
+ // Open database. Disable compression since it affects the creation
+ // of layers and the code below is trying to test against a very
+ // specific scenario.
+ leveldb::DB* db;
+ leveldb::Options db_options;
+ db_options.create_if_missing = true;
+ db_options.compression = leveldb::kNoCompression;
+ ASSERT_LEVELDB_OK(leveldb::DB::Open(db_options, dbpath, &db));
+
+ // create first key range
+ leveldb::WriteBatch batch;
+ for (size_t i = 0; i < kNumKeys; i++) {
+ batch.Put(Key1(i), "value for range 1 key");
+ }
+ ASSERT_LEVELDB_OK(db->Write(leveldb::WriteOptions(), &batch));
+
+ // create second key range
+ batch.Clear();
+ for (size_t i = 0; i < kNumKeys; i++) {
+ batch.Put(Key2(i), "value for range 2 key");
+ }
+ ASSERT_LEVELDB_OK(db->Write(leveldb::WriteOptions(), &batch));
+
+ // delete second key range
+ batch.Clear();
+ for (size_t i = 0; i < kNumKeys; i++) {
+ batch.Delete(Key2(i));
+ }
+ ASSERT_LEVELDB_OK(db->Write(leveldb::WriteOptions(), &batch));
+
+ // compact database
+ std::string start_key = Key1(0);
+ std::string end_key = Key1(kNumKeys - 1);
+ leveldb::Slice least(start_key.data(), start_key.size());
+ leveldb::Slice greatest(end_key.data(), end_key.size());
+
+ // commenting out the line below causes the example to work correctly
+ db->CompactRange(&least, &greatest);
+
+ // count the keys
+ leveldb::Iterator* iter = db->NewIterator(leveldb::ReadOptions());
+ size_t num_keys = 0;
+ for (iter->SeekToFirst(); iter->Valid(); iter->Next()) {
+ num_keys++;
+ }
+ delete iter;
+ ASSERT_EQ(kNumKeys, num_keys) << "Bad number of keys";
+
+ // close database
+ delete db;
+ DestroyDB(dbpath, leveldb::Options());
+}
+
+} // anonymous namespace
+
+int main(int argc, char** argv) {
+ testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}
diff --git a/issues/issue200_test.cc b/issues/issue200_test.cc
new file mode 100644
index 0000000..4eba23a
--- /dev/null
+++ b/issues/issue200_test.cc
@@ -0,0 +1,59 @@
+// Copyright (c) 2013 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.
+
+// Test for issue 200: when iterator switches direction from backward
+// to forward, the current key can be yielded unexpectedly if a new
+// mutation has been added just before the current key.
+
+#include "gtest/gtest.h"
+#include "leveldb/db.h"
+#include "util/testutil.h"
+
+namespace leveldb {
+
+TEST(Issue200, Test) {
+ // Get rid of any state from an old run.
+ std::string dbpath = testing::TempDir() + "leveldb_issue200_test";
+ DestroyDB(dbpath, Options());
+
+ DB* db;
+ Options options;
+ options.create_if_missing = true;
+ ASSERT_LEVELDB_OK(DB::Open(options, dbpath, &db));
+
+ WriteOptions write_options;
+ ASSERT_LEVELDB_OK(db->Put(write_options, "1", "b"));
+ ASSERT_LEVELDB_OK(db->Put(write_options, "2", "c"));
+ ASSERT_LEVELDB_OK(db->Put(write_options, "3", "d"));
+ ASSERT_LEVELDB_OK(db->Put(write_options, "4", "e"));
+ ASSERT_LEVELDB_OK(db->Put(write_options, "5", "f"));
+
+ ReadOptions read_options;
+ Iterator* iter = db->NewIterator(read_options);
+
+ // Add an element that should not be reflected in the iterator.
+ ASSERT_LEVELDB_OK(db->Put(write_options, "25", "cd"));
+
+ iter->Seek("5");
+ ASSERT_EQ(iter->key().ToString(), "5");
+ iter->Prev();
+ ASSERT_EQ(iter->key().ToString(), "4");
+ iter->Prev();
+ ASSERT_EQ(iter->key().ToString(), "3");
+ iter->Next();
+ ASSERT_EQ(iter->key().ToString(), "4");
+ iter->Next();
+ ASSERT_EQ(iter->key().ToString(), "5");
+
+ delete iter;
+ delete db;
+ DestroyDB(dbpath, options);
+}
+
+} // namespace leveldb
+
+int main(int argc, char** argv) {
+ testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}
diff --git a/issues/issue320_test.cc b/issues/issue320_test.cc
new file mode 100644
index 0000000..c08296a
--- /dev/null
+++ b/issues/issue320_test.cc
@@ -0,0 +1,131 @@
+// Copyright (c) 2019 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 <cstdint>
+#include <cstdlib>
+#include <iostream>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "gtest/gtest.h"
+#include "leveldb/db.h"
+#include "leveldb/write_batch.h"
+#include "util/testutil.h"
+
+namespace leveldb {
+
+namespace {
+
+// Creates a random number in the range of [0, max).
+int GenerateRandomNumber(int max) { return std::rand() % max; }
+
+std::string CreateRandomString(int32_t index) {
+ static const size_t len = 1024;
+ char bytes[len];
+ size_t i = 0;
+ while (i < 8) {
+ bytes[i] = 'a' + ((index >> (4 * i)) & 0xf);
+ ++i;
+ }
+ while (i < sizeof(bytes)) {
+ bytes[i] = 'a' + GenerateRandomNumber(26);
+ ++i;
+ }
+ return std::string(bytes, sizeof(bytes));
+}
+
+} // namespace
+
+TEST(Issue320, Test) {
+ std::srand(0);
+
+ bool delete_before_put = false;
+ bool keep_snapshots = true;
+
+ std::vector<std::unique_ptr<std::pair<std::string, std::string>>> test_map(
+ 10000);
+ std::vector<Snapshot const*> snapshots(100, nullptr);
+
+ DB* db;
+ Options options;
+ options.create_if_missing = true;
+
+ std::string dbpath = testing::TempDir() + "leveldb_issue320_test";
+ ASSERT_LEVELDB_OK(DB::Open(options, dbpath, &db));
+
+ uint32_t target_size = 10000;
+ uint32_t num_items = 0;
+ uint32_t count = 0;
+ std::string key;
+ std::string value, old_value;
+
+ WriteOptions writeOptions;
+ ReadOptions readOptions;
+ while (count < 200000) {
+ if ((++count % 1000) == 0) {
+ std::cout << "count: " << count << std::endl;
+ }
+
+ int index = GenerateRandomNumber(test_map.size());
+ WriteBatch batch;
+
+ if (test_map[index] == nullptr) {
+ num_items++;
+ test_map[index].reset(new std::pair<std::string, std::string>(
+ CreateRandomString(index), CreateRandomString(index)));
+ batch.Put(test_map[index]->first, test_map[index]->second);
+ } else {
+ ASSERT_LEVELDB_OK(
+ db->Get(readOptions, test_map[index]->first, &old_value));
+ if (old_value != test_map[index]->second) {
+ std::cout << "ERROR incorrect value returned by Get" << std::endl;
+ std::cout << " count=" << count << std::endl;
+ std::cout << " old value=" << old_value << std::endl;
+ std::cout << " test_map[index]->second=" << test_map[index]->second
+ << std::endl;
+ std::cout << " test_map[index]->first=" << test_map[index]->first
+ << std::endl;
+ std::cout << " index=" << index << std::endl;
+ ASSERT_EQ(old_value, test_map[index]->second);
+ }
+
+ if (num_items >= target_size && GenerateRandomNumber(100) > 30) {
+ batch.Delete(test_map[index]->first);
+ test_map[index] = nullptr;
+ --num_items;
+ } else {
+ test_map[index]->second = CreateRandomString(index);
+ if (delete_before_put) batch.Delete(test_map[index]->first);
+ batch.Put(test_map[index]->first, test_map[index]->second);
+ }
+ }
+
+ ASSERT_LEVELDB_OK(db->Write(writeOptions, &batch));
+
+ if (keep_snapshots && GenerateRandomNumber(10) == 0) {
+ int i = GenerateRandomNumber(snapshots.size());
+ if (snapshots[i] != nullptr) {
+ db->ReleaseSnapshot(snapshots[i]);
+ }
+ snapshots[i] = db->GetSnapshot();
+ }
+ }
+
+ for (Snapshot const* snapshot : snapshots) {
+ if (snapshot) {
+ db->ReleaseSnapshot(snapshot);
+ }
+ }
+
+ delete db;
+ DestroyDB(dbpath, options);
+}
+
+} // namespace leveldb
+
+int main(int argc, char** argv) {
+ testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}