#include "gtest/gtest.h" #include "db/NewDB.h" // NewDB 的头文件 #include "leveldb/env.h" #include "leveldb/db.h" #include #include #include #include // 用于计时 #include // 用于存储延迟 using namespace std; using namespace leveldb; Status OpenDB(std::string dbName, NewDB** db) { Options options = Options(); options.create_if_missing = true; return NewDB::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 = "testdb2"; // TEST(TestNewDB, PersistentIndexTest) { // // 创建 NewDB 实例 // NewDB* db; // ASSERT_TRUE(OpenDB(testdbname, &db).ok()); // // 批量插入数据 // std::vector> bulk_data; // const int num_records = 1000; // 适当减少记录数,以便测试 // for (int i = 0; i < num_records; ++i) { // std::string key = "k_" + GenerateRandomString(10); // FieldArray fields = { // {"name", GenerateRandomString(10)}, // {"address", GenerateRandomString(25)}, // {"phone", GenerateRandomString(11)} // }; // bulk_data.emplace_back(key, fields); // ASSERT_TRUE(db->Put_fields(WriteOptions(), key, fields).ok()); // } // // 创建索引字段 // db->CreateIndexOnField("address"); // // 关闭数据库 // delete db; // // 重新打开数据库 // ASSERT_TRUE(OpenDB(testdbname, &db).ok()); // // 验证索引字段是否仍然存在 // for (const auto& [key, fields] : bulk_data) { // // 获取并验证字段数据 // FieldArray retrieved_fields; // ASSERT_TRUE(db->Get_fields(ReadOptions(), Slice(key), &retrieved_fields).ok()); // EXPECT_EQ(retrieved_fields.size(), fields.size()); // // 验证索引是否能正确找到对应的键 // Field field_to_query{"address", fields[1].second}; // 使用 address 字段进行查询 // std::vector matching_keys = db->QueryByIndex(field_to_query); // EXPECT_FALSE(matching_keys.empty()); // 应该能找到对应的键 // EXPECT_NE(std::find(matching_keys.begin(), matching_keys.end(), key), matching_keys.end()); // } // // 关闭数据库 // delete db; // } // TEST(TestNewDB, BulkCreateIndexAndQueryTest) { // // 创建 NewDB 实例 // NewDB* db; // ASSERT_TRUE(OpenDB(testdbname, &db).ok()); // // 批量插入数据 // std::vector> bulk_data; // const int num_records = 10000; // for (int i = 0; i < num_records; ++i) { // std::string key = "k_" + GenerateRandomString(10); // FieldArray fields = { // {"name", GenerateRandomString(10)}, // {"address", GenerateRandomString(25)}, // {"phone", GenerateRandomString(11)} // }; // bulk_data.emplace_back(key, fields); // ASSERT_TRUE(db->Put_fields(WriteOptions(), key, fields).ok()); // } // // 创建索引字段 // db->CreateIndexOnField("address"); // // 验证插入的数据和索引 // for (const auto& [key, fields] : bulk_data) { // // 获取并验证字段数据 // FieldArray retrieved_fields; // ASSERT_TRUE(db->Get_fields(ReadOptions(), Slice(key), &retrieved_fields).ok()); // EXPECT_EQ(retrieved_fields.size(), fields.size()); // // 验证插入的每个字段 // 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); // 字段值 // if (fields[i].second != retrieved_fields[i].second) { // std::cerr << "Mismatch at index: " << i // << ", Key: " << key // << ", Field Name: " << fields[i].first // << ", Expected: " << fields[i].second // << ", Retrieved: " << retrieved_fields[i].second // << std::endl; // } // } // // 验证索引是否能正确找到对应的键 // Field field_to_query{"address", fields[1].second}; // 使用 address 字段进行查询 // std::vector matching_keys = db->QueryByIndex(field_to_query); // EXPECT_FALSE(matching_keys.empty()); // 应该能找到对应的键 // EXPECT_NE(std::find(matching_keys.begin(), matching_keys.end(), key), matching_keys.end()); // } // delete db; // } TEST(TestNewDB, QueryByIndexPerformance) { // 创建 NewDB 实例 NewDB* db; ASSERT_TRUE(OpenDB(testdbname, &db).ok()); // 批量插入数据 std::vector> bulk_data; const int num_records = 10000; for (int i = 0; i < num_records; ++i) { std::string key = "k_" + GenerateRandomString(10); FieldArray fields = { {"name", GenerateRandomString(10)}, {"address", GenerateRandomString(25)}, {"phone", GenerateRandomString(11)} }; bulk_data.emplace_back(key, fields); ASSERT_TRUE(db->Put_fields(WriteOptions(), key, fields).ok()); } // 创建索引字段 db->CreateIndexOnField("address"); // 测试查询延迟 auto start_time = std::chrono::high_resolution_clock::now(); // 记录开始时间 // 验证插入的数据和索引 for (const auto& [key, fields] : bulk_data) { // 获取并验证字段数据 FieldArray retrieved_fields; ASSERT_TRUE(db->Get_fields(ReadOptions(), Slice(key), &retrieved_fields).ok()); EXPECT_EQ(retrieved_fields.size(), fields.size()); // 验证插入的每个字段 // 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); // 字段值 // if (fields[i].second != retrieved_fields[i].second) { // std::cerr << "Mismatch at index: " << i // << ", Key: " << key // << ", Field Name: " << fields[i].first // << ", Expected: " << fields[i].second // << ", Retrieved: " << retrieved_fields[i].second // << std::endl; // } // } // 验证索引是否能正确找到对应的键 Field field_to_query{"address", fields[1].second}; // 使用 address 字段进行查询 std::vector matching_keys = db->QueryByIndex(field_to_query); EXPECT_FALSE(matching_keys.empty()); // 应该能找到对应的键 EXPECT_NE(std::find(matching_keys.begin(), matching_keys.end(), key), matching_keys.end()); } auto end_time = std::chrono::high_resolution_clock::now(); // 记录结束时间 auto duration = std::chrono::duration_cast(end_time - start_time).count(); cout << "Throughput: " << num_records * 1000 / duration << " OPS" << endl; cout << "Total Latency " << duration << " ms" << endl; delete db; } // TEST(TestNewDB, FindKeysByFieldPerformance) { // // 创建 NewDB 实例 // NewDB* db; // ASSERT_TRUE(OpenDB(testdbname, &db).ok()); // // 批量插入数据 // std::vector> bulk_data; // const int num_records = 100000; // for (int i = 0; i < num_records; ++i) { // std::string key = "k_" + GenerateRandomString(10); // FieldArray fields = { // {"name", GenerateRandomString(10)}, // {"address", GenerateRandomString(25)}, // {"phone", GenerateRandomString(11)} // }; // bulk_data.emplace_back(key, fields); // ASSERT_TRUE(db->Put_fields(WriteOptions(), key, fields).ok()); // } // // 创建索引字段 // db->CreateIndexOnField("address"); // // 测试查询延迟 // auto start_time = std::chrono::high_resolution_clock::now(); // 记录开始时间 // // 验证插入的数据和索引 // for (const auto& [key, fields] : bulk_data) { // // 获取并验证字段数据 // FieldArray retrieved_fields; // ASSERT_TRUE(db->Get_fields(ReadOptions(), Slice(key), &retrieved_fields).ok()); // EXPECT_EQ(retrieved_fields.size(), fields.size()); // // 验证插入的每个字段 // // 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); // 字段值 // // if (fields[i].second != retrieved_fields[i].second) { // // std::cerr << "Mismatch at index: " << i // // << ", Key: " << key // // << ", Field Name: " << fields[i].first // // << ", Expected: " << fields[i].second // // << ", Retrieved: " << retrieved_fields[i].second // // << std::endl; // // } // // } // // 验证索引是否能正确找到对应的键 // Field field_to_query{"address", fields[1].second}; // 使用 address 字段进行查询 // std::vector matching_keys = db->FindKeysByField(field_to_query); // EXPECT_FALSE(matching_keys.empty()); // 应该能找到对应的键 // EXPECT_NE(std::find(matching_keys.begin(), matching_keys.end(), key), matching_keys.end()); // } // auto end_time = std::chrono::high_resolution_clock::now(); // 记录结束时间 // auto duration = std::chrono::duration_cast(end_time - start_time).count(); // cout << "Throughput: " << num_records * 1000 / duration << " OPS" << endl; // cout << "Total Latency " << duration << " ms" << endl; // delete db; // } //测试创建二级索引后批量插入、以及删除索引后的查询 // TEST(TestNewDB, BulkPutFieldsAndDeleteIndexPerformance) { // // 创建 NewDB 实例 // NewDB* db; // ASSERT_TRUE(OpenDB(testdbname, &db).ok()); // db->CreateIndexOnField("address"); // // 批量插入数据 // std::vector> bulk_data; // const int num_records = 150000; // for (int i = 0; i < num_records; ++i) { // std::string key = "k_" + GenerateRandomString(10); // FieldArray fields = { // {"name", GenerateRandomString(10)}, // {"address", GenerateRandomString(25)}, // {"phone", GenerateRandomString(11)} // }; // bulk_data.emplace_back(key, fields); // ASSERT_TRUE(db->Put_fields(WriteOptions(), key, fields).ok()); // } // // 验证插入的数据和索引 // for (const auto& [key, fields] : bulk_data) { // // 获取并验证字段数据 // FieldArray retrieved_fields; // ASSERT_TRUE(db->Get_fields(ReadOptions(), Slice(key), &retrieved_fields).ok()); // EXPECT_EQ(retrieved_fields.size(), fields.size()); // // 验证插入的每个字段 // 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); // 字段值 // } // // 验证索引是否能正确找到对应的键 // Field field_to_query{"address", fields[1].second}; // 使用 address 字段进行查询 // std::vector matching_keys = db->QueryByIndex(field_to_query); // EXPECT_FALSE(matching_keys.empty()); // 应该能找到对应的键 // EXPECT_NE(std::find(matching_keys.begin(), matching_keys.end(), key), matching_keys.end()); // } // // 测试插入吞吐量 // auto start_time = std::chrono::high_resolution_clock::now(); // 记录开始时间 // // 删除部分数据 // const int num_updates = 100000; // for (int i = 0; i < num_updates; ++i) { // auto& [key, fields] = bulk_data[i]; // ASSERT_TRUE(db->Delete(WriteOptions(), key)); // } // // for (int i = 0; i < num_updates; ++i) { // // Field query_field{"address", bulk_data[i].second[1].second}; // // std::vector matching_keys = db->QueryByIndex(query_field); // // EXPECT_TRUE(matching_keys.empty()); // // } // // 删除索引 // ASSERT_TRUE(db->DeleteIndex("address")); // auto end_time = std::chrono::high_resolution_clock::now(); // 记录结束时间 // auto duration = std::chrono::duration_cast(end_time - start_time).count(); // // 计算吞吐量并输出 // cout << "Throughput: " << num_updates * 1000 / duration << " OPS" << endl; // cout << "Total Latency " << duration << " ms" << endl; // // // 验证删除索引后无法再通过索引查询到数据 // // for (const auto& [key, fields] : bulk_data) { // // Field field_to_query{"address", fields[1].second}; // 使用 address 字段进行查询 // // std::vector matching_keys = db->QueryByIndex(field_to_query); // // EXPECT_TRUE(matching_keys.empty()); // 索引已被删除,应该找不到任何匹配的键 // // } // delete db; // } // TEST(TestNewDB, UpdateFieldsAndQueryIndexPerformance) { // // 创建 NewDB 实例 // NewDB* db; // ASSERT_TRUE(OpenDB(testdbname, &db).ok()); // // 创建索引字段 // ASSERT_TRUE(db->CreateIndexOnField("address")); // // 批量插入数据 // const int num_records = 200000; // std::vector> initial_bulk_data; // for (int i = 0; i < num_records; ++i) { // std::string key = "k_" + GenerateRandomString(10); // FieldArray fields = { // {"name", GenerateRandomString(10)}, // {"address", GenerateRandomString(25)}, // {"phone", GenerateRandomString(11)} // }; // initial_bulk_data.emplace_back(key, fields); // ASSERT_TRUE(db->Put_fields(WriteOptions(), key, fields).ok()); // } // //验证初始数据的索引查询 // for (const auto& [key, fields] : initial_bulk_data) { // Field query_field{"address", fields[1].second}; // 使用 address 字段进行查询 // std::vector matching_keys = db->QueryByIndex(query_field); // ASSERT_FALSE(matching_keys.empty()); // 应该能找到对应的键 // EXPECT_NE(std::find(matching_keys.begin(), matching_keys.end(), key), matching_keys.end()); // } // // 更新部分数据 // const int num_updates = 100000; // std::vector> updated_bulk_data; // // 测试插入吞吐量 // auto start_time = std::chrono::high_resolution_clock::now(); // 记录开始时间 // for (int i = 0; i < num_updates; ++i) { // auto& [key, fields] = initial_bulk_data[i]; // FieldArray updated_fields = { // {"name", fields[0].second}, // {"address", GenerateRandomString(15)}, // 更新 address // {"phone", fields[2].second} // }; // updated_bulk_data.emplace_back(key, updated_fields); // ASSERT_TRUE(db->Put_fields(WriteOptions(), key, updated_fields).ok()); // } // auto end_time = std::chrono::high_resolution_clock::now(); // 记录结束时间 // auto duration = std::chrono::duration_cast(end_time - start_time).count(); // // 计算吞吐量并输出 // cout << "Throughput: " << num_updates * 1000 / duration << " OPS" << endl; // cout << "Total Latency " << duration << " ms" << endl; // // 验证更新后的数据和索引 // for (const auto& [key, updated_fields] : updated_bulk_data) { // // 获取并验证字段数据 // FieldArray retrieved_fields; // ASSERT_TRUE(db->Get_fields(ReadOptions(), Slice(key), &retrieved_fields).ok()); // EXPECT_EQ(retrieved_fields.size(), updated_fields.size()); // // 验证插入的每个字段 // for (size_t i = 0; i < updated_fields.size(); ++i) { // EXPECT_EQ(updated_fields[i].first, retrieved_fields[i].first); // 字段名 // EXPECT_EQ(updated_fields[i].second, retrieved_fields[i].second); // 字段值 // } // // 验证新的 address 字段值存在于索引中 // Field query_field_new{"address", updated_fields[1].second}; // std::vector matching_keys_new = db->QueryByIndex(query_field_new); // ASSERT_FALSE(matching_keys_new.empty()); // 新地址应该能找到对应的键 // EXPECT_NE(std::find(matching_keys_new.begin(), matching_keys_new.end(), key), matching_keys_new.end()); // } // for (int i = 0; i < num_updates; ++i) { // // 验证旧的 address 字段值不再存在于索引中 // Field query_field_old{"address", initial_bulk_data[i].second[1].second}; // std::vector matching_keys_old = db->QueryByIndex(query_field_old); // EXPECT_TRUE(matching_keys_old.empty()); // 旧地址不应该再找到对应的键 // } // delete db; // } int main(int argc, char** argv) { // 设置全局随机种子 SetGlobalSeed(static_cast(time(nullptr))); testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); }