#include "leveldb/write_batch.h"
|
|
|
|
#include "db/dbformat.h"
|
|
#include "leveldb/db.h"
|
|
#include "util/coding.h"
|
|
#include "leveldb/my_leveldb.h"
|
|
#include "unordered_map"
|
|
#include <sstream>
|
|
namespace leveldb {
|
|
//反序列化为字段数组
|
|
void MyLevelDB::ParseValue(const std::string& value_str,
|
|
FieldArray& resFieldArray) {
|
|
std::stringstream ss(value_str);
|
|
std::string segment;
|
|
|
|
// 按逗号分割字符串
|
|
while (std::getline(ss, segment, ',')) {
|
|
std::string key;
|
|
std::string value;
|
|
std::stringstream kv(segment);
|
|
|
|
if (std::getline(kv, key, ':') && std::getline(kv, value, ':')) {
|
|
if (!key.empty() && !value.empty()) {
|
|
resFieldArray.push_back(std::make_pair(key, value));
|
|
// std::cout << ((resFieldArray.back()).first).data() << std::endl;
|
|
} else {
|
|
std::cerr << "Invalid key-value pair: " << segment << std::endl;
|
|
}
|
|
} else {
|
|
std::cerr << "Failed to parse segment: " << segment << std::endl;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//序列化为字符串
|
|
void MyLevelDB::SerializeValue(const FieldArray& fields,
|
|
std::string& resString) {
|
|
resString.clear();
|
|
for (int i = 0; i < fields.size(); i++) {
|
|
const std::string& key = fields[i].first;
|
|
const std::string& value = fields[i].second;
|
|
|
|
resString += key + ":" +value;
|
|
if (i != fields.size() - 1) {
|
|
resString += ",";
|
|
}
|
|
}
|
|
}
|
|
|
|
Status MyLevelDB::PutWithFields(const WriteOptions& options,const std::string& key,const FieldArray& fields) {
|
|
std::string value;
|
|
SerializeValue(fields, value);
|
|
auto slice_key = Slice(key.c_str());
|
|
auto slice_value = Slice(value.c_str());
|
|
Status s = _fields_db->Put(options, slice_key, slice_value);
|
|
|
|
std::unordered_map<int, int> match;
|
|
std::unique_lock<std::mutex> l(mutex_);
|
|
for (int i = 0; i < fields.size(); i++) {
|
|
for (size_t idx = 0; idx < index_list_.size(); idx++) {
|
|
const auto& i_name = index_list_[idx];
|
|
if (fields[i].first == i_name) {
|
|
match[i] = idx;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
for (auto item : match) {
|
|
std::string composed_key;
|
|
composed_key += fields[item.first].second + ":" + key;
|
|
s = index_db[item.second]->Put(options, composed_key, Slice());
|
|
}
|
|
return s;
|
|
}
|
|
Status MyLevelDB::FindKeysByField(const ReadOptions& options, const Field field,
|
|
std::vector<std::string>* keys) {
|
|
auto it = _fields_db->NewIterator(options);
|
|
it->SeekToFirst();
|
|
keys->clear();
|
|
while (it->Valid()) {
|
|
auto val = it->value();
|
|
FieldArray arr;
|
|
auto str_val = std::string(val.data(), val.size());
|
|
ParseValue(str_val, arr);
|
|
for (auto pr : arr) {
|
|
if (pr.first == field.first && pr.second == field.second) {
|
|
Slice key = it->key();
|
|
keys->push_back(std::string(key.data(), key.size()));
|
|
break;
|
|
}
|
|
}
|
|
it->Next();
|
|
}
|
|
delete it;
|
|
return Status::OK();
|
|
}
|
|
|
|
Status MyLevelDB::CreateIndexOnField(const std::string& field_name) {
|
|
for (const auto& field : this->index_list_) {
|
|
if (field == field_name) {
|
|
return Status::InvalidArgument(field_name,
|
|
"Index already exists for this field");
|
|
}
|
|
}
|
|
index_list_.push_back(field_name);
|
|
Options op = _op;
|
|
DB* field_db;
|
|
op.index_mode = true;
|
|
Status status = DB::Open(op, _db_name + "_index_" + field_name, &field_db);
|
|
index_db.push_back(field_db);
|
|
if (!status.ok()) {
|
|
std::cerr << "Failed to open index DB: " << status.ToString() << std::endl;
|
|
abort();
|
|
}
|
|
return status;
|
|
}
|
|
|
|
Status MyLevelDB::DeleteIndex(std::string& field_name) {
|
|
auto it = std::find(index_list_.begin(), index_list_.end(), field_name);
|
|
if (it == index_list_.end()) {
|
|
return Status::NotFound("Index not found for this field");
|
|
}
|
|
// 从列表中移除该字段
|
|
index_list_.erase(it);
|
|
return Status::OK();
|
|
}
|
|
|
|
void MyLevelDB::QueryByIndex(const ReadOptions& options, Field& field,
|
|
std::vector<std::string>& keys) {
|
|
int i = 0;
|
|
for (; i < index_list_.size(); i++) {
|
|
if (index_list_[i] == field.first) {
|
|
break;
|
|
}
|
|
}
|
|
assert(i != index_list_.size());
|
|
|
|
auto it = index_db[i]->NewIterator(options);
|
|
it->SeekToFirst();
|
|
while (it->Valid()) {
|
|
auto val = it->key();
|
|
auto str_val = std::string(val.data(), val.size());
|
|
|
|
std::string key;
|
|
std::string value;
|
|
std::stringstream kv(str_val);
|
|
|
|
std::getline(kv, key, ':');
|
|
std::getline(kv, value, ':');
|
|
if (key == field.second) {
|
|
keys.push_back(value);
|
|
}
|
|
it->Next();
|
|
}
|
|
delete it;
|
|
}
|
|
|
|
Status MyLevelDB::Put(const WriteOptions& options, const Slice& key,
|
|
const Slice& value) {
|
|
return _fields_db->Put(options, key, value);
|
|
}
|
|
|
|
Status MyLevelDB::Delete(const WriteOptions& options, const Slice& key) {
|
|
return _fields_db->Delete(options, key);
|
|
}
|
|
|
|
Status MyLevelDB::Write(const WriteOptions& options, WriteBatch* updates) {
|
|
assert(0);
|
|
return Status();
|
|
}
|
|
|
|
Status MyLevelDB::Get(const ReadOptions& options, const Slice& key,
|
|
std::string* value) {
|
|
return _fields_db->Get(options, key, value);
|
|
}
|
|
|
|
Iterator* MyLevelDB::NewIterator(const ReadOptions& options) {
|
|
return _fields_db->NewIterator(options);
|
|
}
|
|
|
|
const Snapshot* MyLevelDB::GetSnapshot() { return _fields_db->GetSnapshot(); }
|
|
|
|
void MyLevelDB::ReleaseSnapshot(const Snapshot* snapshot) {
|
|
return _fields_db->ReleaseSnapshot(snapshot);
|
|
}
|
|
|
|
bool MyLevelDB::GetProperty(const Slice& property, std::string* value) {
|
|
return false;
|
|
}
|
|
|
|
void MyLevelDB::GetApproximateSizes(const Range* range, int n,
|
|
uint64_t* sizes) {
|
|
/* uint64_t temp = 0;
|
|
_main_db->GetApproximateSizes(range, n, sizes);
|
|
for (auto& index_db : field_db_) {
|
|
index_db->GetApproximateSizes(range, n, &temp);
|
|
*sizes += temp;
|
|
}*/
|
|
}
|
|
|
|
void MyLevelDB::CompactRange(const Slice* begin, const Slice* end) {
|
|
_fields_db->CompactRange(begin, end);
|
|
}
|
|
}
|