leveldb是一个非常高效的可嵌入式K-V数据库,在.NET下有着基于win实现的包装leveldb.net;不过leveldb.net只提供了基于byte[]和string的处理,这显然会对使用的时候带来不方便,毕竟在编写应用的时候都是希望通过对象的方式来存储,如我们常见的redis,mongodb和memcached等等都提供对象方式的读写.以下主要讲解leveldb.net基础上封装一层序列化功能方便使用.

制定对象化的访问接口

为了不修改leveldb.net的代码,所以选择在他基础过行封装,为了清楚需要些什么简单地定义了一个规则

 public interface IDBManager
{
IFormater Formater { get; set; } void Set(string key, object data); object Get(string key, Type type); T Get<T>(string key); void Open(); LevelDB.DB DataBase
{
get;
} }

代码非常简单主要封装了GET,SET,实际上还有DELETE操作,这里偷懒就没做了:),为了提供灵活序列化规则所以在这个管理接口上还提供了一个Formater属性.下面是这相接口的详细实现:

public class LevelDBManager : IDBManager
{ public LevelDBManager()
{ } private LevelDB.DB mDataBase; public string Path { get; set; } public IFormater Formater
{
get;
set;
} public void Open()
{
mDataBase = new LevelDB.DB(Path, new Options() { CreateIfMissing = true }); } public void Set(string key, object data)
{ FormaterBuffer buffer = Formater.Pop();
try
{ int count = Formater.Serialize(data, buffer, );
mDataBase.Put(Encoding.UTF8.GetBytes(key), buffer.Array, , count);
}
finally
{
Formater.Push(buffer);
}
} public object Get(string key, Type type)
{
FormaterBuffer buffer = Formater.Pop();
long count;
object result = null; try
{
count = mDataBase.Get(Encoding.UTF8.GetBytes(key), buffer.Array);
if (count > )
{
result = Formater.Deserialize(type, buffer, , (int)count); }
return result;
}
finally
{
Formater.Push(buffer);
} } public T Get<T>(string key)
{
return (T)Get(key, typeof(T));
} public DB DataBase
{
get { return mDataBase; }
}
}

相信以上那些简知的代码也比较好理解,所以就不详细说明了.

可扩展的序列化规则

由于在使用上的需要,都习惯用些不同序列化方式来进行对象序列化,这个封装为了实现一个比较高的灵活度,所以对象序列化过程也制定了一个接口进行隔离.主要为了满足不同人的胃口.

   public interface IFormater
{
FormaterBuffer Pop(); void Push(FormaterBuffer data); int Serialize(object data, FormaterBuffer buffer, int offset); object Deserialize(Type type, FormaterBuffer buffer, int offset, int count);
}

比较简单定义了序列化和反序列化的方法,不过为了一些性能上的考虑增加了buffer的复用功能,这个设计紧紧用作需要追求这方面性能要求而准备.下面看一下json和protobuf的实现是怎样的:

 public abstract class FormaterBase:IFormater
{
private Stack<FormaterBuffer> mBufferPool = new Stack<FormaterBuffer>(); const int BUFFER_SIZE = * * ; public FormaterBase()
{
for (int i = ; i < ; i++)
{
mBufferPool.Push(new FormaterBuffer(BUFFER_SIZE));
}
}
public FormaterBuffer Pop()
{
lock (mBufferPool)
{
if(mBufferPool.Count>)
return mBufferPool.Pop();
return new FormaterBuffer(BUFFER_SIZE);
}
}
public void Push(FormaterBuffer data)
{
lock (mBufferPool)
{
mBufferPool.Push(data);
}
} public abstract int Serialize(object data, FormaterBuffer buffer, int offset); public abstract object Deserialize(Type type, FormaterBuffer buffer, int offset, int count); }
  • json

    public class JsnoFormater:FormaterBase
    { public int Serialize(object data, byte[] buffer, int offset)
    {
    string json = Newtonsoft.Json.JsonConvert.SerializeObject(data);
    return Encoding.UTF8.GetBytes(json, , json.Length, buffer, offset);
    } public override int Serialize(object data, FormaterBuffer buffer, int offset)
    {
    string json = Newtonsoft.Json.JsonConvert.SerializeObject(data);
    return Encoding.UTF8.GetBytes(json, , json.Length, buffer.Array, offset);
    } public override object Deserialize(Type type, FormaterBuffer buffer, int offset, int count)
    {
    string value = Encoding.UTF8.GetString(buffer.Array, offset, count);
    return Newtonsoft.Json.JsonConvert.DeserializeObject(value, type);
    }
    }
  • protobuf
     public class ProtobufFormater:FormaterBase
    { public override int Serialize(object data, FormaterBuffer buffer, int offset)
    {
    buffer.Seek(offset);
    ProtoBuf.Meta.RuntimeTypeModel.Default.Serialize(buffer.Stream, data);
    return (int)buffer.Stream.Position;
    } public override object Deserialize(Type type, FormaterBuffer buffer, int offset, int count)
    {
    buffer.Stream.SetLength(count + offset);
    buffer.Seek(offset);
    return ProtoBuf.Meta.RuntimeTypeModel.Default.Deserialize(buffer.Stream, null, type);
    }
    }

leveldb.net的一些简单性能改造

虽然leveldb.net只以win dll的基础上包装,但在包装过程的确有些方法针对我个人来说做得并不理想,主要体现在buffer复用方面.其实get,set方法都存在这情况.

 /// <summary>
/// Set the database entry for "key" to "value".
/// </summary>
public void Put(byte[] key, byte[] value, WriteOptions options)
{
IntPtr error;
LevelDBInterop.leveldb_put(this.Handle, options.Handle, key, (IntPtr)key.Length, value, (IntPtr)value.LongLength, out error);
LevelDBException.Check(error);
GC.KeepAlive(options);
GC.KeepAlive(this);
}
public unsafe byte[] Get(byte[] key, ReadOptions options)
{
IntPtr error;
IntPtr lengthPtr;
var valuePtr = LevelDBInterop.leveldb_get(this.Handle, options.Handle, key, (IntPtr)key.Length, out lengthPtr, out error);
LevelDBException.Check(error);
if (valuePtr == IntPtr.Zero)
return null;
try
{
var length = (long)lengthPtr;
var value = new byte[length];
var valueNative = (byte*)valuePtr.ToPointer();
for (long i = ; i < length; ++i)
value[i] = valueNative[i];
return value;
}
finally
{
LevelDBInterop.leveldb_free(valuePtr);
GC.KeepAlive(options);
GC.KeepAlive(this);
}
}

两上个方法都不支持从外部带入buffer的情况,当需要高并发操作的情况而对象序列化内容又比较大的情况下,那的确是会让人感觉到不满意.所以在这基础上添加了一些有利于buffer复用的方法来支持高并发操作下的性能需要.

 public void Put(byte[] key, byte[] value, int offset, int length, WriteOptions options)
{
IntPtr error;
LevelDBInterop.leveldb_put(this.Handle, options.Handle, key, (IntPtr)key.Length, value, (IntPtr)length, out error);
LevelDBException.Check(error);
GC.KeepAlive(options);
GC.KeepAlive(this);
}
public unsafe long Get(byte[] key, byte[] buffer, ReadOptions options)
{
IntPtr error;
IntPtr lengthPtr;
var valuePtr = LevelDBInterop.leveldb_get(this.Handle, options.Handle, key, (IntPtr)key.Length, out lengthPtr, out error);
LevelDBException.Check(error);
if (valuePtr == IntPtr.Zero)
return ;
try
{
var length = (long)lengthPtr;
var valueNative = (byte*)valuePtr.ToPointer();
Marshal.Copy((IntPtr)valuePtr, buffer, , (int)length);
return length;
}
finally
{
LevelDBInterop.leveldb_free(valuePtr); }
}

leveldb.net对象读写封装的更多相关文章

  1. js原生设计模式——7原型模式之真正的原型模式——对象复制封装

    <!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8&qu ...

  2. JAVA之旅(四)——面向对象思想,成员/局部变量,匿名对象,封装 , private,构造方法,构造代码块

    JAVA之旅(四)--面向对象思想,成员/局部变量,匿名对象,封装 , private,构造方法,构造代码块 加油吧,节奏得快点了 1.概述 上篇幅也是讲了这点,这篇幅就着重的讲一下思想和案例 就拿买 ...

  3. 第二十六节:复习Java语言基础-Java的概述,匿名对象,封装,构造函数

    Java基础 Java语言概述 Java语言 语言 描述 javaee 企业版 javase 标准版 javame 小型版 JDK JDK(Java开发工具包) Java语言 语言 Java语言 Ja ...

  4. JavaScript大杂烩3 - 理解JavaScript对象的封装性

    JavaScript是面向对象的 JavaScript是一种基于对象的语言,你遇到的所有东西,包括字符串,数字,数组,函数等等,都是对象. 面向过程还是面向对象? JavaScript同时兼有的面向过 ...

  5. 01 语言基础+高级:1-2 面向对象和封装_day06【类与对象、封装、构造方法】

    day06[类与对象.封装.构造方法] 面向对象类与对象三大特征——封装构造方法 能够理解面向对象的思想能够明确类与对象关系能够掌握类的定义格式能够掌握创建对象格式,并访问类中的成员能够完成手机类的练 ...

  6. Python中用类实现对象和封装

    """ 用类实现对象和封装 对象:对应客观世界的事物,将描述事物的一组数据和与这组数据有关的操作封装在一起, 形成一个实体,这个实体就是对象 类:具有相同或相似性质的对象 ...

  7. c# 面相对象2-之封装性

    一.封装特性: 这是一种隐藏的特性.可以用一个公式来展示类的封装特性: 封装的类=数据  +  对此数据进行的操作(即算法) 通俗的说,封装就是:包起外界不必要知道的东西,只向外界展露可供展示的东西. ...

  8. (79)Wangdao.com第十五天_JavaScript 对象的继承_prototype原型对象_封装_函数式编程

    javascript 内置了许多 function 函数(){...} js 执行首先就会执行自己内置的函数定义 (function Function.function Object) 对象的继承 大 ...

  9. JAVA的对象和封装及static与final的用法(详解)

    一:软件出现的目的 1:用计算机的语言描述现实世界 2:用计算机解决现实世界的问题 编程思维:  使用面向对象的思想(描述)面向对象的世界     (符合人类的思维习惯) 二:面向对象设计和开发程序的 ...

随机推荐

  1. ajax执行完成后,再执行下面的代码的解决办法

    一般ajax设置的都是异步的,但是有时候我们有这种需求,就是等ajax执行完成之后,在执行下面的函数. 1设置async:false 在jq中直接设置了ajax是异步的还是同步的 一般如果不写这个,默 ...

  2. information_schema系列二(列,列权限,事件,存储引擎)

    这个系列的文章主要是为了能够让自己了解MySQL5.7的一些系统表,统一做一下备注和使用,也希望分享出来让大家能够有一点点的受益. 1:COLUMNS 老规矩.查一下这个表,看一下记录,由于这个是看表 ...

  3. window删除文件时提示: 源文件名长度大于系统支持的长度

    有时候删除windows中的目录的时候,会出现"源文件名长度大于系统支持的长度", 而导致不能删除, 作为一个程序猿, 怎么可以被这个折服呢, 原理: 利用 Java  递归删除文 ...

  4. anyexec

    http://www.codesec.net/view/420386.html http://www.cnblogs.com/qiyebao/p/5362101.html http://www.mon ...

  5. Factory Method(工厂方法)-对象创建型模式

    1.意图 定义一个用于创建对象的接口,让子类决定实例化哪一个类.Factory Method使一个类的实例化延迟到其子类. 2.动机 框架使用抽象类定义和维护对象之间的关系.这些对象的创建通常也由框架 ...

  6. map,list

    ---恢复内容开始--- Map<String, List> map=new HashMap<String,List>() HashMap可以理解成是一对对数据的集合我暂时把L ...

  7. C#动态执行字符串(动态创建代码)

    在编写C#程序的时候,有时我们需要动态生成一些代码并执行.然而C#不像JavaScript有一个Eval函数,可以动态的执行代码.所有这些功能都要我们自己去完成.如下是实例. 动态创建代码: usin ...

  8. log4net记录日志到数据库自定义字段

    假设数据库中有如下自定义字段:   1.根据自定义字段定义日志信息对象     public class MessageLog     {           /// <summary> ...

  9. 手动开启/关闭Oracle数据库

    @echo off@echo 启动/关闭数据库set /p flag=您是否要启动数据库?(是按Y启动,否按N关闭) goto answer%flag% goto end :answery echo ...

  10. OA项目之分页

    using System; using System.Collections.Generic; using System.Linq; using System.Web; namespace Digit ...