my simplest kv db
最简单的kv db
最基本的网络连接 使用STL map存储key value 作为多线程互斥的简单例子。
以后有机会逐步优化添加功能
1增加ASIO 异步通讯
2优化存储空间 传递指针 避免过多的拷贝操作
3优化代码结构
4优化全局锁 操作map时候 锁定部分区域而不是锁全局 。(思路在之前博客有提过多线程查找大量数据加锁的速度降低)
效果图:

部分代码
#include "NetWork.h"
#include "Handler.h"
#include <thread> void DEF::NetWorkClass::work() {
try {
while () {
std::shared_ptr<boost::asio::ip::tcp::socket> psocket =
std::make_shared<boost::asio::ip::tcp::socket>(*pio_service_);
pacceptor_->accept(*psocket);
std::thread t = std::thread(DEF::Handler, psocket);
t.detach();
}
}
catch (std::exception& e) {
std::cerr << __FUNCTION__ << " " <<
e.what() << std::endl;
}
return;
}
NetWork.cpp
#pragma once
#include "PreHead.h"
#include <boost/asio.hpp>
#include <memory>
#include <iostream> using boost::asio::ip::tcp; NAMESPACEBEGIN(DEF) class NetWorkClass {
public:
NetWorkClass(short port):port_(port),pacceptor_ (nullptr), pio_service_(nullptr){}
bool Init() {
bool b = false;
pio_service_ = std::make_shared<boost::asio::io_service>();
if (nullptr == pio_service_) {
std::cerr << __FUNCTION__ << " make io_service() error!" << std::endl;
return b;
}
pacceptor_ = std::make_shared<tcp::acceptor>(*pio_service_,
tcp::endpoint(tcp::v4(), port_));
if (nullptr == pio_service_) {
std::cerr << __FUNCTION__ << " make acceptor() error!" << std::endl;
return b;
} b = true;
return b;
} void work(); private:
short port_;
std::shared_ptr<tcp::acceptor> pacceptor_;
std::shared_ptr<boost::asio::io_service> pio_service_;
}; NAMESPACEEND
NetWork.h
#pragma once
#include "PreHead.h"
#include <memory>
#include <iostream>
#include <boost/asio.hpp> NAMESPACEBEGIN(DEF) bool Handler(std::shared_ptr<boost::asio::ip::tcp::socket> psocket); struct Item {
std::string command_;
std::string key_;
std::string value_;
std::string result_;
}; class ParseRecvString {
public:
static void TestSplitBySpace();
static std::vector<std::string> SplitBySpace(const std::string& recvStr) {
std::vector<std::string> vecStr;
size_t begPos = recvStr.find_first_not_of(' ');
size_t endPos = recvStr.find_first_of(' ', begPos+);
while (begPos != std::string::npos) {
endPos = recvStr.find_first_of(' ', begPos);
if (endPos != std::string::npos){
vecStr.push_back(recvStr.substr(begPos, endPos - begPos));
begPos = recvStr.find_first_not_of(' ', endPos + );
}
else {
vecStr.push_back(recvStr.substr(begPos));
begPos = endPos;
}
} return vecStr;
} private:
}; class CommandHandler {
public:
CommandHandler(const std::vector<std::string>& command) :command_(command) {} private:
std::vector<std::string> command_;
}; class Session {
public:
Session(std::shared_ptr<boost::asio::ip::tcp::socket> psocket): psocket_(psocket){}
Session(const Session& s) = delete;
Session operator=(const Session& s) = delete;
bool LoopHandle();
private:
void SetFunc(const std::vector<std::string>& vecStr, Item& item);
void GetFunc(const std::vector<std::string>& vecStr, Item& item);
void AppendFunc(const std::vector<std::string>& vecStr, Item& item);
void PreAppendFunc(const std::vector<std::string>& vecStr, Item& item);
void DeleteFunc(const std::vector<std::string>& vecStr, Item& item);
void DispatchCommand(const std::vector<std::string>& vecStr, Item& item);
bool ParseRecvData(char* recvData,size_t len,Item& item);
std::shared_ptr<boost::asio::ip::tcp::socket> psocket_;
}; NAMESPACEEND
Handler.h
#include "Handler.h"
#include "DbStored.h"
#include <iostream>
#include <string> extern DEF::DBStored g_dbStored; bool DEF::Handler(std::shared_ptr<boost::asio::ip::tcp::socket> psocket) {
bool b = false;
Session s(psocket);
b = s.LoopHandle(); return b;
}
bool DEF::Session::ParseRecvData(char* recvData, size_t len, Item& item) {
bool b = false;
recvData[len] = '\0';
std::string recvstr(recvData);
std::vector<std::string> vecStr = ParseRecvString::SplitBySpace(recvstr);
DispatchCommand(vecStr,item); return b;
} void DEF::Session::SetFunc(const std::vector<std::string>& vecStr, Item& item) {
assert(vecStr.size() >= );
bool b = g_dbStored.InsertDBWithLock(vecStr[], vecStr[]);
item.key_ = vecStr[];
item.value_ = vecStr[];
if (b) {
item.result_ = "STORED";
}
else {
item.result_ = "STORED_FAILED";
}
return ;
} void DEF::Session::GetFunc(const std::vector<std::string>& vecStr, Item& item) {
assert(vecStr.size() >= );
std::string getVal;
bool b = g_dbStored.GetFromDbWithLock(vecStr[], getVal);
item.key_ = vecStr[];
item.value_ = getVal;
if (b) {
item.result_ = getVal;
}
else {
item.result_ = "GET_FAILED";
}
return ;
} void DEF::Session::AppendFunc(const std::vector<std::string>& vecStr, Item& item) {
assert(); return ;
} void DEF::Session::PreAppendFunc(const std::vector<std::string>& vecStr, Item& item) {
assert(); return ;
} void DEF::Session::DeleteFunc(const std::vector<std::string>& vecStr, Item& item) { return ;
} void DEF::Session::DispatchCommand(const std::vector<std::string>& vecStr, Item& item)
{
std::string s = vecStr[];
std::string result;
transform(s.begin(), s.end(), s.begin(), tolower);
//可使用MAP 进行命令分发
if (s == "set") {
item.command_ = "set";
SetFunc(vecStr, item);
}
else if (s == "get") {
item.command_ = "get";
GetFunc(vecStr, item);
}
else if (s == "append") {
item.command_ = "append";
AppendFunc(vecStr, item);
}
else if (s == "preappend") {
item.command_ = "preappend";
PreAppendFunc(vecStr, item);
}
else if (s == "del") {
item.command_ = "del";
DeleteFunc(vecStr, item);
}
else {
item.result_ = "ERROR_COMMAND";
} return;
} void DEF::ParseRecvString::TestSplitBySpace()
{
std::string s1 = " set ";
std::string s2 = " set";
std::string s3 = "set";
std::string s4 = "set ";
std::string s5 = " set mykey myvalue";
std::string s6 = " set mykey myvalue ";
std::string s7 = " set mykey myvalue ";
std::string s8 = "set mykey myvalue"; std::vector<std::string> vs; vs = DEF::ParseRecvString::SplitBySpace(s1);
assert(vs.size() == && vs[] == "set");
vs.clear();
vs = DEF::ParseRecvString::SplitBySpace(s2);
assert(vs.size() == && vs[] == "set");
vs.clear();
vs = DEF::ParseRecvString::SplitBySpace(s3);
assert(vs.size() == && vs[] == "set");
vs.clear();
vs = DEF::ParseRecvString::SplitBySpace(s4);
assert(vs.size() == && vs[] == "set");
vs.clear();
vs = DEF::ParseRecvString::SplitBySpace(s5);
assert(vs.size() == && vs[] == "set" && vs[] == "mykey" && vs[] == "myvalue");
vs.clear();
vs = DEF::ParseRecvString::SplitBySpace(s6);
assert(vs.size() == && vs[] == "set" && vs[] == "mykey" && vs[] == "myvalue");
vs.clear();
vs = DEF::ParseRecvString::SplitBySpace(s7);
assert(vs.size() == && vs[] == "set" && vs[] == "mykey" && vs[] == "myvalue");
vs.clear();
vs = DEF::ParseRecvString::SplitBySpace(s8);
assert(vs.size() == && vs[] == "set" && vs[] == "mykey" && vs[] == "myvalue");
vs.clear();
} bool DEF::Session::LoopHandle() {
bool b = false;
if (psocket_ == nullptr)
return b;
char recvData[];
try {
while () {
boost::system::error_code error;
size_t len = psocket_->read_some(boost::asio::buffer(recvData,), error);
if (error == boost::asio::error::eof) {
return (b = true);
}
else if (error) {
throw boost::system::system_error(error);
}
Item item;
b = ParseRecvData(recvData, len,item);
len = psocket_->write_some(boost::asio::buffer(item.result_.c_str(),item.result_.size()),
error);
if (error) {
throw boost::system::system_error(error);
}
}
}
catch (std::exception& e) {
std::cerr << e.what() << std::endl;
}
return b;
}
Handler.cpp
my simplest kv db的更多相关文章
- 一些开源搜索引擎实现——倒排使用原始文件,列存储Hbase,KV store如levelDB、mongoDB、redis,以及SQL的,如sqlite或者xxSQL
本文说明:除开ES,Solr,sphinx系列的其他开源搜索引擎汇总于此. A search engine based on Node.js and LevelDB A persistent, n ...
- Sina App Engine(SAE)入门教程(3)-KVDB使用
简介 因为传统关系型数据库在分布式环境下表现的扩展性不足等缺点,近年来NoSQL的概念渐渐成为业界关注的焦点,越来越多的技术人员也习惯于使用NoSQL数据库进行日常开发,SAE为了应对这种新需求,也进 ...
- 优秀it博客和文章
优秀博客 综合 杨文博(供职于百度公司,任复合搜索部资深研发工程师,目前作为tech lead,负责垂直行业搜索后端架构研发.) 杨远骋 徐宥(Google 软件工程师. 这个中文博客是我的思考记录, ...
- 广告频次控制(frequency capping)
频次控制介绍 广告中的频次控制是指控制一个用户最多在指定时间内看到一个广告(或相似广告)的次数,比如广告主可以限制一个用户最多只能一天看到一个广告3次(频次控制也可以让publisher来指定,但本文 ...
- ledisdb:支持类redis接口的嵌入式nosql
ledisdb现在可以支持嵌入式使用.你可以将其作为一个独立的lib(类似leveldb)直接嵌入到你自己的应用中去,而无需在启动单独的服务. ledisdb提供的API仍然类似redis接口.首先, ...
- kv_storage.go
package storage //kv 存储引擎实现 import ( "github.com/cznic/kv" "io" ) //kv 存 ...
- MIT-6.824 Lab 3: Fault-tolerant Key/Value Service
概述 lab2中实现了raft协议,本lab将在raft之上实现一个可容错的k/v存储服务,第一部分是实现一个不带日志压缩的版本,第二部分是实现日志压缩.时间原因我只完成了第一部分. 设计思路 如上图 ...
- 根据已经commit的数据,进行leader和peon之间的同步
Leader Election基本设计 按照rank表示优先级解决冲突问题,为每个monitor预先分配了一个rank 只会接受优先级(rank)比自己高.epoch比上次已接受的epoch大的选举请 ...
- Storage,Memcache,KVDB都是存储服务,如何区分何时用何种服务
Storage :是SAE为开发者提供的分布式文件存储服务,用来存放用户的持久化存储的文件.用户需要先在在线管理平台创建Domain(相当于一级子目录). Storage为开发者提供分布式文件存 ...
随机推荐
- 【Python】断言功能Assertion
转自 https://www.cnblogs.com/cicaday/p/python-assert.html Python Assert 为何不尽如人意 Python中的断言用起来非常简单,你可以在 ...
- CentOS 7下给nginx安装SSL证书
0. DNS要能解析你的网址(域名解析和主机解析,例如example.com和www.example.com都要能解析.注意泛解析记录*.example.com可以存在但在本文中暂时无法用于https ...
- git 一个分支完全覆盖另一个分支
1,git push origin develop:master -f就可以把本地的develop分支强制(-f)推送到远程master 2,git checkout master // 切换到旧的分 ...
- Git-撤销(回退)已经add,commit或push的提交
本文只阐述如何解决问题,不会对git的各种概念多做介绍,如果有兴趣可以点击下面的链接,进行详细的学习:Pro Git本文适用的环境 现在先假设几个环境,本文将会给出相应的解决方法:1. 本地代码(或文 ...
- 备份与还原mysql 数据库的常用命令。
一.备份数据: Mysqldump常用命令: mysqldump -u用户名 -p密码 --databases 数据库1 数据库2 > xxx.sql 常见选项: -u: 用户名 -p: 密码 ...
- JAVA 异常类型结构分析
JAVA 异常类型结构分析 Throwable 是所有异常类型的基类,Throwable 下一层分为两个分支,Error 和 Exception. Error 和 Exception Error Er ...
- node项目初始化的一些配置
1. const port = process.env.PORT || 9001; 本地开发用9001端口 2. package.json中配置几个启动命令 "scripts": ...
- REST framwork之解析器
一 我们首先要知道解析器是什么以及他的功能: REST framework 包含许多内置的解析器类,允许接受各种媒体类型(media types)的请求.还支持自定义解析器,这使你可以灵活地设计 AP ...
- 1-hadoop、mr
1.HDFS的优缺点: 优点: ① 高容错 ② 可扩展 ③ 适合大文件存储 ④ 可构建在廉价的机器上 缺点: ① 高延迟 ② 文件不能修改 ③ 不适合小文件存储 2.HDFS架构(类似于文件系统): ...
- BZOJ 2173 luoguo P4451 [国家集训队]整数的lqp拆分
整数的lqp拆分 [问题描述] lqp在为出题而烦恼,他完全没有头绪,好烦啊… 他首先想到了整数拆分.整数拆分是个很有趣的问题.给你一个正整数N,对于N的一个整数拆分就是满足任意m>0,a1 , ...