当前位置: 移动技术网 > IT编程>开发语言>.net > leveldb.net对象读写封装

leveldb.net对象读写封装

2018年11月16日  | 移动技术网IT编程  | 我要评论

遛狗网,61005com财神图库,呼和浩特宠物出售信息

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

              

            }

        }

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网