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
*------------------------------------- -*