初識:LevelDB
上篇文章緣起:BigTable可以說是已經把論文Bigtable: A Distributed Storage System for Structured Data
中的內容掰扯的明明白白,如果哪位小夥伴感覺還有不理解的點,可以點連線進去再反覆琢磨幾遍,說不定就頓悟了呢~
之所以先花時間把BigTable掰扯了一篇,就是為了引出今天的主人公,LevelDB,接下來呢,我會一點點分享自己閱讀LevelDB原始碼遇到的問題和學習到的一些技術,希望大家多多關注,如有問題,也請大家多多留言,一起學習,一起Happy~
LevelDB是個啥?
LevelDB是對BigTable中KV儲存分片Tablet的高度復刻,是由Jeff Dean和Sanjay Ghemawat,這兩位大牛也是BigTable論文的作者,儘管我們不能對BigTable的底層實現一探究竟,不過,開源的LevelDB還是可以讓我們對其管中窺豹呢~
簡而言之,LevelDB就是一個由Google開源的高效的單機Key/Value儲存系統,該儲存系統提供了Key到Value的有序對映。
LevelDB有啥特點
- LevelDB中Key/Value可以是任意長度的位元組陣列
- LevelDB中的資料是按Key有序儲存的,也就是說,範圍查詢效率會很高
- LevelDB支援使用者提供自定義Key排序規則
- 與其他KV儲存系統類似,提供
Put(key, value)
,Get(key)
,Delete(key)
這些基本操作 - LevelDB支援在一個原子批量操作中對同一個Key執行多次修改操作
- LevelDB通過瞬時快照(Transient Snapshot)為使用者提供一致的資料檢視
- LevelDB支援資料的前向/後向迭代遍歷
- LevelDB底層使用Snappy壓縮演算法自動對資料進行壓縮
- LevelDB將外部活動(例如,檔案系統操作)抽象為虛擬介面,為使用者自定義這些作業系統互動方式提供了便利,也就是說,使用者可以自定義底層到底是與Linux系統互動,還是與Windows系統互動,甚至於HDFS/GFS等分散式檔案系統~
LevelDB有哪些限制
- LevelDB不是SQL資料庫,不存在關係資料模型,也不支援SQL查詢,同樣不支援索引
- 給定LevelDB資料庫,同一時刻,該資料庫只能由單程式(可能是多執行緒)訪問
- LevelDB庫本身不是基於C/S(Client/Server)模型的,也就是說,如果你想要像MySQL等各種其他資料庫那樣,通過客戶端連線遠端伺服器的方式訪問LevelDB的話,那麼,你需要自己將LevelDB包裝成服務端,然後再實現相應的客戶端才可以
這部分呢,先簡單介紹了LevelDB的特性以及使用限制,其實呢,也從側面給出了LevelDB的使用場景,比較適合單機KV儲存。
LevelDB快速上手
ε=(´ο`*)))唉、其實呢,我現在的主語言是Java,並不是C/C++,太久不用C/C++了,如果有啥錯誤,各位看官多多提點~
Windows下LevelDB從入門到放棄
Windows下編譯LevelDB太噁心了,TM有毒,放棄了、我只是想編譯除錯下而已,各種攔路虎,算了,愛誰誰,真心感覺Windows下除了他自家的全家桶外,別的都不好用,就TM有毒,真是服氣了,不搞了,想在Windows下用LevelDB的,自己掂量著辦~
Linux下LevelDB快樂地玩耍
LevelDB編譯安裝
相比於Windows下LevelDB的編譯,Linux環境下簡直不要太友好,唯一的缺點就是,用Idea用習慣了,除錯有點不太在行~
[root@cos leveldb-1.22]# mkdir -p build && cd build
# 注意:為了除錯時可以進入LevelDB庫原始碼,這裡最好編譯成Debug版本
# 編譯成Debug版本
[root@cos build]# cmake -DCMAKE_BUILD_TYPE=Debug .. && cmake --build .
# 編譯成Release版本
[root@cos build]# cmake -DCMAKE_BUILD_TYPE=Release .. && cmake --build .
# 將連結檔案拷貝到/usr/local/lib目錄下,以便程式呼叫
[root@cos build]# cp libleveldb.a /usr/local/lib/
# 將標頭檔案拷貝到/usr/local/include中,以便程式引用
[root@cos leveldb-1.22]# cp -r include/leveldb/ /usr/local/include/
LevelDB測試程式碼
#include <cassert>
#include <iostream>
#include <string>
#include <leveldb/db.h>
int main() {
leveldb::DB* db;
leveldb::Options options;
// 配置項:如果LevelDB資料庫目錄不存在,則自動建立
options.create_if_missing = true;
leveldb::Status status = leveldb::DB::Open(options, "/root/testdb", &db);
assert(status.ok());
std::string key = "apple";
std::string value = "Apple";
// 將key/value鍵值對寫入LevelDB資料庫
leveldb::Status s = db->Put(leveldb::WriteOptions(), key, value);
std::string get;
// 寫入成功後,嘗試根據key進行檢索
if(s.ok()) {
s = db->Get(leveldb::ReadOptions(), key, &get);
}
if(s.ok()) {
std::cout << "讀取到Key=" << key << "對應的Value=" << get << "." << std::endl;
} else {
std::cout << "讀取失敗!" << std::endl;
}
delete db;
return 0;
}
編譯並執行程式,結果如下:
# 對main.cc原始檔進行編譯
[root@cos leveldb]# g++ -o main main.cc -pthread -lleveldb -std=c++11
# 執行main可執行程式
[root@cos leveldb]# ./main
讀取到Key=apple對應的Value=Apple.
Linux下C/C++程式碼除錯
額(⊙o⊙)…前面說了,我不是做C/C++開發的,Linux是最小化安裝的,想除錯下程式碼,難為死我了,高手直接跳過就好~
GDB基本介紹
諸如GDB等程式碼偵錯程式的無外乎兩種功能:
- 幫助程式設計師看到程式執行時內部到底是個啥樣
- 幫助程式設計師知道其程式崩潰時程式正在幹啥
基本上每種語言都有程式碼偵錯程式,而偵錯程式的功能也無非就上面說的這兩種功能。
GDB能做的事情,大概可以分為四類,這四類功能可以幫助程式設計師快速定位Bug。
- 啟動應用程式,同時指定可能影響程式的引數
- 在指定條件下停止程式(斷點)
- 檢查程式停止時到底發生了計算(獲取程式執行到斷點時的狀態資訊)
- 修改程式中的內容,使得程式設計師可以嘗試糾正Bug的影響,從而繼續除錯程式碼
通過Shell命令gdb
可以啟動GDB,一旦GDB啟動成功,程式設計師就可以不斷地在終端中輸入命令來告知GDB下一步要幹嘛,如果想要終止的話,則需要輸入quit
命令。
使用者可以執行gdb
命令的同時不輸入任何引數,但是,大多數場景下,使用者會輸入1到2個引數,如下所示。
# 將可執行程式作為引數,程式編譯時需要新增-g引數
gdb program
# 將可執行程式以及core檔案作為引數
gdb program core
# 如果想要除錯正在執行的程式,則需要將程式ID作為第二個引數
gdb program 1234
gdb -p 1234
GDB常用命令
這裡只是介紹一些常用的GDB命令,更多的話,大家去看man gdb
文件吧
break [file:]functiop
:在指定檔案[file]
的functiop
方法入口設定斷點
run [arglist]
:啟動程式,引數列表為arglist
bt
:Backtrace: 顯示程式棧
print expr
:計算表示式expr
的結果
c
:繼續執行程式,直到遇到下一個斷點
next
:執行下一行(除非遇到斷點);也就是說,該命令無論下一行呼叫多少方法,會直接跳過,除非函式內部有斷點
edit [file:]function
:檢視指定檔案中的方法的斷點資訊
list [file:]function
:列出當前斷點附近的程式碼
step
:執行下一行程式碼,如果該行程式碼有方法呼叫則進入該方法
help name
:展示GDB的name命令的幫助資訊。
注意:上面命令中,next
縮寫為n
,step
縮寫為s
,分別是按行除錯和單步除錯,還有c
命令,都是非常常用的~
LevelDB程式碼除錯樣例
# 對main.cc原始檔進行編譯,同時加入除錯資訊,後續可以使用gdb進行除錯
[root@cos leveldb]# g++ -o main main.cc -pthread -lleveldb -std=c++11
# 使用gdb對main進行除錯
[root@cos leveldb]# gdb -tui main
注意:為了除錯方便,最好使用-tui
引數,這樣的話,除錯時,就可以像Idea那樣,邊看程式碼邊加斷點了~
除錯時,大概就是下圖的樣子~
注意:如果在編譯LevelDB時未指定為Debug版本,則無法像圖2那樣進入到LevelDB原始碼。
初識:LevelDB小結
其實吧,LevelDB的核心原始碼及架構,我已經看的七七八八了,就是,本身我主語言是Java的,然後,我就一直沒有勇氣去Debug到原始碼中仔細瞅一瞅,趁著這次梳理的機會,打算一點點跟進去看看、可能會更新的有點慢,不過,好事多磨,希望大家多多關注,同時也歡迎各位C/C++大佬多多指正,多多交流。
另外,大家可以關注我的微信公眾號,部落格會同步更新的喲~
白嫖多不好,關注下再走唄~