|
|
@ -1236,39 +1236,73 @@ void DBImpl::ReleaseSnapshot(const Snapshot* snapshot) { |
|
|
|
// Convenience methods
|
|
|
|
Status DBImpl::Put(const WriteOptions& o, const Slice& key, const Slice& val) { |
|
|
|
//ToDo
|
|
|
|
WriteBatch batch; // 创建事务
|
|
|
|
WriteBatch batch; // 主数据库的事务
|
|
|
|
WriteBatch indexBatch; // 二级索引数据库的事务
|
|
|
|
Status s; |
|
|
|
|
|
|
|
// 在主数据库写入数据
|
|
|
|
batch.Put(key, val); |
|
|
|
|
|
|
|
// 遍历fieldWithIndex_,检查是否需要更新索引
|
|
|
|
for (const auto& field : fieldWithIndex_) { |
|
|
|
size_t field_pos = val.ToString().find(field + ":"); |
|
|
|
if (field_pos != std::string::npos) { |
|
|
|
size_t value_start = field_pos + field.size() + 1; // 跳过 "fieldName:"
|
|
|
|
size_t value_end = val.ToString().find("|", value_start); // 查找下一个分隔符
|
|
|
|
if (value_end == std::string::npos) { |
|
|
|
value_end = val.ToString().size(); |
|
|
|
// 如果当前是 indexDb_ 的 Put 操作,只提交主数据库的事务
|
|
|
|
if (indexDb_ != nullptr) { |
|
|
|
// 记录已插入的主数据库的键
|
|
|
|
std::vector<Slice> keysInserted; |
|
|
|
|
|
|
|
// 在主数据库写入数据
|
|
|
|
batch.Put(key, val); |
|
|
|
keysInserted.push_back(key); |
|
|
|
|
|
|
|
// 遍历 fieldWithIndex_,检查是否需要更新索引
|
|
|
|
for (const auto& field : fieldWithIndex_) { |
|
|
|
size_t field_pos = val.ToString().find(field + ":"); |
|
|
|
if (field_pos != std::string::npos) { |
|
|
|
size_t value_start = field_pos + field.size() + 1; // 跳过 "fieldName:"
|
|
|
|
size_t value_end = val.ToString().find("|", value_start); // 查找下一个分隔符
|
|
|
|
if (value_end == std::string::npos) { |
|
|
|
value_end = val.ToString().size(); |
|
|
|
} |
|
|
|
std::string fieldValue = val.ToString().substr(value_start, value_end - value_start); |
|
|
|
|
|
|
|
if (!fieldValue.empty()) { |
|
|
|
std::string indexKey = field + ":" + fieldValue; |
|
|
|
std::string indexValue = key.ToString(); |
|
|
|
|
|
|
|
// 将索引插入操作加入二级索引数据库的事务
|
|
|
|
indexBatch.Put(Slice(indexKey), Slice(indexValue)); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// 提交主数据库的 WriteBatch
|
|
|
|
s = this->Write(o, &batch); |
|
|
|
if (!s.ok()) { |
|
|
|
return s; // 如果主数据库写入失败,则直接返回错误
|
|
|
|
} |
|
|
|
|
|
|
|
// 提交二级索引数据库的 WriteBatch
|
|
|
|
s = indexDb_->Write(o, &indexBatch); |
|
|
|
if (!s.ok()) { |
|
|
|
// 如果二级索引数据库写入失败,回滚主数据库的写入
|
|
|
|
// 回滚操作:删除已经写入主数据库的键
|
|
|
|
for (const auto& insertedKey : keysInserted) { |
|
|
|
batch.Delete(insertedKey); // 撤销主数据库的插入操作
|
|
|
|
} |
|
|
|
std::string fieldValue = val.ToString().substr(value_start, value_end - value_start); |
|
|
|
|
|
|
|
if (!fieldValue.empty()) { |
|
|
|
std::string indexKey = field + ":" + fieldValue; |
|
|
|
std::string indexValue = key.ToString(); |
|
|
|
|
|
|
|
// 将索引插入操作加入事务
|
|
|
|
batch.Put(Slice(indexKey), Slice(indexValue)); |
|
|
|
// 执行回滚:将主数据库的删除操作写入
|
|
|
|
Status rollbackStatus = this->Write(o, &batch); |
|
|
|
if (!rollbackStatus.ok()) { |
|
|
|
return rollbackStatus; // 如果回滚操作失败,返回回滚错误
|
|
|
|
} |
|
|
|
|
|
|
|
return s; // 返回二级索引数据库写入失败的状态
|
|
|
|
} |
|
|
|
} else { |
|
|
|
// 如果是 indexDb_ 调用 Put,则只提交主数据库的 WriteBatch
|
|
|
|
batch.Put(key, val); |
|
|
|
s = this->Write(o, &batch); |
|
|
|
if (!s.ok()) { |
|
|
|
return s; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// 使用 `this->Write` 提交事务
|
|
|
|
s = this->Write(o, &batch); |
|
|
|
if (!s.ok()) { |
|
|
|
return s; |
|
|
|
} |
|
|
|
return Status::OK(); |
|
|
|
return Status::OK(); // 成功时返回 OK
|
|
|
|
//ToDo end
|
|
|
|
//return DB::Put(o, key, val);
|
|
|
|
} |
|
|
@ -1281,31 +1315,42 @@ Status DBImpl::Delete(const WriteOptions& options, const Slice& key) { |
|
|
|
// 在主数据库删除数据
|
|
|
|
batch.Delete(key); |
|
|
|
|
|
|
|
// 遍历fieldWithIndex_,检查是否需要删除索引
|
|
|
|
for (const auto& field : fieldWithIndex_) { |
|
|
|
size_t field_pos = key.ToString().find(field + ":"); |
|
|
|
if (field_pos != std::string::npos) { |
|
|
|
size_t value_start = field_pos + field.size() + 1; |
|
|
|
size_t value_end = key.ToString().find("|", value_start); |
|
|
|
if (value_end == std::string::npos) { |
|
|
|
value_end = key.ToString().size(); |
|
|
|
} |
|
|
|
std::string fieldValue = key.ToString().substr(value_start, value_end - value_start); |
|
|
|
|
|
|
|
if (!fieldValue.empty()) { |
|
|
|
std::string indexKey = field + ":" + fieldValue; |
|
|
|
|
|
|
|
// 将索引删除操作加入事务
|
|
|
|
batch.Delete(Slice(indexKey)); |
|
|
|
// 如果不是在 indexDb_ 上调用 Delete,则需要处理索引删除
|
|
|
|
if (indexDb_ != nullptr) { |
|
|
|
// 遍历fieldWithIndex_,检查是否需要删除索引
|
|
|
|
for (const auto& field : fieldWithIndex_) { |
|
|
|
size_t field_pos = key.ToString().find(field + ":"); |
|
|
|
if (field_pos != std::string::npos) { |
|
|
|
size_t value_start = field_pos + field.size() + 1; |
|
|
|
size_t value_end = key.ToString().find("|", value_start); |
|
|
|
if (value_end == std::string::npos) { |
|
|
|
value_end = key.ToString().size(); |
|
|
|
} |
|
|
|
std::string fieldValue = key.ToString().substr(value_start, value_end - value_start); |
|
|
|
|
|
|
|
if (!fieldValue.empty()) { |
|
|
|
std::string indexKey = field + ":" + fieldValue; |
|
|
|
|
|
|
|
// 将索引删除操作加入事务
|
|
|
|
batch.Delete(Slice(indexKey)); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// 使用 `this->Write` 提交事务
|
|
|
|
s = this->Write(options, &batch); |
|
|
|
// 如果是 indexDb_ 调用,则仅提交该数据库的删除操作
|
|
|
|
if (this == indexDb_) { |
|
|
|
s = indexDb_->Write(options, &batch); // 删除操作直接提交给 indexDb_
|
|
|
|
} else { |
|
|
|
// 使用 `this->Write` 提交事务
|
|
|
|
s = this->Write(options, &batch); // 提交给主数据库和索引数据库的事务
|
|
|
|
} |
|
|
|
|
|
|
|
if (!s.ok()) { |
|
|
|
// 如果操作失败,则返回错误状态
|
|
|
|
return s; |
|
|
|
} |
|
|
|
|
|
|
|
return Status::OK(); |
|
|
|
//ToDo end
|
|
|
|
//return DB::Delete(options, key);
|
|
|
@ -1679,28 +1724,21 @@ Status DBImpl::DeleteIndex(const std::string& fieldName) { |
|
|
|
// Query by index (retrieve all values indexed by a field)
|
|
|
|
std::vector<std::string> DBImpl::QueryByIndex(const std::string& fieldName) { |
|
|
|
std::vector<std::string> results; |
|
|
|
|
|
|
|
// 假设您有一个存储索引的数据库 indexDb_
|
|
|
|
// 例如:leveldb::DB* indexDb_;,并且它存储字段名称到值的映射
|
|
|
|
leveldb::ReadOptions read_options; |
|
|
|
leveldb::Iterator* it = indexDb_->NewIterator(read_options); |
|
|
|
|
|
|
|
for (it->Seek(fieldName); it->Valid(); it->Next()) { |
|
|
|
std::string key = it->key().ToString(); |
|
|
|
std::string value = it->value().ToString(); |
|
|
|
// 仅将非空值添加到结果中
|
|
|
|
if (key == fieldName && !value.empty()) { |
|
|
|
results.push_back(value); |
|
|
|
} |
|
|
|
std::string value; |
|
|
|
|
|
|
|
// 使用 Get 方法从 indexDb_ 中获取与 fieldName 对应的值
|
|
|
|
leveldb::Status s = indexDb_->Get(read_options, fieldName, &value); |
|
|
|
|
|
|
|
if (s.ok() && !value.empty()) { |
|
|
|
// 如果获取的值非空,则将其添加到结果列表
|
|
|
|
results.push_back(value); |
|
|
|
} else if (!s.ok()) { |
|
|
|
// 如果查询发生错误,则处理错误
|
|
|
|
std::cerr << "Error querying index for field: " << fieldName |
|
|
|
<< ". Status: " << s.ToString() << std::endl; |
|
|
|
} |
|
|
|
|
|
|
|
if (!it->status().ok()) { |
|
|
|
// 处理查询错误
|
|
|
|
std::cerr << "Error querying index: " << it->status().ToString() << std::endl; |
|
|
|
} |
|
|
|
|
|
|
|
delete it; |
|
|
|
|
|
|
|
return results; |
|
|
|
} |
|
|
|
|
|
|
|