zoukankan      html  css  js  c++  java
  • leveldb.net对象读写封装

            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, 0);
                    mDataBase.Put(Encoding.UTF8.GetBytes(key), buffer.Array, 0, 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 > 0)
                    {
                        result = Formater.Deserialize(type, buffer, 0, (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 = 1024 * 1024 * 1;
    
            public FormaterBase()
            {
                for (int i = 0; i < 20; i++)
                {
                    mBufferPool.Push(new FormaterBuffer(BUFFER_SIZE));
                }
            }
            public FormaterBuffer Pop()
            {
                lock (mBufferPool)
                {
                    if(mBufferPool.Count>0)
                        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, 0, 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, 0, 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 = 0; 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 0;
                try
                {
                    var length = (long)lengthPtr;
                    var valueNative = (byte*)valuePtr.ToPointer();
                    Marshal.Copy((IntPtr)valuePtr, buffer, 0, (int)length);
                    return length;
                }
                finally
                {
                    LevelDBInterop.leveldb_free(valuePtr);
                  
                }
            }
  • 相关阅读:
    Mvc5+Ef 6.0入门开发随笔(2.MVC的简单创建与使用图文详解)
    转载:CSDN mvc ef 的简单增删改查操作
    插件
    Jmeter-后置处理器--json提取器
    jmeter的几种参数化方式
    Python--变量命名规范
    Python--对list、tuple、dict的操作
    Python--列表中字符串按照某种规则排序的方法
    Python--遍历文件夹下所有文件和目录的方法(os.walk(rootdir)函数返回一个三元素元祖)
    Python--递归函数实现:多维嵌套字典数据无限遍历
  • 原文地址:https://www.cnblogs.com/smark/p/3953577.html
Copyright © 2011-2022 走看看