diff --git a/include/leveldb/options.h b/include/leveldb/options.h index 465ba3a..cae933c 100644 --- a/include/leveldb/options.h +++ b/include/leveldb/options.h @@ -177,7 +177,7 @@ struct LEVELDB_EXPORT ReadOptions { // Options that control write operations struct LEVELDB_EXPORT WriteOptions { - explicit WriteOptions(size_t separateThreshold = 5) + explicit WriteOptions(size_t separateThreshold = 16) : separate_threshold(separateThreshold) {} // WriteOptions() = default; diff --git a/test/kv_test.cc b/test/kv_test.cc index 7555732..c39a8a0 100644 --- a/test/kv_test.cc +++ b/test/kv_test.cc @@ -8,7 +8,7 @@ using namespace leveldb; constexpr int short_value_size = 4; constexpr int long_value_size = 32; -constexpr int data_size = 512; +constexpr int data_size = 32; Status OpenDB(std::string dbName, DB **db) { std::string rm_command = "rm -rf " + dbName; @@ -33,47 +33,47 @@ void InsertData(DB *db, int value_size) { } -// void GetData(DB *db, int size = (1 << 30), int value_size = 0) { -// ReadOptions readOptions; -// int key_num = data_size / value_size; + void GetData(DB *db, int size = (1 << 30), int value_size = 0) { + ReadOptions readOptions; + int key_num = data_size / value_size; -// // 点查 -// srand(42); -// 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); -// } -// } + // 点查 + srand(42); + 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(TestTTL, GetValue) { -// DB *db; -// if(OpenDB("testdb_ReadTTL", &db).ok() == false) { -// std::cerr << "open db failed" << std::endl; -// abort(); -// } -// InsertData(db, short_value_size); + TEST(TestKV, GetValue) { + DB *db; + if(OpenDB("testdb_TestKV_short_value", &db).ok() == false) { + std::cerr << "open db failed" << std::endl; + abort(); + } + InsertData(db, short_value_size); -// ReadOptions readOptions; -// Status status; -// int key_num = data_size / short_value_size; -// srand(42); -// for (int i = 0; i < key_num; i++) { -// // int key_ = rand() % key_num+1; -// std::string key = std::to_string(i); -// std::string value; -// std::string expected_value(short_value_size, 'a'); -// status = db->Get(readOptions, key, &value); + ReadOptions readOptions; + Status status; + int key_num = data_size / short_value_size; + srand(42); + for (int i = 0; i < key_num; i++) { + // int key_ = rand() % key_num+1; + std::string key = std::to_string(i); + std::string value; + std::string expected_value(short_value_size, 'a'); + status = db->Get(readOptions, key, &value); // std::cout << key << std::endl; -// ASSERT_TRUE(status.ok()); -// EXPECT_EQ(expected_value, value); -// } -// } + ASSERT_TRUE(status.ok()); + EXPECT_EQ(expected_value, value); + } + } -TEST(TestTTL, GetLongValue) { +TEST(TestKV, GetLongValue) { DB *db; - if(OpenDB("testdb_ReadTTL_1", &db).ok() == false) { + if(OpenDB("testdb_TestKV_long_value", &db).ok() == false) { std::cerr << "open db failed" << std::endl; abort(); } @@ -82,13 +82,15 @@ TEST(TestTTL, GetLongValue) { ReadOptions readOptions; Status status; int key_num = data_size / long_value_size; - for (int i = 14; i < key_num; i++) { + for (int i = 0; i < key_num; i++) { +// for (int i = 0; i < key_num - 1; i++) { // int key_ = rand() % key_num+1; std::string key = std::to_string(i); std::string value; std::string expected_value(long_value_size, 'a'); status = db->Get(readOptions, key, &value); std::cout << key << std::endl; + std::cout << status.ToString() << std::endl; ASSERT_TRUE(status.ok()); EXPECT_EQ(expected_value, value); } diff --git a/test/value_field_test.cc b/test/value_field_test.cc index 1613e81..6772e57 100644 --- a/test/value_field_test.cc +++ b/test/value_field_test.cc @@ -6,246 +6,242 @@ using namespace leveldb; Status OpenDB(const std::string& dbName, DB** db) { - // 如果数据库已经存在,则删除它。 - std::string rm_command = "rm -rf " + dbName; - system(rm_command.c_str()); + // 如果数据库已经存在,则删除它。 + std::string rm_command = "rm -rf " + dbName; + system(rm_command.c_str()); - Options options; - options.create_if_missing = true; - return DB::Open(options, dbName, db); + Options options; + options.create_if_missing = true; + return DB::Open(options, dbName, db); } class FieldsTest : public ::testing::Test { -protected: - void SetUp() override { - Status s = OpenDB("testdb", &db_); - EXPECT_TRUE(s.ok()) << "Failed to open database: " << s.ToString(); - } - - void TearDown() override { - delete db_; - db_ = nullptr; - } - - DB* db_ = nullptr; // 数据库实例指针。 + protected: + void SetUp() override { + Status s = OpenDB("testdb", &db_); + EXPECT_TRUE(s.ok()) << "Failed to open database: " << s.ToString(); + } + + void TearDown() override { + delete db_; + db_ = nullptr; + } + + DB* db_ = nullptr; // 数据库实例指针。 }; // 测试各种构造函数 -// TEST_F(FieldsTest, TestConstructors) { -// // 单个 Field 构造 -// Fields f_single(Field("single", "value")); -// EXPECT_EQ(f_single.size(), 1); -// EXPECT_TRUE(f_single.HasField("single")); - -// // FieldArray 构造 -// FieldArray fields = {{"array1", "value1"}, {"array2", "value2"}}; -// Fields f_array(fields); -// EXPECT_EQ(f_array.size(), 2); -// EXPECT_TRUE(f_array.HasField("array1")); -// EXPECT_TRUE(f_array.HasField("array2")); - -// // field_names 数组构造 -// std::vector field_names = {"name1", "name2"}; -// Fields f_names(field_names); -// EXPECT_EQ(f_names.size(), 2); -// } - -// // 测试构造函数内的SortFields的实现 -// TEST_F(FieldsTest, TestSortFields) { -// // 准备一组未排序的字段数据 -// FieldArray unsorted_fields = { -// {"field3", "value3"}, -// {"field1", "value1"}, -// {"field2", "value2"}, -// {"field5", "value5"}, -// {"field4", "value4"} -// }; - -// // 创建 Fields 对象,构造函数应该自动调用 SortFields -// Fields f(unsorted_fields); - -// // 验证字段是否已经正确排序 -// EXPECT_TRUE(std::is_sorted(f.begin(), f.end(), -// [](const Field& lhs, const Field& rhs) { -// return lhs.first < rhs.first; -// })) << "Fields are not sorted after constructor."; - -// // 验证排序后的字段顺序是否符合预期 -// std::vector expected_order = {"field1", "field2", "field3", "field4", "field5"}; -// size_t index = 0; -// for (const auto& field : f) { -// EXPECT_EQ(field.first, expected_order[index++]) << "Field order is incorrect after constructor sorting."; -// } -// } - -// // 测试 operator[] 访问功能 -// TEST_F(FieldsTest, TestOperatorBracketAccess) { -// // 创建一个 Fields 对象并添加一些字段 -// FieldArray fields = {{"field1", "value1"}, {"field2", "value2"}}; -// Fields f(fields); - -// // 使用 operator[] 来获取字段值 -// EXPECT_EQ(f["field1"], "value1"); -// EXPECT_EQ(f["field2"], "value2"); - -// // 尝试获取不存在的字段,应该返回空字符串 -// testing::internal::CaptureStderr(); -// EXPECT_EQ(f["nonexistent_field"], ""); -// } - -// // 测试 operator[] 更新功能 -// TEST_F(FieldsTest, TestOperatorBracketUpdate) { -// // 创建一个 Fields 对象并添加一些字段 -// Fields f; - -// // 使用 operator[] 来设置字段值(字段不存在时应插入) -// f["field1"] = "value1"; -// EXPECT_EQ(f["field1"], "value1"); - -// // 更新已存在的字段值 -// f["field1"] = "new_value1"; -// EXPECT_EQ(f["field1"], "new_value1"); - -// // 插入多个新字段 -// f["field2"] = "value2"; -// f["field3"] = "value3"; - -// // 验证所有字段都已正确插入 -// EXPECT_EQ(f.size(), 3); -// EXPECT_EQ(f["field1"], "new_value1"); -// EXPECT_EQ(f["field2"], "value2"); -// EXPECT_EQ(f["field3"], "value3"); - -// } +TEST_F(FieldsTest, TestConstructors) { + // 单个 Field 构造 + Fields f_single(Field("single", "value")); + EXPECT_EQ(f_single.size(), 1); + EXPECT_TRUE(f_single.HasField("single")); + + // FieldArray 构造 + FieldArray fields = {{"array1", "value1"}, {"array2", "value2"}}; + Fields f_array(fields); + EXPECT_EQ(f_array.size(), 2); + EXPECT_TRUE(f_array.HasField("array1")); + EXPECT_TRUE(f_array.HasField("array2")); + + // field_names 数组构造 + std::vector field_names = {"name1", "name2"}; + Fields f_names(field_names); + EXPECT_EQ(f_names.size(), 2); +} + +// 测试构造函数内的SortFields的实现 +TEST_F(FieldsTest, TestSortFields) { + // 准备一组未排序的字段数据 + FieldArray unsorted_fields = { + {"field3", "value3"}, + {"field1", "value1"}, + {"field2", "value2"}, + {"field5", "value5"}, + {"field4", "value4"} + }; + + // 创建 Fields 对象,构造函数应该自动调用 SortFields + Fields f(unsorted_fields); + + // 验证字段是否已经正确排序 + EXPECT_TRUE(std::is_sorted(f.begin(), f.end(), + [](const Field& lhs, const Field& rhs) { + return lhs.first < rhs.first; + })) << "Fields are not sorted after constructor."; + + // 验证排序后的字段顺序是否符合预期 + std::vector expected_order = {"field1", "field2", "field3", "field4", "field5"}; + size_t index = 0; + for (const auto& field : f) { + EXPECT_EQ(field.first, expected_order[index++]) << "Field order is incorrect after constructor sorting."; + } +} + +// 测试 operator[] 访问功能 +TEST_F(FieldsTest, TestOperatorBracketAccess) { + // 创建一个 Fields 对象并添加一些字段 + FieldArray fields = {{"field1", "value1"}, {"field2", "value2"}}; + Fields f(fields); + + // 使用 operator[] 来获取字段值 + EXPECT_EQ(f["field1"], "value1"); + EXPECT_EQ(f["field2"], "value2"); + + // 尝试获取不存在的字段,应该返回空字符串 + testing::internal::CaptureStderr(); + EXPECT_EQ(f["nonexistent_field"], ""); +} + +// 测试 operator[] 更新功能 +TEST_F(FieldsTest, TestOperatorBracketUpdate) { + // 创建一个 Fields 对象并添加一些字段 + Fields f; + + // 使用 operator[] 来设置字段值(字段不存在时应插入) + f["field1"] = "value1"; + EXPECT_EQ(f["field1"], "value1"); + + // 更新已存在的字段值 + f["field1"] = "new_value1"; + EXPECT_EQ(f["field1"], "new_value1"); + + // 插入多个新字段 + f["field2"] = "value2"; + f["field3"] = "value3"; + + // 验证所有字段都已正确插入 + EXPECT_EQ(f.size(), 3); + EXPECT_EQ(f["field1"], "new_value1"); + EXPECT_EQ(f["field2"], "value2"); + EXPECT_EQ(f["field3"], "value3"); + +} // 测试批量删除功能 TEST_F(FieldsTest, TestBulkDelete) { - const size_t num_fields = 10000; - leveldb::WriteBatch batch; - - std::string a = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; - - // 准备大量字段数据,并通过 PutFields 插入到数据库 - for (size_t i = 0; i < num_fields; ++i) { - std::string key = "key_" + std::to_string(i); - FieldArray fields = {{"field" + std::to_string(i), "value_" + a}}; - Fields f(fields); - Status status = db_->PutFields(WriteOptions(), Slice(key), f); - EXPECT_TRUE(status.ok()) << "Failed to put fields for key: " << key; - } - -// 批量删除一半的字段 -// for (size_t i = 0; i < num_fields / 2; ++i) { -// std::string key = "key_" + std::to_string(i); -// Status status = db_->Delete(WriteOptions(), key); -// EXPECT_TRUE(status.ok()) << "Failed to delete key: " << key; -// } - - // 验证删除后的字段数量和内容 - for (size_t i = 0; i < num_fields; ++i) { - std::string key = "key_" + std::to_string(i); - Fields fields; - Status status = db_->GetFields(ReadOptions(), Slice(key), fields); - - if (i < num_fields / 2) { - EXPECT_FALSE(status.ok()) << "Deleted key still exists: " << key; - auto field_value = fields.GetField("field" + std::to_string(i)); - EXPECT_EQ(field_value.second, "value_" ) << "Incorrect value for non-deleted field: " << key; -// } else { -// EXPECT_TRUE(status.ok()) << "Missing non-deleted key: " << key; -// auto field_value = fields.GetField("field" + std::to_string(i)); -// EXPECT_EQ(field_value.second, "value_" + a) << "Incorrect value for non-deleted field: " << key; - } + const size_t num_fields = 1000; + leveldb::WriteBatch batch; + + // 准备大量字段数据,并通过 PutFields 插入到数据库 + for (size_t i = 0; i < num_fields; ++i) { + std::string key = "key_" + std::to_string(i); + FieldArray fields = {{"field" + std::to_string(i), "value_" + std::to_string(i)}}; + Fields f(fields); + Status status = db_->PutFields(WriteOptions(), Slice(key), f); + EXPECT_TRUE(status.ok()) << "Failed to put fields for key: " << key; + } + + // 批量删除一半的字段 + for (size_t i = 0; i < num_fields / 2; ++i) { + std::string key = "key_" + std::to_string(i); + Status status = db_->Delete(WriteOptions(), key); + EXPECT_TRUE(status.ok()) << "Failed to delete key: " << key; + } + + // 验证删除后的字段数量和内容 + for (size_t i = 0; i < num_fields; ++i) { + std::string key = "key_" + std::to_string(i); + Fields fields; + Status status = db_->GetFields(ReadOptions(), Slice(key), fields); + + if (i < num_fields / 2) { + EXPECT_FALSE(status.ok()) << "Deleted key still exists: " << key; + } else { + EXPECT_TRUE(status.ok()) << "Missing non-deleted key: " << key; + auto field_value = fields.GetField("field" + std::to_string(i)); + EXPECT_EQ(field_value.second, "value_" + std::to_string(i)) << "Incorrect value for non-deleted field: " << key; } + } } // 测试批量更新操作 -//TEST_F(FieldsTest, TestBulkUpdate) { -// const size_t num_fields = 500; -// leveldb::WriteBatch batch; -// -// // 准备大量字段数据,并通过 PutFields 插入到数据库 -// for (size_t i = 0; i < num_fields; ++i) { -// std::string key = "key_" + std::to_string(i); -// FieldArray fields = {{"field" + std::to_string(i), "old_value_" + std::to_string(i)}}; -// Fields f(fields); -// Status status = db_->PutFields(WriteOptions(), Slice(key), f); -// EXPECT_TRUE(status.ok()) << "Failed to put fields for key: " << key; -// } -// -// // 批量更新一半的字段 -// for (size_t i = 0; i < num_fields / 2; ++i) { -// std::string key = "key_" + std::to_string(i); -// FieldArray update_fields = {{"field" + std::to_string(i), "new_value_" + std::to_string(i)}}; -// Fields f(update_fields); -// Status status = db_->PutFields(WriteOptions(), Slice(key), f); -// EXPECT_TRUE(status.ok()) << "Failed to update fields for key: " << key; -// } -// -// // 验证更新后的字段值 -// for (size_t i = 0; i < num_fields; ++i) { -// std::string key = "key_" + std::to_string(i); -// Fields fields; -// Status status = db_->GetFields(ReadOptions(), Slice(key), fields); -// EXPECT_TRUE(status.ok()) << "Failed to read key: " << key; -// -// auto field_value = fields.GetField("field" + std::to_string(i)); -// auto expected_value = (i < num_fields / 2) ? ("new_value_" + std::to_string(i)) : ("old_value_" + std::to_string(i)); -// EXPECT_EQ(field_value.second, expected_value) << "Incorrect value for updated field: " << key; -// } -//} -// -//// 测试批量插入、序列化/反序列化、删除以及 FindKeysByFields 功能 -//TEST_F(FieldsTest, TestBulkInsertSerializeDeleteAndFindKeys) { -// const size_t num_entries = 500; -// -// // 准备大量键值对数据,并通过 PutFields 插入到数据库 -// for (size_t i = num_entries; i > 0; --i) { -// std::string key = "key_" + std::to_string(i); -// FieldArray fields = {{"field1", "value1_" + std::to_string(i)}, {"field2", "value2_"}}; -// Fields ffields(fields); -// Status status = db_->PutFields(WriteOptions(), Slice(key), ffields); -// EXPECT_TRUE(status.ok()) << "Failed to put fields for key: " << key << ", error: " << status.ToString(); -// } -// -// // 验证插入的数据是否正确 -// for (size_t i = 1; i <= num_entries; ++i) { -// std::string key = "key_" + std::to_string(i); -// Fields fields; -// Status status = db_->GetFields(ReadOptions(), Slice(key), fields); -// EXPECT_TRUE(status.ok()) << "Failed to read key: " << key << ", error: " << status.ToString(); -// -// // 使用 GetField 方法验证字段值 -// auto field1_value = fields.GetField("field1"); -// auto field2_value = fields.GetField("field2"); -// -// EXPECT_EQ(field1_value.second, "value1_" + std::to_string(i)) << "Incorrect value for field1 in key: " << key; -// EXPECT_EQ(field2_value.second, "value2_") << "Incorrect value for field2 in key: " << key; -// } -// -// // 使用 Delete 删除第一个键值对 -// Status status = db_->Delete(WriteOptions(), "key_1"); -// EXPECT_TRUE(status.ok()) << "Failed to delete key: key_1, error: " << status.ToString(); -// -// // 使用 FindKeysByFields 查找包含特定字段的键 -// FieldArray fields_to_find = {{"field2", "value2_"}}; -// std::vector found_keys = Fields::FindKeysByFields(db_, fields_to_find); -// -// // 验证找到的键是否正确 -// EXPECT_EQ(found_keys.size(), num_entries - 1) << "Expected " << num_entries - 1 << " keys but found " << found_keys.size(); -// for (size_t i = 2; i <= num_entries; ++i) { -// std::string expected_key = "key_" + std::to_string(i); -// EXPECT_TRUE(std::find(found_keys.begin(), found_keys.end(), expected_key) != found_keys.end()) -// << "Key not found: " << expected_key; -// } -// -// // 再次查找,这次没有符合条件的字段 -// FieldArray no_match_fields = {{"nonexistent_field", ""}}; -// found_keys = Fields::FindKeysByFields(db_, no_match_fields); -// EXPECT_TRUE(found_keys.empty()) << "Expected an empty result for non-matching fields."; -//} +TEST_F(FieldsTest, TestBulkUpdate) { + const size_t num_fields = 500; + leveldb::WriteBatch batch; + + // 准备大量字段数据,并通过 PutFields 插入到数据库 + for (size_t i = 0; i < num_fields; ++i) { + std::string key = "key_" + std::to_string(i); + FieldArray fields = {{"field" + std::to_string(i), "old_value_" + std::to_string(i)}}; + Fields f(fields); + Status status = db_->PutFields(WriteOptions(), Slice(key), f); + EXPECT_TRUE(status.ok()) << "Failed to put fields for key: " << key; + } + + // 批量更新一半的字段 + for (size_t i = 0; i < num_fields / 2; ++i) { + std::string key = "key_" + std::to_string(i); + FieldArray update_fields = {{"field" + std::to_string(i), "new_value_" + std::to_string(i)}}; + Fields f(update_fields); + Status status = db_->PutFields(WriteOptions(), Slice(key), f); + EXPECT_TRUE(status.ok()) << "Failed to update fields for key: " << key; + } + + // 验证更新后的字段值 + for (size_t i = 0; i < num_fields; ++i) { + std::string key = "key_" + std::to_string(i); + Fields fields; + Status status = db_->GetFields(ReadOptions(), Slice(key), fields); + EXPECT_TRUE(status.ok()) << "Failed to read key: " << key; + + auto field_value = fields.GetField("field" + std::to_string(i)); + auto expected_value = (i < num_fields / 2) ? ("new_value_" + std::to_string(i)) : ("old_value_" + std::to_string(i)); + EXPECT_EQ(field_value.second, expected_value) << "Incorrect value for updated field: " << key; + } +} + +// 测试批量插入、序列化/反序列化、删除以及 FindKeysByFields 功能 +TEST_F(FieldsTest, TestBulkInsertSerializeDeleteAndFindKeys) { + const size_t num_entries = 500; + + // 准备大量键值对数据,并通过 PutFields 插入到数据库 + for (size_t i = num_entries; i > 0; --i) { + std::string key = "key_" + std::to_string(i); + FieldArray fields = {{"field1", "value1_" + std::to_string(i)}, {"field2", "value2_"}}; + Fields ffields(fields); + Status status = db_->PutFields(WriteOptions(), Slice(key), ffields); + EXPECT_TRUE(status.ok()) << "Failed to put fields for key: " << key << ", error: " << status.ToString(); + } + + // 验证插入的数据是否正确 + for (size_t i = 1; i <= num_entries; ++i) { + std::string key = "key_" + std::to_string(i); + Fields fields; + Status status = db_->GetFields(ReadOptions(), Slice(key), fields); + EXPECT_TRUE(status.ok()) << "Failed to read key: " << key << ", error: " << status.ToString(); + + // 使用 GetField 方法验证字段值 + auto field1_value = fields.GetField("field1"); + auto field2_value = fields.GetField("field2"); + + EXPECT_EQ(field1_value.second, "value1_" + std::to_string(i)) << "Incorrect value for field1 in key: " << key; + EXPECT_EQ(field2_value.second, "value2_") << "Incorrect value for field2 in key: " << key; + } + + // 使用 Delete 删除第一个键值对 + Status status = db_->Delete(WriteOptions(), "key_1"); + EXPECT_TRUE(status.ok()) << "Failed to delete key: key_1, error: " << status.ToString(); + + // 使用 FindKeysByFields 查找包含特定字段的键 + FieldArray fields_to_find = {{"field2", "value2_"}}; + std::vector found_keys = Fields::FindKeysByFields(db_, fields_to_find); + + // 验证找到的键是否正确 + EXPECT_EQ(found_keys.size(), num_entries - 1) << "Expected " << num_entries - 1 << " keys but found " << found_keys.size(); + for (size_t i = 2; i <= num_entries; ++i) { + std::string expected_key = "key_" + std::to_string(i); + EXPECT_TRUE(std::find(found_keys.begin(), found_keys.end(), expected_key) != found_keys.end()) + << "Key not found: " << expected_key; + } + + // 再次查找,这次没有符合条件的字段 + FieldArray no_match_fields = {{"nonexistent_field", ""}}; + found_keys = Fields::FindKeysByFields(db_, no_match_fields); + EXPECT_TRUE(found_keys.empty()) << "Expected an empty result for non-matching fields."; +} int main(int argc, char** argv) { - ::testing::InitGoogleTest(&argc, argv); - return RUN_ALL_TESTS(); + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); } \ No newline at end of file