diff --git a/test/consistency_test.cc b/test/consistency_test.cc new file mode 100644 index 0000000..3d4421b --- /dev/null +++ b/test/consistency_test.cc @@ -0,0 +1,361 @@ +#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 = "dbtest76"; + + +TEST(TestNewDB, PUTRecoveryTest) { +// put_fields-新增 + // 创建 NewDB 实例 + NewDB* db; + ASSERT_TRUE(OpenNewDB(testdbname, &db).ok()); + + db->CreateIndexOnField("address"); + // 批量插入数据 + std::vector> bulk_data; + std::vector bulk_index; + int num_records = 100; + for (int i = 0; i < num_records; ++i) { + std::string key = "k_" + GenerateRandomString(10); + FieldArray fields = { + {"name", GenerateRandomString(5)}, + {"address", GenerateRandomString(15)}, + {"phone", GenerateRandomString(11)} + }; + bulk_data.emplace_back(key, fields); + bulk_index.emplace_back(db->ConstructIndexKey(key, fields[1])); + + // std::cout << key << "..." << db->SerializeValue(fields) << std::endl; + + ASSERT_TRUE(db->Put_fields(WriteOptions(), key, fields).ok()); + } + // for(auto& key:bulk_index){ + // std::cout << key << std::endl; + // } + delete db; + +// 模拟崩溃 + // 创建 DB 实例 + DB* data_db; + ASSERT_TRUE(OpenDB(testdbname + "_data", &data_db).ok()); + // 删除部分数据 + int num_updates = 20; + for (int i = 0; i < num_updates; ++i) { + auto& [key, fields] = bulk_data[i]; + ASSERT_TRUE(data_db->Delete(WriteOptions(), key).ok()); + } + delete data_db; + + // 创建 DB 实例 + DB* index_db; + ASSERT_TRUE(OpenDB(testdbname + "_index", &index_db).ok()); + for (int i = 0; i < num_updates; ++i) { + auto& key = bulk_index[i]; + ASSERT_TRUE(index_db->Delete(WriteOptions(), key).ok()); + } + delete index_db; + + +// 测试是否能通过recoverDB恢复 + // 创建 NewDB 实例 + NewDB* db_2; + ASSERT_TRUE(OpenNewDB(testdbname, &db_2).ok()); + + // 验证插入的数据和索引 + for (const auto& [key, fields] : bulk_data) { + // 获取并验证字段数据 + FieldArray retrieved_fields; + ASSERT_TRUE(db_2->Get_fields(ReadOptions(), Slice(key), &retrieved_fields).ok()); + + // 验证插入的每个字段 + for (size_t i = 0; i < fields.size(); ++i) { + EXPECT_EQ(fields[i].first, retrieved_fields[i].first); // 字段名 + EXPECT_EQ(fields[i].second, retrieved_fields[i].second); // 字段值 + } + } + delete db_2; + + // 创建 DB 实例 + DB* index_db_2; + ASSERT_TRUE(OpenDB(testdbname + "_index", &index_db_2).ok()); + for (const auto& key : bulk_index) { + // 获取并验证字段数据 + std::string value; + ASSERT_TRUE(index_db_2->Get(ReadOptions(), Slice(key), &value).ok()); + } + delete index_db_2; +} + +TEST(TestNewDB, UpdateRecoveryTest) { +// put_fields-更新 + // 创建 NewDB 实例 + NewDB* db_3; + ASSERT_TRUE(OpenNewDB(testdbname, &db_3).ok()); + + db_3->CreateIndexOnField("address"); + // 批量插入数据 + std::vector> bulk_data; + std::vector bulk_index; + int num_records = 100; + for (int i = 0; i < num_records; ++i) { + std::string key = "k_" + GenerateRandomString(10); + FieldArray fields = { + {"name", GenerateRandomString(5)}, + {"address", GenerateRandomString(15)}, + {"phone", GenerateRandomString(11)} + }; + bulk_data.emplace_back(key, fields); + bulk_index.emplace_back(db_3->ConstructIndexKey(key, fields[1])); + + // std::cout << key << "..." << db->SerializeValue(fields) << std::endl; + + ASSERT_TRUE(db_3->Put_fields(WriteOptions(), key, fields).ok()); + } + + // 更新数据 + std::vector> bulk_data_update; + std::vector bulk_index_update; + num_records = 20; + for (int i = 0; i < num_records; ++i) { + auto& [key, fields] = bulk_data[i]; + FieldArray fields_update = { + {"name", fields[0].second}, + {"address", GenerateRandomString(15)}, + {"phone", fields[2].second} + }; + bulk_data_update.emplace_back(key, fields_update); + bulk_index_update.emplace_back(db_3->ConstructIndexKey(key, fields_update[1])); + + ASSERT_TRUE(db_3->Put_fields(WriteOptions(), key, fields_update).ok()); + } + + delete db_3; + + +// 模拟崩溃 + // 创建 DB 实例 + DB* data_db_2; + ASSERT_TRUE(OpenDB(testdbname + "_data", &data_db_2).ok()); + // 删除部分数据 + int num_updates = 10; + for (int i = 0; i < num_updates; ++i) { + auto& [key, fields] = bulk_data_update[i]; + ASSERT_TRUE(data_db_2->Delete(WriteOptions(), key).ok()); + } + delete data_db_2; + + // 创建 DB 实例 + DB* index_db_3; + ASSERT_TRUE(OpenDB(testdbname + "_index", &index_db_3).ok()); + for (int i = 0; i < num_updates; ++i) { + auto& key = bulk_index_update[i]; + ASSERT_TRUE(index_db_3->Delete(WriteOptions(), key).ok()); + } + delete index_db_3; + +// 测试是否能通过recoverDB恢复 + // 创建 NewDB 实例 + NewDB* db_4; + ASSERT_TRUE(OpenNewDB(testdbname, &db_4).ok()); + + // 验证插入的数据和索引 + for (const auto& [key, fields] : bulk_data_update) { + // 获取并验证字段数据 + FieldArray retrieved_fields; + ASSERT_TRUE(db_4->Get_fields(ReadOptions(), Slice(key), &retrieved_fields).ok()); + + // 验证插入的每个字段 + for (size_t i = 0; i < fields.size(); ++i) { + EXPECT_EQ(fields[i].first, retrieved_fields[i].first); // 字段名 + EXPECT_EQ(fields[i].second, retrieved_fields[i].second); // 字段值 + } + } + delete db_4; + + // 创建 DB 实例 + DB* index_db_4; + ASSERT_TRUE(OpenDB(testdbname + "_index", &index_db_4).ok()); + for (const auto& key : bulk_index_update) { + // 获取并验证字段数据 + std::string value; + ASSERT_TRUE(index_db_4->Get(ReadOptions(), Slice(key), &value).ok()); + } + delete index_db_4; +} + +TEST(TestNewDB, DeleteRecoveryTest) { + // 创建 NewDB 实例 + NewDB* db_3; + ASSERT_TRUE(OpenNewDB(testdbname, &db_3).ok()); + + db_3->CreateIndexOnField("address"); + // 批量插入数据 + std::vector> bulk_data; + std::vector bulk_index; + int num_records = 100; + for (int i = 0; i < num_records; ++i) { + std::string key = "k_" + GenerateRandomString(10); + FieldArray fields = { + {"name", GenerateRandomString(5)}, + {"address", GenerateRandomString(15)}, + {"phone", GenerateRandomString(11)} + }; + bulk_data.emplace_back(key, fields); + bulk_index.emplace_back(db_3->ConstructIndexKey(key, fields[1])); + + ASSERT_TRUE(db_3->Put_fields(WriteOptions(), key, fields).ok()); + } + + // 删除数据 + std::vector> bulk_data_delete; + std::vector bulk_index_delete; + num_records = 20; + for (int i = 0; i < num_records; ++i) { + auto& [key, fields] = bulk_data[i]; + bulk_data_delete.emplace_back(key, fields); + bulk_index_delete.emplace_back(db_3->ConstructIndexKey(key, fields[1])); + + ASSERT_TRUE(db_3->Delete(WriteOptions(), key)); + } + + delete db_3; + +// 模拟崩溃 + // 创建 DB 实例 + DB* data_db_2; + ASSERT_TRUE(OpenDB(testdbname + "_data", &data_db_2).ok()); + // 恢复部分数据 + int num_updates = 10; + for (int i = 0; i < num_updates; ++i) { + auto& [key, fields] = bulk_data_delete[i]; + ASSERT_TRUE(data_db_2->Put_fields(WriteOptions(), key, fields).ok()); + } + delete data_db_2; + + // 创建 DB 实例 + DB* index_db_3; + ASSERT_TRUE(OpenDB(testdbname + "_index", &index_db_3).ok()); + for (int i = 0; i < num_updates; ++i) { + auto& key = bulk_index_delete[i]; + ASSERT_TRUE(index_db_3->Put(WriteOptions(), key, "").ok()); + } + delete index_db_3; + +// 测试是否能通过recoverDB恢复 + // 创建 NewDB 实例 + NewDB* db_4; + ASSERT_TRUE(OpenNewDB(testdbname, &db_4).ok()); + + // 验证插入的数据和索引 + for (const auto& [key, fields] : bulk_data_delete) { + // 获取并验证字段数据 + FieldArray retrieved_fields; + ASSERT_FALSE(db_4->Get_fields(ReadOptions(), Slice(key), &retrieved_fields).ok()); + } + delete db_4; + + // 创建 DB 实例 + DB* index_db_4; + ASSERT_TRUE(OpenDB(testdbname + "_index", &index_db_4).ok()); + for (const auto& key : bulk_index_delete) { + // 获取并验证字段数据 + std::string value; + ASSERT_FALSE(index_db_4->Get(ReadOptions(), Slice(key), &value).ok()); + } + delete index_db_4; +} + + +TEST(TestNewDB, QueryIndexTest) { + // 创建 NewDB 实例 + NewDB* db; + ASSERT_TRUE(OpenNewDB(testdbname, &db).ok()); + + db->CreateIndexOnField("address"); + + std::string key = "k_" + GenerateRandomString(10); + FieldArray fields = { + {"name", GenerateRandomString(5)}, + {"address", GenerateRandomString(15)}, + {"phone", GenerateRandomString(11)} + }; + ASSERT_TRUE(db->Put_fields(WriteOptions(), key, fields).ok()); + + delete db; + + // 创建 DB 实例 + DB* data_db; + ASSERT_TRUE(OpenDB(testdbname + "_data", &data_db).ok()); + // update the address + FieldArray fields_new = { + {"name", fields[0].second}, + {"address", GenerateRandomString(15)}, + {"phone", fields[2].second} + }; + ASSERT_TRUE(data_db->Put_fields(WriteOptions(), key, fields_new).ok()); + delete data_db; + + // 创建 NewDB 实例 + NewDB* db_2; + ASSERT_TRUE(OpenNewDB(testdbname, &db_2).ok()); + + // 验证索引是否能正确找到对应的键 + Field field_to_query{"address", fields[1].second}; // 使用 address 字段进行查询 + std::vector matching_keys = db_2->QueryByIndex(field_to_query); + EXPECT_TRUE(matching_keys.empty()); + + delete db_2; +} + + +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