鍵值數據庫的設計實現總結(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!並且要考慮系統兼容性!

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