leveldb

int main(int argc, char** argv)
        {
            leveldb::DB* db;
            leveldb::Options options;
            // 如果打开已存在数据库的时候,需要抛出错误,将以下代码插在leveldb::DB::Open方法前面
            options.create_if_missing = true;
            // 打开一个数据库实例
            leveldb::Status status = leveldb::DB::Open(options, "/tmp/testdb", &db);
            assert(status.ok());
            // LevelDB提供了Put、Get和Delete三个方法对数据库进行添加、查询和删除
            std::string key = "key";
            std::string value = "value";
            // 添加key=value
            status = db->Put(leveldb::WriteOptions(), key, value);
            assert(status.ok());
            // 根据key查询value
            status = db->Get(leveldb::ReadOptions(), key, &value);
            assert(status.ok());
            std::cout<             // 修改操作(原生没有提供)由添加和删除合起来实现
            std::string key2 = "key2";
            // 添加key2=value               
            status = db->Put(leveldb::WriteOptions(),key2,value);
            assert(status.ok());
            // 删除key
            status = db->Delete(leveldb::WriteOptions(), key);
            // 查询key2
            assert(status.ok());
            status = db->Get(leveldb::ReadOptions(), key2, &value);
            assert(status.ok());
            std::cout<             // 查询key
            status = db->Get(leveldb::ReadOptions(), key, &value);
            if (!status.ok())
            {
               std::cerr<             }   
            else
            {
                std::cout<             }
            // 在对数据库进行了一系列的操作之后,需要对数据库进行关闭,该操作比较简单即删除该对象即可  
            delete db;
            return 0;
        }
        #g++ -o main main.cpp ../leveldb/libleveldb.a -lpthread -I../leveldb/include
        实例编译完成后,如下来执行即可看到结果:
        #./main
        value
        key2==value
        key: NotFound:

一个LevelDB数据库需要有一个对应的文件系统目录名字,该数据库的所有内容都存储在这个目录下。
        LevelDB的使用很简单,一般分三步走:
        (1)打开一个数据库实例。
        (2)对这个数据库实例进行插入,修改和查询操作。
        (3)最后在使用完成之后,关闭该数据库。

对数据库的简单读、写操作LevelDB提供了Put,Delete和Get三个方法对数据库进行修改和查询

特点:
1、key和value都是任意长度的字节数组;
2、entry(即一条K-V记录)默认是按照key的字典顺序存储的,当然开发者也可以重载这个排序函数;
3、提供的基本操作接口:Put()、Delete()、Get()、Batch();
4、支持批量操作以原子操作进行;
5、可以创建数据全景的snapshot(快照),并允许在快照中查找数据;
6、可以通过前向(或后向)迭代器遍历数据(迭代器会隐含的创建一个snapshot);
7、自动使用Snappy压缩数据;
8、可移植性;

10.1.6 iterator.h

遍历器接口非常简单,支持前向和反向遍历。还支持seek到某一个key.支持注册cleanup函数.实现是DBIter.

class Iterator {
 public:
  Iterator();
  virtual ~Iterator();

  // An iterator is either positioned at a key/value pair, or
  // not valid.  This method returns true iff the iterator is valid.
  virtual bool Valid() const = 0;

  // Position at the first key in the source.  The iterator is Valid()
  // after this call iff the source is not empty.
  virtual void SeekToFirst() = 0;

  // Position at the last key in the source.  The iterator is
  // Valid() after this call iff the source is not empty.
  virtual void SeekToLast() = 0;

  // Position at the first key in the source that at or past target
  // The iterator is Valid() after this call iff the source contains
  // an entry that comes at or past target.
  virtual void Seek(const Slice& target) = 0;

  // Moves to the next entry in the source.  After this call, Valid() is
  // true iff the iterator was not positioned at the last entry in the source.
  // REQUIRES: Valid()
  virtual void Next() = 0;

  // Moves to the previous entry in the source.  After this call, Valid() is
  // true iff the iterator was not positioned at the first entry in source.
  // REQUIRES: Valid()
  virtual void Prev() = 0;

  // Return the key for the current entry.  The underlying storage for
  // the returned slice is valid only until the next modification of
  // the iterator.
  // REQUIRES: Valid()
  virtual Slice key() const = 0;

  // Return the value for the current entry.  The underlying storage for
  // the returned slice is valid only until the next modification of
  // the iterator.
  // REQUIRES: !AtEnd() && !AtStart()
  virtual Slice value() const = 0;

  // If an error has occurred, return it.  Else return an ok status.
  virtual Status status() const = 0;

  // Clients are allowed to register function/arg1/arg2 triples that
  // will be invoked when this iterator is destroyed.
  //
  // Note that unlike all of the preceding methods, this method is
  // not abstract and therefore clients should not override it.
  typedef void (*CleanupFunction)(void* arg1, void* arg2);
  void RegisterCleanup(CleanupFunction function, void* arg1, void* arg2);

 private:
  struct Cleanup {
    CleanupFunction function;
    void* arg1;
    void* arg2;
    Cleanup* next;
  };
  Cleanup cleanup_;

  // No copying allowed
  Iterator(const Iterator&);
  void operator=(const Iterator&);
};

这个里面部分实现在table/iterator.cc里面有.都非常简单.创建好cleanup对象然后组织称为链表,在析构函数时候调用.

Iterator::Iterator() {
  cleanup_.function = NULL;
  cleanup_.next = NULL;
}

Iterator::~Iterator() {
  if (cleanup_.function != NULL) {
    (*cleanup_.function)(cleanup_.arg1, cleanup_.arg2);
    for (Cleanup* c = cleanup_.next; c != NULL; ) {
      (*c->function)(c->arg1, c->arg2);
      Cleanup* next = c->next;
      delete c;
      c = next;
    }
  }
}

void Iterator::RegisterCleanup(CleanupFunction func, void* arg1, void* arg2) {
  assert(func != NULL);
  Cleanup* c;
  if (cleanup_.function == NULL) {
    c = &cleanup_;
  } else {
    c = new Cleanup;
    c->next = cleanup_.next;
    cleanup_.next = c;
  }
  c->function = func;
  c->arg1 = arg1;
  c->arg2 = arg2;
}
 IIteration

下面的例子展示了如何打印数据库中的所有键值对。

leveldb::Iterator* it = db->NewIterator(leveldb::ReadOptions());

  for (it->SeekToFirst(); it->Valid(); it->Next()) {

    cout << it->key().ToString() << ": "  << it->value().ToString() << endl;

  }

  assert(it->status().ok());  // Check for any errors found during the scan

  delete it;

 

下面的例子展示了如何访问key在[start,limit)范围内的情况:

for (it->Seek(start);

     it->Valid() && it->key().ToString() < limit;

     it->Next()) {

    ...

}

下面展示了逆序访问(注意:逆序访问会比正序访问要慢)

for (it->SeekToLast(); it->Valid(); it->Prev()) { ... }

 原子更新操作

在将key2插入之后key1删除之前调用的进程挂掉,在不同的key下存在相同的value。WriteBatch类可以通过一系列的更新操作来避免这个问题。

#include "leveldb/write_batch.h"

...

std::string value;

leveldb::Status s = db->Get(leveldb::ReadOptions(), key1, &value);

if (s.ok()) {

  leveldb::WriteBatch batch;

  batch.Delete(key1);

  batch.Put(key2, value);

     s = db->Write(leveldb::WriteOptions(), &batch);

}

WriteBatch类顺序的执行一系列的操作。在例子中,要在插入之前调用删除操作。这样当key1和key2相同的时候,不需要结束错误的删除值的操作。

WriteBatch类除了原子性的好处之外,可以大大加快大批量更新操作的速度。

1,下载levelDB源码

Git clone https://github.com/google/leveldb.git


2,编译LevelDB

cd leveldb & make all

编译完成之后在当前目录多了两个目录:out-shared和out-static

在out-static目录下有我们需要的libleveldb.a


3,在当前目录新建文件夹test

touch test; cd test


4,在test目录新建测试代码test.cpp

[cpp] view plain copy
print?在CODE上查看代码片派生到我的代码片

    #include <assert.h>  
    #include <string.h>  
    #include <iostream>  
    #include "leveldb/db.h"  
      
    int main(){  
            leveldb::DB* db;  
            leveldb::Options options;  
            options.create_if_missing = true;  
            leveldb::Status status = leveldb::DB::Open(options,"/tmp/testdb", &db);  
            assert(status.ok());  
      
            std::string k1 = "name";  
            std::string v1 = "jim";  
      
            status = db->Put(leveldb::WriteOptions(), k1, v1);  
            assert(status.ok());  
      
            status = db->Get(leveldb::ReadOptions(), k1, &v1);  
            assert(status.ok());  
            std::cout<<"k1:"<<k1<<"; v1:"<<v1<<std::endl;  
              
            std::string k2 = "age";  
            std::string v2 = "20";  
      
            status = db->Put(leveldb::WriteOptions(), k2, v2);  
            assert(status.ok());  
            status = db->Get(leveldb::ReadOptions(), k2, &v2);  
            assert(status.ok());  
            std::cout<<"k2:"<<k2<<"; v2:"<<v2<<std::endl;  
      
            status = db->Delete(leveldb::WriteOptions(), k2);  
            assert(status.ok());  
            std::cout<<"Delete k2.."<<std::endl;  
            status = db->Get(leveldb::ReadOptions(),k2, &v2);  
            if(!status.ok())  
                std::cerr<<"k2:"<<k2<<"; "<<status.ToString()<<std::endl;  
            else  
                std::cout<<"k2:"<<k2<<"; v2:"<<v2<<std::endl;  
      
            delete db;  
            return 0;  
    }  


5,编译前的准备

把libleveldb.a拷贝到当前目录

cp ../out-static/libleveldb.a ./

把leveldb/include目录添加到PATH :

cd ..; export PATH=$PATH:$(pwd)/include; cd test

6,编译运行

编译:

g++ -o test test.cpp libleveldb.a -lpthread -I../include

运行:

[cpp] view plain copy
print?在CODE上查看代码片派生到我的代码片

    ➜  test git:(master) ✗ ./test  
    k1:name; v1:jim  
    k2:age; v2:20  
    Delete k2..  
    k2:age; NotFound:  


到目前为止,我们就基本可以使用leveldb了。


9, 执行完.test之后,在/tmp/testdb下面产生了leveldb相关的文件:

[cpp] view plain copy
print?在CODE上查看代码片派生到我的代码片

    ➜  test git:(master) ✗ ls -alh /tmp/testdb  
    total 56  
    drwxr-xr-x  10 root  wheel   340B 10  3 12:51 .  
    drwxrwxrwt  14 root  wheel   476B 10  3 12:31 ..  
    -rw-r--r--   1 root  wheel   148B 10  3 12:14 000005.ldb  
    -rw-r--r--   1 root  wheel   148B 10  3 12:51 000008.ldb  
    -rw-r--r--   1 root  wheel    80B 10  3 12:51 000009.log  
    -rw-r--r--   1 root  wheel    16B 10  3 12:51 CURRENT  
    -rw-r--r--   1 root  wheel     0B 10  3 11:57 LOCK  
    -rw-r--r--   1 root  wheel   309B 10  3 12:51 LOG  
    -rw-r--r--   1 root  wheel   309B 10  3 12:14 LOG.old  
    -rw-r--r--   1 root  wheel   110B 10  3 12:51 MANIFEST-000007  



8,  根据LevelDB官方网站的描述,LevelDB的特点和限制如下:
特点:
1、key和value都是任意长度的字节数组;
2、entry(即一条K-V记录)默认是按照key的字典顺序存储的,当然开发者也可以重载这个排序函数;
3、提供的基本操作接口:Put()、Delete()、Get()、Batch();
4、支持批量操作以原子操作进行;
5、可以创建数据全景的snapshot(快照),并允许在快照中查找数据;
6、可以通过前向(或后向)迭代器遍历数据(迭代器会隐含的创建一个snapshot);
7、自动使用Snappy压缩数据;
8、可移植性;
限制:
1、非关系型数据模型(NoSQL),不支持sql语句,也不支持索引;
2、一次只允许一个进程访问一个特定的数据库;
3、没有内置的C/S架构,但开发者可以使用LevelDB库自己封装一个server; 


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值