leveldb原始碼剖析 編碼

2021-07-29 01:45:28 字數 2966 閱讀 7910

leveldb是乙個google出品的單機kv資料庫。用c++編寫,**量很小,大概只有1~2萬行。**寫的可以用優雅來形容,毫無疑問是我至今看到的最優雅的c++**。而且由於**量比較小,可以直接通讀整個原始碼,了解乙個完整的kv系統的構建流程。是乙個很好的學習材料。這也是我第一次讀資料庫方面的原始碼,嘗試用部落格記錄閱讀過程。在閱讀原始碼的過程中,感覺自己有了很大的提高。希望再寫一遍,把這種提高深刻以下!

本系列的leveldb原始碼剖析就從資料編碼開始

必要性

資料編碼演算法實現在util/coding.h和util/coding.cpp兩個檔案中。

leveldb中的資料編碼主要是將整型數編碼成可以和ascii碼區分的二進位制形式,然後實現和kv統一的儲存方式。比如在儲存乙個鍵值對時

key = "hello" , value = "world"
如果我們直接像下面這樣將kv的ascii都相鄰儲存

那肯定是不行的,因為在實際查詢的時候,我們根本區分不出key和value的邊界。一種可行的方式是這樣的

這樣,我們根據key和value的長度,就可以對它們進行區分了。但是這裡的k_len和v_len的儲存還有一些其他的講究。

回到前面的例子。對於key = 「hello」 value = 「world」,我們採用這裡的儲存方式的話,則記憶體布局可能是這樣的:

這裡,我們直接將數字的ascii碼儲存進去。本例中恰好都是單位的數字,如果是多位,則先將數字轉換成字串,再將每位依次儲存。當然,這樣儲存數字是不對的。因為如果key或者value剛好是數字字串,那就亂套了。

所以我們可以看出對數字進行編碼儲存的必要性。

實現

leveldb對數字的編碼很簡單:將數字按連續的位元組直接儲存。整型數包括32位和64位,下面我們以32位為例看一下它是怎麼對數字進行編碼的。

對於數字54,它的二進位制形式如下:

110110
當然,這裡只列了最低的8位,後面的24位都是0,則按照編碼它在記憶體中的形式如下:

最高的三個位元組都是0,最低的位元組為00110110,這裡我們會發現乙個問題,為了與字元ascii碼區分,以免造成kv儲存混亂,我們沒有按照 『5」4』的形式儲存54,但是這裡的00110110對應的卻是另乙個字元的ascii碼—6.於是前面所做的努力於事無補了。當然也並不是那麼糟糕,比如我們可以事先固定下來用於儲存k_len的是32位8個位元組,這樣直接讀取8個位元組進來當k_len也可以,這種固定長度的編碼實現在encodefixed32函式中。但是顯然這樣會造成儲存浪費,比如這裡的54,前面三個位元組都是0,我們實際只需要儲存後面的乙個位元組就可以了,如果儲存4個位元組的話會造成75%的儲存浪費,太不值得了。leveldb採用了變長編碼來解決這個問題:

變長編碼主要是建立在ascii碼的特點上。從標準的ascii碼

我們可以觀察到,所有字元的ascii碼的最高位都是0。所以我們可以利用這個最高位來區分用於儲存數值的區域和用於儲存key-value的區域。我們這裡也以32位為例進行說明,對32位整型數的變成編碼實現在

encodevarint32函式中。因為最高位要用來做標記位,因此變長編碼不像前面的演算法那樣以每個位元組為單位進行編碼,它以7位為乙個單位進行編碼:

最後面的3位為補位,也就是說對於乙個32位的整型數,最長需要5*8=40位來對它進行編碼儲存。這裡的意思就是對於32位的整型數字,它的每七位儲存在乙個位元組中,這樣空出的一位用來做標記位,以區分每個位元組對應的是ascii碼資訊還是數值資訊。

因為現在我們可以區分每個位元組應該用於計算數值還是它是屬於key-value值,因此就不必要像前面那樣固定儲存的位元組數,現在只需要儲存有效位數就可以了。由於數值至少有乙個位元組,因此對於每個key-value儲存域,它的第乙個位元組,以及key值後的第乙個位元組肯定是用於計算長度,不屬於具體的key-value值,因此leveldb對於變長編碼的第乙個位元組並不做標記處理,這裡以防讀**的時候有困惑。

總結

leveldb數值編碼主要包括fixed固定型編碼和variant變長型編碼。固定型編碼很簡單,就是將整型數按位元組編碼,因為實現約定了用於儲存數值的長度,因此不會造成和具體的key-value儲存產生混亂,但是這種編碼會造成空間浪費。於是響應引入了變長編碼,變長編碼基於所有字元的ascii碼的最高位都是0的特點,用最高位做標記,在每個位元組中只儲存整型數的7位,最高位做標記用,這樣就只需要通過判斷標記位就可以區分用於表示數值的域和用於儲存key-value的具體值的域了。

leveldb編碼部分還是相對比較簡單的。詳細實現再看原始碼,這裡就不貼了。再接再厲!

LevelDB原始碼剖析之Memtable 1

memtable是leveldb很重要的一塊,leveldb的核心之一。我們肯定關注kv資料在memtable中是如何組織的,秘密在skip list中。在leveldb中,所有記憶體中的kv資料都儲存在memtable中,物理disk則儲存在sstable中。在系統執行過程中,如果memtable...

leveldb原始碼剖析1 1 基礎概述之原始碼搭建

leveldb是乙個開源的單機kv儲存庫,其作者是谷歌工程師jeff dean和sanjay ghemawat。很多開源lsm儲存引擎都基於或使用leveldb,例如rocksdb。關鍵原始碼目錄介紹 其中,db和table是功能的核心,部分資料結構在util中。如果沒做過資料庫引擎的人,建議看 以...

leveldb 原始碼導讀

1,slice.h中slice是leveldb內部使用的字串類,很簡單 2,leveldb 儲存編碼 對於位元組儲存分大端小端位元組序還是小端小端位元組序 leveldb使用的是小端位元組序儲存,低位位元組排放在記憶體的低位址端,高位位元組排放在記憶體的高位址端。編碼分為變長的varint和固定大小...