|
@ -1,14 +1,19 @@ |
|
|
#include "fielddb/field_db.h"
|
|
|
#include "fielddb/field_db.h"
|
|
|
#include <cstdint>
|
|
|
#include <cstdint>
|
|
|
|
|
|
#include <cstdio>
|
|
|
#include <string>
|
|
|
#include <string>
|
|
|
|
|
|
#include <utility>
|
|
|
#include <vector>
|
|
|
#include <vector>
|
|
|
#include "leveldb/db.h"
|
|
|
#include "leveldb/db.h"
|
|
|
#include "leveldb/env.h"
|
|
|
#include "leveldb/env.h"
|
|
|
#include "leveldb/options.h"
|
|
|
#include "leveldb/options.h"
|
|
|
#include "leveldb/status.h"
|
|
|
#include "leveldb/status.h"
|
|
|
|
|
|
#include "leveldb/write_batch.h"
|
|
|
#include "db/write_batch_internal.h"
|
|
|
#include "db/write_batch_internal.h"
|
|
|
|
|
|
#include "util/mutexlock.h"
|
|
|
#include "util/serialize_value.h"
|
|
|
#include "util/serialize_value.h"
|
|
|
#include "fielddb/encode_index.h"
|
|
|
#include "fielddb/encode_index.h"
|
|
|
|
|
|
#include "fielddb/meta.h"
|
|
|
|
|
|
|
|
|
namespace fielddb { |
|
|
namespace fielddb { |
|
|
using namespace leveldb; |
|
|
using namespace leveldb; |
|
@ -37,38 +42,144 @@ Status FieldDB::OpenFieldDB(const Options& options, |
|
|
(*dbptr)->dbname_ = name; |
|
|
(*dbptr)->dbname_ = name; |
|
|
|
|
|
|
|
|
status = (*dbptr)->Recover(); |
|
|
status = (*dbptr)->Recover(); |
|
|
|
|
|
|
|
|
|
|
|
(*dbptr)->options_ = &options; |
|
|
|
|
|
(*dbptr)->env_ = options.env; |
|
|
return status; |
|
|
return status; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// todo
|
|
|
|
|
|
|
|
|
// TODO:Recover
|
|
|
Status FieldDB::Recover() { |
|
|
Status FieldDB::Recover() { |
|
|
//
|
|
|
|
|
|
|
|
|
//TODO:
|
|
|
|
|
|
//1. 遍历所有Index类型的meta,重建内存中的index_状态表
|
|
|
|
|
|
//2. 寻找所有KV类型的meta,再次提交一遍请求
|
|
|
|
|
|
//3. 等待所有请求完成
|
|
|
return Status::OK(); |
|
|
return Status::OK(); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
Request *FieldDB::GetHandleInterval() { |
|
|
|
|
|
mutex_.AssertHeld(); //保证队列是互斥访问的
|
|
|
|
|
|
Request *tail = taskqueue_.front(); |
|
|
|
|
|
for(auto *req_ptr : taskqueue_) { |
|
|
|
|
|
if(req_ptr->isDeleteReq() || req_ptr->isiCreateReq()) { |
|
|
|
|
|
return tail; |
|
|
|
|
|
} |
|
|
|
|
|
tail = req_ptr; |
|
|
|
|
|
} |
|
|
|
|
|
return tail; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
Status FieldDB::HandleRequest(Request &req) { |
|
|
|
|
|
MutexLock L(&mutex_); |
|
|
|
|
|
taskqueue_.push_back(&req); |
|
|
|
|
|
Again: |
|
|
|
|
|
while(!req.done && &req != taskqueue_.front()) { |
|
|
|
|
|
req.cond_.Wait(); |
|
|
|
|
|
} |
|
|
|
|
|
if(req.done) { |
|
|
|
|
|
return req.s; //在返回时自动释放锁L
|
|
|
|
|
|
} |
|
|
|
|
|
Request *tail = GetHandleInterval(); |
|
|
|
|
|
WriteBatch KVBatch,IndexBatch,MetaBatch; |
|
|
|
|
|
Status status; |
|
|
|
|
|
if(!tail->isiCreateReq() && !tail->isiDeleteReq()) { |
|
|
|
|
|
//表明这一个区间并没有涉及index的创建删除
|
|
|
|
|
|
{ |
|
|
|
|
|
//1. 构建各个Batch。构建的过程中要保证索引状态的一致性,需要上锁。
|
|
|
|
|
|
MutexLock iL(&index_mu); |
|
|
|
|
|
for(auto *req_ptr : taskqueue_) { |
|
|
|
|
|
req_ptr->ConstructBatch(KVBatch, IndexBatch, MetaBatch, this); |
|
|
|
|
|
if(req_ptr == tail) break; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
//2. 首先写入meta,再并发写入index和kv,完成之后清除meta数据
|
|
|
|
|
|
//此处可以放锁是因为写入的有序性可以通过队列来保证
|
|
|
|
|
|
mutex_.Unlock(); |
|
|
|
|
|
WriteOptions op; |
|
|
|
|
|
status = metaDB_->Write(op, &MetaBatch); |
|
|
|
|
|
//TODO:index的写入需要在另外一个线程中同时完成
|
|
|
|
|
|
status = indexDB_->Write(op, &IndexBatch); |
|
|
|
|
|
status = kvDB_->Write(op, &KVBatch); |
|
|
|
|
|
//3. 将meta数据清除
|
|
|
|
|
|
MetaCleaner cleaner; |
|
|
|
|
|
cleaner.Collect(MetaBatch); |
|
|
|
|
|
cleaner.CleanMetaBatch(metaDB_); |
|
|
|
|
|
mutex_.Lock(); |
|
|
|
|
|
} else { |
|
|
|
|
|
//对于创建和删除索引的请求,通过prepare完成索引状态的更新
|
|
|
|
|
|
MutexLock iL(&index_mu); |
|
|
|
|
|
req.Prepare(this); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
while(true) { |
|
|
|
|
|
Request *ready = taskqueue_.front(); |
|
|
|
|
|
taskqueue_.pop_front(); |
|
|
|
|
|
//当前ready不是队首,不是和index的创建有关
|
|
|
|
|
|
if(ready != &req && !ready->isPending() && |
|
|
|
|
|
!req.isiCreateReq() && !req.isiDeleteReq()) { |
|
|
|
|
|
ready->s = status; |
|
|
|
|
|
ready->done = true; |
|
|
|
|
|
ready->cond_.Signal(); |
|
|
|
|
|
} |
|
|
|
|
|
if (ready == tail) break; |
|
|
|
|
|
} |
|
|
|
|
|
if(!taskqueue_.empty()) { |
|
|
|
|
|
taskqueue_.front()->cond_.Signal(); |
|
|
|
|
|
} |
|
|
|
|
|
//如果done==true,那么就不会继续等待直接退出
|
|
|
|
|
|
//如果处于某个请求的pending list里面,那么就会继续等待重新入队
|
|
|
|
|
|
//这里用了万恶的goto,蛤蛤
|
|
|
|
|
|
goto Again; |
|
|
|
|
|
|
|
|
|
|
|
// return status;
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//这里把一个空串作为常规put的name
|
|
|
Status FieldDB::Put(const WriteOptions &options, const Slice &key, const Slice &value) { |
|
|
Status FieldDB::Put(const WriteOptions &options, const Slice &key, const Slice &value) { |
|
|
return kvDB_->Put(options, key, value); |
|
|
|
|
|
|
|
|
FieldArray FA = {{"",value.ToString()}}; |
|
|
|
|
|
return PutFields(options, key, FA); |
|
|
|
|
|
// return kvDB_->Put(options, key, value);
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// TODO:需要对是否进行index更新做处理
|
|
|
// TODO:需要对是否进行index更新做处理
|
|
|
Status FieldDB::PutFields(const WriteOptions &Options, |
|
|
Status FieldDB::PutFields(const WriteOptions &Options, |
|
|
const Slice &key, const FieldArray &fields) { |
|
|
const Slice &key, const FieldArray &fields) { |
|
|
//
|
|
|
|
|
|
return kvDB_->PutFields(Options, key, fields); |
|
|
|
|
|
|
|
|
//这里是为了const和slice-string的转换被迫搞得
|
|
|
|
|
|
std::string key_ = key.ToString(); |
|
|
|
|
|
FieldArray fields_ = fields; |
|
|
|
|
|
|
|
|
|
|
|
FieldsReq req(&key_,&fields_,&mutex_); |
|
|
|
|
|
|
|
|
|
|
|
Status status = HandleRequest(req); |
|
|
|
|
|
return status; |
|
|
|
|
|
// return kvDB_->PutFields(Options, key, fields);
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// todo: 删除有索引的key时indexdb也要同步
|
|
|
// todo: 删除有索引的key时indexdb也要同步
|
|
|
Status FieldDB::Delete(const WriteOptions &options, const Slice &key) { |
|
|
Status FieldDB::Delete(const WriteOptions &options, const Slice &key) { |
|
|
//
|
|
|
//
|
|
|
return kvDB_->Delete(options, key); |
|
|
|
|
|
|
|
|
std::string key_ = key.ToString(); |
|
|
|
|
|
DeleteReq req(&key_,&mutex_); |
|
|
|
|
|
Status status = HandleRequest(req); |
|
|
|
|
|
return status; |
|
|
|
|
|
// return kvDB_->Delete(options, key);
|
|
|
} |
|
|
} |
|
|
// TODO:根据updates里面的东西,要对是否需要更新index进行分别处理
|
|
|
// TODO:根据updates里面的东西,要对是否需要更新index进行分别处理
|
|
|
Status FieldDB::Write(const WriteOptions &options, WriteBatch *updates) { |
|
|
Status FieldDB::Write(const WriteOptions &options, WriteBatch *updates) { |
|
|
|
|
|
//或许应该再做一个接口?或者基于现有的接口进行改造
|
|
|
return Status::OK(); |
|
|
return Status::OK(); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
//由于常规put将空串作为name,这里也需要适当修改
|
|
|
Status FieldDB::Get(const ReadOptions &options, const Slice &key, std::string *value) { |
|
|
Status FieldDB::Get(const ReadOptions &options, const Slice &key, std::string *value) { |
|
|
return kvDB_->Get(options, key, value); |
|
|
|
|
|
|
|
|
// return kvDB_->Get(options, key, value);
|
|
|
|
|
|
FieldArray fields; |
|
|
|
|
|
Status s = GetFields(options, key, &fields); |
|
|
|
|
|
if(!s.ok()) { |
|
|
|
|
|
return s; |
|
|
|
|
|
} |
|
|
|
|
|
*value = fields[0].second; |
|
|
|
|
|
return s; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
Status FieldDB::GetFields(const ReadOptions &options, const Slice &key, FieldArray *fields) { |
|
|
Status FieldDB::GetFields(const ReadOptions &options, const Slice &key, FieldArray *fields) { |
|
@ -99,45 +210,62 @@ Status FieldDB::CreateIndexOnField(const std::string& field_name) { |
|
|
//taskQueue相关
|
|
|
//taskQueue相关
|
|
|
//写锁 是不是只需要给putfields设置一把锁就行
|
|
|
//写锁 是不是只需要给putfields设置一把锁就行
|
|
|
|
|
|
|
|
|
std::vector<std::pair<std::string, std::string>> keysAndVal = |
|
|
|
|
|
FindKeysAndValByFieldName(field_name); |
|
|
|
|
|
WriteBatch writeBatch; |
|
|
|
|
|
Slice value = Slice(); |
|
|
|
|
|
for (auto &kvPair : keysAndVal){ |
|
|
|
|
|
std::string indexKey; |
|
|
|
|
|
AppendIndexKey(&indexKey, |
|
|
|
|
|
ParsedInternalIndexKey(kvPair.first, field_name, kvPair.second)); |
|
|
|
|
|
writeBatch.Put(indexKey, value); |
|
|
|
|
|
} |
|
|
|
|
|
Status s = indexDB_->Write(WriteOptions(), &writeBatch); |
|
|
|
|
|
if (!s.ok()) return s; |
|
|
|
|
|
|
|
|
|
|
|
index_[field_name] = Exist; |
|
|
|
|
|
//唤醒taskqueue
|
|
|
|
|
|
|
|
|
// std::vector<std::pair<std::string, std::string>> keysAndVal =
|
|
|
|
|
|
// FindKeysAndValByFieldName(field_name);
|
|
|
|
|
|
// WriteBatch writeBatch;
|
|
|
|
|
|
// Slice value = Slice();
|
|
|
|
|
|
// for (auto &kvPair : keysAndVal){
|
|
|
|
|
|
// std::string indexKey;
|
|
|
|
|
|
// AppendIndexKey(&indexKey,
|
|
|
|
|
|
// ParsedInternalIndexKey(kvPair.first, field_name, kvPair.second));
|
|
|
|
|
|
// writeBatch.Put(indexKey, value);
|
|
|
|
|
|
// }
|
|
|
|
|
|
// Status s = indexDB_->Write(WriteOptions(), &writeBatch);
|
|
|
|
|
|
// if (!s.ok()) return s;
|
|
|
|
|
|
|
|
|
|
|
|
// index_[field_name].first = Exist;
|
|
|
|
|
|
// //唤醒taskqueue
|
|
|
|
|
|
// return s;
|
|
|
|
|
|
std::string Field = field_name; |
|
|
|
|
|
iCreateReq req(&Field,&mutex_); |
|
|
|
|
|
HandleRequest(req); |
|
|
|
|
|
WriteBatch KVBatch,IndexBatch,MetaBatch; |
|
|
|
|
|
req.ConstructBatch(KVBatch, IndexBatch, MetaBatch, this); |
|
|
|
|
|
indexDB_->Write(WriteOptions(), &IndexBatch); |
|
|
|
|
|
req.Finalize(this); |
|
|
|
|
|
return req.s; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
Status FieldDB::DeleteIndex(const std::string &field_name) { |
|
|
Status FieldDB::DeleteIndex(const std::string &field_name) { |
|
|
//taskQueue相关
|
|
|
//taskQueue相关
|
|
|
//写锁
|
|
|
//写锁
|
|
|
std::vector<std::pair<std::string, std::string>> keysAndVal = |
|
|
|
|
|
FindKeysAndValByFieldName(field_name); |
|
|
|
|
|
WriteBatch writeBatch; |
|
|
|
|
|
for (auto &kvPair : keysAndVal){ |
|
|
|
|
|
std::string indexKey; |
|
|
|
|
|
AppendIndexKey(&indexKey, |
|
|
|
|
|
ParsedInternalIndexKey(kvPair.first, field_name, kvPair.second)); |
|
|
|
|
|
writeBatch.Delete(indexKey); |
|
|
|
|
|
} |
|
|
|
|
|
Status s = indexDB_->Write(WriteOptions(), &writeBatch); |
|
|
|
|
|
if (!s.ok()) return s; |
|
|
|
|
|
|
|
|
// std::vector<std::pair<std::string, std::string>> keysAndVal =
|
|
|
|
|
|
// FindKeysAndValByFieldName(field_name);
|
|
|
|
|
|
// WriteBatch writeBatch;
|
|
|
|
|
|
// for (auto &kvPair : keysAndVal){
|
|
|
|
|
|
// std::string indexKey;
|
|
|
|
|
|
// AppendIndexKey(&indexKey,
|
|
|
|
|
|
// ParsedInternalIndexKey(kvPair.first, field_name, kvPair.second));
|
|
|
|
|
|
// writeBatch.Delete(indexKey);
|
|
|
|
|
|
// }
|
|
|
|
|
|
// Status s = indexDB_->Write(WriteOptions(), &writeBatch);
|
|
|
|
|
|
// if (!s.ok()) return s;
|
|
|
|
|
|
|
|
|
index_.erase(field_name); |
|
|
|
|
|
//唤醒taskqueue
|
|
|
|
|
|
|
|
|
// index_.erase(field_name);
|
|
|
|
|
|
// //唤醒taskqueue
|
|
|
|
|
|
// return s;
|
|
|
|
|
|
std::string Field = field_name; |
|
|
|
|
|
iDeleteReq req(&Field,&mutex_); |
|
|
|
|
|
HandleRequest(req); |
|
|
|
|
|
WriteBatch KVBatch,IndexBatch,MetaBatch; |
|
|
|
|
|
req.ConstructBatch(KVBatch, IndexBatch, MetaBatch, this); |
|
|
|
|
|
indexDB_->Write(WriteOptions(), &IndexBatch); |
|
|
|
|
|
req.Finalize(this); |
|
|
|
|
|
return req.s; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
std::vector<std::string> FieldDB::QueryByIndex(const Field &field, Status *s) { |
|
|
std::vector<std::string> FieldDB::QueryByIndex(const Field &field, Status *s) { |
|
|
if (index_.count(field.first) == 0 || index_[field.first] != Exist){ |
|
|
|
|
|
|
|
|
if (index_.count(field.first) == 0 || index_[field.first].first != Exist){ |
|
|
*s = Status::NotFound(Slice()); |
|
|
*s = Status::NotFound(Slice()); |
|
|
return std::vector<std::string>(); |
|
|
return std::vector<std::string>(); |
|
|
} |
|
|
} |
|
|