首先要保证mapkeeper可以在ycsb上被load和run,在前面的博文中我写了具体的操作方法。
在把数据库和自己的数据库相连时候,首先要保证自己的机器的环境中有boost和thrift。同时保证mapkeeper文件夹中对应的thrift已经编译成功。
那么什么是thrift呢?这里给出维基百科的解释:
Thrift包含一套完整的栈来创建客户端和服务端程序。顶层部分是由Thrift定义生成的代码。而服务则由这个文件客户端和处理器代码生成。在生成的代码里会创建不同于内建类型的数据结构,并将其作为结果发送。协议和传输层是运行时库的一部分。有了Thrift,就可以定义一个服务或改变通讯和传输协议,而无需重新编译代码。除了客户端部分之外,Thrift还包括服务器基础设施来集成协议和传输,如阻塞、非阻塞及多线程服务器。栈中作为I/O基础的部分对于不同的语言则有不同的实现。
Thrift支持众多通讯协议:
- TBinaryProtocol – 一种简单的二进制格式,简单,但没有为空间效率而优化。比文本协议处理起来更快,但更难于调试。
- TCompactProtocol – 更紧凑的二进制格式,处理起来通常同样高效。
- TDebugProtocol – 一种人类可读的文本格式,用来协助调试。
- TDenseProtocol – 与TCompactProtocol类似,将传输数据的元信息剥离。
- TJSONProtocol – 使用JSON对数据编码。
- TSimpleJSONProtocol – 一种只写协议,它不能被Thrift解析,因为它使用JSON时丢弃了元数据。适合用脚本语言来解析。
下面开始连接自己数据库的准备工作:
1.在mapkeeper中添加一个新的自己数据库的文件夹
mkdir newdb/
2.在newdb文件夹中新建一个Makefile文件
vi Makefile
3.Makefile文件中添加以下内容
include ../Makefile.config
EXECUTABLE = mapkeeper_RHDB
all : thrift
g++ -Wall -o $(EXECUTABLE) *cpp -I $(THRIFT_DIR)/include/thrift -I $(THRIFT_DIR)/include \
/usr/local/lib/libsnappy.a -lboost_thread -lboost_filesystem -lthrift -I ../thrift/gen-cpp \
-L $(THRIFT_DIR)/lib \
-L ../thrift/gen-cpp -lmapkeeper \
-Wl,-rpath,\$$ORIGIN/../thrift/gen-cpp \
-Wl,-rpath,$(THRIFT_DIR)/lib \
-std=c++11
thrift:
make -C ../thrift
run:
./$(EXECUTABLE) 1 0 0
clean :
- rm -rf $(THRIFT_SRC) $(EXECUTABLE) *.o
wipe:
- rm -rf data/*
4.下面开始新建一个server接口用于连接自己的数据库。
/**
* This is a implementation of the mapkeeper interface that uses newdb
*/
#include <cstdio>
#include "MapKeeper.h"
#include <boost/ptr_container/ptr_map.hpp>
#include <boost/thread/shared_mutex.hpp>
#include <boost/filesystem.hpp>
#include <sys/types.h>
#include <dirent.h>
#include <errno.h>
#include <protocol/TBinaryProtocol.h>
#include <server/TThreadedServer.h>
#include <transport/TServerSocket.h>
#include <transport/TBufferTransports.h>
using namespace ::apache::thrift;
using namespace ::apache::thrift::protocol;
using namespace ::apache::thrift::transport;
using namespace ::apache::thrift::server;
using namespace ::apache::thrift::concurrency;
using boost::shared_ptr;
using namespace boost::filesystem;
using namespace mapkeeper;
int syncmode;
int blindinsert;
int blindupdate;
class newdbServer: virtual public MapKeeperIf {
public:
newdbServer(const std::string& directoryName) :
directoryName_(directoryName) {
// open all the existing databases
}
ResponseCode::type ping() {
return ResponseCode::Success;
}
ResponseCode::type addMap(const std::string& mapName) {
return ResponseCode::Success;
}
ResponseCode::type dropMap(const std::string& mapName) {
}
void listMaps(StringListResponse& _return) {
DIR *dp;
struct dirent *dirp;
if((dp = opendir(directoryName_.c_str())) == NULL) {
_return.responseCode = ResponseCode::Success;
return;
}
while ((dirp = readdir(dp)) != NULL) {
_return.values.push_back(std::string(dirp->d_name));
}
closedir(dp);
_return.responseCode = ResponseCode::Success;
}
void scan(RecordListResponse& _return, const std::string& mapName, const ScanOrder::type order,
const std::string& startKey, const bool startKeyIncluded,
const std::string& endKey, const bool endKeyIncluded,
const int32_t maxRecords, const int32_t maxBytes) {
}
void scanAscending(RecordListResponse& _return, std::map<std::string, std::string>& map,
const std::string& startKey, const bool startKeyIncluded,
const std::string& endKey, const bool endKeyIncluded,
const int32_t maxRecords, const int32_t maxBytes) {
_return.responseCode = ResponseCode::ScanEnded;
}
void scanDescending(RecordListResponse& _return, std::map<std::string, std::string>& map,
const std::string& startKey, const bool startKeyIncluded,
const std::string& endKey, const bool endKeyIncluded,
const int32_t maxRecords, const int32_t maxBytes) {
_return.responseCode = ResponseCode::ScanEnded;
}
void get(BinaryResponse& _return, const std::string& mapName, const std::string& key) {
_return.responseCode = ResponseCode::Success;
}
ResponseCode::type put(const std::string& mapName, const std::string& key, const std::string& value) {
std::string mapName_ = mapName;
return ResponseCode::Success;
}
ResponseCode::type insert(const std::string& mapName, const std::string& key, const std::string& value) {
// TODO Get and Put should be within a same transaction
return ResponseCode::Success;
}
ResponseCode::type update(const std::string& mapName, const std::string& key, const std::string& value) {
// TODO Get and Put should be within a same transaction
return ResponseCode::Success;
}
ResponseCode::type remove(const std::string& mapName, const std::string& key) {
return ResponseCode::Success;
}
private:
std::string directoryName_; // directory to store db files.
boost::shared_mutex mutex_; // protect map_
};
int main(int argc, char **argv) {
if(argc != 4) { printf("Usage: %s <sync:0 or 1> <blindinsert:0 or 1> <blindupdate:0 or 1>\n", argv[0]); }
syncmode = atoi(argv[1]);
blindinsert = atoi(argv[2]);
blindupdate = atoi(argv[3]);
int port = 9090;
std::shared_ptr<newdbServer> handler(new newdbBServer("data"));
std::shared_ptr<TProcessor> processor(new MapKeeperProcessor(handler));
std::shared_ptr<TServerTransport> serverTransport(new TServerSocket(port));
std::shared_ptr<TTransportFactory> transportFactory(new TFramedTransportFactory());
std::shared_ptr<TProtocolFactory> protocolFactory(new TBinaryProtocolFactory());
TThreadedServer server (processor, serverTransport, transportFactory, protocolFactory);
server.serve();
return 0;
}
5.判断新建的接口是否可以连接成功(和leveldb连接方式类似):
./mapkeeper_newdb 1 -d ~/mapkeeper/newdb/data
6.之后只要把自己的接口加进newdbserver中就可以啦。。真的搞了好久额,好难额。