@ -0,0 +1,254 @@ | |||
#include "gtest/gtest.h" | |||
#include "db/NewDB.h" // NewDB 的头文件 | |||
#include "leveldb/env.h" | |||
#include "leveldb/db.h" | |||
#include "db/write_batch_internal.h" | |||
#include <iostream> | |||
#include <random> | |||
#include <ctime> | |||
#include <thread> | |||
#include <mutex> | |||
#include <chrono> | |||
#include <atomic> | |||
using namespace leveldb; | |||
// 全局计数器 | |||
std::atomic<int> put_count(0); | |||
std::atomic<int> delete_count(0); | |||
std::atomic<int> create_index_count(0); | |||
std::atomic<int> delete_index_count(0); | |||
std::atomic<int> total_operations(0); | |||
std::mutex latency_mutex; | |||
std::vector<long long> latencies; | |||
thread_local std::vector<long long> put_latencies_local; | |||
thread_local std::vector<long long> delete_latencies_local; | |||
thread_local std::vector<long long> update_latencies_local; | |||
std::mutex put_latency_mutex; | |||
std::vector<long long> put_latencies; | |||
std::mutex delete_latency_mutex; | |||
std::vector<long long> delete_latencies; | |||
std::mutex update_latency_mutex; | |||
std::vector<long long> update_latencies; | |||
// void RecordLatency(long long duration) { | |||
// std::unique_lock<std::mutex> lock(latency_mutex); | |||
// latencies.push_back(duration); | |||
// } | |||
void RecordLatency(long long duration, const std::string& op_type) { | |||
if (op_type == "PUT") { | |||
put_latencies_local.push_back(duration); | |||
} else if (op_type == "DELETE") { | |||
delete_latencies_local.push_back(duration); | |||
} else if (op_type == "UPDATE") { | |||
update_latencies_local.push_back(duration); | |||
} | |||
} | |||
void MergeLatencies() { | |||
{ | |||
std::unique_lock<std::mutex> lock(put_latency_mutex); | |||
put_latencies.insert(put_latencies.end(), | |||
put_latencies_local.begin(), | |||
put_latencies_local.end()); | |||
} | |||
{ | |||
std::unique_lock<std::mutex> lock(delete_latency_mutex); | |||
delete_latencies.insert(delete_latencies.end(), | |||
delete_latencies_local.begin(), | |||
delete_latencies_local.end()); | |||
} | |||
{ | |||
std::unique_lock<std::mutex> lock(update_latency_mutex); | |||
update_latencies.insert(update_latencies.end(), | |||
update_latencies_local.begin(), | |||
update_latencies_local.end()); | |||
} | |||
} | |||
Status OpenNewDB(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<int> 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; | |||
} | |||
int getRandomInRange(int min, int max) { | |||
return min + std::rand() % ((max + 1) - min); | |||
} | |||
std::mutex results_mutex; | |||
std::vector<bool> results; | |||
void InsertResult(bool TRUEorFALSE){ | |||
std::unique_lock<std::mutex> lock(results_mutex, std::defer_lock); | |||
lock.lock(); | |||
results.emplace_back(TRUEorFALSE); | |||
lock.unlock(); | |||
} | |||
std::string testdbname = "dbtest36"; | |||
void thread_task_put(NewDB* db, int thread_id, int num_operations) { | |||
for (int i = 0; i < num_operations; ++i) { | |||
auto start = std::chrono::high_resolution_clock::now(); | |||
std::string key = "k_" + std::to_string(thread_id) + "_" + std::to_string(i); | |||
FieldArray fields = { | |||
{"name", "User" + std::to_string(i)}, | |||
{"email", "user" + std::to_string(i) + "@test.com"} | |||
}; | |||
db->Put_fields(WriteOptions(), key, fields); | |||
total_operations++; | |||
auto end = std::chrono::high_resolution_clock::now(); | |||
long long duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start).count(); | |||
RecordLatency(duration, "PUT"); | |||
} | |||
// 合并本线程的延迟数据 | |||
MergeLatencies(); | |||
} | |||
void thread_task_delete(NewDB* db, int thread_id, int num_operations) { | |||
for (int i = 0; i < num_operations; ++i) { | |||
int key_index = getRandomInRange(0, 9999); | |||
std::string key = "k_" + std::to_string(key_index); | |||
auto start = std::chrono::high_resolution_clock::now(); | |||
db->Delete(WriteOptions(), key); | |||
delete_count++; | |||
auto end = std::chrono::high_resolution_clock::now(); | |||
long long duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start).count(); | |||
RecordLatency(duration, "DELETE"); | |||
total_operations++; | |||
} | |||
// 合并本线程的延迟数据 | |||
MergeLatencies(); | |||
} | |||
void thread_task_update(NewDB* db, int thread_id, int num_operations) { | |||
for (int i = 0; i < num_operations; ++i) { | |||
std::string key = "k_" + std::to_string(thread_id) + "_" + std::to_string(i); | |||
FieldArray fields = { | |||
{"email", "updated_user" + std::to_string(i) + "@test.com"} | |||
}; | |||
auto start = std::chrono::high_resolution_clock::now(); | |||
db->Put_fields(WriteOptions(), key, fields); // 简单地更新一个字段 | |||
total_operations++; | |||
auto end = std::chrono::high_resolution_clock::now(); | |||
long long duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start).count(); | |||
RecordLatency(duration, "UPDATE"); | |||
} | |||
// 合并本线程的延迟数据 | |||
MergeLatencies(); | |||
} | |||
// 并发测试:包括 put, delete, update | |||
TEST(NewDBTest, ConcurrencyTest_mul) { | |||
NewDB* db; | |||
ASSERT_TRUE(OpenNewDB(testdbname, &db).ok()); | |||
const int thread_num_put = 10; | |||
const int thread_num_delete = 1; | |||
const int thread_num_update = 0; | |||
const int operations_per_thread = 10; | |||
const int operations_per_thread_delete = 50; | |||
const int operations_per_thread_update = 50; | |||
std::vector<std::thread> threads; | |||
auto start = std::chrono::high_resolution_clock::now(); | |||
// 启动 PUT 线程 | |||
for (int i = 0; i < thread_num_put; ++i) { | |||
threads.emplace_back(thread_task_put, db, i, operations_per_thread); | |||
} | |||
// 启动 DELETE 线程 | |||
for (int i = 0; i < thread_num_delete; ++i) { | |||
threads.emplace_back(thread_task_delete, db, i, operations_per_thread_delete); | |||
} | |||
// 启动 UPDATE 线程 | |||
for (int i = 0; i < thread_num_update; ++i) { | |||
threads.emplace_back(thread_task_update, db, i, operations_per_thread_update); | |||
} | |||
for (auto& th : threads) { | |||
th.join(); | |||
} | |||
auto end = std::chrono::high_resolution_clock::now(); | |||
long long total_duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count(); | |||
auto calculate_latency = [](const std::vector<long long>& latencies) { | |||
long long sum = 0; | |||
for (auto& lat : latencies) { | |||
sum += lat; | |||
} | |||
return std::make_pair(sum, latencies.size() > 0 ? static_cast<double>(sum) / latencies.size() : 0); | |||
}; | |||
auto [put_sum, put_avg] = calculate_latency(put_latencies); | |||
auto [delete_sum, delete_avg] = calculate_latency(delete_latencies); | |||
auto [update_sum, update_avg] = calculate_latency(update_latencies); | |||
std::cout << "Total Operations: " << total_operations.load() << std::endl; | |||
std::cout << "Total Duration: " << total_duration << " ms" << std::endl; | |||
std::cout << "Throughput (ops/sec): " << static_cast<double>(total_operations.load()) / (total_duration / 1000.0) << std::endl; | |||
std::cout << "\nPUT Operations:" << std::endl; | |||
std::cout << " Total Latency (ms): " << put_sum / 1000.0 << std::endl; | |||
std::cout << " Average Latency (us): " << put_avg << std::endl; | |||
std::cout << "\nDELETE Operations:" << std::endl; | |||
std::cout << " Total Latency (ms): " << delete_sum / 1000.0 << std::endl; | |||
std::cout << " Average Latency (us): " << delete_avg << std::endl; | |||
std::cout << "\nUPDATE Operations:" << std::endl; | |||
std::cout << " Total Latency (ms): " << update_sum / 1000.0 << std::endl; | |||
std::cout << " Average Latency (us): " << update_avg << std::endl; | |||
delete db; | |||
} | |||
int main(int argc, char** argv) { | |||
// 设置全局随机种子 | |||
SetGlobalSeed(static_cast<unsigned>(time(nullptr))); | |||
testing::InitGoogleTest(&argc, argv); | |||
return RUN_ALL_TESTS(); | |||
} |
@ -0,0 +1,198 @@ | |||
#include "gtest/gtest.h" | |||
#include "db/NewDB.h" // NewDB 的头文件 | |||
#include "leveldb/env.h" | |||
#include "leveldb/db.h" | |||
#include "db/write_batch_internal.h" | |||
#include <iostream> | |||
#include <random> | |||
#include <ctime> | |||
#include <thread> | |||
#include <mutex> | |||
#include <chrono> | |||
#include <atomic> | |||
using namespace leveldb; | |||
// 全局计数器 | |||
std::atomic<int> put_count(0); | |||
std::atomic<int> delete_count(0); | |||
std::atomic<int> create_index_count(0); | |||
std::atomic<int> delete_index_count(0); | |||
std::atomic<int> total_operations(0); | |||
std::mutex latency_mutex; | |||
std::vector<long long> latencies; | |||
void RecordLatency(long long duration) { | |||
std::unique_lock<std::mutex> lock(latency_mutex); | |||
latencies.push_back(duration); | |||
} | |||
Status OpenNewDB(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<int> 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; | |||
} | |||
int getRandomInRange(int min, int max) { | |||
return min + std::rand() % ((max + 1) - min); | |||
} | |||
std::mutex results_mutex; | |||
std::vector<bool> results; | |||
void InsertResult(bool TRUEorFALSE){ | |||
std::unique_lock<std::mutex> lock(results_mutex, std::defer_lock); | |||
lock.lock(); | |||
results.emplace_back(TRUEorFALSE); | |||
lock.unlock(); | |||
} | |||
std::string testdbname = "dbtest36"; | |||
// 多线程插入 | |||
void thread_task_put(NewDB* db, int thread_id, int num_operations) { | |||
for (int i = 0; i < num_operations; ++i) { | |||
auto start = std::chrono::high_resolution_clock::now(); | |||
std::string key = "k_" + std::to_string(thread_id) + "_" + std::to_string(i); | |||
FieldArray fields = { | |||
{"name", "User" + std::to_string(i)}, | |||
{"email", "user" + std::to_string(i) + "@test.com"} | |||
}; | |||
db->Put_fields(WriteOptions(), key, fields); | |||
total_operations++; | |||
auto end = std::chrono::high_resolution_clock::now(); | |||
long long duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count(); | |||
RecordLatency(duration); | |||
} | |||
} | |||
// // 测试吞吐量和延迟 | |||
// TEST(TestNewDB, PerformanceTest) { | |||
// NewDB* db; | |||
// ASSERT_TRUE(OpenNewDB(testdbname, &db).ok()); | |||
// const int thread_num = 100; | |||
// std::vector<std::thread> threads; | |||
// auto test_start = std::chrono::high_resolution_clock::now(); | |||
// for (int i = 0; i < thread_num; ++i) { | |||
// threads.emplace_back([=]() { thread_task_put(db, i); }); | |||
// threads.emplace_back([=]() { thread_task_delete(db, i); }); | |||
// threads.emplace_back([=]() { thread_task_createindex(db, i); }); | |||
// threads.emplace_back([=]() { thread_task_deleteindex(db, i); }); | |||
// } | |||
// for (auto& th : threads) { | |||
// if (th.joinable()) { | |||
// th.join(); | |||
// } | |||
// } | |||
// auto test_end = std::chrono::high_resolution_clock::now(); | |||
// long long total_duration = std::chrono::duration_cast<std::chrono::milliseconds>(test_end - test_start).count(); | |||
// // 计算吞吐量 | |||
// double throughput = static_cast<double>(total_operations) / (total_duration / 1000.0); | |||
// // 计算平均延迟 | |||
// long long sum_latency = 0; | |||
// for (auto& lat : latencies) { | |||
// sum_latency += lat; | |||
// } | |||
// double avg_latency = static_cast<double>(sum_latency) / latencies.size(); | |||
// std::cout << "Total Operations: " << total_operations.load() << std::endl; | |||
// std::cout << "Throughput (ops/sec): " << throughput << std::endl; | |||
// std::cout << "Average Latency (us): " << avg_latency << std::endl; | |||
// std::cout << "PUT operations: " << put_count.load() << std::endl; | |||
// std::cout << "DELETE operations: " << delete_count.load() << std::endl; | |||
// std::cout << "CREATE INDEX operations: " << create_index_count.load() << std::endl; | |||
// std::cout << "DELETE INDEX operations: " << delete_index_count.load() << std::endl; | |||
// delete db; | |||
// } | |||
//并发测试 | |||
TEST(NewDBTest, ConcurrencyTest) { | |||
NewDB* db; | |||
ASSERT_TRUE(OpenNewDB(testdbname, &db).ok()); | |||
const int thread_num = 100; | |||
const int operations_per_thread = 10; | |||
std::vector<std::thread> threads; | |||
auto start = std::chrono::high_resolution_clock::now(); | |||
// 启动线程 | |||
for (int i = 0; i < thread_num; ++i) { | |||
threads.emplace_back(thread_task_put, db, i, operations_per_thread); | |||
} | |||
// 等待线程完成 | |||
for (auto& th : threads) { | |||
th.join(); | |||
} | |||
auto end = std::chrono::high_resolution_clock::now(); | |||
long long total_duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count(); | |||
// 计算吞吐量 | |||
double throughput = static_cast<double>(total_operations.load()) / (total_duration / 1000.0); | |||
// 计算平均延迟 | |||
long long sum_latency = 0; | |||
for (auto& lat : latencies) { | |||
sum_latency += lat; | |||
} | |||
double avg_latency = static_cast<double>(sum_latency) / latencies.size(); | |||
//double avg_latency = static_cast<double>(total_duration) * 1000.0 / total_operations.load(); | |||
// 转换为毫秒 | |||
double total_latency_ms = static_cast<double>(sum_latency) / 1000.0; | |||
std::cout << "Total Operations: " << total_operations.load() << std::endl; | |||
std::cout << "Total Duration: " << total_duration << std::endl; | |||
std::cout << "Throughput (ops/sec): " << throughput << std::endl; | |||
std::cout << "Average Latency (us): " << avg_latency << std::endl; | |||
std::cout << "Total Latency (ms): " << total_latency_ms << std::endl; | |||
delete db; | |||
} | |||
int main(int argc, char** argv) { | |||
// 设置全局随机种子 | |||
SetGlobalSeed(static_cast<unsigned>(time(nullptr))); | |||
testing::InitGoogleTest(&argc, argv); | |||
return RUN_ALL_TESTS(); | |||
} |
@ -0,0 +1,236 @@ | |||
#include "gtest/gtest.h" | |||
#include "db/NewDB.h" // NewDB 的头文件 | |||
#include "leveldb/env.h" | |||
#include "leveldb/db.h" | |||
#include <iostream> | |||
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::string testdbname = "testdb1"; | |||
// 测试 NewDB::Put_fields 方法和二级索引的创建 | |||
TEST(TestNewDB, PutFieldsWithIndexTest) { | |||
// 创建 NewDB 实例 | |||
NewDB* db; | |||
if (OpenDB(testdbname, &db).ok() == false) { | |||
std::cerr << "open db failed" << std::endl; | |||
abort(); | |||
} | |||
// 创建索引字段 | |||
db->CreateIndexOnField("address"); | |||
// 定义插入的字段数据 | |||
std::string key1 = "k_1"; | |||
FieldArray fields1 = { | |||
{"name", "Customer#000000001"}, | |||
{"address", "IVhzIApeRb"}, | |||
{"phone", "25-989-741-2988"} | |||
}; | |||
// 定义字段数组,用于获取数据 | |||
FieldArray retrieved_fields; | |||
// 使用 NewDB::Put_fields 插入数据 | |||
db->Put_fields(WriteOptions(), key1, fields1); | |||
// // 检查索引是否成功创建 | |||
// EXPECT_TRUE(db->IsFieldIndexed("address")); // 检查字段是否已索引 | |||
// 获取并验证字段数据 | |||
db->Get_fields(ReadOptions(), key1, &retrieved_fields); | |||
EXPECT_EQ(retrieved_fields.size(), fields1.size()); | |||
// 验证插入的每个字段 | |||
for (size_t i = 0; i < fields1.size(); ++i) { | |||
EXPECT_EQ(fields1[i].first, retrieved_fields[i].first); // 字段名 | |||
EXPECT_EQ(fields1[i].second, retrieved_fields[i].second); // 字段值 | |||
} | |||
// 插入第二条数据 | |||
std::string key2 = "k_2"; | |||
FieldArray fields2 = { | |||
{"name", "Customer#000000002"}, | |||
{"address", "TXkjZEdIrZ"}, | |||
{"phone", "25-123-456-7890"} | |||
}; | |||
db->Put_fields(WriteOptions(), key2, fields2); | |||
// 获取并验证第二条数据 | |||
FieldArray retrieved_fields2; | |||
db->Get_fields(ReadOptions(), key2, &retrieved_fields2); | |||
EXPECT_EQ(retrieved_fields2.size(), fields2.size()); | |||
for (size_t i = 0; i < fields2.size(); ++i) { | |||
EXPECT_EQ(fields2[i].first, retrieved_fields2[i].first); // 字段名 | |||
EXPECT_EQ(fields2[i].second, retrieved_fields2[i].second); // 字段值 | |||
} | |||
// 清理数据库 | |||
delete db; | |||
} | |||
TEST(TestNewDB, DeleteDataTest) { | |||
// 创建 NewDB 实例 | |||
NewDB* db; | |||
ASSERT_TRUE(OpenDB(testdbname, &db).ok()); | |||
// 插入测试数据 | |||
std::string key = "k_3"; | |||
FieldArray fields = { | |||
{"name", "Customer#000000003"}, | |||
{"address", "AddressToDelete"}, | |||
{"phone", "25-789-123-4567"} | |||
}; | |||
ASSERT_TRUE(db->Put_fields(WriteOptions(), key, fields).ok()); | |||
// 删除数据 | |||
ASSERT_TRUE(db->Delete(WriteOptions(), key)); | |||
// 验证数据已被删除 | |||
FieldArray retrieved_fields; | |||
Status s = db->Get_fields(ReadOptions(), key, &retrieved_fields); | |||
ASSERT_FALSE(s.ok()); // 数据应该不存在 | |||
// 清理数据库 | |||
delete db; | |||
} | |||
TEST(TestNewDB, QueryByIndexTest) { | |||
// 创建 NewDB 实例 | |||
NewDB* db; | |||
ASSERT_TRUE(OpenDB(testdbname, &db).ok()); | |||
// 创建索引字段 | |||
db->CreateIndexOnField("address"); | |||
// 插入测试数据 | |||
std::string key1 = "k_4"; | |||
FieldArray fields1 = { | |||
{"name", "Customer#000000004"}, | |||
{"address", "AddressToFind"}, | |||
{"phone", "25-987-654-3210"} | |||
}; | |||
ASSERT_TRUE(db->Put_fields(WriteOptions(), key1, fields1).ok()); | |||
// 查询索引 | |||
Field field_to_query{"address", "AddressToFind"}; | |||
std::vector<std::string> matching_keys = db->QueryByIndex(field_to_query); | |||
// 验证查询结果 | |||
ASSERT_EQ(matching_keys.size(), 1); | |||
EXPECT_EQ(matching_keys[0], key1); | |||
// 清理数据库 | |||
delete db; | |||
} | |||
TEST(TestNewDB, DeleteIndexTest) { | |||
// 创建 NewDB 实例 | |||
NewDB* db; | |||
ASSERT_TRUE(OpenDB(testdbname, &db).ok()); | |||
// 创建索引字段 | |||
db->CreateIndexOnField("address"); | |||
// 插入测试数据 | |||
std::string key1 = "k_5"; | |||
FieldArray fields1 = { | |||
{"name", "Customer#000000005"}, | |||
{"address", "AddressToDeleteIndex"}, | |||
{"phone", "25-123-456-7890"} | |||
}; | |||
ASSERT_TRUE(db->Put_fields(WriteOptions(), key1, fields1).ok()); | |||
// 删除索引 | |||
ASSERT_TRUE(db->DeleteIndex("address:AddressToDeleteIndex_k_5")); | |||
// 尝试查询已删除的索引 | |||
Field field_to_query{"address", "AddressToDeleteIndex"}; | |||
std::vector<std::string> matching_keys = db->QueryByIndex(field_to_query); | |||
// 验证查询结果为空 | |||
EXPECT_TRUE(matching_keys.empty()); | |||
// 清理数据库 | |||
delete db; | |||
} | |||
TEST(TestNewDB, UpdateFieldsAndQueryIndexTest) { | |||
// 创建 NewDB 实例 | |||
NewDB* db; | |||
ASSERT_TRUE(OpenDB(testdbname, &db).ok()); | |||
// 创建索引字段 | |||
db->CreateIndexOnField("address"); | |||
// 插入初始数据 | |||
std::string key = "k_6"; | |||
FieldArray initial_fields = { | |||
{"name", "Customer#000000006"}, | |||
{"address", "InitialAddress"}, | |||
{"phone", "25-987-654-3210"} | |||
}; | |||
ASSERT_TRUE(db->Put_fields(WriteOptions(), key, initial_fields).ok()); | |||
// 验证初始数据的索引查询 | |||
Field query_field1{"address", "InitialAddress"}; | |||
std::vector<std::string> matching_keys = db->QueryByIndex(query_field1); | |||
ASSERT_EQ(matching_keys.size(), 1); | |||
EXPECT_EQ(matching_keys[0], key); | |||
// 更新数据 | |||
FieldArray updated_fields = { | |||
{"name", "Customer#000000006"}, | |||
{"address", "UpdatedAddress"}, | |||
{"phone", "25-987-654-3210"} | |||
}; | |||
ASSERT_TRUE(db->Put_fields(WriteOptions(), key, updated_fields).ok()); | |||
// 获取并验证字段数据 | |||
FieldArray retrieved_fields; | |||
db->Get_fields(ReadOptions(), key, &retrieved_fields); | |||
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_field2{"address", "UpdatedAddress"}; | |||
matching_keys = db->QueryByIndex(query_field2); | |||
ASSERT_EQ(matching_keys.size(), 1); | |||
EXPECT_EQ(matching_keys[0], key); | |||
// 验证旧的 address 字段值不再存在于索引中 | |||
matching_keys = db->QueryByIndex(query_field1); | |||
ASSERT_EQ(matching_keys.size(), 0); | |||
EXPECT_TRUE(matching_keys.empty()); | |||
// 清理数据库 | |||
// db->Delete(WriteOptions(), "k_1"); | |||
// db->Delete(WriteOptions(), "k_2"); | |||
// db->Delete(WriteOptions(), "k_3"); | |||
// db->Delete(WriteOptions(), "k_4"); | |||
// db->Delete(WriteOptions(), "k_5"); | |||
// db->Delete(WriteOptions(), "k_6"); | |||
delete db; | |||
} | |||
// 主函数运行所有测试 | |||
int main(int argc, char** argv) { | |||
testing::InitGoogleTest(&argc, argv); | |||
return RUN_ALL_TESTS(); | |||
} |
@ -0,0 +1,436 @@ | |||
#include "gtest/gtest.h" | |||
#include "db/NewDB.h" // NewDB 的头文件 | |||
#include "leveldb/env.h" | |||
#include "leveldb/db.h" | |||
#include <iostream> | |||
#include <random> | |||
#include <ctime> | |||
#include <chrono> // 用于计时 | |||
#include <vector> // 用于存储延迟 | |||
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<int> 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<std::pair<std::string, FieldArray>> 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<std::string> 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<std::pair<std::string, FieldArray>> 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<std::string> 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<std::pair<std::string, FieldArray>> 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<std::string> 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<std::chrono::milliseconds>(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<std::pair<std::string, FieldArray>> 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<std::string> 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<std::chrono::milliseconds>(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<std::pair<std::string, FieldArray>> 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<std::string> 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<std::string> 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<std::chrono::milliseconds>(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<std::string> 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<std::pair<std::string, FieldArray>> 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<std::string> 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<std::pair<std::string, FieldArray>> 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<std::chrono::milliseconds>(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<std::string> 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<std::string> 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<unsigned>(time(nullptr))); | |||
testing::InitGoogleTest(&argc, argv); | |||
return RUN_ALL_TESTS(); | |||
} |
@ -0,0 +1,107 @@ | |||
#include "gtest/gtest.h" | |||
#include "db/NewDB.h" // NewDB 的头文件 | |||
#include "leveldb/env.h" | |||
#include "leveldb/db.h" | |||
#include <chrono> // 用于计时 | |||
#include <random> // 用于生成随机数 | |||
#include <vector> // 用于存储延迟 | |||
using namespace std; | |||
using namespace leveldb; | |||
// 随机生成字符串的辅助函数 | |||
std::string GenerateRandomString(size_t length) { | |||
const char charset[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; | |||
const size_t max_index = sizeof(charset) - 1; | |||
std::random_device rd; | |||
std::mt19937 generator(rd()); | |||
std::uniform_int_distribution<size_t> distribution(0, max_index); | |||
std::string random_str; | |||
for (size_t i = 0; i < length; ++i) { | |||
random_str += charset[distribution(generator)]; | |||
} | |||
return random_str; | |||
} | |||
// 打开数据库的辅助函数 | |||
Status OpenDB(std::string dbName, NewDB** db) { | |||
Options options; | |||
options.create_if_missing = true; | |||
Status s = NewDB::Open(options, dbName, db); | |||
if (!s.ok()) { | |||
cerr << "Error opening database: " << s.ToString() << endl; | |||
} | |||
return s; | |||
} | |||
std::string testdbname = "testdb_for_performance"; | |||
// 延迟测试 | |||
void TestLatency(int num_operations, std::vector<int64_t>& lat_res) { | |||
int64_t latency = 0; | |||
auto end_time = std::chrono::steady_clock::now(); | |||
auto last_time = end_time; | |||
for (int i = 0; i < num_operations; ++i) { | |||
// 记录操作的延迟 | |||
end_time = std::chrono::steady_clock::now(); | |||
latency = std::chrono::duration_cast<std::chrono::milliseconds>( | |||
end_time - last_time).count(); | |||
last_time = end_time; | |||
lat_res.emplace_back(latency); | |||
} | |||
} | |||
// 吞吐量测试 | |||
TEST(TestNewDB, PutFieldsThroughputTest) { | |||
// 创建 NewDB 实例 | |||
NewDB* db; | |||
ASSERT_TRUE(OpenDB(testdbname, &db).ok()); | |||
// 插入索引字段 | |||
db->CreateIndexOnField("address"); | |||
// 延迟测试 | |||
vector<int64_t> latencies; // 存储每次插入的延迟 | |||
int num_inserts = 1000; // 插入的条数 | |||
// 测试插入吞吐量 | |||
auto start_time = std::chrono::high_resolution_clock::now(); // 记录开始时间 | |||
for (int i = 0; i < num_inserts; ++i) { | |||
std::string key = "k_" + std::to_string(i); | |||
// 随机生成字段内容 | |||
FieldArray fields = { | |||
{"name", "Customer#" + std::to_string(i)}, | |||
{"address", GenerateRandomString(10)}, // 随机生成地址 | |||
{"phone", GenerateRandomString(12)} // 随机生成电话号码 | |||
}; | |||
db->Put_fields(WriteOptions(), key, fields); | |||
} | |||
// 延迟测试 | |||
TestLatency(num_inserts, latencies); | |||
auto end_time = std::chrono::high_resolution_clock::now(); // 记录结束时间 | |||
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end_time - start_time).count(); | |||
// 计算吞吐量并输出 | |||
cout << "Throughput: " << num_inserts * 1000 / duration << " OPS" << endl; | |||
// 输出延迟 | |||
// for (size_t i = 0; i < latencies.size(); ++i) { | |||
// cout << "Latency for operation " << i + 1 << ": " << latencies[i] << " ms" << endl; | |||
// } | |||
cout << "Latency for operation " << latencies.size()-1 << ": " << latencies[latencies.size()-1] << " ms" << endl; | |||
// 清理数据库 | |||
delete db; | |||
} | |||
// 主函数运行所有测试 | |||
int main(int argc, char** argv) { | |||
testing::InitGoogleTest(&argc, argv); | |||
return RUN_ALL_TESTS(); | |||
} |