初識:LevelDB

一紙微言發表於2020-07-14

初識:LevelDB

上篇文章緣起:BigTable可以說是已經把論文Bigtable: A Distributed Storage System for Structured Data中的內容掰扯的明明白白,如果哪位小夥伴感覺還有不理解的點,可以點連線進去再反覆琢磨幾遍,說不定就頓悟了呢~

之所以先花時間把BigTable掰扯了一篇,就是為了引出今天的主人公,LevelDB,接下來呢,我會一點點分享自己閱讀LevelDB原始碼遇到的問題和學習到的一些技術,希望大家多多關注,如有問題,也請大家多多留言,一起學習,一起Happy~

LevelDB是個啥?

LevelDB是對BigTable中KV儲存分片Tablet的高度復刻,是由Jeff DeanSanjay 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。

  1. 啟動應用程式,同時指定可能影響程式的引數
  2. 在指定條件下停止程式(斷點)
  3. 檢查程式停止時到底發生了計算(獲取程式執行到斷點時的狀態資訊)
  4. 修改程式中的內容,使得程式設計師可以嘗試糾正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縮寫為nstep縮寫為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++大佬多多指正,多多交流。

另外,大家可以關注我的微信公眾號,部落格會同步更新的喲~
白嫖多不好,關注下再走唄~