leveldb.net對象讀寫封裝

        leveldb是一個很是高效的可嵌入式K-V數據庫,在.NET下有着基於win實現的包裝leveldb.net;不過leveldb.net只提供了基於byte[]和string的處理,這顯然會對使用的時候帶來不方便,畢竟在編寫應用的時候都是但願經過對象的方式來存儲,如咱們常見的redis,mongodb和memcached等等都提供對象方式的讀寫.如下主要講解leveldb.net基礎上封裝一層序列化功能方便使用.redis

制定對象化的訪問接口

爲了避免修改leveldb.net的代碼,因此選擇在他基礎過行封裝,爲了清楚須要些什麼簡單地定義了一個規則mongodb

 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; }
        }
    }

相信以上那些簡知的代碼也比較好理解,因此就不詳細說明了.json

可擴展的序列化規則

因爲在使用上的須要,都習慣用些不一樣序列化方式來進行對象序列化,這個封裝爲了實現一個比較高的靈活度,因此對象序列化過程也制定了一個接口進行隔離.主要爲了知足不一樣人的胃口.併發

 

   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的實現是怎樣的:ide

 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方法都存在這狀況.memcached

 

 /// <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);
              
            }
        }
相關文章
相關標籤/搜索