leveldb在.Net中的使用

2019-02-25  本文已影响0人  njim3

前言

Leveldb是一个google实现的非常高效的kv数据库,目前的版本1.2能够支持billion级别的数据量了。 在这个数量级别下还有着非常高的性能,主要归功于它的良好的设计。特别是LSM算法。[节选自百度百科]
leveldb的功能十分强大,并且我司的项目上使用到了leveldb,但是无奈有一个bug。借本篇简书,对bug的解决以及leveldb的使用一同进行编写。

使用方法

本示例在Visual Studio 2015下进行编译通过。请笔者在阅读之前先准备好环境。

安装leveldb.net库

在Visual Studio中有一个非常好用的工具nuget(Tools -> NuGet Package Manager),可以在菜单里面对nuget安装的库进行安装和卸载,也可以通过命令行进行安装库。

在这里安装的是LevelDB.Net库, LevelDB.Net库

使用方法

根据面向对象的三大准则:封装、继承和多态,对于该库的使用,必须要写一个类来对其进行二次封装,即编写一个工具类,这样在上层使用会更方便一些。

  1. 建立LeveldbUtil类,并且引入leveldb库
using LevelDB;
  1. 单例的实现
private static LeveldbUtil _instance = null;
private static readonly object synObject = new object();

private LevelDB.DB levelDB;
private string dbName = "data";

private LeveldbUtil()
{
    Options options = new Options()
    {
        CreateIfMissing = true,
    };

    this.levelDB = LevelDB.DB.Open(this.dbName, options);
}

public static LeveldbUtil Instance
{
    get
    {
        if (null == _instance)
        {
            lock (synObject)
            {
                if (null == _instance)
                    _instance = new LeveldbUtil();
            }
        }

        return _instance;
    }
}

这里单例的实现使用到static变量来实现,在实现的过程中需要进行加锁,保证该代码被执行一次。

  1. 实现数据库的增、删和查操作
public void writeData(string key, byte[] value)
{
    this.levelDB.Put(new WriteOptions(), key, value);
}

public void delDataWithKey(string key)
{
    this.levelDB.Delete(new WriteOptions() { Sync = true }, key);
}

public byte[] getFirstValue(ref string key)
{
    Iterator iterator = this.levelDB.NewIterator(new ReadOptions());

    iterator.SeekToFirst();

    if (!iterator.Valid())
        return null;

    key = iterator.Key().ToString();
    byte[] res = iterator.Value().ToArray();

    iterator.Dispose();

    return res;
}

public byte[] getValueWithKey(string key)
{
    byte[] val = this.levelDB.Get(new ReadOptions(), key).ToArray();

    return val == null ? null : val;
}

在getFirstValue中使用到了iterator,一定要注意的是使用完之后要进行Dispose,否则程序执行完成之后会报“System.AccessViolationException”错误,即访问了非法的内存空间。
另外一个操作是对数据库进行统计数目和大小,代码如下:

public void getDataSize(ref long dataCount, ref long dataSize)
{
    dataCount = 0;
    dataSize = 0;

    Iterator iterator = this.levelDB.NewIterator(new ReadOptions());

    iterator.SeekToFirst();

    while (iterator.Valid())
    {
        ++dataCount;

        byte[] valBytes = Convert.FromBase64String(iterator.Value().ToString());

        dataSize += valBytes.LongLength;

        iterator.Next();
    }

    iterator.Dispose();
}

同样的iterator也需要进行Dispose。在使用结束数据库后,将数据库关闭,

public void closeDB()
{
    this.levelDB.Dispose();
}

这样,leveldb的工具类便完成,使用就比较简单,唯一再次说明的就是,在使用完成之后一定要调用closeDB,否则数据有可能留在内存中,造成索引和数据的丢失。

结束语

本文对leveldb在.net进行了工具类的实现。笔者在实现的过程中遇到了许多问题,例如单例忘了加lock,在使用iterator过程中未将iterator进行释放,还有就是忘记关闭数据库。其中iterator未释放这个问题解决了好久,因为程序在运行结束后报内存访问错误,因此没有意识到这个问题。毕竟leveldb是由C++编写,需要严格的按照“谁分配谁回收”的原则使用内存。在这里也算是做一个总结,希望读者在使用的过程中可以少走些弯路,更快速的完成需求,完成项目。

最后,demo已经托管至github。

https://github.com/njim3/LevelDBDemo.git
上一篇 下一篇

猜你喜欢

热点阅读