|
|
@ -0,0 +1,112 @@ |
|
|
|
#include <chrono>
|
|
|
|
#include <iomanip>
|
|
|
|
#include <iostream>
|
|
|
|
#include <leveldb/db.h>
|
|
|
|
#include <leveldb/options.h>
|
|
|
|
#include <numeric>
|
|
|
|
#include <sstream>
|
|
|
|
#include <string>
|
|
|
|
#include <thread>
|
|
|
|
#include <vector>
|
|
|
|
|
|
|
|
#include "leveldb/env.h"
|
|
|
|
|
|
|
|
#include "gtest/gtest.h"
|
|
|
|
|
|
|
|
using namespace leveldb; |
|
|
|
// 根据字段值查找所有包含该字段的 key,遍历
|
|
|
|
std::vector<std::string> FindKeysByField(leveldb::DB* db, const Field& field) { |
|
|
|
std::vector<std::string> keys; |
|
|
|
leveldb::Iterator* it = db->NewIterator(leveldb::ReadOptions()); |
|
|
|
|
|
|
|
for (it->SeekToFirst(); it->Valid() ; it->Next()) { |
|
|
|
std::string key = it->key().ToString(); |
|
|
|
FieldArray fields; |
|
|
|
db->Get_Fields(leveldb::ReadOptions(), key, fields); |
|
|
|
for (const auto& f : fields) { |
|
|
|
if (f.name == field.name && f.value == field.value) { |
|
|
|
keys.push_back(key); |
|
|
|
break; // 假设每个key中每个字段值唯一
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
delete it; |
|
|
|
return keys; |
|
|
|
} |
|
|
|
|
|
|
|
Status OpenDB(std::string dbName, DB** db) { |
|
|
|
Options options; |
|
|
|
options.create_if_missing = true; |
|
|
|
return DB::Open(options, dbName, db); |
|
|
|
} |
|
|
|
|
|
|
|
// 测试函数,使用多线程进行并发读写测试
|
|
|
|
TEST(ConcurrentTest, Basic) { |
|
|
|
DB* db; |
|
|
|
WriteOptions writeOptions; |
|
|
|
ReadOptions readOptions; |
|
|
|
if (!OpenDB("testdb", &db).ok()) { |
|
|
|
std::cerr << "open db failed" << std::endl; |
|
|
|
abort(); |
|
|
|
} |
|
|
|
const int numThreads = 10; |
|
|
|
const int numOperationsPerThread = 100; |
|
|
|
std::vector<std::thread> threads; |
|
|
|
|
|
|
|
// 创建写线程
|
|
|
|
for (int i = 0; i < numThreads / 2; ++i) { |
|
|
|
threads.emplace_back([&db, i, numOperationsPerThread]() { |
|
|
|
WriteOptions writeOptions; |
|
|
|
for (int j = 0; j < numOperationsPerThread; ++j) { |
|
|
|
std::string key = "key_" + std::to_string(i * numOperationsPerThread + j); |
|
|
|
FieldArray fields = { |
|
|
|
{"name", "Customer" + std::to_string(i * numOperationsPerThread + j)}, |
|
|
|
{"address", "Address" + std::to_string(i * numOperationsPerThread + j)}, |
|
|
|
{"phone", "1234567890"} |
|
|
|
}; |
|
|
|
db->Put_Fields(writeOptions, key, fields); |
|
|
|
} |
|
|
|
}); |
|
|
|
} |
|
|
|
|
|
|
|
// 创建读线程
|
|
|
|
for (int i = 0; i < numThreads / 2; ++i) { |
|
|
|
threads.emplace_back([&db, i, numOperationsPerThread]() { |
|
|
|
ReadOptions readOptions; |
|
|
|
Field queryField = {"name", "Customer"}; |
|
|
|
for (int j = 0; j < numOperationsPerThread; ++j) { |
|
|
|
std::string key = "key_" + std::to_string(i * numOperationsPerThread + j % (numOperationsPerThread * (numThreads / 2))); |
|
|
|
FieldArray fields; |
|
|
|
db->Get_Fields(readOptions, key, fields); |
|
|
|
bool found = false; |
|
|
|
for (const auto& field : fields) { |
|
|
|
if (field.name == queryField.name && |
|
|
|
field.value.substr(0, queryField.value.size()) == queryField.value) { // 部分匹配以测试前缀搜索的效果
|
|
|
|
found = true; |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
// 添加断言检查读取的正确性
|
|
|
|
// ASSERT_TRUE(found);
|
|
|
|
} |
|
|
|
|
|
|
|
// 测试查找功能
|
|
|
|
// std::vector<std::string> foundKeys = db.FindKeysByField(queryField);
|
|
|
|
// 添加断言检查查找的正确性
|
|
|
|
// ASSERT_EQ(foundKeys.size(), expectedSize);
|
|
|
|
}); |
|
|
|
} |
|
|
|
|
|
|
|
// 等待所有线程完成
|
|
|
|
for (auto& thread : threads) { |
|
|
|
thread.join(); |
|
|
|
} |
|
|
|
|
|
|
|
delete db; |
|
|
|
} |
|
|
|
|
|
|
|
int main(int argc, char** argv) { |
|
|
|
testing::InitGoogleTest(&argc, argv); |
|
|
|
return RUN_ALL_TESTS(); |
|
|
|
} |