键值数据库的设计实现总结(SDS)

写这个数据库也已经有段时间了,在我心中此项目的第一个版本算是完成了,所以做一下小结,更多的功能以后再继续迭代即可!

1. 引言

1.1 编写目的

学习搭建rpc框架,自己阅读了部分redis实现源码,想实现一个加深印象,将学习的网络方面的知识学以致用。等等…

1.2 项目概述

客户端和服务器协议:Google Protocol buffer
RPC部分实现的功能:序列化和反序列化,发送远程命令
项目服务器使用Reactor模式设计的框架,为每一个连接设置了相应的读回调,写回调,每个连接套接字设置了EPOLLIN+非阻塞模式。实现了string和hash两种操作,并实现了save和bgsave两种持久化操作,bgsave操作通过创建新进程实现。项目中添加了最大堆定时器,为每个客户端设置了保活时间。当客户端产生一次活动时,会自动为该客户端延长时间,对于一些一直不活动的客户端,服务器会定时检查连接队列,并剔除闲置客户端。定时器通过统一事件源触发。
客户端实现比较简单,使用readline进行命令行输入,并设置了检测命令的合法模块,检测客户端是否与服务器建立了连接,要是没建立连接,会尝试和服务器建立5次连接。直到建立连接成功。

1.3 术语定义

术语名称 术语含义
GPB Google Protocol Buffer
Server 服务器
Client 客户端

1.4 引用文档

名称 作者
Redis设计与实现 黄建宏
Redis深度探险 钱文品
Google Protocol Buffer Google Protocol Buffer
高性能服务器 游双

2. 设计决策

2.1 设计目标

2.1.1 运行环境

LInux Ubuntu18.10

2.1.2 开发环境及工具

vim+vimplus+gcc 编译器

2.1.3 技术限制

书读的有点少

2.2 设计原则

严格遵守需求规格说明书设计,使用一些面向对象语言中的一些设计模式例如工厂模式,减少代码的复用性。

3. 逻辑架构设计

3.1 设计决策

Server设计领域模型如下:

在这里插入图片描述
client设计:

在这里插入图片描述

3.2 软件单元

  • server端
    直接看.cpp文件吧,类中的成员比较多,不好陈述,所以选择每个.cpp文件中的相关方法,将整个项目的功能实现加以描述。

aeEventloop.cpp
在这里插入图片描述
第一个就不说了,见名知意!
addServerEvent主要功能就是初始化时创建监听套接字,并设置好相应的回调函数。
addTimerEvent该方法创建一个eventfd并设置好相应的回调函数。
aeEventloop构造方法,创建了时间堆,创建了epoll检测引擎
下面是析构函数
aeProcessEvent该方法处理不同的事件,当aeEventloop将事件收集到vecotor中,该方法就会将其中的各种方法进行分类处理。
initDataInfo初始化时间堆中的相关数据
kickClient处理不活跃的客户端
notifyToSave 通知保存
setCallBack 设置回调函数
start 开始启动服务例程

aeEpoll.cpp

在这里插入图片描述
很简单的操作,可以看懂!

rpc.cpp

在这里插入图片描述
反序列化,发送响应请求。

aeEvent.cpp

在这里插入图片描述
读回调,和写回调函数。

timerHeap.cpp

在这里插入图片描述
MyTimer 时间堆上的节点,TimerManager是时间堆管理器。
detect_timers检测到期时间,若有超时客户端,就执行回调函数处理。
其它函数太鸡肋,不解释了。

cmdProcess.cpp

在这里插入图片描述
findCmd在进行发序列化之后,判查找命令是否存在。
initCmdCb初始化命令回调函数,每个命令对应一个回调函数。
initRedis 初始化数据库(就是从文件中将已经持久化的数据读出来)
processMsg处理不同的命令请求
sendMsg发送消息

cmdSet.cpp
在这里插入图片描述

addObjectToDb添加对象到数据库。
append增加数据库
countRedis获取当前数据库的数量
expend扩大容纳数据库容器的容量
findCmd 查找命令
getDB获取指定数据库对象
initCmdCb初始化命令集合
initRedis初始化数据库
redisCommandProc 数据库各种命令处理函数,根据命令的不同回调在命令集中找相应的回调函数
cb 数据库各种命令对象对应的回调函数

redisDb.cpp和redisDb.h
因为是键值数据库,所以对于大部分对象而言操作比较相似,所以利用C++多态机制实现了工厂模式,父类为抽象类dbObject,设置了许多虚方法,对于strings和hashSet都是继承了dbObject,redisDb通过hashmap管理dbObject,如图。键值为请求的key对象,key对象,成员是要访问对象的键值,类型,以及数据库编号三元组唯一确定对象在数据库中的值。

在这里插入图片描述
在这里插入图片描述

  • redisDb.cpp
    在这里插入图片描述
    getValue
    getValues hash获取值,将以vector对象的形式返回。

该数据库管理对象的模型如下:

在这里插入图片描述

  • redisDb.h

在这里插入图片描述

目前实现了两种类型的操作。
在这里插入图片描述
抽象基类。
在这里插入图片描述

在这里插入图片描述
hash操作,setValue实现多参数设置。
在这里插入图片描述
strings对象,内部数据。
在这里插入图片描述
equalFunc和hashFunc设置hash函数。
factory工厂根据不同提示,返回不同对象。

在这里插入图片描述
rdb.cpp
持久化功能
下面是两大对象在文件中的存储格式:

  • hash
    在这里插入图片描述
  • string

在这里插入图片描述

ctp存的是类型编号,数字编号之类,在初始化数据库的时候,都会通过正则表达式辨别。然后其他解析之类的函数就不作解释了!可以看源代码。

在这里插入图片描述
recoverDb.cpp

恢复数据库,因为我将每个数据库单独存在一个文件中,0号数据存在.db_0文件,后面以此类推,其中或有一个redis_fileName文件,存放的是数据库文件名,在恢复的时候,先读取.redis_fileName,将所有数据库文件名存在vector中,然后遍历vector再通过mmap映射将文件内容映射到string中,然后解析string就行。

在这里插入图片描述
在这里插入图片描述

客户端设计比较简单,读者可自行研究!

3.3 处理流程

在这里插入图片描述

4 运行演示

在这里插入图片描述
源代码 感谢star或者fork!本代码仅供阅读参考学习,在个人平台上运行的话可能得安装配置google protocol buffer!并且要考虑系统兼容性!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章