From c28776f15d5b7128aabe11525d843377d63feff2 Mon Sep 17 00:00:00 2001 From: Estella <10225101469@stu.ecnu.edu.cn> Date: Sun, 5 Jan 2025 22:05:26 +0800 Subject: [PATCH] add tests --- CMakeLists.txt | 4 ++ db/NewDB.h | 26 +++++++++++ test/constancy_test.cc | 94 ++++++++++++++++++++++++++++++++++++++ test/db_test1.cc | 26 +++++++++++ test/field_test.cc | 96 +++++++++++++++++++++++++++++++++++++++ test/ttl_test.cc | 119 ------------------------------------------------- 6 files changed, 246 insertions(+), 119 deletions(-) create mode 100644 test/constancy_test.cc create mode 100644 test/db_test1.cc create mode 100644 test/field_test.cc delete mode 100644 test/ttl_test.cc diff --git a/CMakeLists.txt b/CMakeLists.txt index bf5843b..877e774 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -525,6 +525,10 @@ add_executable(db_test1 ) target_link_libraries(db_test1 leveldb) +add_executable(kv_index_test +"${PROJECT_SOURCE_DIR}/test/kv_index_test.cc" +) +target_link_libraries(kv_index_test PRIVATE leveldb gtest) add_executable(field_test "${PROJECT_SOURCE_DIR}/test/field_test.cc" diff --git a/db/NewDB.h b/db/NewDB.h index 05c8a05..21a51b6 100644 --- a/db/NewDB.h +++ b/db/NewDB.h @@ -19,11 +19,25 @@ class LEVELDB_EXPORT NewDB { virtual ~NewDB(); + std::string SerializeValue(const FieldArray& fields); + FieldArray ParseValue(const std::string& value_str); + std::string ConstructIndexKey(const Slice& key, const Field& field); + std::string ExtractIndexKey(const Slice& key); + std::string ConstructRecoverKey(std::string UserOpID, std::string TinyOpID, std::string DBname); + std::string ConstructRecoverValue(std::string TinyOp, std::string key, std::string value); + std::string ExtractRecoverKey(std::string s); + std::pair ExtractRecoverValue(std::string s, std::string* TinyOp); + std::string ConstructUserOpID(std::thread::id thread_id); + static Status Open(const Options& options, const std::string& name, NewDB** dbptr); // 改为返回 NewDB* 类型-橙 Status Put_fields(const WriteOptions& options, const Slice& key, const FieldArray& fields); + + std::pair UpdateIndex(const WriteOptions& options, const Slice& key, + const FieldArray& fields, const FieldArray& current_fields); + Status Get_fields(const ReadOptions& options, const Slice& key, FieldArray* fields); @@ -32,6 +46,10 @@ class LEVELDB_EXPORT NewDB { std::vector FindKeysByField(Field &field); + // std::string ConstructKey(const Slice& key, const Field& field); + + // std::string ExtractKey(const Slice& key); + bool CreateIndexOnField(const std::string& field_name); std::vector QueryByIndex(Field &field); @@ -42,10 +60,18 @@ class LEVELDB_EXPORT NewDB { std::unordered_set indexed_fields_read; std::unordered_set indexed_fields_write; + std::unordered_set putting_keys; + private: std::unique_ptr data_db_; std::unique_ptr index_db_; + + std::unique_ptr recover_db_; + + std::mutex db_mutex_; // 用于跨数据库操作的互斥锁 + + uint64_t TinyOpID; }; } diff --git a/test/constancy_test.cc b/test/constancy_test.cc new file mode 100644 index 0000000..0a21302 --- /dev/null +++ b/test/constancy_test.cc @@ -0,0 +1,94 @@ +#include "gtest/gtest.h" +#include "db/NewDB.h" // NewDB 的头文件 +#include "leveldb/env.h" +#include "leveldb/db.h" +#include "db/write_batch_internal.h" +#include +#include +#include +#include + +using namespace leveldb; + +Status OpenNewDB(std::string dbName, NewDB** db) { + Options options = Options(); + options.create_if_missing = true; + return NewDB::Open(options, dbName, db); +} + +Status OpenDB(std::string dbName, DB **db) { + Options options; + options.create_if_missing = true; + return DB::Open(options, dbName, db); +} + +// 全局的随机数引擎 +std::default_random_engine rng; + +// 设置随机种子 +void SetGlobalSeed(unsigned seed) { + rng.seed(seed); +} + +// 生成随机字符串 +std::string GenerateRandomString(size_t length) { + static const char alphanum[] = + "0123456789" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz"; + + std::uniform_int_distribution dist(0, sizeof(alphanum) - 2); + + std::string str(length, 0); + for (size_t i = 0; i < length; ++i) { + str[i] = alphanum[dist(rng)]; + } + return str; +} + +std::string testdbname = "dbtest1"; + +TEST(TestNewDB, ConstancyTest) { + // 创建 NewDB 实例 + NewDB* db; + ASSERT_TRUE(OpenNewDB(testdbname, &db).ok()); + + db->CreateIndexOnField("address"); + + delete db; + + // 创建 NewDB 实例 + NewDB* db_2; + ASSERT_TRUE(OpenNewDB(testdbname, &db_2).ok()); + + std::string key = "k_" + GenerateRandomString(10); + FieldArray fields = { + {"name", GenerateRandomString(5)}, + {"address", GenerateRandomString(15)}, + {"phone", GenerateRandomString(11)} + }; + std::string index_key = db->ConstructIndexKey(key, fields[1]); + db->Put_fields(WriteOptions(), key, fields); + + delete db_2; + + // 创建 DB 实例 + DB* index_db; + ASSERT_TRUE(OpenDB(testdbname + "_index", &index_db).ok()); + + std::string prefix = index_key; + leveldb::Iterator* iter = index_db->NewIterator(leveldb::ReadOptions()); + for(iter->Seek(prefix); iter->Valid() && iter->key().starts_with(prefix); iter->Next()){ + Slice find_key = iter->key(); + EXPECT_EQ(find_key.ToString(), index_key); + } + delete iter; + delete index_db; +} + +int main(int argc, char** argv) { + // 设置全局随机种子 + SetGlobalSeed(static_cast(time(nullptr))); + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} \ No newline at end of file diff --git a/test/db_test1.cc b/test/db_test1.cc new file mode 100644 index 0000000..7e5eb3a --- /dev/null +++ b/test/db_test1.cc @@ -0,0 +1,26 @@ +#include "leveldb/db.h" +#include + +using namespace std; +using namespace leveldb; + +int main() { + DB* db = nullptr; + Options op; + op.create_if_missing = true; + Status status = DB::Open(op, "testdb", &db); + assert(status.ok()); + db->Put(WriteOptions(), "001", "leveldb"); + string s; + db->Get(ReadOptions(), "001", &s); + cout<Put(WriteOptions(), "002", "world"); + string s1; + db->Delete(WriteOptions(), "002"); + db->Get(ReadOptions(), "002", &s1); + cout<Put_fields(WriteOptions(), key, fields); + + db->Get_fields(ReadOptions(), key, &fields); + + //清理数据库 + delete db; +} +// 测试 FindKeysByField 函数 + /* + 1.在测试中创建多个键值对,验证 FindKeysByField 能否正确地查找并返回匹配的键。 + 2.使用 FindKeysByField 查找字段值,检查它是否能够找到匹配的键。 + */ +TEST(TestSchema, FindKeysByFieldTest) { + DB *db; + if (OpenDB("testdb", &db).ok() == false) { + std::cerr << "open db failed" << std::endl; + abort(); + } + + // 插入多个键值对 + std::string key1 = "k_1"; + FieldArray fields1 = { + {"name", "Customer#000000001"}, + {"address", "IVhzIApeRb"}, + {"phone", "25-989-741-2988"} + }; + db->Put_fields(WriteOptions(), key1, fields1); + + std::string key2 = "k_2"; + FieldArray fields2 = { + {"name", "Customer#000000002"}, + {"address", "IVhzIApeRb"}, + {"phone", "25-123-456-7890"} + }; + db->Put_fields(WriteOptions(), key2, fields2); + + std::string key3 = "k_3"; + FieldArray fields3 = { + {"name", "Customer#000000003"}, + {"address", "TXkjZEdIrZ"}, + {"phone", "25-555-888-1234"} + }; + db->Put_fields(WriteOptions(), key3, fields3); + + // 测试 FindKeysByField + Field search_field = {"address", "IVhzIApeRb"}; + std::vector matching_keys = db->FindKeysByField(db, search_field); + + EXPECT_EQ(matching_keys.size(), 2); + EXPECT_TRUE(std::find(matching_keys.begin(), matching_keys.end(), key1) != matching_keys.end()); + EXPECT_TRUE(std::find(matching_keys.begin(), matching_keys.end(), key2) != matching_keys.end()); + + // 清理数据库 + delete db; +} +int main(int argc, char** argv) { + // All tests currently run with the same read-only file limits. + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/test/ttl_test.cc b/test/ttl_test.cc deleted file mode 100644 index 1417bca..0000000 --- a/test/ttl_test.cc +++ /dev/null @@ -1,119 +0,0 @@ - - -#include "gtest/gtest.h" - -#include "leveldb/env.h" -#include "leveldb/db.h" - - -using namespace leveldb; - -constexpr int value_size = 2048; -constexpr int data_size = 128 << 20; - -Status OpenDB(std::string dbName, DB **db) { - Options options; - options.create_if_missing = true; - return DB::Open(options, dbName, db); -} - -void InsertData(DB *db, uint64_t ttl/* second */) { - WriteOptions writeOptions; - int key_num = data_size / value_size; - srand(static_cast(time(0))); - //srand(0); - for (int i = 0; i < key_num; i++) { - int key_ = rand() % key_num+1; - std::string key = std::to_string(key_); - std::string value(value_size, 'a'); - db->Put(writeOptions, key, value, ttl); - } -} - -void GetData(DB *db, int size = (1 << 30)) { - ReadOptions readOptions; - int key_num = data_size / value_size; - - // 点查 - srand(static_cast(time(0))); - //srand(0); - for (int i = 0; i < 100; i++) { - int key_ = rand() % key_num+1; - std::string key = std::to_string(key_); - std::string value; - db->Get(readOptions, key, &value); - } -} -//暂时先注释掉写入Test-橙 -TEST(TestTTL, ReadTTL) { - DB *db; - if(OpenDB("testdb", &db).ok() == false) { - std::cerr << "open db failed" << std::endl; - abort(); - } - - uint64_t ttl = 20; - - InsertData(db, ttl); - - ReadOptions readOptions; - Status status; - int key_num = data_size / value_size; - srand(static_cast(time(0))); - for (int i = 0; i < 100; i++) { - int key_ = rand() % key_num+1; - std::string key = std::to_string(key_); - std::string value; - status = db->Get(readOptions, key, &value); - // 输出 key 值 - // std::cout << "Key: " << key << std::endl; - ASSERT_TRUE(status.ok()); - } - - Env::Default()->SleepForMicroseconds(ttl * 1000000); - - for (int i = 0; i < 100; i++) { - int key_ = rand() % key_num+1; - std::string key = std::to_string(key_); - std::string value; - status = db->Get(readOptions, key, &value); - ASSERT_FALSE(status.ok()); - } - delete db; -} - -TEST(TestTTL, CompactionTTL) { - DB *db; - - if(OpenDB("testdb", &db).ok() == false) { - std::cerr << "open db failed" << std::endl; - abort(); - } - - uint64_t ttl = 20; - InsertData(db, ttl); - //这里为什么要定义两个ranges1?-橙 - leveldb::Range ranges[1]; - ranges[0] = leveldb::Range("-", "A"); - uint64_t sizes[1]; - db->GetApproximateSizes(ranges, 1, sizes); - // printf("part1\n"); - ASSERT_GT(sizes[0], 0); - - Env::Default()->SleepForMicroseconds(ttl * 1000000); - - db->CompactRange(nullptr, nullptr); - // 先注释掉重复定义的-橙 - // leveldb::Range ranges[1]; - ranges[0] = leveldb::Range("-", "A"); - // uint64_t sizes[1]; - db->GetApproximateSizes(ranges, 1, sizes); - ASSERT_EQ(sizes[0], 0); -} - - -int main(int argc, char** argv) { - // All tests currently run with the same read-only file limits. - testing::InitGoogleTest(&argc, argv); - return RUN_ALL_TESTS(); -}