日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

LevelDB 源码剖析(一)准备工作:环境搭建、接口使用、常用优化

發(fā)布時(shí)間:2024/4/11 编程问答 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 LevelDB 源码剖析(一)准备工作:环境搭建、接口使用、常用优化 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

文章目錄

  • 環(huán)境搭建
  • 實(shí)戰(zhàn)使用
    • 創(chuàng)建、關(guān)閉數(shù)據(jù)庫(kù)
    • 數(shù)據(jù)讀、寫、刪除
    • 批量處理
    • 迭代器遍歷
  • 常用優(yōu)化方案
    • 壓縮
    • 緩存
    • 過(guò)濾器
    • 命名


環(huán)境搭建

# 下載源碼 git clone https://github.com/google/leveldb.git# 下載依賴第三方庫(kù)(benchmark、googletest) git submodule update --init # 執(zhí)行編譯 cd leveldb/ mkdir -p build && cd build cmake -DCMAKE_BUILD_TYPE=Debug .. && cmake --build .# 頭文件加入系統(tǒng)目錄 cp -r ./include/leveldb /usr/include/ cp build/libleveldb.a /usr/local/lib/


實(shí)戰(zhàn)使用

創(chuàng)建、關(guān)閉數(shù)據(jù)庫(kù)

創(chuàng)建數(shù)據(jù)庫(kù)或打開(kāi)數(shù)據(jù)庫(kù),均通過(guò) Open 函數(shù)實(shí)現(xiàn)。Open 為一個(gè)靜態(tài)成員函數(shù),其函數(shù)聲明如下所示:

static Status Open(const Options& options, const std::string& name,DB** dbptr);
  • const Options & options:用于指定數(shù)據(jù)庫(kù)創(chuàng)建或打開(kāi)后的基本行為。
  • const std::string & name:用于指定數(shù)據(jù)庫(kù)的名稱。
  • DB* dbptr*:定義了一個(gè)DB類型的指針的指針,該指針作為Open函數(shù)操作后傳給調(diào)用者使用的DB類型的實(shí)際指針。
  • Status:當(dāng)操作成功時(shí),函數(shù)返回 status.ok() 的值為 True,*dbptr 分配了不為 NULL 的實(shí)際指針地址;若其中的操作存在錯(cuò)誤,則 status.ok() 的值為 False,并且對(duì)應(yīng)的 *dbptr 為 NULL。

關(guān)閉數(shù)據(jù)庫(kù)非常簡(jiǎn)單,只需要使用 delete 釋放 db 即可。

代碼示例如下:

#include"leveldb/db.h" #include<string> #include<iostream>using namespace std;int main() {leveldb::DB* db;leveldb::Options op;op.create_if_missing = true;//打開(kāi)數(shù)據(jù)庫(kù)leveldb::Status status = leveldb::DB::Open(op, "/tmp/testdb", &db);if(!status.ok()){cout << status.ToString() << endl;exit(1);}//關(guān)閉數(shù)據(jù)庫(kù)delete db;return 0; }


數(shù)據(jù)讀、寫、刪除

數(shù)據(jù)庫(kù)中的讀、寫與刪除操作分別用 Get 、 Put、Delete 這3個(gè)接口函數(shù)實(shí)現(xiàn)。接口定義如下:

Status Get(const ReadOptions& options, const Slice& key,std::string* value); Status Put(const WriteOptions&, const Slice& key,const Slice& value); Status Delete(const WriteOptions&, const Slice& key);
  • ReadOptions& options:代表實(shí)際讀操作傳入的行為參數(shù)。
  • WriteOptions& options:代表實(shí)際寫操作傳入的行為參數(shù)。

這里需要注意的是 Delete 并不會(huì)直接刪除數(shù)據(jù),而是在對(duì)應(yīng)位置插入一個(gè) key 的刪除標(biāo)志,然后在后續(xù)的Compaction 過(guò)程中才最終去除這條 key-value 記錄。

代碼示例如下:

#include"leveldb/db.h" #include"leveldb/slice.h" #include<iostream>using namespace std;int main() {leveldb::DB* db;leveldb::Options op;op.create_if_missing = true;//打開(kāi)數(shù)據(jù)庫(kù)leveldb::Status status = leveldb::DB::Open(op, "/tmp/testdb", &db);if(!status.ok()){cout << status.ToString() << endl;exit(1);}//寫入數(shù)據(jù)leveldb::Slice key("hello");string value("world");status = db->Put(leveldb::WriteOptions(), key, value);if(status.ok()){cout << "key: " << key.ToString() << " value: " << value << " 寫入成功。" << endl;}//查找數(shù)據(jù)status = db->Get(leveldb::ReadOptions(), key, &value);if(status.ok()){cout << "key: " << key.ToString() << " value: " << value << " 查找成功。" << endl;}//刪除數(shù)據(jù)status = db->Delete(leveldb::WriteOptions(), key);if(status.ok()){cout << "key: " << key.ToString() << " 刪除成功。" << endl;}//關(guān)閉數(shù)據(jù)庫(kù)delete db;return 0; }


批量處理

針對(duì)大量的操作,LevelDB 不具有傳統(tǒng)數(shù)據(jù)庫(kù)所具備的事務(wù)操作機(jī)制,然而它提供了一種批量操作的方法。這種批量操作方法主要具有兩個(gè)作用:一是提供了一種原子性的批量操作方法;二是提高了整體的數(shù)據(jù)操作速度。

LevelDB 針對(duì)批量操作定義了 WriteBatch 的類型。WriteBatch 有 3 個(gè)非常重要的接口:數(shù)據(jù)寫(Put)、數(shù)據(jù)刪 除(Delete)以及清空批量寫入緩存(Clear),具體定義如下所示:

class LEVELDB_EXPORT WriteBatch {public: //...void Put(const Slice& key, const Slice& value);void Delete(const Slice& key);void Clear();//... };

當(dāng)我們想將 WriteBatch 中的數(shù)據(jù)寫入 DB 時(shí),只需要調(diào)用 Write 接口,其主要用于處理之前保存在 WriteBatch 對(duì)象中的所有批量操作,其詳細(xì)接口定義如下所示:

Status Write(const WriteOptions& options, WriteBatch* updates);
  • 注意:一旦我們寫入完成后,就會(huì)調(diào)用 updates 中的 Clear 來(lái)清空之前保存的批量操作。

代碼示例如下:

#include"leveldb/db.h" #include"leveldb/slice.h" #include"leveldb/write_batch.h" #include<iostream>using namespace std;int main() {leveldb::DB* db;leveldb::Options op;op.create_if_missing = true;//打開(kāi)數(shù)據(jù)庫(kù)leveldb::Status status = leveldb::DB::Open(op, "/tmp/testdb", &db);if(!status.ok()){cout << status.ToString() << endl;exit(1);}//批量寫入leveldb::Slice key;string value;leveldb::WriteBatch batch;for(int i = 0; i < 10; i++){value = ('0' + i);key = "k" + value;batch.Put(key, value);}status = db->Write(leveldb::WriteOptions(), &batch);if(status.ok()){cout << "批量寫入成功" << endl; }//批量刪除for(int i = 0; i < 10; i++){key = "k" + ('0' + i);batch.Delete(key);}status = db->Write(leveldb::WriteOptions(), &batch);if(status.ok()){cout << "批量刪除成功" << endl; }//關(guān)閉數(shù)據(jù)庫(kù)delete db;return 0; }


迭代器遍歷

針對(duì) DB 中所有的數(shù)據(jù)記錄,LevelDB 不僅支持前向的遍歷,也支持反向的遍歷。在 DB 對(duì)象類型中,通過(guò)調(diào)用NewIterator 創(chuàng)建一個(gè)新的迭代器對(duì)象,該接口具體定義如下:

Iterator* NewIterator(const ReadOptions&);
  • ReadOptions& option:用于指定在遍歷訪問(wèn)過(guò)程中的相關(guān)設(shè)置。

這里有一個(gè)需要注意的地方,這里返回的迭代器不能直接使用,而是需要先使用對(duì)應(yīng)的 Seek 操作偏移到指定位置后才能進(jìn)行對(duì)應(yīng)的迭代操作。

代碼示例如下:

#include"leveldb/db.h" #include"leveldb/slice.h" #include"leveldb/iterator.h" #include<iostream>using namespace std;int main() {leveldb::DB* db;leveldb::Options op;op.create_if_missing = true;//打開(kāi)數(shù)據(jù)庫(kù)leveldb::Status status = leveldb::DB::Open(op, "/tmp/testdb", &db);if(!status.ok()){cout << status.ToString() << endl;exit(1);}leveldb::Iterator* it = db->NewIterator(leveldb::ReadOptions());//正向遍歷cout << "開(kāi)始正向遍歷:" << endl;for(it->SeekToFirst(); it->Valid(); it->Next()){cout << "key: " << it->key().ToString() << " value: " << it->value().ToString() << endl;}//逆向遍歷cout << "開(kāi)始逆向遍歷:" << endl;for(it->SeekToLast(); it->Valid(); it->Prev()){cout << "key: " << it->key().ToString() << " value: " << it->value().ToString() << endl;}//范圍查詢cout << "開(kāi)始范圍查詢:" << endl;for(it->Seek("k4"); it->Valid() && it->key().ToString() < "k8"; it->Next()){cout << "key: " << it->key().ToString() << " value: " << it->value().ToString() << endl;}delete it;//關(guān)閉數(shù)據(jù)庫(kù)delete db;return 0; }


常用優(yōu)化方案

壓縮

當(dāng)每一個(gè)塊寫入存儲(chǔ)設(shè)備中時(shí),可以選擇是否對(duì)塊進(jìn)行壓縮后再存儲(chǔ),以及 Options 參數(shù)的 compression 成員變量決定是否開(kāi)啟壓縮。默認(rèn)情況下,壓縮是開(kāi)啟的,且壓縮的速度很快,基本對(duì)整體的性能沒(méi)有太大影響

用戶在調(diào)用時(shí),可以用 kNoCompression 或 kSnappyCompression 對(duì) compression 參數(shù)進(jìn)行設(shè)定,從而確定塊在實(shí)際存儲(chǔ)過(guò)程中是否進(jìn)行壓縮。

leveldb::Options op; op.compression = leveldb::kNoCompression; //不啟用壓縮 op.compression = leveldb::kSnappyCompression; //Snappy壓縮


緩存

Cache的作用是充分利用內(nèi)存空間,減少磁盤的 I/O 操作,從而提升整體運(yùn)行性能。LevelDB 默認(rèn)的 Cache 采用的是 LRU 算法,即近期最少使用的數(shù)據(jù)優(yōu)先從 Cache 中淘汰,而經(jīng)常使用的數(shù)據(jù)駐留在內(nèi)存,從而實(shí)現(xiàn)對(duì)需要頻繁讀取的數(shù)據(jù)的快速訪問(wèn)。

LevelDB 中定義了一個(gè)全局函數(shù) NewLRUCache 用于創(chuàng)建一個(gè) LRUCache。

leveldb::Options op; op.block_cache = leveldb::NewLRUCache(10 * 1024 * 1024); //參數(shù)主要用于指定LevelDB的塊的Cache空間,如果為NULL則默認(rèn)為8MB


過(guò)濾器

由于 LevelDB 中所有的數(shù)據(jù)均保存在磁盤中,因而一次 Get 的調(diào)用,有可能導(dǎo)致多次的磁盤 I/O 操作。為了盡可能減少讀過(guò)程時(shí)磁盤 I/O 的操作次數(shù),LevelDB 采用了 FilterPolicy 機(jī)制。LevelDB 中 Options 對(duì)象類型的filter_policy 參數(shù),主要用于確定運(yùn)行過(guò)程中 Get 所遵循的 FilterPolicy 機(jī)制。

用戶可以通過(guò)調(diào)用 NewBloomFilterPolicy 接口函數(shù)以創(chuàng)建布隆過(guò)濾器,并將其賦值給對(duì)應(yīng)的 filter_policy 參數(shù)。

leveldb::Options op; op.filter_policy = leveldb::NewBloomFilterPolicy(10);


命名

LevelDB 中磁盤數(shù)據(jù)讀取與緩存均以塊為單位,并且實(shí)際存儲(chǔ)中所有的數(shù)據(jù)記錄均以 key 進(jìn)行順序存儲(chǔ)。根據(jù)排序結(jié)果,相鄰的 key 所對(duì)應(yīng)的數(shù)據(jù)記錄一般均會(huì)存儲(chǔ)在同一個(gè)塊中。正是由于這一特性,用戶針對(duì)自身的應(yīng)用場(chǎng)景需要充分考慮如何優(yōu)化 key 的命名設(shè)計(jì),從而最大限度地提升整體的讀取性能。

為了提升性能,命名規(guī)則是:針對(duì)需要經(jīng)常同時(shí)訪問(wèn)的數(shù)據(jù),其 key 在命名時(shí),可以通過(guò)將這些 key 設(shè)置相同的前綴保證這些數(shù)據(jù)的 key 是相鄰近的,從而使這些數(shù)據(jù)可存儲(chǔ)在同一個(gè)塊內(nèi)。 基于此,那些不常用的數(shù)據(jù)記錄自然會(huì)放置在其他塊內(nèi)。

總結(jié)

以上是生活随笔為你收集整理的LevelDB 源码剖析(一)准备工作:环境搭建、接口使用、常用优化的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。