当前位置: 首页 > 工具软件 > LevelDB > 使用案例 >

LevelDb(一):LevelDb简介

澹台阳秋
2023-12-01

1. leveldb简介

2. hello world

    2.1 leveldb源码下载和编译

    2.2 hello world程序


1. leveldb简介

    LevelDb是google的工程师Jeff Dean和Sanjay Ghemawat这两位大神级别的工程师发起的开源项目,这两位是Google重量级的工程师,为数甚少的Google Fellow之二。Jeff Dean其人是Google大规模分布式平台Bigtable和MapReduce主要设计和实现者,Sanjay Ghemawat是Google大规模分布式平台GFS,Bigtable和MapReduce主要设计和实现工程师。Google大数据的三驾马车论文参考:GFS论文阅读Mapreduce论文阅读BigTable论文阅读

    LevelDb是能够处理十亿级别规模Key-Value型数据持久性存储的嵌入式数据库,内部没有设计成C/S网络结构,必须和服务部署在同一台服务器。levelDB其实也是一个C++程序库,是可以可以被编译和链接到我们自己的程序中的库,而不是像Redis那样是一个数据库服务器。LevelDb本质上是一个存储引擎,即一套存储系统以及在这套存储系统上提供的一些操作接口。LevelDb有如下一些特点:

  • 首先,LevelDb是一个持久化存储的KV系统,和Redis这种内存型的KV系统不同,redis是一个内存数据库,它是将KV写入内存中,而LevelDb不会像Redis一样狂吃内存,而是将大部分数据存储到磁盘上。从某种意义上说,redis是非持久化的,而levelDB是实时持久化的。
  • 其次,LevelDb在存储数据时,是根据记录的key值有序存储的,就是说相邻的key值在存储文件中是依次顺序存储的,而应用可以自定义key大小比较函数,LevleDb会按照用户定义的比较函数依序存储这些记录。
  • 再次,像大多数KV系统一样,LevelDb的操作接口很简单,基本操作包括写记录,读记录以及删除记录。也支持针对多条操作的原子批量操作。
  • 另外,LevelDb支持数据快照(snapshot)功能,使得读取操作不受写操作影响,可以在读操作过程中始终看到一致的数据。
  • 除此外,LevelDb还支持数据压缩等操作,这对于减小存储空间以及增快IO效率都有直接的帮助。

2. hello world

2.1 leveldb源码下载和编译

git clone --recurse-submodules https://github.com/google/leveldb.git
mkdir -p build
cd build
cmake -DCMAKE_BUILD_TYPE=Release .. && cmake --build .

    编译好之后,在build目录会生成libleveldb.a静态库文件,在使用时,我们只需要把源码中的头文件目录leveldb/加入到我们工程的include目录,并且把编译好的静态库文件加入到我们工程的lib目录即可,这里我使用cmake来编译工程,具体的工程配置和编译参考GoogleTest入门在编译过程中注意需要链接pthread线程库。

2.2 hello world程序

    接下来我们来分析一下leveldb的hello world程序。

#include <iostream>
#include <cassert>

#include "leveldb/db.h"
#include "leveldb/write_batch.h"

int main()
{
    // Open a database.
    leveldb::DB* db;
    leveldb::Options opts;
    opts.create_if_missing = true;
    leveldb::Status status = leveldb::DB::Open(opts, "./testdb", &db);
    assert(status.ok());
    
    // Write data.
    status = db->Put(leveldb::WriteOptions(), "name", "jinhelin");
    assert(status.ok());

    // Read data.
    std::string val;
    status = db->Get(leveldb::ReadOptions(), "name", &val);
    assert(status.ok());
    std::cout << val << std::endl;

    // Batch atomic write.
    leveldb::WriteBatch batch;
    batch.Delete("name");
    batch.Put("name0", "jinhelin0");
    batch.Put("name1", "jinhelin1");
    batch.Put("name2", "jinhelin2");
    batch.Put("name3", "jinhelin3");
    batch.Put("name4", "jinhelin4");
    batch.Put("name5", "jinhelin5");
    batch.Put("name6", "jinhelin6");
    batch.Put("name7", "jinhelin7");
    batch.Put("name8", "jinhelin8");
    batch.Put("name9", "jinhelin9");
    status = db->Write(leveldb::WriteOptions(), &batch);
    assert(status.ok());

    // Scan database.
    leveldb::Iterator* it = db->NewIterator(leveldb::ReadOptions());
    for (it->SeekToFirst(); it->Valid(); it->Next()) {
        std::cout << it->key().ToString() << ": " << 
          it->value().ToString() << std::endl;
    }
    assert(it->status().ok());
    
    // Range scan, example: [name3, name8)
    for (it->Seek("name3"); 
         it->Valid() && it->key().ToString() < "name8"; 
         it->Next()) {
        std::cout << it->key().ToString() << ": " << 
          it->value().ToString() << std::endl;
    } 

    // Close a database.
    delete db;
}

    这个例子简单介绍了 LevelDB 的基本用法,包括:

(1)打开数据库:

    leveldb::DB* db;
    leveldb::Options opts;
    opts.create_if_missing = true;
    leveldb::Status status = leveldb::DB::Open(opts, "./testdb", &db);
    assert(status.ok());

    leveldb::DB::Open()打开数据库需要三个参数:

  • leveldb::Options :控制 DB 行为的一些参数。在这里 create_if_missing 为 true 表示如果数据库./testdb 存在就直接打开,不存在就创建。
  • ./testdb :LevelDB 数据库的根目录。一个 LevelDB 数据库存放在一个目录下。
  • &db :用来返回一个 LevelDB 实例。
  • leveldb::Status :封装了 leveldb 接口返回的详细信息。

 (2)写入一条数据:

    status = db->Put(leveldb::WriteOptions(), "name", "jinhelin");
    assert(status.ok());

        db->put 接口的三个参数:

  • leveldb::WriteOptions :目前里面只有一个 sync 成员。表示写完 WAL 后是否需要 flush。
  • 另外两个参数分别是本次写入数据的 Key 和 Value。

(3)读取一条数据:

    std::string val;
    status = db->Get(leveldb::ReadOptions(), "name", &val);
    assert(status.ok());
    std::cout << val << std::endl;

    Get 接口和 Put 接口比较像,除了 leveldb::ReadOptions 参数是用来控制读操作的. 

(4)批量原子操作:

    leveldb::WriteBatch batch;
    batch.Delete("name");
    batch.Put("name0", "jinhelin0");
    batch.Put("name1", "jinhelin1");
    batch.Put("name2", "jinhelin2");
    batch.Put("name3", "jinhelin3");
    batch.Put("name4", "jinhelin4");
    batch.Put("name5", "jinhelin5");
    batch.Put("name6", "jinhelin6");
    batch.Put("name7", "jinhelin7");
    batch.Put("name8", "jinhelin8");
    batch.Put("name9", "jinhelin9");
    status = db->Write(leveldb::WriteOptions(), &batch);
    assert(status.ok());

      LevelDB 的 Write 接口支持原子地修改多条数据,主要参数是 leveldb::WriteBatch 。 

(5)数据库的遍历和范围查找:

    leveldb::Iterator* it = db->NewIterator(leveldb::ReadOptions());
    for (it->SeekToFirst(); it->Valid(); it->Next()) {
        std::cout << it->key().ToString() << ": " << 
          it->value().ToString() << std::endl;
    }
    assert(it->status().ok());
    
    // Range scan, example: [name3, name8)
    for (it->Seek("name3"); 
         it->Valid() && it->key().ToString() < "name8"; 
         it->Next()) {
        std::cout << it->key().ToString() << ": " << 
          it->value().ToString() << std::endl;
    }

    LevelDB 通过提供 leveldb::Iterator 来实现范围查找。 

(6)关闭数据库:

     delete db;

    关闭数据库时需要删除掉创建的数据库实例,让其调用析构函数处理一些收尾工作。

 类似资料: