Leveldb.net Object Read-write encapsulation

Source: Internet
Author: User
Tags object serialization serialization

Leveldb is a very efficient embeddable k-v database with a win-based packaging leveldb.net under. NET, but Leveldb.net only provides byte[-based] and string processing, which is obviously inconvenient for use. After all, when you write an application, you want to store it by object, such as our common Redis,mongodb and memcached, and so on, which provide the object's way of reading and writing. The following main explanations are leveldb.net based on the encapsulation of a layer of serialization functionality for ease of use.Developing an object-accessible interface

In order not to modify the code of the Leveldb.net, so choose in his base over line encapsulation, in order to clear what needs to simply define a rule

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;        }           }
The code is very simple mainly encapsulates the get,set, in fact, there are delete operations, here lazy did not do:), in order to provide a flexible serialization rules so on this management interface also provides a Formater property. The following is a detailed implementation of this phase interface:
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;} }    }
I believe the above-mentioned code is better understood, so it is not explained in detail.Extensible serialization Rules

Because of the need to use, it is customary to use a few different serialization methods for object serialization, the package in order to achieve a relatively high degree of flexibility, so the object serialization process also developed an interface for isolation. Mainly to meet the appetite of different people.

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);    }
It is simpler to define serialization and deserialization, but for some performance reasons the reuse of buffer is increased, and the design is tightly prepared for the need to pursue performance requirements. Let's look at the JSON and PROTOBUF implementations:
Public abstract class Formaterbase:iformater {private stack<formaterbuffer> mbufferpool = new Stack<f        Ormaterbuffer> ();        const int BUFFER_SIZE = 1024 * 1024 * 1;  Public Formaterbase () {for (int i = 0; i <; i++) {Mbufferpool.push (new            Formaterbuffer (buffer_size)); }} public Formaterbuffer Pop () {lock (Mbufferpool) {if (Mbuffe                rpool.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 = N Ewtonsoft.            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) {s Tring 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);        }    }
Some simple performance modifications of leveldb.net

Although leveldb.net only on the basis of the win DLL packaging, but in the packaging process there are some methods for me personally do not ideal, mainly reflected in the buffer reuse. In fact, the Get,set method has this situation.

///<summary>//Set The database entry for "key" to "value". </summary> public void Put (byte[] key, byte[] value, writeoptions options) {IntPtr err            Or 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); }        }
Two The previous method does not support the case from the outside into the buffer, when the need for high concurrency operations and the object serialization of the content is relatively large, it does make people feel dissatisfied. Therefore, a number of buffer multiplexing methods are added to support the performance needs of high concurrency operations. .
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);                          }        }

*--------------------------------------
*Personal Station:Www.ikende.com www.asquestion.com              
*Personal Open Source projectGithub.com/ikende             
*------------------------------------- -*

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.