From ac71ef1ec65d1b8ee33428b351440a247fce39e1 Mon Sep 17 00:00:00 2001 From: Christopher Schuchardt Date: Fri, 24 May 2024 17:10:30 -0400 Subject: [PATCH 1/6] Changed LevelDbStore --- src/Plugins/LevelDBStore/Cache.cs | 44 ++ src/Plugins/LevelDBStore/Comparator.cs | 144 ++++++ src/Plugins/LevelDBStore/CompressionLevel.cs | 25 + src/Plugins/LevelDBStore/DB.cs | 484 ++++++++++++++++++ src/Plugins/LevelDBStore/DBExtensions.cs | 29 ++ src/Plugins/LevelDBStore/Env.cs | 30 ++ src/Plugins/LevelDBStore/Helper.cs | 43 ++ .../LevelDBStore/IO/Data/LevelDB/DB.cs | 114 ----- .../LevelDBStore/IO/Data/LevelDB/Helper.cs | 63 --- .../LevelDBStore/IO/Data/LevelDB/Iterator.cs | 86 ---- .../IO/Data/LevelDB/LevelDBException.cs | 23 - .../LevelDBStore/IO/Data/LevelDB/Options.cs | 98 ---- .../IO/Data/LevelDB/ReadOptions.cs | 50 -- .../LevelDBStore/IO/Data/LevelDB/Snapshot.cs | 35 -- .../IO/Data/LevelDB/WriteBatch.cs | 40 -- .../IO/Data/LevelDB/WriteOptions.cs | 36 -- src/Plugins/LevelDBStore/Iterator.cs | 216 ++++++++ src/Plugins/LevelDBStore/LevelDBHandle.cs | 61 +++ .../LevelDB/Native.cs => LevelDBInterop.cs} | 81 ++- src/Plugins/LevelDBStore/LevelDBStore.csproj | 1 + src/Plugins/LevelDBStore/LevelDbFreeHandle.cs | 48 ++ src/Plugins/LevelDBStore/Logger.cs | 39 ++ src/Plugins/LevelDBStore/NativePointer.cs | 358 +++++++++++++ src/Plugins/LevelDBStore/Options.cs | 213 ++++++++ src/Plugins/LevelDBStore/PinnedSafeHandle.cs | 52 ++ .../Plugins/Storage/LevelDBStore.cs | 4 +- .../LevelDBStore/Plugins/Storage/Snapshot.cs | 62 +-- .../LevelDBStore/Plugins/Storage/Store.cs | 75 +-- src/Plugins/LevelDBStore/ReadOptions.cs | 62 +++ src/Plugins/LevelDBStore/Result.cs | 43 ++ src/Plugins/LevelDBStore/SnapShot.cs | 46 ++ src/Plugins/LevelDBStore/WriteBatch.cs | 102 ++++ src/Plugins/LevelDBStore/WriteOptions.cs | 53 ++ 33 files changed, 2196 insertions(+), 664 deletions(-) create mode 100644 src/Plugins/LevelDBStore/Cache.cs create mode 100644 src/Plugins/LevelDBStore/Comparator.cs create mode 100644 src/Plugins/LevelDBStore/CompressionLevel.cs create mode 100644 src/Plugins/LevelDBStore/DB.cs create mode 100644 src/Plugins/LevelDBStore/DBExtensions.cs create mode 100644 src/Plugins/LevelDBStore/Env.cs create mode 100644 src/Plugins/LevelDBStore/Helper.cs delete mode 100644 src/Plugins/LevelDBStore/IO/Data/LevelDB/DB.cs delete mode 100644 src/Plugins/LevelDBStore/IO/Data/LevelDB/Helper.cs delete mode 100644 src/Plugins/LevelDBStore/IO/Data/LevelDB/Iterator.cs delete mode 100644 src/Plugins/LevelDBStore/IO/Data/LevelDB/LevelDBException.cs delete mode 100644 src/Plugins/LevelDBStore/IO/Data/LevelDB/Options.cs delete mode 100644 src/Plugins/LevelDBStore/IO/Data/LevelDB/ReadOptions.cs delete mode 100644 src/Plugins/LevelDBStore/IO/Data/LevelDB/Snapshot.cs delete mode 100644 src/Plugins/LevelDBStore/IO/Data/LevelDB/WriteBatch.cs delete mode 100644 src/Plugins/LevelDBStore/IO/Data/LevelDB/WriteOptions.cs create mode 100644 src/Plugins/LevelDBStore/Iterator.cs create mode 100644 src/Plugins/LevelDBStore/LevelDBHandle.cs rename src/Plugins/LevelDBStore/{IO/Data/LevelDB/Native.cs => LevelDBInterop.cs} (86%) create mode 100644 src/Plugins/LevelDBStore/LevelDbFreeHandle.cs create mode 100644 src/Plugins/LevelDBStore/Logger.cs create mode 100644 src/Plugins/LevelDBStore/NativePointer.cs create mode 100644 src/Plugins/LevelDBStore/Options.cs create mode 100644 src/Plugins/LevelDBStore/PinnedSafeHandle.cs create mode 100644 src/Plugins/LevelDBStore/ReadOptions.cs create mode 100644 src/Plugins/LevelDBStore/Result.cs create mode 100644 src/Plugins/LevelDBStore/SnapShot.cs create mode 100644 src/Plugins/LevelDBStore/WriteBatch.cs create mode 100644 src/Plugins/LevelDBStore/WriteOptions.cs diff --git a/src/Plugins/LevelDBStore/Cache.cs b/src/Plugins/LevelDBStore/Cache.cs new file mode 100644 index 0000000000..45022b44eb --- /dev/null +++ b/src/Plugins/LevelDBStore/Cache.cs @@ -0,0 +1,44 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// Cache.cs file belongs to the neo project and is free +// software distributed under the MIT software license, see the +// accompanying file LICENSE in the main directory of the +// repository or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +namespace LevelDB +{ + /// + /// A Cache is an interface that maps keys to values. It has internal + /// synchronization and may be safely accessed concurrently from + /// multiple threads. It may automatically evict entries to make room + /// for new entries. Values have a specified charge against the cache + /// capacity. For example, a cache where the values are variable + /// length strings, may use the length of the string as the charge for + /// the string. + /// + /// A builtin cache implementation with a least-recently-used eviction + /// policy is provided. Clients may use their own implementations if + /// they want something more sophisticated (like scan-resistance, a + /// custom eviction policy, variable cache sizing, etc.) + /// + public class Cache : LevelDBHandle + { + /// + /// Create a new cache with a fixed size capacity. This implementation + /// of Cache uses a LRU eviction policy. + /// + public Cache(int capacity) + { + Handle = LevelDBInterop.leveldb_cache_create_lru(capacity); + } + + protected override void FreeUnManagedObjects() + { + LevelDBInterop.leveldb_cache_destroy(Handle); + } + } +} diff --git a/src/Plugins/LevelDBStore/Comparator.cs b/src/Plugins/LevelDBStore/Comparator.cs new file mode 100644 index 0000000000..d87fbafa50 --- /dev/null +++ b/src/Plugins/LevelDBStore/Comparator.cs @@ -0,0 +1,144 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// Comparator.cs file belongs to the neo project and is free +// software distributed under the MIT software license, see the +// accompanying file LICENSE in the main directory of the +// repository or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +using LevelDB.NativePointer; +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using System.Text; + +namespace LevelDB +{ + public class Comparator : LevelDBHandle + { + private sealed class Inner : IDisposable + { + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + private delegate void Destructor(IntPtr gCHandleThis); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + private delegate int Compare(IntPtr gCHandleThisg, + IntPtr data1, IntPtr size1, + IntPtr data2, IntPtr size2); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + private delegate IntPtr Name(IntPtr gCHandleThis); + + + private static readonly Destructor s_destructor + = (gCHandleThis) => + { + var h = GCHandle.FromIntPtr(gCHandleThis); + var @this = h.Target as Inner; + + @this.Dispose(); + + // TODO: At the point 'Free' is entered, this delegate may become eligible to be GC'd. + // TODO: Need to look whether GC might run between then, and when this delegate returns. + h.Free(); + }; + + private static readonly Compare s_compare = + (gCHandleThis, data1, size1, data2, size2) => + { + var @this = GCHandle.FromIntPtr(gCHandleThis).Target as Inner; + return @this._cmp(new NativeArray { _baseAddr = data1, _byteLength = size1 }, + new NativeArray { _baseAddr = data2, _byteLength = size2 }); + }; + + private static readonly Name s_nameAccessor = + (gCHandleThis) => + { + var @this = GCHandle.FromIntPtr(gCHandleThis).Target as Inner; + return @this.NameValue; + }; + + private Func _cmp; + private GCHandle _namePinned; + + public IntPtr Init(string name, Func cmp) + { + // TODO: Complete member initialization + _cmp = cmp; + + _namePinned = GCHandle.Alloc( + Encoding.ASCII.GetBytes(name), + GCHandleType.Pinned); + + var thisHandle = GCHandle.Alloc(this); + + var chandle = LevelDBInterop.leveldb_comparator_create( + GCHandle.ToIntPtr(thisHandle), + Marshal.GetFunctionPointerForDelegate(s_destructor), + Marshal.GetFunctionPointerForDelegate(s_compare), + Marshal.GetFunctionPointerForDelegate(s_nameAccessor) + ); + + if (chandle == default) + thisHandle.Free(); + return chandle; + } + + private unsafe IntPtr NameValue + { + get + { + // TODO: this is probably not the most effective way to get a pinned string + var s = ((byte[])_namePinned.Target); + fixed (byte* p = s) + { + // Note: pinning the GCHandle ensures this value should remain stable + // Note: outside of the 'fixed' block. + return (IntPtr)p; + } + } + } + + public void Dispose() + { + if (_namePinned.IsAllocated) + _namePinned.Free(); + } + } + + private Comparator(string name, Func cmp) + { + var inner = new Inner(); + try + { + Handle = inner.Init(name, cmp); + } + finally + { + if (Handle == default) + inner.Dispose(); + } + } + + public static Comparator Create(string name, Func cmp) + { + return new Comparator(name, cmp); + } + public static Comparator Create(string name, IComparer cmp) + { + return new Comparator(name, (a, b) => cmp.Compare(a, b)); + } + + protected override void FreeUnManagedObjects() + { + if (Handle != default) + { + // indirectly invoked CleanupInner + LevelDBInterop.leveldb_comparator_destroy(Handle); + } + } + } +} diff --git a/src/Plugins/LevelDBStore/CompressionLevel.cs b/src/Plugins/LevelDBStore/CompressionLevel.cs new file mode 100644 index 0000000000..2dbad51c47 --- /dev/null +++ b/src/Plugins/LevelDBStore/CompressionLevel.cs @@ -0,0 +1,25 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// CompressionLevel.cs file belongs to the neo project and is free +// software distributed under the MIT software license, see the +// accompanying file LICENSE in the main directory of the +// repository or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +namespace LevelDB +{ + /// + /// DB contents are stored in a set of blocks, each of which holds a + /// sequence of key,value pairs. Each block may be compressed before + /// being stored in a file. The following enum describes which + /// compression method (if any) is used to compress a block. + /// + public enum CompressionLevel + { + NoCompression = 0, + SnappyCompression = 1 + } +} diff --git a/src/Plugins/LevelDBStore/DB.cs b/src/Plugins/LevelDBStore/DB.cs new file mode 100644 index 0000000000..193f267d87 --- /dev/null +++ b/src/Plugins/LevelDBStore/DB.cs @@ -0,0 +1,484 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// DB.cs file belongs to the neo project and is free +// software distributed under the MIT software license, see the +// accompanying file LICENSE in the main directory of the +// repository or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +using LevelDB.NativePointer; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using System.Text; + +namespace LevelDB +{ + /// + /// A DB is a persistent ordered map from keys to values. + /// A DB is safe for concurrent access from multiple threads without any external synchronization. + /// + public class DB : LevelDBHandle, IEnumerable>, IEnumerable>, IEnumerable> + { + private static readonly Encoding s_uTF8 = Encoding.UTF8; + public readonly static Encoding DefaultEncoding = s_uTF8; + + private readonly Cache _cache; + private readonly Logger _infoLog; + private readonly Comparator _comparator; + private readonly Encoding _encoding; + + static void Throw(IntPtr error) + { + Throw(error, msg => new Exception(msg)); + } + + static void Throw(IntPtr error, Func exception) + { + if (error != IntPtr.Zero) + { + try + { + var msg = Marshal.PtrToStringAnsi(error); + throw exception(msg); + } + finally + { + LevelDBInterop.leveldb_free(error); + } + } + } + + public DB(string name, Options options) + : this(name, DefaultEncoding, options) + { + } + + /// + /// Open the database with the specified "name". + /// + public DB(string name, Encoding encoding, Options options) + { + _cache = options.Cache; + _infoLog = options.InfoLog; + _comparator = options.Comparator; + Handle = LevelDBInterop.leveldb_open(options.Handle, name, out var error); + _encoding = encoding; + + Throw(error, msg => new UnauthorizedAccessException(msg)); + } + + public void Close() + { + (this as IDisposable).Dispose(); + } + + /// + /// Set the database entry for "key" to "value". + /// Note: consider setting new WriteOptions{ Sync = true }. + /// + public void Put(string key, string value, WriteOptions options) + { + Put(_encoding.GetBytes(key), _encoding.GetBytes(value), options); + } + + /// + /// Set the database entry for "key" to "value". + /// + public void Put(string key, string value) + { + Put(key, value, new WriteOptions()); + } + + /// + /// Set the database entry for "key" to "value". + /// + public void Put(byte[] key, byte[] value) + { + Put(key, value, new WriteOptions()); + } + + /// + /// Set the database entry for "key" to "value". + /// Note: consider setting new WriteOptions{ Sync = true }. + /// + public void Put(byte[] key, byte[] value, WriteOptions options) + { + LevelDBInterop.leveldb_put(Handle, options.Handle, key, checked((IntPtr)key.LongLength), value, checked((IntPtr)value.LongLength), out var error); + Throw(error); + } + + /// + /// Set the database entry for "key" to "value". + /// Note: consider setting new WriteOptions{ Sync = true }. + /// + public void Put(int key, int[] value) + { + Put(key, value, new WriteOptions()); + } + + /// + /// Set the database entry for "key" to "value". + /// Note: consider setting new WriteOptions{ Sync = true }. + /// + public void Put(int key, int[] value, WriteOptions options) + { + LevelDBInterop.leveldb_put(Handle, options.Handle, ref key, (IntPtr)sizeof(int), value, checked((IntPtr)(value.LongLength * 4)), out var error); + Throw(error); + } + + /// + /// Remove the database entry (if any) for "key". + /// It is not an error if "key" did not exist in the database. + /// + public void Delete(string key) + { + Delete(key, new WriteOptions()); + } + + /// + /// Remove the database entry (if any) for "key". + /// It is not an error if "key" did not exist in the database. + /// Note: consider setting new WriteOptions{ Sync = true }. + /// + public void Delete(string key, WriteOptions options) + { + Delete(_encoding.GetBytes(key), options); + } + + /// + /// Remove the database entry (if any) for "key". + /// It is not an error if "key" did not exist in the database. + /// + public void Delete(byte[] key) + { + Delete(key, new WriteOptions()); + } + + /// + /// Remove the database entry (if any) for "key". + /// It is not an error if "key" did not exist in the database. + /// Note: consider setting new WriteOptions{ Sync = true }. + /// + public void Delete(byte[] key, WriteOptions options) + { + LevelDBInterop.leveldb_delete(Handle, options.Handle, key, checked((IntPtr)key.LongLength), out var error); + Throw(error); + } + + public void Write(WriteBatch batch) + { + Write(batch, new WriteOptions()); + } + + public void Write(WriteBatch batch, WriteOptions options) + { + LevelDBInterop.leveldb_write(Handle, options.Handle, batch.Handle, out var error); + Throw(error); + } + + /// + /// If the database contains an entry for "key" return the value, + /// otherwise return null. + /// + public string Get(string key, ReadOptions options) + { + var value = Get(_encoding.GetBytes(key), options); + if (value != null) return _encoding.GetString(value); + return null; + } + + /// + /// If the database contains an entry for "key" return the value, + /// otherwise return null. + /// + public string Get(string key) + { + return Get(key, ReadOptions.Default); + } + + /// + /// If the database contains an entry for "key" return the value, + /// otherwise return null. + /// + public byte[] Get(byte[] key) + { + return Get(key, ReadOptions.Default); + } + + /// + /// If the database contains an entry for "key" return the value, + /// otherwise return null. + /// + public byte[] Get(byte[] key, ReadOptions options) + { + var v = LevelDBInterop.leveldb_get(Handle, options.Handle, key, checked((IntPtr)key.LongLength), out var length, out var error); + Throw(error); + + if (v != IntPtr.Zero) + { + try + { + + var len = (long)length; + int c = 0, si = 0; + + var bytes = new byte[len]; + + while (si < len) + { + if (len - si > int.MaxValue) + c += int.MaxValue; + else + c += checked((int)(len - si)); + + // Method has a ~2GB limit. + Marshal.Copy(v, bytes, si, c); + + si += c; + } + return bytes; + } + finally + { + LevelDBInterop.leveldb_free(v); + } + } + return null; + } + + /// + /// If the database contains an entry for "key" return the value, + /// otherwise return null. + /// + public int[] Get(int key) + { + return Get(key, ReadOptions.Default); + } + + /// + /// If the database contains an entry for "key" return the value, + /// otherwise return null. + /// + public int[] Get(int key, ReadOptions options) + { + + IntPtr v; + v = LevelDBInterop.leveldb_get(Handle, options.Handle, ref key, (IntPtr)sizeof(int), out var length, out var error); + Throw(error); + + if (v != IntPtr.Zero) + { + try + { + var len = (long)length / 4; + int c = 0, si = 0; + + var bytes = new int[len]; + + while (si < len) + { + if (len - si > int.MaxValue) + c += int.MaxValue; + else + c += checked((int)(len - si)); + + // Method has a ~2GB limit. + Marshal.Copy(v, bytes, si, c); + + si += c; + } + return bytes; + } + finally + { + LevelDBInterop.leveldb_free(v); + } + } + return null; + } + + public bool Contains(byte[] key, ReadOptions options) + { + var value = LevelDBInterop.leveldb_get(Handle, options.Handle, key, (IntPtr)key.Length, out _, out var error); + Throw(error); + + if (value != IntPtr.Zero) + { + LevelDBInterop.leveldb_free(value); + return true; + } + + return false; + } + + public NativeArray GetRaw(NativeArray key) + where T : struct + { + return GetRaw(key, ReadOptions.Default); + } + public NativeArray GetRaw(NativeArray key, ReadOptions options) + where T : struct + { + + var handle = new LevelDbFreeHandle(); + + // todo: remove typecast to int + var v = (Ptr)LevelDBInterop.leveldb_get( + Handle, + options.Handle, + key._baseAddr, + key._byteLength, + out var length, + out _); + + handle.SetHandle((IntPtr)v); + + // round down, truncating the array slightly if needed + var count = (IntPtr)((ulong)length / Ptr.SizeofT); + + return new NativeArray { _baseAddr = v, _count = count, _handle = handle }; + } + + /// + /// Return an iterator over the contents of the database. + /// The result of CreateIterator is initially invalid (caller must + /// call one of the Seek methods on the iterator before using it). + /// + public Iterator CreateIterator() + { + return CreateIterator(ReadOptions.Default); + } + + /// + /// Return an iterator over the contents of the database. + /// The result of CreateIterator is initially invalid (caller must + /// call one of the Seek methods on the iterator before using it). + /// + public Iterator CreateIterator(ReadOptions options) + { + return new Iterator(LevelDBInterop.leveldb_create_iterator(Handle, options.Handle), _encoding); + } + + /// + /// Return a handle to the current DB state. + /// Iterators and Gets created with this handle will all observe a stable snapshot of the current DB state. + /// + public SnapShot CreateSnapshot() + { + return new SnapShot(LevelDBInterop.leveldb_create_snapshot(Handle), this); + } + + /// + /// DB implementations can export properties about their state + /// via this method. If "property" is a valid property understood by this + /// DB implementation, fills "*value" with its current value and returns + /// true. Otherwise returns false. + /// + /// Valid property names include: + /// + /// "leveldb.num-files-at-level" - return the number of files at level , + /// where is an ASCII representation of a level number (e.g. "0"). + /// "leveldb.stats" - returns a multi-line string that describes statistics + /// about the internal operation of the DB. + /// + public string PropertyValue(string name) + { + string result = null; + var ptr = LevelDBInterop.leveldb_property_value(Handle, name); + if (ptr != IntPtr.Zero) + { + try + { + return Marshal.PtrToStringAnsi(ptr); + } + finally + { + LevelDBInterop.leveldb_free(ptr); + } + } + return result; + } + + /// + /// If a DB cannot be opened, you may attempt to call this method to + /// resurrect as much of the contents of the database as possible. + /// Some data may be lost, so be careful when calling this function + /// on a database that contains important information. + /// + public static void Repair(Options options, string name) + { + LevelDBInterop.leveldb_repair_db(options.Handle, name, out var error); + Throw(error); + } + + /// + /// Destroy the contents of the specified database. + /// Be very careful using this method. + /// + public static void Destroy(Options options, string name) + { + LevelDBInterop.leveldb_destroy_db(options.Handle, name, out var error); + Throw(error); + } + + protected override void FreeUnManagedObjects() + { + if (Handle != default) + LevelDBInterop.leveldb_close(Handle); + + // it's critical that the database be closed first, as the logger and cache may depend on it. + + _cache?.Dispose(); + + _comparator?.Dispose(); + + _infoLog?.Dispose(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + IEnumerator> IEnumerable>.GetEnumerator() + { + using var sn = CreateSnapshot(); + using var iterator = CreateIterator(new ReadOptions { Snapshot = sn }); + iterator.SeekToFirst(); + while (iterator.IsValid()) + { + yield return new KeyValuePair(iterator.KeyAsString(), iterator.ValueAsString()); + iterator.Next(); + } + } + + public IEnumerator> GetEnumerator() + { + using var sn = CreateSnapshot(); + using var iterator = CreateIterator(new ReadOptions { Snapshot = sn }); + iterator.SeekToFirst(); + while (iterator.IsValid()) + { + yield return new KeyValuePair(iterator.Key(), iterator.Value()); + iterator.Next(); + } + } + + IEnumerator> IEnumerable>.GetEnumerator() + { + using var sn = CreateSnapshot(); + using var iterator = CreateIterator(new ReadOptions { Snapshot = sn }); + iterator.SeekToFirst(); + while (iterator.IsValid()) + { + yield return new KeyValuePair(iterator.KeyAsInt(), iterator.ValueAsInts()); + iterator.Next(); + } + } + } +} diff --git a/src/Plugins/LevelDBStore/DBExtensions.cs b/src/Plugins/LevelDBStore/DBExtensions.cs new file mode 100644 index 0000000000..b65a419b90 --- /dev/null +++ b/src/Plugins/LevelDBStore/DBExtensions.cs @@ -0,0 +1,29 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// DBExtensions.cs file belongs to the neo project and is free +// software distributed under the MIT software license, see the +// accompanying file LICENSE in the main directory of the +// repository or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +namespace LevelDB +{ + public static class DBExtensions + { + public static void CopyToByteArray(this int source, byte[] destination, int offset) + { + //if (destination == null) throw new ArgumentException("Destination array cannot be null"); + + // check if there is enough space for all the 4 bytes we will copy + //if (destination.Length < offset + 4) throw new ArgumentException("Not enough room in the destination array"); + + destination[offset] = (byte)(source >> 24); // fourth byte + destination[offset + 1] = (byte)(source >> 16); // third byte + destination[offset + 2] = (byte)(source >> 8); // second byte + destination[offset + 3] = (byte)source; // last byte is already in proper position + } + } +} diff --git a/src/Plugins/LevelDBStore/Env.cs b/src/Plugins/LevelDBStore/Env.cs new file mode 100644 index 0000000000..cd7ea540d4 --- /dev/null +++ b/src/Plugins/LevelDBStore/Env.cs @@ -0,0 +1,30 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// Env.cs file belongs to the neo project and is free +// software distributed under the MIT software license, see the +// accompanying file LICENSE in the main directory of the +// repository or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +namespace LevelDB +{ + /// + /// A default environment to access operating system functionality like + /// the filesystem etc of the current operating system. + /// + public class Env : LevelDBHandle + { + public Env() + { + Handle = LevelDBInterop.leveldb_create_default_env(); + } + + protected override void FreeUnManagedObjects() + { + LevelDBInterop.leveldb_env_destroy(Handle); + } + } +} diff --git a/src/Plugins/LevelDBStore/Helper.cs b/src/Plugins/LevelDBStore/Helper.cs new file mode 100644 index 0000000000..0e55017ff1 --- /dev/null +++ b/src/Plugins/LevelDBStore/Helper.cs @@ -0,0 +1,43 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// Helper.cs file belongs to the neo project and is free +// software distributed under the MIT software license, see the +// accompanying file LICENSE in the main directory of the +// repository or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +using LevelDB; +using System; +using System.Collections.Generic; + +namespace Neo.IO.Data.LevelDB +{ + public static class Helper + { + public static IEnumerable<(byte[], byte[])> Seek(this DB db, byte[] prefix, ReadOptions options) + { + using var it = db.CreateIterator(options); + + for (it.Seek(prefix); it.IsValid(); it.Next()) + yield return new(it.Key(), it.Value()); + } + + public static IEnumerable<(byte[], byte[])> SeekPrev(this DB db, byte[] prefix, ReadOptions options) + { + using var it = db.CreateIterator(options); + + it.Seek(prefix); + + if (!it.IsValid()) + it.SeekToLast(); + else if (it.Key().AsSpan().SequenceCompareTo(prefix) > 0) + it.Prev(); + + for (; it.IsValid(); it.Prev()) + yield return new(it.Key(), it.Value()); + } + } +} diff --git a/src/Plugins/LevelDBStore/IO/Data/LevelDB/DB.cs b/src/Plugins/LevelDBStore/IO/Data/LevelDB/DB.cs deleted file mode 100644 index 60e0e24e5a..0000000000 --- a/src/Plugins/LevelDBStore/IO/Data/LevelDB/DB.cs +++ /dev/null @@ -1,114 +0,0 @@ -// Copyright (C) 2015-2024 The Neo Project. -// -// DB.cs file belongs to the neo project and is free -// software distributed under the MIT software license, see the -// accompanying file LICENSE in the main directory of the -// repository or http://www.opensource.org/licenses/mit-license.php -// for more details. -// -// Redistribution and use in source and binary forms with or without -// modifications are permitted. - -using System; -using System.IO; - -namespace Neo.IO.Data.LevelDB -{ - public class DB : IDisposable - { - private IntPtr handle; - - /// - /// Return true if haven't got valid handle - /// - public bool IsDisposed => handle == IntPtr.Zero; - - private DB(IntPtr handle) - { - this.handle = handle; - } - - public void Dispose() - { - if (handle != IntPtr.Zero) - { - Native.leveldb_close(handle); - handle = IntPtr.Zero; - } - } - - public void Delete(WriteOptions options, byte[] key) - { - Native.leveldb_delete(handle, options.handle, key, (UIntPtr)key.Length, out IntPtr error); - NativeHelper.CheckError(error); - } - - public byte[] Get(ReadOptions options, byte[] key) - { - IntPtr value = Native.leveldb_get(handle, options.handle, key, (UIntPtr)key.Length, out UIntPtr length, out IntPtr error); - try - { - NativeHelper.CheckError(error); - return value.ToByteArray(length); - } - finally - { - if (value != IntPtr.Zero) Native.leveldb_free(value); - } - } - - public bool Contains(ReadOptions options, byte[] key) - { - IntPtr value = Native.leveldb_get(handle, options.handle, key, (UIntPtr)key.Length, out _, out IntPtr error); - NativeHelper.CheckError(error); - - if (value != IntPtr.Zero) - { - Native.leveldb_free(value); - return true; - } - - return false; - } - - public Snapshot GetSnapshot() - { - return new Snapshot(handle); - } - - public Iterator NewIterator(ReadOptions options) - { - return new Iterator(Native.leveldb_create_iterator(handle, options.handle)); - } - - public static DB Open(string name) - { - return Open(name, Options.Default); - } - - public static DB Open(string name, Options options) - { - IntPtr handle = Native.leveldb_open(options.handle, Path.GetFullPath(name), out IntPtr error); - NativeHelper.CheckError(error); - return new DB(handle); - } - - public void Put(WriteOptions options, byte[] key, byte[] value) - { - Native.leveldb_put(handle, options.handle, key, (UIntPtr)key.Length, value, (UIntPtr)value.Length, out IntPtr error); - NativeHelper.CheckError(error); - } - - public static void Repair(string name, Options options) - { - Native.leveldb_repair_db(options.handle, Path.GetFullPath(name), out IntPtr error); - NativeHelper.CheckError(error); - } - - public void Write(WriteOptions options, WriteBatch write_batch) - { - Native.leveldb_write(handle, options.handle, write_batch.handle, out IntPtr error); - NativeHelper.CheckError(error); - } - } -} diff --git a/src/Plugins/LevelDBStore/IO/Data/LevelDB/Helper.cs b/src/Plugins/LevelDBStore/IO/Data/LevelDB/Helper.cs deleted file mode 100644 index 2ac3a0005f..0000000000 --- a/src/Plugins/LevelDBStore/IO/Data/LevelDB/Helper.cs +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright (C) 2015-2024 The Neo Project. -// -// Helper.cs file belongs to the neo project and is free -// software distributed under the MIT software license, see the -// accompanying file LICENSE in the main directory of the -// repository or http://www.opensource.org/licenses/mit-license.php -// for more details. -// -// Redistribution and use in source and binary forms with or without -// modifications are permitted. - -using Neo.Persistence; -using System; -using System.Collections.Generic; -using System.Runtime.InteropServices; - -namespace Neo.IO.Data.LevelDB -{ - public static class Helper - { - public static IEnumerable Seek(this DB db, ReadOptions options, byte[] prefix, SeekDirection direction, Func resultSelector) - { - using Iterator it = db.NewIterator(options); - if (direction == SeekDirection.Forward) - { - for (it.Seek(prefix); it.Valid(); it.Next()) - yield return resultSelector(it.Key(), it.Value()); - } - else - { - // SeekForPrev - - it.Seek(prefix); - if (!it.Valid()) - it.SeekToLast(); - else if (it.Key().AsSpan().SequenceCompareTo(prefix) > 0) - it.Prev(); - - for (; it.Valid(); it.Prev()) - yield return resultSelector(it.Key(), it.Value()); - } - } - - public static IEnumerable FindRange(this DB db, ReadOptions options, byte[] startKey, byte[] endKey, Func resultSelector) - { - using Iterator it = db.NewIterator(options); - for (it.Seek(startKey); it.Valid(); it.Next()) - { - byte[] key = it.Key(); - if (key.AsSpan().SequenceCompareTo(endKey) > 0) break; - yield return resultSelector(key, it.Value()); - } - } - - internal static byte[] ToByteArray(this IntPtr data, UIntPtr length) - { - if (data == IntPtr.Zero) return null; - byte[] buffer = new byte[(int)length]; - Marshal.Copy(data, buffer, 0, (int)length); - return buffer; - } - } -} diff --git a/src/Plugins/LevelDBStore/IO/Data/LevelDB/Iterator.cs b/src/Plugins/LevelDBStore/IO/Data/LevelDB/Iterator.cs deleted file mode 100644 index 6c025380fb..0000000000 --- a/src/Plugins/LevelDBStore/IO/Data/LevelDB/Iterator.cs +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright (C) 2015-2024 The Neo Project. -// -// Iterator.cs file belongs to the neo project and is free -// software distributed under the MIT software license, see the -// accompanying file LICENSE in the main directory of the -// repository or http://www.opensource.org/licenses/mit-license.php -// for more details. -// -// Redistribution and use in source and binary forms with or without -// modifications are permitted. - -using System; - -namespace Neo.IO.Data.LevelDB -{ - public class Iterator : IDisposable - { - private IntPtr handle; - - internal Iterator(IntPtr handle) - { - this.handle = handle; - } - - private void CheckError() - { - Native.leveldb_iter_get_error(handle, out IntPtr error); - NativeHelper.CheckError(error); - } - - public void Dispose() - { - if (handle != IntPtr.Zero) - { - Native.leveldb_iter_destroy(handle); - handle = IntPtr.Zero; - } - } - - public byte[] Key() - { - IntPtr key = Native.leveldb_iter_key(handle, out UIntPtr length); - CheckError(); - return key.ToByteArray(length); - } - - public void Next() - { - Native.leveldb_iter_next(handle); - CheckError(); - } - - public void Prev() - { - Native.leveldb_iter_prev(handle); - CheckError(); - } - - public void Seek(byte[] target) - { - Native.leveldb_iter_seek(handle, target, (UIntPtr)target.Length); - } - - public void SeekToFirst() - { - Native.leveldb_iter_seek_to_first(handle); - } - - public void SeekToLast() - { - Native.leveldb_iter_seek_to_last(handle); - } - - public bool Valid() - { - return Native.leveldb_iter_valid(handle); - } - - public byte[] Value() - { - IntPtr value = Native.leveldb_iter_value(handle, out UIntPtr length); - CheckError(); - return value.ToByteArray(length); - } - } -} diff --git a/src/Plugins/LevelDBStore/IO/Data/LevelDB/LevelDBException.cs b/src/Plugins/LevelDBStore/IO/Data/LevelDB/LevelDBException.cs deleted file mode 100644 index c9cca42070..0000000000 --- a/src/Plugins/LevelDBStore/IO/Data/LevelDB/LevelDBException.cs +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright (C) 2015-2024 The Neo Project. -// -// LevelDBException.cs file belongs to the neo project and is free -// software distributed under the MIT software license, see the -// accompanying file LICENSE in the main directory of the -// repository or http://www.opensource.org/licenses/mit-license.php -// for more details. -// -// Redistribution and use in source and binary forms with or without -// modifications are permitted. - -using System.Data.Common; - -namespace Neo.IO.Data.LevelDB -{ - public class LevelDBException : DbException - { - internal LevelDBException(string message) - : base(message) - { - } - } -} diff --git a/src/Plugins/LevelDBStore/IO/Data/LevelDB/Options.cs b/src/Plugins/LevelDBStore/IO/Data/LevelDB/Options.cs deleted file mode 100644 index 989987eeed..0000000000 --- a/src/Plugins/LevelDBStore/IO/Data/LevelDB/Options.cs +++ /dev/null @@ -1,98 +0,0 @@ -// Copyright (C) 2015-2024 The Neo Project. -// -// Options.cs file belongs to the neo project and is free -// software distributed under the MIT software license, see the -// accompanying file LICENSE in the main directory of the -// repository or http://www.opensource.org/licenses/mit-license.php -// for more details. -// -// Redistribution and use in source and binary forms with or without -// modifications are permitted. - -using System; - -namespace Neo.IO.Data.LevelDB -{ - public class Options - { - public static readonly Options Default = new Options(); - internal readonly IntPtr handle = Native.leveldb_options_create(); - - public bool CreateIfMissing - { - set - { - Native.leveldb_options_set_create_if_missing(handle, value); - } - } - - public bool ErrorIfExists - { - set - { - Native.leveldb_options_set_error_if_exists(handle, value); - } - } - - public bool ParanoidChecks - { - set - { - Native.leveldb_options_set_paranoid_checks(handle, value); - } - } - - public int WriteBufferSize - { - set - { - Native.leveldb_options_set_write_buffer_size(handle, (UIntPtr)value); - } - } - - public int MaxOpenFiles - { - set - { - Native.leveldb_options_set_max_open_files(handle, value); - } - } - - public int BlockSize - { - set - { - Native.leveldb_options_set_block_size(handle, (UIntPtr)value); - } - } - - public int BlockRestartInterval - { - set - { - Native.leveldb_options_set_block_restart_interval(handle, value); - } - } - - public CompressionType Compression - { - set - { - Native.leveldb_options_set_compression(handle, value); - } - } - - public IntPtr FilterPolicy - { - set - { - Native.leveldb_options_set_filter_policy(handle, value); - } - } - - ~Options() - { - Native.leveldb_options_destroy(handle); - } - } -} diff --git a/src/Plugins/LevelDBStore/IO/Data/LevelDB/ReadOptions.cs b/src/Plugins/LevelDBStore/IO/Data/LevelDB/ReadOptions.cs deleted file mode 100644 index 727ae9f02a..0000000000 --- a/src/Plugins/LevelDBStore/IO/Data/LevelDB/ReadOptions.cs +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright (C) 2015-2024 The Neo Project. -// -// ReadOptions.cs file belongs to the neo project and is free -// software distributed under the MIT software license, see the -// accompanying file LICENSE in the main directory of the -// repository or http://www.opensource.org/licenses/mit-license.php -// for more details. -// -// Redistribution and use in source and binary forms with or without -// modifications are permitted. - -using System; - -namespace Neo.IO.Data.LevelDB -{ - public class ReadOptions - { - public static readonly ReadOptions Default = new ReadOptions(); - internal readonly IntPtr handle = Native.leveldb_readoptions_create(); - - public bool VerifyChecksums - { - set - { - Native.leveldb_readoptions_set_verify_checksums(handle, value); - } - } - - public bool FillCache - { - set - { - Native.leveldb_readoptions_set_fill_cache(handle, value); - } - } - - public Snapshot Snapshot - { - set - { - Native.leveldb_readoptions_set_snapshot(handle, value.handle); - } - } - - ~ReadOptions() - { - Native.leveldb_readoptions_destroy(handle); - } - } -} diff --git a/src/Plugins/LevelDBStore/IO/Data/LevelDB/Snapshot.cs b/src/Plugins/LevelDBStore/IO/Data/LevelDB/Snapshot.cs deleted file mode 100644 index 14280fbc8f..0000000000 --- a/src/Plugins/LevelDBStore/IO/Data/LevelDB/Snapshot.cs +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright (C) 2015-2024 The Neo Project. -// -// Snapshot.cs file belongs to the neo project and is free -// software distributed under the MIT software license, see the -// accompanying file LICENSE in the main directory of the -// repository or http://www.opensource.org/licenses/mit-license.php -// for more details. -// -// Redistribution and use in source and binary forms with or without -// modifications are permitted. - -using System; - -namespace Neo.IO.Data.LevelDB -{ - public class Snapshot : IDisposable - { - internal IntPtr db, handle; - - internal Snapshot(IntPtr db) - { - this.db = db; - handle = Native.leveldb_create_snapshot(db); - } - - public void Dispose() - { - if (handle != IntPtr.Zero) - { - Native.leveldb_release_snapshot(db, handle); - handle = IntPtr.Zero; - } - } - } -} diff --git a/src/Plugins/LevelDBStore/IO/Data/LevelDB/WriteBatch.cs b/src/Plugins/LevelDBStore/IO/Data/LevelDB/WriteBatch.cs deleted file mode 100644 index ad82dad450..0000000000 --- a/src/Plugins/LevelDBStore/IO/Data/LevelDB/WriteBatch.cs +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (C) 2015-2024 The Neo Project. -// -// WriteBatch.cs file belongs to the neo project and is free -// software distributed under the MIT software license, see the -// accompanying file LICENSE in the main directory of the -// repository or http://www.opensource.org/licenses/mit-license.php -// for more details. -// -// Redistribution and use in source and binary forms with or without -// modifications are permitted. - -using System; - -namespace Neo.IO.Data.LevelDB -{ - public class WriteBatch - { - internal readonly IntPtr handle = Native.leveldb_writebatch_create(); - - ~WriteBatch() - { - Native.leveldb_writebatch_destroy(handle); - } - - public void Clear() - { - Native.leveldb_writebatch_clear(handle); - } - - public void Delete(byte[] key) - { - Native.leveldb_writebatch_delete(handle, key, (UIntPtr)key.Length); - } - - public void Put(byte[] key, byte[] value) - { - Native.leveldb_writebatch_put(handle, key, (UIntPtr)key.Length, value, (UIntPtr)value.Length); - } - } -} diff --git a/src/Plugins/LevelDBStore/IO/Data/LevelDB/WriteOptions.cs b/src/Plugins/LevelDBStore/IO/Data/LevelDB/WriteOptions.cs deleted file mode 100644 index 48915ba480..0000000000 --- a/src/Plugins/LevelDBStore/IO/Data/LevelDB/WriteOptions.cs +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright (C) 2015-2024 The Neo Project. -// -// WriteOptions.cs file belongs to the neo project and is free -// software distributed under the MIT software license, see the -// accompanying file LICENSE in the main directory of the -// repository or http://www.opensource.org/licenses/mit-license.php -// for more details. -// -// Redistribution and use in source and binary forms with or without -// modifications are permitted. - -using System; - -namespace Neo.IO.Data.LevelDB -{ - public class WriteOptions - { - public static readonly WriteOptions Default = new WriteOptions(); - public static readonly WriteOptions SyncWrite = new WriteOptions { Sync = true }; - - internal readonly IntPtr handle = Native.leveldb_writeoptions_create(); - - public bool Sync - { - set - { - Native.leveldb_writeoptions_set_sync(handle, value); - } - } - - ~WriteOptions() - { - Native.leveldb_writeoptions_destroy(handle); - } - } -} diff --git a/src/Plugins/LevelDBStore/Iterator.cs b/src/Plugins/LevelDBStore/Iterator.cs new file mode 100644 index 0000000000..961a369fa8 --- /dev/null +++ b/src/Plugins/LevelDBStore/Iterator.cs @@ -0,0 +1,216 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// Iterator.cs file belongs to the neo project and is free +// software distributed under the MIT software license, see the +// accompanying file LICENSE in the main directory of the +// repository or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +using System; +using System.Runtime.InteropServices; +using System.Text; +namespace LevelDB +{ + /// + /// An iterator yields a sequence of key/value pairs from a database. + /// + public class Iterator : LevelDBHandle + { + private readonly Encoding _encoding; + + internal Iterator(IntPtr Handle, Encoding encoding) + { + _encoding = encoding; + this.Handle = Handle; + } + + /// + /// An iterator is either positioned at a key/value pair, or + /// not valid. + /// + /// This method returns true iff the iterator is valid. + public bool IsValid() + { + return (int)LevelDBInterop.leveldb_iter_valid(Handle) != 0; + } + + /// + /// Position at the first key in the source. + /// The iterator is Valid() after this call iff the source is not empty. + /// + public void SeekToFirst() + { + LevelDBInterop.leveldb_iter_seek_to_first(Handle); + Throw(); + } + + /// + /// Position at the last key in the source. + /// The iterator is Valid() after this call iff the source is not empty. + /// + public void SeekToLast() + { + LevelDBInterop.leveldb_iter_seek_to_last(Handle); + Throw(); + } + + /// + /// Position at the first key in the source that at or past target + /// The iterator is Valid() after this call iff the source contains + /// an entry that comes at or past target. + /// + public void Seek(byte[] key) + { + LevelDBInterop.leveldb_iter_seek(Handle, key, key.Length); + Throw(); + } + + /// + /// Position at the first key in the source that at or past target + /// The iterator is Valid() after this call iff the source contains + /// an entry that comes at or past target. + /// + public void Seek(string key) + { + Seek(_encoding.GetBytes(key)); + } + + /// + /// Position at the first key in the source that at or past target + /// The iterator is Valid() after this call iff the source contains + /// an entry that comes at or past target. + /// + public void Seek(int key) + { + LevelDBInterop.leveldb_iter_seek(Handle, ref key, 4); + Throw(); + } + + /// + /// Moves to the next entry in the source. + /// After this call, Valid() is true iff the iterator was not positioned at the last entry in the source. + /// REQUIRES: Valid() + /// + public void Next() + { + LevelDBInterop.leveldb_iter_next(Handle); + Throw(); + } + + /// + /// Moves to the previous entry in the source. + /// After this call, Valid() is true iff the iterator was not positioned at the first entry in source. + /// REQUIRES: Valid() + /// + public void Prev() + { + LevelDBInterop.leveldb_iter_prev(Handle); + Throw(); + } + + + /// + /// Return the key for the current entry. + /// REQUIRES: Valid() + /// + public int KeyAsInt() + { + int length; + var key = LevelDBInterop.leveldb_iter_key(Handle, out length); + Throw(); + + if (length != 4) throw new Exception("Key is not an integer"); + + return Marshal.ReadInt32(key); + } + + /// + /// Return the key for the current entry. + /// REQUIRES: Valid() + /// + public string KeyAsString() + { + return _encoding.GetString(Key()); + } + + /// + /// Return the key for the current entry. + /// REQUIRES: Valid() + /// + public byte[] Key() + { + int length; + var key = LevelDBInterop.leveldb_iter_key(Handle, out length); + Throw(); + + var bytes = new byte[length]; + Marshal.Copy(key, bytes, 0, length); + return bytes; + } + + /// + /// Return the value for the current entry. + /// REQUIRES: Valid() + /// + public int[] ValueAsInts() + { + int length; + var value = LevelDBInterop.leveldb_iter_value(Handle, out length); + Throw(); + + var bytes = new int[length / 4]; + Marshal.Copy(value, bytes, 0, length / 4); + return bytes; + } + + /// + /// Return the value for the current entry. + /// REQUIRES: Valid() + /// + public string ValueAsString() + { + return _encoding.GetString(Value()); + } + + /// + /// Return the value for the current entry. + /// REQUIRES: Valid() + /// + public byte[] Value() + { + int length; + var value = LevelDBInterop.leveldb_iter_value(Handle, out length); + Throw(); + + var bytes = new byte[length]; + Marshal.Copy(value, bytes, 0, length); + return bytes; + } + + /// + /// If an error has occurred, throw it. + /// + void Throw() + { + Throw(msg => new Exception(msg)); + } + + /// + /// If an error has occurred, throw it. + /// + void Throw(Func exception) + { + IntPtr error; + LevelDBInterop.leveldb_iter_get_error(Handle, out error); + if (error != IntPtr.Zero) throw exception(Marshal.PtrToStringAnsi(error)); + } + + protected override void FreeUnManagedObjects() + { + LevelDBInterop.leveldb_iter_destroy(Handle); + } + } +} diff --git a/src/Plugins/LevelDBStore/LevelDBHandle.cs b/src/Plugins/LevelDBStore/LevelDBHandle.cs new file mode 100644 index 0000000000..2c679b47a0 --- /dev/null +++ b/src/Plugins/LevelDBStore/LevelDBHandle.cs @@ -0,0 +1,61 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// LevelDBHandle.cs file belongs to the neo project and is free +// software distributed under the MIT software license, see the +// accompanying file LICENSE in the main directory of the +// repository or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +using System; + +namespace LevelDB +{ + /// + /// Base class for all LevelDB objects + /// Implement IDisposable as prescribed by http://msdn.microsoft.com/en-us/library/b1yfkh5e.aspx by overriding the two additional virtual methods + /// + public abstract class LevelDBHandle : IDisposable + { + public IntPtr Handle { protected set; get; } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected virtual void FreeManagedObjects() + { + } + + protected virtual void FreeUnManagedObjects() + { + } + + bool _disposed = false; + void Dispose(bool disposing) + { + if (!_disposed) + { + if (disposing) + { + FreeManagedObjects(); + } + if (Handle != IntPtr.Zero) + { + FreeUnManagedObjects(); + Handle = IntPtr.Zero; + } + _disposed = true; + } + } + + ~LevelDBHandle() + { + Dispose(false); + } + } +} diff --git a/src/Plugins/LevelDBStore/IO/Data/LevelDB/Native.cs b/src/Plugins/LevelDBStore/LevelDBInterop.cs similarity index 86% rename from src/Plugins/LevelDBStore/IO/Data/LevelDB/Native.cs rename to src/Plugins/LevelDBStore/LevelDBInterop.cs index acf8fa82b9..f98f489e19 100644 --- a/src/Plugins/LevelDBStore/IO/Data/LevelDB/Native.cs +++ b/src/Plugins/LevelDBStore/LevelDBInterop.cs @@ -1,6 +1,6 @@ // Copyright (C) 2015-2024 The Neo Project. // -// Native.cs file belongs to the neo project and is free +// LevelDBInterop.cs file belongs to the neo project and is free // software distributed under the MIT software license, see the // accompanying file LICENSE in the main directory of the // repository or http://www.opensource.org/licenses/mit-license.php @@ -10,18 +10,11 @@ // modifications are permitted. using System; -using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -namespace Neo.IO.Data.LevelDB +namespace LevelDB { - public enum CompressionType : byte - { - kNoCompression = 0x0, - kSnappyCompression = 0x1 - } - - public static class Native + public static class LevelDBInterop { #region Logger [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] @@ -39,16 +32,25 @@ public static class Native public static extern void leveldb_close(IntPtr /*DB */ db); [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] - public static extern void leveldb_put(IntPtr /* DB */ db, IntPtr /* WriteOptions*/ options, byte[] key, UIntPtr keylen, byte[] val, UIntPtr vallen, out IntPtr errptr); + public static extern void leveldb_put(IntPtr /* DB */ db, IntPtr /* WriteOptions*/ options, byte[] key, IntPtr keylen, byte[] val, IntPtr vallen, out IntPtr errptr); + + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern void leveldb_put(IntPtr /* DB */ db, IntPtr /* WriteOptions*/ options, ref int key, IntPtr keylen, int[] val, IntPtr vallen, out IntPtr errptr); [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] - public static extern void leveldb_delete(IntPtr /* DB */ db, IntPtr /* WriteOptions*/ options, byte[] key, UIntPtr keylen, out IntPtr errptr); + public static extern void leveldb_delete(IntPtr /* DB */ db, IntPtr /* WriteOptions*/ options, byte[] key, IntPtr keylen, out IntPtr errptr); [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] public static extern void leveldb_write(IntPtr /* DB */ db, IntPtr /* WriteOptions*/ options, IntPtr /* WriteBatch */ batch, out IntPtr errptr); [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] - public static extern IntPtr leveldb_get(IntPtr /* DB */ db, IntPtr /* ReadOptions*/ options, byte[] key, UIntPtr keylen, out UIntPtr vallen, out IntPtr errptr); + public static extern IntPtr leveldb_get(IntPtr /* DB */ db, IntPtr /* ReadOptions*/ options, byte[] key, IntPtr keylen, out IntPtr vallen, out IntPtr errptr); + + [DllImport("libleveldb", CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr leveldb_get(IntPtr /* DB */ db, IntPtr /* ReadOptions*/ options, ref int key, IntPtr keylen, out IntPtr vallen, out IntPtr errptr); + + [DllImport("libleveldb", CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr leveldb_get(IntPtr /* DB */ db, IntPtr /* ReadOptions*/ options, IntPtr key, IntPtr keylen, out IntPtr vallen, out IntPtr errptr); //[DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] //static extern void leveldb_approximate_sizes(IntPtr /* DB */ db, int num_ranges, byte[] range_start_key, long range_start_key_len, byte[] range_limit_key, long range_limit_key_len, out long sizes); @@ -94,8 +96,7 @@ public static class Native public static extern void leveldb_iter_destroy(IntPtr /*Iterator*/ iterator); [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] - [return: MarshalAs(UnmanagedType.U1)] - public static extern bool leveldb_iter_valid(IntPtr /*Iterator*/ iterator); + public static extern byte leveldb_iter_valid(IntPtr /*Iterator*/ iterator); [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] public static extern void leveldb_iter_seek_to_first(IntPtr /*Iterator*/ iterator); @@ -104,7 +105,10 @@ public static class Native public static extern void leveldb_iter_seek_to_last(IntPtr /*Iterator*/ iterator); [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] - public static extern void leveldb_iter_seek(IntPtr /*Iterator*/ iterator, byte[] key, UIntPtr length); + public static extern void leveldb_iter_seek(IntPtr /*Iterator*/ iterator, byte[] key, int length); + + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern void leveldb_iter_seek(IntPtr /*Iterator*/ iterator, ref int key, int length); [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] public static extern void leveldb_iter_next(IntPtr /*Iterator*/ iterator); @@ -113,10 +117,10 @@ public static class Native public static extern void leveldb_iter_prev(IntPtr /*Iterator*/ iterator); [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] - public static extern IntPtr leveldb_iter_key(IntPtr /*Iterator*/ iterator, out UIntPtr length); + public static extern IntPtr leveldb_iter_key(IntPtr /*Iterator*/ iterator, out int length); [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] - public static extern IntPtr leveldb_iter_value(IntPtr /*Iterator*/ iterator, out UIntPtr length); + public static extern IntPtr leveldb_iter_value(IntPtr /*Iterator*/ iterator, out int length); [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] public static extern void leveldb_iter_get_error(IntPtr /*Iterator*/ iterator, out IntPtr error); @@ -130,22 +134,22 @@ public static class Native public static extern void leveldb_options_destroy(IntPtr /*Options*/ options); [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] - public static extern void leveldb_options_set_create_if_missing(IntPtr /*Options*/ options, [MarshalAs(UnmanagedType.U1)] bool o); + public static extern void leveldb_options_set_create_if_missing(IntPtr /*Options*/ options, byte o); [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] - public static extern void leveldb_options_set_error_if_exists(IntPtr /*Options*/ options, [MarshalAs(UnmanagedType.U1)] bool o); + public static extern void leveldb_options_set_error_if_exists(IntPtr /*Options*/ options, byte o); [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] public static extern void leveldb_options_set_info_log(IntPtr /*Options*/ options, IntPtr /* Logger */ logger); [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] - public static extern void leveldb_options_set_paranoid_checks(IntPtr /*Options*/ options, [MarshalAs(UnmanagedType.U1)] bool o); + public static extern void leveldb_options_set_paranoid_checks(IntPtr /*Options*/ options, byte o); [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] public static extern void leveldb_options_set_env(IntPtr /*Options*/ options, IntPtr /*Env*/ env); [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] - public static extern void leveldb_options_set_write_buffer_size(IntPtr /*Options*/ options, UIntPtr size); + public static extern void leveldb_options_set_write_buffer_size(IntPtr /*Options*/ options, long size); [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] public static extern void leveldb_options_set_max_open_files(IntPtr /*Options*/ options, int max); @@ -154,20 +158,19 @@ public static class Native public static extern void leveldb_options_set_cache(IntPtr /*Options*/ options, IntPtr /*Cache*/ cache); [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] - public static extern void leveldb_options_set_block_size(IntPtr /*Options*/ options, UIntPtr size); + public static extern void leveldb_options_set_block_size(IntPtr /*Options*/ options, long size); [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] public static extern void leveldb_options_set_block_restart_interval(IntPtr /*Options*/ options, int interval); [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] - public static extern void leveldb_options_set_compression(IntPtr /*Options*/ options, CompressionType level); - - [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] - public static extern void leveldb_options_set_comparator(IntPtr /*Options*/ options, IntPtr /*Comparator*/ comparer); + public static extern void leveldb_options_set_compression(IntPtr /*Options*/ options, int level); [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] public static extern void leveldb_options_set_filter_policy(IntPtr /*Options*/ options, IntPtr /*FilterPolicy*/ policy); + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern void leveldb_options_set_comparator(IntPtr /*Options*/ options, IntPtr /*Comparator*/ comparer); [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] public static extern IntPtr leveldb_filterpolicy_create_bloom(int bits_per_key); #endregion @@ -180,10 +183,10 @@ public static class Native public static extern void leveldb_readoptions_destroy(IntPtr /*ReadOptions*/ options); [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] - public static extern void leveldb_readoptions_set_verify_checksums(IntPtr /*ReadOptions*/ options, [MarshalAs(UnmanagedType.U1)] bool o); + public static extern void leveldb_readoptions_set_verify_checksums(IntPtr /*ReadOptions*/ options, byte o); [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] - public static extern void leveldb_readoptions_set_fill_cache(IntPtr /*ReadOptions*/ options, [MarshalAs(UnmanagedType.U1)] bool o); + public static extern void leveldb_readoptions_set_fill_cache(IntPtr /*ReadOptions*/ options, byte o); [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] public static extern void leveldb_readoptions_set_snapshot(IntPtr /*ReadOptions*/ options, IntPtr /*SnapShot*/ snapshot); @@ -200,10 +203,10 @@ public static class Native public static extern void leveldb_writebatch_clear(IntPtr /* WriteBatch */ batch); [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] - public static extern void leveldb_writebatch_put(IntPtr /* WriteBatch */ batch, byte[] key, UIntPtr keylen, byte[] val, UIntPtr vallen); + public static extern void leveldb_writebatch_put(IntPtr /* WriteBatch */ batch, byte[] key, int keylen, byte[] val, int vallen); [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] - public static extern void leveldb_writebatch_delete(IntPtr /* WriteBatch */ batch, byte[] key, UIntPtr keylen); + public static extern void leveldb_writebatch_delete(IntPtr /* WriteBatch */ batch, byte[] key, int keylen); [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] public static extern void leveldb_writebatch_iterate(IntPtr /* WriteBatch */ batch, object state, Action put, Action deleted); @@ -217,7 +220,7 @@ public static class Native public static extern void leveldb_writeoptions_destroy(IntPtr /*WriteOptions*/ options); [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] - public static extern void leveldb_writeoptions_set_sync(IntPtr /*WriteOptions*/ options, [MarshalAs(UnmanagedType.U1)] bool o); + public static extern void leveldb_writeoptions_set_sync(IntPtr /*WriteOptions*/ options, byte o); #endregion #region Cache @@ -247,18 +250,4 @@ public static extern IntPtr /* leveldb_comparator_t* */ #endregion } - - internal static class NativeHelper - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void CheckError(IntPtr error) - { - if (error != IntPtr.Zero) - { - string message = Marshal.PtrToStringAnsi(error); - Native.leveldb_free(error); - throw new LevelDBException(message); - } - } - } } diff --git a/src/Plugins/LevelDBStore/LevelDBStore.csproj b/src/Plugins/LevelDBStore/LevelDBStore.csproj index ba82156b18..ebe2b69388 100644 --- a/src/Plugins/LevelDBStore/LevelDBStore.csproj +++ b/src/Plugins/LevelDBStore/LevelDBStore.csproj @@ -5,6 +5,7 @@ Neo.Plugins.Storage.LevelDBStore Neo.Plugins.Storage true + 12 diff --git a/src/Plugins/LevelDBStore/LevelDbFreeHandle.cs b/src/Plugins/LevelDBStore/LevelDbFreeHandle.cs new file mode 100644 index 0000000000..ec55ce04ec --- /dev/null +++ b/src/Plugins/LevelDBStore/LevelDbFreeHandle.cs @@ -0,0 +1,48 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// LevelDbFreeHandle.cs file belongs to the neo project and is free +// software distributed under the MIT software license, see the +// accompanying file LICENSE in the main directory of the +// repository or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +using System; +using System.Runtime.InteropServices; + +namespace LevelDB +{ + // Wraps pointers to be freed with leveldb_free (e.g. returned by leveldb_get) + // + // reference on safe handles: http://blogs.msdn.com/b/bclteam/archive/2006/06/23/644343.aspx + internal class LevelDbFreeHandle : SafeHandle + { + public LevelDbFreeHandle() + : base(default, true) + { + } + + override protected bool ReleaseHandle() + { + if (handle != default) + LevelDBInterop.leveldb_free(handle); + handle = default; + return true; + } + + public override bool IsInvalid + { + get { return handle != default; } + } + + public new void SetHandle(IntPtr p) + { + if (handle != default) + ReleaseHandle(); + + base.SetHandle(p); + } + } +} diff --git a/src/Plugins/LevelDBStore/Logger.cs b/src/Plugins/LevelDBStore/Logger.cs new file mode 100644 index 0000000000..20a0a435a6 --- /dev/null +++ b/src/Plugins/LevelDBStore/Logger.cs @@ -0,0 +1,39 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// Logger.cs file belongs to the neo project and is free +// software distributed under the MIT software license, see the +// accompanying file LICENSE in the main directory of the +// repository or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +using System; +using System.Runtime.InteropServices; + +namespace LevelDB +{ + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public delegate void Log(string msg); + + public class Logger : LevelDBHandle + { + public Logger(Log log) + { + var p = Marshal.GetFunctionPointerForDelegate(log); + Handle = LevelDBInterop.leveldb_logger_create(p); + } + + public static implicit operator Logger(Log log) + { + return new Logger(log); + } + + protected override void FreeUnManagedObjects() + { + if (Handle != default(IntPtr)) + LevelDBInterop.leveldb_logger_destroy(Handle); + } + } +} diff --git a/src/Plugins/LevelDBStore/NativePointer.cs b/src/Plugins/LevelDBStore/NativePointer.cs new file mode 100644 index 0000000000..dd70e48874 --- /dev/null +++ b/src/Plugins/LevelDBStore/NativePointer.cs @@ -0,0 +1,358 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// NativePointer.cs file belongs to the neo project and is free +// software distributed under the MIT software license, see the +// accompanying file LICENSE in the main directory of the +// repository or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Runtime.InteropServices; + +namespace LevelDB.NativePointer +{ + // note: sizeof(Ptr<>) == sizeof(IntPtr) allows you to create Ptr> of arbitrary depth and "it just works" + // IntPtr severely lacks appropriate arithmetic operators; up-promotions to ulong used instead. + public struct Ptr(IntPtr addr) + where T : struct + { + private IntPtr _addr = addr; + + // cannot use 'sizeof' operator on generic type parameters + public static readonly uint SizeofT = (uint)Marshal.SizeOf(typeof(T)); + private static readonly IDeref s_deref = GetDeref(); + + private static IDeref GetDeref() + { + if (typeof(T) == typeof(int)) + return (IDeref)new IntDeref(); + + // TODO: other concrete implementations of IDeref. + // (can't be made generic; will not type check) + + // fallback + return new MarshalDeref(); + } + + public static explicit operator Ptr(IntPtr p) + { + return new Ptr(p); + } + public static explicit operator IntPtr(Ptr p) + { + return p._addr; + } + + // operator Ptr(Ptr) + public static Ptr Cast(Ptr p) + where U : struct + { + return new Ptr(p._addr); + } + + public void Inc() { Advance((IntPtr)1); } + public void Dec() { Advance((IntPtr)(-1)); } + + public void Advance(IntPtr d) + { + _addr = (IntPtr)((ulong)_addr + SizeofT * (ulong)d); + } + public readonly IntPtr Diff(Ptr p2) + { + var diff = (long)(((ulong)_addr) - ((ulong)p2._addr)); + Debug.Assert(diff % SizeofT == 0); + + return checked((IntPtr)(diff / SizeofT)); + } + public readonly T Deref() + { + return s_deref.Deref(_addr); + } + public readonly void DerefWrite(T newValue) + { + s_deref.DerefWrite(_addr, newValue); + } + + // C-style pointer arithmetic. IntPtr is used in place of C's ptrdiff_t + #region pointer/intptr arithmetic + public static Ptr operator ++(Ptr p) + { + p.Inc(); + return p; + } + public static Ptr operator --(Ptr p) + { + p.Dec(); + return p; + } + public static Ptr operator +(Ptr p, IntPtr offset) + { + p.Advance(offset); + return p; + } + public static Ptr operator +(IntPtr offset, Ptr p) + { + p.Advance(offset); + return p; + } + public static Ptr operator -(Ptr p, IntPtr offset) + { + p.Advance((IntPtr)(0 - (ulong)offset)); + return p; + } + public static IntPtr operator -(Ptr p, Ptr p2) + { + return p.Diff(p2); + } + public readonly T this[IntPtr offset] + { + get { return (this + offset).Deref(); } + + set { (this + offset).DerefWrite(value); } + } + #endregion + + #region comparisons + public override readonly bool Equals(object obj) + { + if (obj is not Ptr) + return false; + return this == (Ptr)obj; + } + public override readonly int GetHashCode() + { + return checked((int)_addr ^ (int)(IntPtr)((long)_addr >> 6)); + } + public static bool operator ==(Ptr p, Ptr p2) + { + return (IntPtr)p == (IntPtr)p2; + } + public static bool operator !=(Ptr p, Ptr p2) + { + return (IntPtr)p != (IntPtr)p2; + } + public static bool operator <(Ptr p, Ptr p2) + { + return (ulong)(IntPtr)p < (ulong)(IntPtr)p2; + } + public static bool operator >(Ptr p, Ptr p2) + { + return (ulong)(IntPtr)p > (ulong)(IntPtr)p2; + } + public static bool operator <=(Ptr p, Ptr p2) + { + return (ulong)(IntPtr)p <= (ulong)(IntPtr)p2; + } + public static bool operator >=(Ptr p, Ptr p2) + { + return (ulong)(IntPtr)p >= (ulong)(IntPtr)p2; + } + #endregion + + #region pointer/int/long arithmetic (convenience) + public static Ptr operator +(Ptr p, long offset) + { + return p + checked((IntPtr)offset); + } + public static Ptr operator +(long offset, Ptr p) + { + return p + checked((IntPtr)offset); + } + public static Ptr operator -(Ptr p, long offset) + { + return p - checked((IntPtr)offset); + } + public T this[long offset] + { + readonly get { return this[checked((IntPtr)offset)]; } + set { this[checked((IntPtr)offset)] = value; } + } + #endregion + } + + public struct NativeArray + : IDisposable + { + public IntPtr _baseAddr; + public IntPtr _byteLength; + + public SafeHandle _handle; + + public readonly void Dispose() + { + _handle?.Dispose(); + } + + public static NativeArray FromArray(T[] arr, long start = 0, long count = -1) + where T : struct + { + if (count < 0) count = arr.LongLength - start; + + var h = new PinnedSafeHandle(arr); + return new NativeArray { _baseAddr = h.Ptr + start, _count = checked((IntPtr)count), _handle = h }; + } + } + + public struct NativeArray + : IEnumerable + , IDisposable + where T : struct + { + public Ptr _baseAddr; + public IntPtr _count; + + public SafeHandle _handle; + + public static implicit operator NativeArray(NativeArray arr) + { + return new NativeArray + { + _baseAddr = (IntPtr)arr._baseAddr, + _byteLength = (IntPtr)((ulong)(IntPtr)(arr._baseAddr + arr._count) - (ulong)(IntPtr)(arr._baseAddr)), + _handle = arr._handle + }; + } + public static explicit operator NativeArray(NativeArray arr) + { + var baseAddr = (Ptr)arr._baseAddr; + var count = ((Ptr)(IntPtr)((ulong)arr._baseAddr + (ulong)arr._byteLength)) - baseAddr; + + return new NativeArray { _baseAddr = baseAddr, _count = count, _handle = arr._handle }; + } + + #region IEnumerable + + public readonly IEnumerator GetEnumerator() + { + return new Enumerator(_baseAddr, _baseAddr + _count, _handle); + } + + readonly System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + private class Enumerator(Ptr start, Ptr end, SafeHandle handle) : IEnumerator + { + private Ptr _current = start; + private Ptr _end = end; + private int _state = 0; + private readonly SafeHandle _handle = handle; + + public void Dispose() + { + GC.KeepAlive(_handle); + } + + public T Current + { + get + { + if (_handle != null && _handle.IsClosed) + throw new InvalidOperationException("Dereferencing a closed handle"); + if (_state != 1) + throw new InvalidOperationException("Attempt to invoke Current on invalid enumerator"); + return _current.Deref(); + } + } + + public bool MoveNext() + { + switch (_state) + { + case 0: + _state = 1; + return _current != _end; + case 1: + ++_current; + if (_current == _end) + _state = 2; + return _current != _end; + case 2: + default: + return false; + } + } + + public void Reset() + { + throw new NotImplementedException(); + } + + object System.Collections.IEnumerator.Current + { + get { return Current; } + } + } + + #endregion + + public T this[IntPtr offset] + { + readonly get + { + if ((ulong)offset >= (ulong)_count) + throw new IndexOutOfRangeException("offest"); + var val = _baseAddr[offset]; + GC.KeepAlive(this); + return val; + } + set + { + if ((ulong)offset >= (ulong)_count) + throw new IndexOutOfRangeException("offest"); + _baseAddr[offset] = value; + GC.KeepAlive(this); + } + } + public T this[long offset] + { + readonly get { return this[checked((IntPtr)offset)]; } + set { this[checked((IntPtr)offset)] = value; } + } + + public readonly void Dispose() + { + _handle?.Dispose(); + } + } + + #region dereferencing abstraction + interface IDeref + { + T Deref(IntPtr addr); + void DerefWrite(IntPtr addr, T newValue); + } + internal unsafe class IntDeref : IDeref + { + public int Deref(IntPtr addr) + { + var p = (int*)addr; + return *p; + } + + public void DerefWrite(IntPtr addr, int newValue) + { + var p = (int*)addr; + *p = newValue; + } + } + internal class MarshalDeref : IDeref + { + public T Deref(IntPtr addr) + { + return (T)Marshal.PtrToStructure(addr, typeof(T)); + } + + public void DerefWrite(IntPtr addr, T newValue) + { + Marshal.StructureToPtr(newValue, addr, false); + } + } + #endregion +} diff --git a/src/Plugins/LevelDBStore/Options.cs b/src/Plugins/LevelDBStore/Options.cs new file mode 100644 index 0000000000..08f40de635 --- /dev/null +++ b/src/Plugins/LevelDBStore/Options.cs @@ -0,0 +1,213 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// Options.cs file belongs to the neo project and is free +// software distributed under the MIT software license, see the +// accompanying file LICENSE in the main directory of the +// repository or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +namespace LevelDB +{ + /// + /// Options to control the behavior of a database (passed to Open) + /// + /// the setter methods for InfoLogger, Env, and Cache only "safe to clean up guarantee". Do not + /// use Option object if throws. + /// + public class Options : LevelDBHandle + { + public static readonly Options Default = new Options(); + + private Logger _infoLog; + + public Options() + { + Handle = LevelDBInterop.leveldb_options_create(); + } + + /// + /// If true, the database will be created if it is missing. + /// + public bool CreateIfMissing + { + set { LevelDBInterop.leveldb_options_set_create_if_missing(Handle, value ? (byte)1 : (byte)0); } + } + + /// + /// If true, an error is raised if the database already exists. + /// + public bool ErrorIfExists + { + set { LevelDBInterop.leveldb_options_set_error_if_exists(Handle, value ? (byte)1 : (byte)0); } + } + + /// + /// If true, the implementation will do aggressive checking of the + /// data it is processing and will stop early if it detects any + /// errors. This may have unforeseen ramifications: for example, a + /// corruption of one DB entry may cause a large number of entries to + /// become unreadable or for the entire DB to become unopenable. + /// + public bool ParanoidChecks + { + set { LevelDBInterop.leveldb_options_set_paranoid_checks(Handle, value ? (byte)1 : (byte)0); } + } + + /// + /// Any internal progress/error information generated by the db will + /// be written to Logger if provided, or to a file stored + /// in the same directory as the DB contents otherwise. + /// + public Logger InfoLog + { + set + { + LevelDBInterop.leveldb_options_set_info_log(Handle, value.Handle); + _infoLog = value; + } + get => _infoLog; + } + + /// + /// Use the specified Env object to interact with the environment, + /// e.g. to read/write files, schedule background work, etc. + /// + public Env Env + { + set + { + LevelDBInterop.leveldb_options_set_env(Handle, value.Handle); + _Env = value; + } + get { return _Env; } + } + + // Any internal progress/error information generated by the db will + // be written to info_log if it is non-NULL, or to a file stored + // in the same directory as the DB contents if info_log is NULL. + + /// + /// Amount of data to build up in memory (backed by an unsorted log + /// on disk) before converting to a sorted on-disk file. + /// + /// Larger values increase performance, especially during bulk loads. + /// Up to two write buffers may be held in memory at the same time, + /// so you may wish to adjust this parameter to control memory usage. + /// Also, a larger write buffer will result in a longer recovery time + /// the next time the database is opened. + /// + /// Default: 4MB + /// + public long WriteBufferSize + { + set { LevelDBInterop.leveldb_options_set_write_buffer_size(Handle, value); } + } + + /// + /// Number of open files that can be used by the DB. You may need to + /// increase this if your database has a large working set (budget + /// one open file per 2MB of working set). + /// + /// Default: 1000 + /// + public int MaxOpenFiles + { + set { LevelDBInterop.leveldb_options_set_max_open_files(Handle, value); } + } + + /// + /// Control over blocks (user data is stored in a set of blocks, and + /// a block is the unit of reading from disk). + /// + /// If not set, leveldb will automatically create and use an 8MB internal cache. + /// + public Cache Cache + { + set + { + LevelDBInterop.leveldb_options_set_cache(Handle, value.Handle); + _Cache = value; + } + get { return _Cache; } + } + + public Comparator Comparator + { + set + { + LevelDBInterop.leveldb_options_set_comparator(Handle, value.Handle); + _Comparator = value; + } + get { return _Comparator; } + } + + /// + /// Approximate size of user data packed per block. Note that the + /// block size specified here corresponds to uncompressed data. The + /// actual size of the unit read from disk may be smaller if + /// compression is enabled. This parameter can be changed dynamically. + /// + /// Default: 4K + /// + public long BlockSize + { + set { LevelDBInterop.leveldb_options_set_block_size(Handle, value); } + } + + /// + /// Number of keys between restart points for delta encoding of keys. + /// This parameter can be changed dynamically. + /// Most clients should leave this parameter alone. + /// + /// Default: 16 + /// + public int RestartInterval + { + set { LevelDBInterop.leveldb_options_set_block_restart_interval(Handle, value); } + } + + /// + /// Compress blocks using the specified compression algorithm. + /// This parameter can be changed dynamically. + /// + /// Default: kSnappyCompression, which gives lightweight but fast compression. + /// + /// Typical speeds of kSnappyCompression on an Intel(R) Core(TM)2 2.4GHz: + /// ~200-500MB/s compression + /// ~400-800MB/s decompression + /// Note that these speeds are significantly faster than most + /// persistent storage speeds, and therefore it is typically never + /// worth switching to kNoCompression. Even if the input data is + /// incompressible, the kSnappyCompression implementation will + /// efficiently detect that and will switch to uncompressed mode. + /// + public CompressionLevel CompressionLevel + { + set { LevelDBInterop.leveldb_options_set_compression(Handle, (int)value); } + } + + public int FilterPolicy + { + set { LevelDBInterop.leveldb_options_set_filter_policy(Handle, LevelDBInterop.leveldb_filterpolicy_create_bloom(value)); } + } + + protected override void FreeUnManagedObjects() + { + if (Handle != default) + LevelDBInterop.leveldb_options_destroy(Handle); + } + + #region "managed wrappers -- must be detached upon successful DB.Create" + + public LevelDB.Env _Env { get; set; } + + public LevelDB.Cache _Cache { get; set; } + + public LevelDB.Comparator _Comparator { get; set; } + + #endregion + } +} diff --git a/src/Plugins/LevelDBStore/PinnedSafeHandle.cs b/src/Plugins/LevelDBStore/PinnedSafeHandle.cs new file mode 100644 index 0000000000..37b1429407 --- /dev/null +++ b/src/Plugins/LevelDBStore/PinnedSafeHandle.cs @@ -0,0 +1,52 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// PinnedSafeHandle.cs file belongs to the neo project and is free +// software distributed under the MIT software license, see the +// accompanying file LICENSE in the main directory of the +// repository or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +using LevelDB.NativePointer; +using System; +using System.Runtime.InteropServices; + +namespace LevelDB +{ + internal class PinnedSafeHandle : SafeHandle + where T : struct + { + private GCHandle pinnedRawData; + + public PinnedSafeHandle(T[] arr) + : base(default(IntPtr), true) + { + pinnedRawData = GCHandle.Alloc(arr, GCHandleType.Pinned); + + // initialize handle last; ensure we only free initialized GCHandles. + handle = pinnedRawData.AddrOfPinnedObject(); + } + + public Ptr Ptr + { + get { return (Ptr)handle; } + } + + public override bool IsInvalid + { + get { return handle == default(IntPtr); } + } + + protected override bool ReleaseHandle() + { + if (handle != default(IntPtr)) + { + pinnedRawData.Free(); + handle = default(IntPtr); + } + return true; + } + } +} diff --git a/src/Plugins/LevelDBStore/Plugins/Storage/LevelDBStore.cs b/src/Plugins/LevelDBStore/Plugins/Storage/LevelDBStore.cs index 9c676e8a7f..947981dfb6 100644 --- a/src/Plugins/LevelDBStore/Plugins/Storage/LevelDBStore.cs +++ b/src/Plugins/LevelDBStore/Plugins/Storage/LevelDBStore.cs @@ -9,7 +9,7 @@ // Redistribution and use in source and binary forms with or without // modifications are permitted. -using Neo.IO.Data.LevelDB; +using LevelDB; using Neo.Persistence; using System; using System.Linq; @@ -28,7 +28,7 @@ public LevelDBStore() public IStore GetStore(string path) { if (Environment.CommandLine.Split(' ').Any(p => p == "/repair" || p == "--repair")) - DB.Repair(path, Options.Default); + DB.Repair(Options.Default, path); return new Store(path); } } diff --git a/src/Plugins/LevelDBStore/Plugins/Storage/Snapshot.cs b/src/Plugins/LevelDBStore/Plugins/Storage/Snapshot.cs index 0b0a63b885..2632546274 100644 --- a/src/Plugins/LevelDBStore/Plugins/Storage/Snapshot.cs +++ b/src/Plugins/LevelDBStore/Plugins/Storage/Snapshot.cs @@ -9,61 +9,49 @@ // Redistribution and use in source and binary forms with or without // modifications are permitted. +using LevelDB; using Neo.IO.Data.LevelDB; using Neo.Persistence; using System.Collections.Generic; -using LSnapshot = Neo.IO.Data.LevelDB.Snapshot; namespace Neo.Plugins.Storage { internal class Snapshot : ISnapshot { - private readonly DB db; - private readonly LSnapshot snapshot; - private readonly ReadOptions options; - private readonly WriteBatch batch; + private readonly DB _db; + private readonly SnapShot _snapshot; + private readonly WriteBatch _batch; + private readonly ReadOptions _readOptions; public Snapshot(DB db) { - this.db = db; - snapshot = db.GetSnapshot(); - options = new ReadOptions { FillCache = false, Snapshot = snapshot }; - batch = new WriteBatch(); + _db = db; + _snapshot = db.CreateSnapshot(); + _batch = new(); + _readOptions = new ReadOptions { FillCache = false, Snapshot = _snapshot }; } - public void Commit() - { - db.Write(WriteOptions.Default, batch); - } + public void Commit() => + _db.Write(_batch); - public void Delete(byte[] key) - { - batch.Delete(key); - } + public void Delete(byte[] key) => + _batch.Delete(key); - public void Dispose() - { - snapshot.Dispose(); - } + public void Dispose() => + _snapshot.Dispose(); - public IEnumerable<(byte[] Key, byte[] Value)> Seek(byte[] prefix, SeekDirection direction = SeekDirection.Forward) - { - return db.Seek(options, prefix, direction, (k, v) => (k, v)); - } + public void Put(byte[] key, byte[] value) => + _batch.Put(key, value); - public void Put(byte[] key, byte[] value) - { - batch.Put(key, value); - } + public bool Contains(byte[] key) => + _db.Contains(key, _readOptions); - public bool Contains(byte[] key) - { - return db.Contains(options, key); - } + public byte[] TryGet(byte[] key) => + _db.Get(key, _readOptions); - public byte[] TryGet(byte[] key) - { - return db.Get(options, key); - } + public IEnumerable<(byte[] Key, byte[] Value)> Seek(byte[] prefix, SeekDirection direction = SeekDirection.Forward) => + direction == SeekDirection.Forward + ? _db.Seek(prefix, new ReadOptions { FillCache = false, }) + : _db.SeekPrev(prefix, new ReadOptions { FillCache = false, }); } } diff --git a/src/Plugins/LevelDBStore/Plugins/Storage/Store.cs b/src/Plugins/LevelDBStore/Plugins/Storage/Store.cs index 27b12a8b64..87994b9829 100644 --- a/src/Plugins/LevelDBStore/Plugins/Storage/Store.cs +++ b/src/Plugins/LevelDBStore/Plugins/Storage/Store.cs @@ -9,59 +9,66 @@ // Redistribution and use in source and binary forms with or without // modifications are permitted. +using LevelDB; using Neo.IO.Data.LevelDB; using Neo.Persistence; +using System.Collections; using System.Collections.Generic; namespace Neo.Plugins.Storage { - internal class Store : IStore + internal class Store : IStore, IEnumerable> { - private readonly DB db; + private readonly DB _db; - public Store(string path) + public Store(string dir) { - db = DB.Open(path, new Options { CreateIfMissing = true, FilterPolicy = Native.leveldb_filterpolicy_create_bloom(15) }); + _db = new(dir, new() + { + CreateIfMissing = true, + // Keep whole blockchain open plus future files + // at lease up to block index 10_000_000 + MaxOpenFiles = 4096, + FilterPolicy = 10, + CompressionLevel = CompressionLevel.SnappyCompression, + }); } - public void Delete(byte[] key) + public Store(string dir, Options options) { - db.Delete(WriteOptions.Default, key); + _db = new DB(dir, options); } - public void Dispose() - { - db.Dispose(); - } + public void Dispose() => + _db.Dispose(); - public IEnumerable<(byte[], byte[])> Seek(byte[] prefix, SeekDirection direction = SeekDirection.Forward) - { - return db.Seek(ReadOptions.Default, prefix, direction, (k, v) => (k, v)); - } + public ISnapshot GetSnapshot() => + new Snapshot(_db); - public ISnapshot GetSnapshot() - { - return new Snapshot(db); - } + public void Delete(byte[] key) => + _db.Delete(key, WriteOptions.Default); - public void Put(byte[] key, byte[] value) - { - db.Put(WriteOptions.Default, key, value); - } + public void Put(byte[] key, byte[] value) => + _db.Put(key, value, WriteOptions.Default); - public void PutSync(byte[] key, byte[] value) - { - db.Put(WriteOptions.SyncWrite, key, value); - } + public void PutSync(byte[] key, byte[] value) => + _db.Put(key, value, WriteOptions.SyncWrite); - public bool Contains(byte[] key) - { - return db.Contains(ReadOptions.Default, key); - } + public bool Contains(byte[] key) => + _db.Contains(key, ReadOptions.Default); - public byte[] TryGet(byte[] key) - { - return db.Get(ReadOptions.Default, key); - } + public byte[] TryGet(byte[] key) => + _db.Get(key, ReadOptions.Default); + + public IEnumerable<(byte[], byte[])> Seek(byte[] prefix, SeekDirection direction = SeekDirection.Forward) => + direction == SeekDirection.Forward + ? _db.Seek(prefix, ReadOptions.Default) + : _db.SeekPrev(prefix, ReadOptions.Default); + + public IEnumerator> GetEnumerator() => + _db.GetEnumerator(); + + IEnumerator IEnumerable.GetEnumerator() => + GetEnumerator(); } } diff --git a/src/Plugins/LevelDBStore/ReadOptions.cs b/src/Plugins/LevelDBStore/ReadOptions.cs new file mode 100644 index 0000000000..c5b73825db --- /dev/null +++ b/src/Plugins/LevelDBStore/ReadOptions.cs @@ -0,0 +1,62 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// ReadOptions.cs file belongs to the neo project and is free +// software distributed under the MIT software license, see the +// accompanying file LICENSE in the main directory of the +// repository or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +namespace LevelDB +{ + /// + /// Options that control read operations. + /// + public class ReadOptions : LevelDBHandle + { + public static readonly ReadOptions Default = new ReadOptions(); + + public ReadOptions() + { + Handle = LevelDBInterop.leveldb_readoptions_create(); + } + + /// + /// If true, all data read from underlying storage will be + /// verified against corresponding checksums. + /// + public bool VerifyCheckSums + { + set { LevelDBInterop.leveldb_readoptions_set_verify_checksums(Handle, value ? (byte)1 : (byte)0); } + } + + /// + /// Should the data read for this iteration be cached in memory? + /// Callers may wish to set this field to false for bulk scans. + /// Default: true + /// + public bool FillCache + { + set { LevelDBInterop.leveldb_readoptions_set_fill_cache(Handle, value ? (byte)1 : (byte)0); } + } + + /// + /// If "snapshot" is provides, read as of the supplied snapshot + /// (which must belong to the DB that is being read and which must + /// not have been released). + /// If "snapshot" is not set, use an implicit + /// snapshot of the state at the beginning of this read operation. + /// + public SnapShot Snapshot + { + set { LevelDBInterop.leveldb_readoptions_set_snapshot(Handle, value.Handle); } + } + + protected override void FreeUnManagedObjects() + { + LevelDBInterop.leveldb_readoptions_destroy(Handle); + } + } +} diff --git a/src/Plugins/LevelDBStore/Result.cs b/src/Plugins/LevelDBStore/Result.cs new file mode 100644 index 0000000000..adc38a39f3 --- /dev/null +++ b/src/Plugins/LevelDBStore/Result.cs @@ -0,0 +1,43 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// Result.cs file belongs to the neo project and is free +// software distributed under the MIT software license, see the +// accompanying file LICENSE in the main directory of the +// repository or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +namespace LevelDB +{ + //public class Result : LevelDBHandle, IEnumerable, IEnumerable + //{ + // private int length; + // public Result(IntPtr handle, int length) + // { + // this.Handle = handle; + // this.length = length; + + // BitConverter.ToInt32(null, 0); + // } + + + // public byte[] Get(byte[] key, ReadOptions options) + // { + // IntPtr error; + // int length; + // var v = LevelDBInterop.leveldb_get(this.Handle, options.Handle, key, key.Length, out length, out error); + // Throw(error); + + // if (v != IntPtr.Zero) + // { + // var bytes = new byte[length]; + // Marshal.Copy(v, bytes, 0, length); + // Marshal.FreeHGlobal(v); + // return bytes; + // } + // return null; + // } + //} +} diff --git a/src/Plugins/LevelDBStore/SnapShot.cs b/src/Plugins/LevelDBStore/SnapShot.cs new file mode 100644 index 0000000000..4cf33f689a --- /dev/null +++ b/src/Plugins/LevelDBStore/SnapShot.cs @@ -0,0 +1,46 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// SnapShot.cs file belongs to the neo project and is free +// software distributed under the MIT software license, see the +// accompanying file LICENSE in the main directory of the +// repository or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +using System; + +namespace LevelDB +{ + /// + /// A Snapshot is an immutable object and can therefore be safely + /// accessed from multiple threads without any external synchronization. + /// + public class SnapShot : LevelDBHandle + { + // pointer to parent so that we can call ReleaseSnapshot(this) when disposed + public WeakReference Parent; // as DB + + internal SnapShot(IntPtr Handle, DB parent) + { + this.Handle = Handle; + Parent = new WeakReference(parent); + } + + internal SnapShot(IntPtr Handle) + { + this.Handle = Handle; + Parent = new WeakReference(null); + } + + protected override void FreeUnManagedObjects() + { + if (Parent.IsAlive) + { + var parent = Parent.Target as DB; + if (parent != null) LevelDBInterop.leveldb_release_snapshot(parent.Handle, Handle); + } + } + } +} diff --git a/src/Plugins/LevelDBStore/WriteBatch.cs b/src/Plugins/LevelDBStore/WriteBatch.cs new file mode 100644 index 0000000000..ecd994610b --- /dev/null +++ b/src/Plugins/LevelDBStore/WriteBatch.cs @@ -0,0 +1,102 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// WriteBatch.cs file belongs to the neo project and is free +// software distributed under the MIT software license, see the +// accompanying file LICENSE in the main directory of the +// repository or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +using System; +using System.Text; + +namespace LevelDB +{ + /// + /// WriteBatch holds a collection of updates to apply atomically to a DB. + /// + /// The updates are applied in the order in which they are added + /// to the WriteBatch. For example, the value of "key" will be "v3" + /// after the following batch is written: + /// + /// batch.Put("key", "v1"); + /// batch.Delete("key"); + /// batch.Put("key", "v2"); + /// batch.Put("key", "v3"); + /// + public class WriteBatch : LevelDBHandle + { + private readonly Encoding _encoding; + + public WriteBatch() + : this(DB.DefaultEncoding) + { + } + + public WriteBatch(Encoding encoding) + { + _encoding = encoding; + Handle = LevelDBInterop.leveldb_writebatch_create(); + } + + /// + /// Clear all updates buffered in this batch. + /// + public void Clear() + { + LevelDBInterop.leveldb_writebatch_clear(Handle); + } + + /// + /// Store the mapping "key->value" in the database. + /// + public WriteBatch Put(string key, string value) + { + return Put(_encoding.GetBytes(key), _encoding.GetBytes(value)); + } + + /// + /// Store the mapping "key->value" in the database. + /// + public WriteBatch Put(byte[] key, byte[] value) + { + LevelDBInterop.leveldb_writebatch_put(Handle, key, key.Length, value, value.Length); + return this; + } + + /// + /// If the database contains a mapping for "key", erase it. + /// Else do nothing. + /// + public WriteBatch Delete(string key) + { + return Delete(_encoding.GetBytes(key)); + } + + /// + /// If the database contains a mapping for "key", erase it. + /// Else do nothing. + /// + public WriteBatch Delete(byte[] key) + { + LevelDBInterop.leveldb_writebatch_delete(Handle, key, key.Length); + return this; + } + + /// + /// Support for iterating over a batch. + /// + public void Iterate(object state, Action put, Action deleted) + { + LevelDBInterop.leveldb_writebatch_iterate(Handle, state, put, deleted); + } + + protected override void FreeUnManagedObjects() + { + LevelDBInterop.leveldb_writebatch_destroy(Handle); + } + + } +} diff --git a/src/Plugins/LevelDBStore/WriteOptions.cs b/src/Plugins/LevelDBStore/WriteOptions.cs new file mode 100644 index 0000000000..b6542a0b65 --- /dev/null +++ b/src/Plugins/LevelDBStore/WriteOptions.cs @@ -0,0 +1,53 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// WriteOptions.cs file belongs to the neo project and is free +// software distributed under the MIT software license, see the +// accompanying file LICENSE in the main directory of the +// repository or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +namespace LevelDB +{ + /// + /// Options that control write operations. + /// + public class WriteOptions : LevelDBHandle + { + public static readonly WriteOptions Default = new WriteOptions(); + public static readonly WriteOptions SyncWrite = new WriteOptions { Sync = true }; + + public WriteOptions() + { + Handle = LevelDBInterop.leveldb_writeoptions_create(); + } + + /// + /// If true, the write will be flushed from the operating system + /// buffer cache (by calling WritableFile::Sync()) before the write + /// is considered complete. If this flag is true, writes will be + /// slower. + /// + /// If this flag is false, and the machine crashes, some recent + /// writes may be lost. Note that if it is just the process that + /// crashes (i.e., the machine does not reboot), no writes will be + /// lost even if sync==false. + /// + /// In other words, a DB write with sync==false has similar + /// crash semantics as the "write()" system call. A DB write + /// with sync==true has similar crash semantics to a "write()" + /// system call followed by "fsync()". + /// + public bool Sync + { + set { LevelDBInterop.leveldb_writeoptions_set_sync(Handle, value ? (byte)1 : (byte)0); } + } + + protected override void FreeUnManagedObjects() + { + LevelDBInterop.leveldb_writeoptions_destroy(Handle); + } + } +} From edd727035c2ffa53243468678d6623af76235d3b Mon Sep 17 00:00:00 2001 From: Jimmy Date: Sun, 26 May 2024 19:17:13 +0800 Subject: [PATCH 2/6] Update src/Plugins/LevelDBStore/SnapShot.cs Co-authored-by: Shargon --- src/Plugins/LevelDBStore/SnapShot.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Plugins/LevelDBStore/SnapShot.cs b/src/Plugins/LevelDBStore/SnapShot.cs index 4cf33f689a..61e3986ae6 100644 --- a/src/Plugins/LevelDBStore/SnapShot.cs +++ b/src/Plugins/LevelDBStore/SnapShot.cs @@ -22,9 +22,9 @@ public class SnapShot : LevelDBHandle // pointer to parent so that we can call ReleaseSnapshot(this) when disposed public WeakReference Parent; // as DB - internal SnapShot(IntPtr Handle, DB parent) + internal SnapShot(IntPtr handle, DB parent) { - this.Handle = Handle; + this.Handle = handle; Parent = new WeakReference(parent); } From fd6e8ae8e9d78bbe866305335aebd2dd1337c7e3 Mon Sep 17 00:00:00 2001 From: Jimmy Date: Sun, 26 May 2024 19:17:48 +0800 Subject: [PATCH 3/6] Update src/Plugins/LevelDBStore/SnapShot.cs Co-authored-by: Shargon --- src/Plugins/LevelDBStore/SnapShot.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Plugins/LevelDBStore/SnapShot.cs b/src/Plugins/LevelDBStore/SnapShot.cs index 61e3986ae6..a3c8243b10 100644 --- a/src/Plugins/LevelDBStore/SnapShot.cs +++ b/src/Plugins/LevelDBStore/SnapShot.cs @@ -28,9 +28,9 @@ internal SnapShot(IntPtr handle, DB parent) Parent = new WeakReference(parent); } - internal SnapShot(IntPtr Handle) + internal SnapShot(IntPtr handle) { - this.Handle = Handle; + this.Handle = handle; Parent = new WeakReference(null); } From fe29eda2c50d92b42818da94a6b352f3c005577c Mon Sep 17 00:00:00 2001 From: Christopher Schuchardt Date: Sun, 26 May 2024 07:19:06 -0400 Subject: [PATCH 4/6] @shargon changed added --- src/Plugins/LevelDBStore/Comparator.cs | 42 ++++++++++------------ src/Plugins/LevelDBStore/DB.cs | 6 ++-- src/Plugins/LevelDBStore/Iterator.cs | 21 +++++------ src/Plugins/LevelDBStore/NativePointer.cs | 4 +-- src/Plugins/LevelDBStore/Result.cs | 43 ----------------------- src/Plugins/LevelDBStore/SnapShot.cs | 19 +++++----- 6 files changed, 40 insertions(+), 95 deletions(-) delete mode 100644 src/Plugins/LevelDBStore/Result.cs diff --git a/src/Plugins/LevelDBStore/Comparator.cs b/src/Plugins/LevelDBStore/Comparator.cs index d87fbafa50..d03fb550db 100644 --- a/src/Plugins/LevelDBStore/Comparator.cs +++ b/src/Plugins/LevelDBStore/Comparator.cs @@ -33,33 +33,27 @@ private delegate int Compare(IntPtr gCHandleThisg, private delegate IntPtr Name(IntPtr gCHandleThis); - private static readonly Destructor s_destructor - = (gCHandleThis) => - { - var h = GCHandle.FromIntPtr(gCHandleThis); - var @this = h.Target as Inner; - - @this.Dispose(); + private static readonly Destructor s_destructor = (gCHandleThis) => + { + var h = GCHandle.FromIntPtr(gCHandleThis); + var @this = h.Target as Inner; - // TODO: At the point 'Free' is entered, this delegate may become eligible to be GC'd. - // TODO: Need to look whether GC might run between then, and when this delegate returns. - h.Free(); - }; + @this.Dispose(); + h.Free(); + }; - private static readonly Compare s_compare = - (gCHandleThis, data1, size1, data2, size2) => - { - var @this = GCHandle.FromIntPtr(gCHandleThis).Target as Inner; - return @this._cmp(new NativeArray { _baseAddr = data1, _byteLength = size1 }, - new NativeArray { _baseAddr = data2, _byteLength = size2 }); - }; + private static readonly Compare s_compare = (gCHandleThis, data1, size1, data2, size2) => + { + var @this = GCHandle.FromIntPtr(gCHandleThis).Target as Inner; + return @this._cmp(new NativeArray { _baseAddr = data1, _byteLength = size1 }, + new NativeArray { _baseAddr = data2, _byteLength = size2 }); + }; - private static readonly Name s_nameAccessor = - (gCHandleThis) => - { - var @this = GCHandle.FromIntPtr(gCHandleThis).Target as Inner; - return @this.NameValue; - }; + private static readonly Name s_nameAccessor = (gCHandleThis) => + { + var @this = GCHandle.FromIntPtr(gCHandleThis).Target as Inner; + return @this.NameValue; + }; private Func _cmp; private GCHandle _namePinned; diff --git a/src/Plugins/LevelDBStore/DB.cs b/src/Plugins/LevelDBStore/DB.cs index 193f267d87..6379d091c6 100644 --- a/src/Plugins/LevelDBStore/DB.cs +++ b/src/Plugins/LevelDBStore/DB.cs @@ -127,7 +127,7 @@ public void Put(int key, int[] value) /// public void Put(int key, int[] value, WriteOptions options) { - LevelDBInterop.leveldb_put(Handle, options.Handle, ref key, (IntPtr)sizeof(int), value, checked((IntPtr)(value.LongLength * 4)), out var error); + LevelDBInterop.leveldb_put(Handle, options.Handle, ref key, sizeof(int), value, checked((IntPtr)(value.LongLength * 4)), out var error); Throw(error); } @@ -268,7 +268,7 @@ public int[] Get(int key, ReadOptions options) { IntPtr v; - v = LevelDBInterop.leveldb_get(Handle, options.Handle, ref key, (IntPtr)sizeof(int), out var length, out var error); + v = LevelDBInterop.leveldb_get(Handle, options.Handle, ref key, sizeof(int), out var length, out var error); Throw(error); if (v != IntPtr.Zero) @@ -304,7 +304,7 @@ public int[] Get(int key, ReadOptions options) public bool Contains(byte[] key, ReadOptions options) { - var value = LevelDBInterop.leveldb_get(Handle, options.Handle, key, (IntPtr)key.Length, out _, out var error); + var value = LevelDBInterop.leveldb_get(Handle, options.Handle, key, key.Length, out _, out var error); Throw(error); if (value != IntPtr.Zero) diff --git a/src/Plugins/LevelDBStore/Iterator.cs b/src/Plugins/LevelDBStore/Iterator.cs index 961a369fa8..dfb3ac39d9 100644 --- a/src/Plugins/LevelDBStore/Iterator.cs +++ b/src/Plugins/LevelDBStore/Iterator.cs @@ -21,10 +21,10 @@ public class Iterator : LevelDBHandle { private readonly Encoding _encoding; - internal Iterator(IntPtr Handle, Encoding encoding) + internal Iterator(IntPtr handle, Encoding encoding) { _encoding = encoding; - this.Handle = Handle; + Handle = handle; } /// @@ -34,7 +34,7 @@ internal Iterator(IntPtr Handle, Encoding encoding) /// This method returns true iff the iterator is valid. public bool IsValid() { - return (int)LevelDBInterop.leveldb_iter_valid(Handle) != 0; + return LevelDBInterop.leveldb_iter_valid(Handle) != 0; } /// @@ -118,8 +118,7 @@ public void Prev() /// public int KeyAsInt() { - int length; - var key = LevelDBInterop.leveldb_iter_key(Handle, out length); + var key = LevelDBInterop.leveldb_iter_key(Handle, out var length); Throw(); if (length != 4) throw new Exception("Key is not an integer"); @@ -142,8 +141,7 @@ public string KeyAsString() /// public byte[] Key() { - int length; - var key = LevelDBInterop.leveldb_iter_key(Handle, out length); + var key = LevelDBInterop.leveldb_iter_key(Handle, out var length); Throw(); var bytes = new byte[length]; @@ -157,8 +155,7 @@ public byte[] Key() /// public int[] ValueAsInts() { - int length; - var value = LevelDBInterop.leveldb_iter_value(Handle, out length); + var value = LevelDBInterop.leveldb_iter_value(Handle, out var length); Throw(); var bytes = new int[length / 4]; @@ -181,8 +178,7 @@ public string ValueAsString() /// public byte[] Value() { - int length; - var value = LevelDBInterop.leveldb_iter_value(Handle, out length); + var value = LevelDBInterop.leveldb_iter_value(Handle, out var length); Throw(); var bytes = new byte[length]; @@ -203,8 +199,7 @@ void Throw() /// void Throw(Func exception) { - IntPtr error; - LevelDBInterop.leveldb_iter_get_error(Handle, out error); + LevelDBInterop.leveldb_iter_get_error(Handle, out var error); if (error != IntPtr.Zero) throw exception(Marshal.PtrToStringAnsi(error)); } diff --git a/src/Plugins/LevelDBStore/NativePointer.cs b/src/Plugins/LevelDBStore/NativePointer.cs index dd70e48874..880459c0a8 100644 --- a/src/Plugins/LevelDBStore/NativePointer.cs +++ b/src/Plugins/LevelDBStore/NativePointer.cs @@ -55,8 +55,8 @@ public static Ptr Cast(Ptr p) return new Ptr(p._addr); } - public void Inc() { Advance((IntPtr)1); } - public void Dec() { Advance((IntPtr)(-1)); } + public void Inc() { Advance(1); } + public void Dec() { Advance(-1); } public void Advance(IntPtr d) { diff --git a/src/Plugins/LevelDBStore/Result.cs b/src/Plugins/LevelDBStore/Result.cs deleted file mode 100644 index adc38a39f3..0000000000 --- a/src/Plugins/LevelDBStore/Result.cs +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright (C) 2015-2024 The Neo Project. -// -// Result.cs file belongs to the neo project and is free -// software distributed under the MIT software license, see the -// accompanying file LICENSE in the main directory of the -// repository or http://www.opensource.org/licenses/mit-license.php -// for more details. -// -// Redistribution and use in source and binary forms with or without -// modifications are permitted. - -namespace LevelDB -{ - //public class Result : LevelDBHandle, IEnumerable, IEnumerable - //{ - // private int length; - // public Result(IntPtr handle, int length) - // { - // this.Handle = handle; - // this.length = length; - - // BitConverter.ToInt32(null, 0); - // } - - - // public byte[] Get(byte[] key, ReadOptions options) - // { - // IntPtr error; - // int length; - // var v = LevelDBInterop.leveldb_get(this.Handle, options.Handle, key, key.Length, out length, out error); - // Throw(error); - - // if (v != IntPtr.Zero) - // { - // var bytes = new byte[length]; - // Marshal.Copy(v, bytes, 0, length); - // Marshal.FreeHGlobal(v); - // return bytes; - // } - // return null; - // } - //} -} diff --git a/src/Plugins/LevelDBStore/SnapShot.cs b/src/Plugins/LevelDBStore/SnapShot.cs index 4cf33f689a..14af56cf9f 100644 --- a/src/Plugins/LevelDBStore/SnapShot.cs +++ b/src/Plugins/LevelDBStore/SnapShot.cs @@ -20,26 +20,25 @@ namespace LevelDB public class SnapShot : LevelDBHandle { // pointer to parent so that we can call ReleaseSnapshot(this) when disposed - public WeakReference Parent; // as DB + public WeakReference _parent; // as DB - internal SnapShot(IntPtr Handle, DB parent) + internal SnapShot(IntPtr handle, DB parent) { - this.Handle = Handle; - Parent = new WeakReference(parent); + Handle = handle; + _parent = new WeakReference(parent); } - internal SnapShot(IntPtr Handle) + internal SnapShot(IntPtr handle) { - this.Handle = Handle; - Parent = new WeakReference(null); + Handle = handle; + _parent = new WeakReference(null); } protected override void FreeUnManagedObjects() { - if (Parent.IsAlive) + if (_parent.IsAlive) { - var parent = Parent.Target as DB; - if (parent != null) LevelDBInterop.leveldb_release_snapshot(parent.Handle, Handle); + if (_parent.Target is DB parent) LevelDBInterop.leveldb_release_snapshot(parent.Handle, Handle); } } } From f19a52a7de9cd347f405c377aeed1e49a6df33f2 Mon Sep 17 00:00:00 2001 From: Christopher Schuchardt Date: Sat, 1 Jun 2024 13:46:51 -0400 Subject: [PATCH 5/6] Removed `Logger` class unused and requires custom `leveldb` dll. --- src/Plugins/LevelDBStore/DB.cs | 8 ++---- src/Plugins/LevelDBStore/Logger.cs | 39 ----------------------------- src/Plugins/LevelDBStore/Options.cs | 17 ------------- 3 files changed, 2 insertions(+), 62 deletions(-) delete mode 100644 src/Plugins/LevelDBStore/Logger.cs diff --git a/src/Plugins/LevelDBStore/DB.cs b/src/Plugins/LevelDBStore/DB.cs index 6379d091c6..358440b743 100644 --- a/src/Plugins/LevelDBStore/DB.cs +++ b/src/Plugins/LevelDBStore/DB.cs @@ -28,7 +28,6 @@ public class DB : LevelDBHandle, IEnumerable>, IEnu public readonly static Encoding DefaultEncoding = s_uTF8; private readonly Cache _cache; - private readonly Logger _infoLog; private readonly Comparator _comparator; private readonly Encoding _encoding; @@ -64,7 +63,6 @@ public DB(string name, Options options) public DB(string name, Encoding encoding, Options options) { _cache = options.Cache; - _infoLog = options.InfoLog; _comparator = options.Comparator; Handle = LevelDBInterop.leveldb_open(options.Handle, name, out var error); _encoding = encoding; @@ -381,8 +379,8 @@ public SnapShot CreateSnapshot() /// /// Valid property names include: /// - /// "leveldb.num-files-at-level" - return the number of files at level , - /// where is an ASCII representation of a level number (e.g. "0"). + /// "leveldb.num-files-at-level" - return the number of files at level , + /// where is an ASCII representation of a level number (e.g. "0"). /// "leveldb.stats" - returns a multi-line string that describes statistics /// about the internal operation of the DB. /// @@ -436,8 +434,6 @@ protected override void FreeUnManagedObjects() _cache?.Dispose(); _comparator?.Dispose(); - - _infoLog?.Dispose(); } IEnumerator IEnumerable.GetEnumerator() diff --git a/src/Plugins/LevelDBStore/Logger.cs b/src/Plugins/LevelDBStore/Logger.cs deleted file mode 100644 index 20a0a435a6..0000000000 --- a/src/Plugins/LevelDBStore/Logger.cs +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright (C) 2015-2024 The Neo Project. -// -// Logger.cs file belongs to the neo project and is free -// software distributed under the MIT software license, see the -// accompanying file LICENSE in the main directory of the -// repository or http://www.opensource.org/licenses/mit-license.php -// for more details. -// -// Redistribution and use in source and binary forms with or without -// modifications are permitted. - -using System; -using System.Runtime.InteropServices; - -namespace LevelDB -{ - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate void Log(string msg); - - public class Logger : LevelDBHandle - { - public Logger(Log log) - { - var p = Marshal.GetFunctionPointerForDelegate(log); - Handle = LevelDBInterop.leveldb_logger_create(p); - } - - public static implicit operator Logger(Log log) - { - return new Logger(log); - } - - protected override void FreeUnManagedObjects() - { - if (Handle != default(IntPtr)) - LevelDBInterop.leveldb_logger_destroy(Handle); - } - } -} diff --git a/src/Plugins/LevelDBStore/Options.cs b/src/Plugins/LevelDBStore/Options.cs index 08f40de635..2cb24ee421 100644 --- a/src/Plugins/LevelDBStore/Options.cs +++ b/src/Plugins/LevelDBStore/Options.cs @@ -21,8 +21,6 @@ public class Options : LevelDBHandle { public static readonly Options Default = new Options(); - private Logger _infoLog; - public Options() { Handle = LevelDBInterop.leveldb_options_create(); @@ -56,21 +54,6 @@ public bool ParanoidChecks set { LevelDBInterop.leveldb_options_set_paranoid_checks(Handle, value ? (byte)1 : (byte)0); } } - /// - /// Any internal progress/error information generated by the db will - /// be written to Logger if provided, or to a file stored - /// in the same directory as the DB contents otherwise. - /// - public Logger InfoLog - { - set - { - LevelDBInterop.leveldb_options_set_info_log(Handle, value.Handle); - _infoLog = value; - } - get => _infoLog; - } - /// /// Use the specified Env object to interact with the environment, /// e.g. to read/write files, schedule background work, etc. From 784a02a5f29d1e20343c275505a98983542c4b36 Mon Sep 17 00:00:00 2001 From: Christopher Schuchardt Date: Mon, 24 Jun 2024 01:55:51 -0400 Subject: [PATCH 6/6] Changed Import to `leveldb` the proper name for support in MacOS --- src/Plugins/LevelDBStore/LevelDBInterop.cs | 132 ++++++++++----------- 1 file changed, 66 insertions(+), 66 deletions(-) diff --git a/src/Plugins/LevelDBStore/LevelDBInterop.cs b/src/Plugins/LevelDBStore/LevelDBInterop.cs index f98f489e19..472f174dbe 100644 --- a/src/Plugins/LevelDBStore/LevelDBInterop.cs +++ b/src/Plugins/LevelDBStore/LevelDBInterop.cs @@ -17,65 +17,65 @@ namespace LevelDB public static class LevelDBInterop { #region Logger - [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + [DllImport("leveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] public static extern IntPtr leveldb_logger_create(IntPtr /* Action */ logger); - [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + [DllImport("leveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] public static extern void leveldb_logger_destroy(IntPtr /* logger*/ option); #endregion #region DB - [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + [DllImport("leveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] public static extern IntPtr leveldb_open(IntPtr /* Options*/ options, string name, out IntPtr error); - [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + [DllImport("leveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] public static extern void leveldb_close(IntPtr /*DB */ db); - [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + [DllImport("leveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] public static extern void leveldb_put(IntPtr /* DB */ db, IntPtr /* WriteOptions*/ options, byte[] key, IntPtr keylen, byte[] val, IntPtr vallen, out IntPtr errptr); - [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + [DllImport("leveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] public static extern void leveldb_put(IntPtr /* DB */ db, IntPtr /* WriteOptions*/ options, ref int key, IntPtr keylen, int[] val, IntPtr vallen, out IntPtr errptr); - [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + [DllImport("leveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] public static extern void leveldb_delete(IntPtr /* DB */ db, IntPtr /* WriteOptions*/ options, byte[] key, IntPtr keylen, out IntPtr errptr); - [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + [DllImport("leveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] public static extern void leveldb_write(IntPtr /* DB */ db, IntPtr /* WriteOptions*/ options, IntPtr /* WriteBatch */ batch, out IntPtr errptr); - [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + [DllImport("leveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] public static extern IntPtr leveldb_get(IntPtr /* DB */ db, IntPtr /* ReadOptions*/ options, byte[] key, IntPtr keylen, out IntPtr vallen, out IntPtr errptr); - [DllImport("libleveldb", CallingConvention = CallingConvention.Cdecl)] + [DllImport("leveldb", CallingConvention = CallingConvention.Cdecl)] public static extern IntPtr leveldb_get(IntPtr /* DB */ db, IntPtr /* ReadOptions*/ options, ref int key, IntPtr keylen, out IntPtr vallen, out IntPtr errptr); - [DllImport("libleveldb", CallingConvention = CallingConvention.Cdecl)] + [DllImport("leveldb", CallingConvention = CallingConvention.Cdecl)] public static extern IntPtr leveldb_get(IntPtr /* DB */ db, IntPtr /* ReadOptions*/ options, IntPtr key, IntPtr keylen, out IntPtr vallen, out IntPtr errptr); - //[DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + //[DllImport("leveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] //static extern void leveldb_approximate_sizes(IntPtr /* DB */ db, int num_ranges, byte[] range_start_key, long range_start_key_len, byte[] range_limit_key, long range_limit_key_len, out long sizes); - [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + [DllImport("leveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] public static extern IntPtr leveldb_create_iterator(IntPtr /* DB */ db, IntPtr /* ReadOption */ options); - [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + [DllImport("leveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] public static extern IntPtr leveldb_create_snapshot(IntPtr /* DB */ db); - [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + [DllImport("leveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] public static extern void leveldb_release_snapshot(IntPtr /* DB */ db, IntPtr /* SnapShot*/ snapshot); - [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + [DllImport("leveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] public static extern IntPtr leveldb_property_value(IntPtr /* DB */ db, string propname); - [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + [DllImport("leveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] public static extern void leveldb_repair_db(IntPtr /* Options*/ options, string name, out IntPtr error); - [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + [DllImport("leveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] public static extern void leveldb_destroy_db(IntPtr /* Options*/ options, string name, out IntPtr error); #region extensions - [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + [DllImport("leveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] public static extern void leveldb_free(IntPtr /* void */ ptr); #endregion @@ -84,156 +84,156 @@ public static class LevelDBInterop #endregion #region Env - [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + [DllImport("leveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] public static extern IntPtr leveldb_create_default_env(); - [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + [DllImport("leveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] public static extern void leveldb_env_destroy(IntPtr /*Env*/ cache); #endregion #region Iterator - [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + [DllImport("leveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] public static extern void leveldb_iter_destroy(IntPtr /*Iterator*/ iterator); - [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + [DllImport("leveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] public static extern byte leveldb_iter_valid(IntPtr /*Iterator*/ iterator); - [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + [DllImport("leveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] public static extern void leveldb_iter_seek_to_first(IntPtr /*Iterator*/ iterator); - [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + [DllImport("leveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] public static extern void leveldb_iter_seek_to_last(IntPtr /*Iterator*/ iterator); - [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + [DllImport("leveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] public static extern void leveldb_iter_seek(IntPtr /*Iterator*/ iterator, byte[] key, int length); - [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + [DllImport("leveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] public static extern void leveldb_iter_seek(IntPtr /*Iterator*/ iterator, ref int key, int length); - [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + [DllImport("leveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] public static extern void leveldb_iter_next(IntPtr /*Iterator*/ iterator); - [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + [DllImport("leveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] public static extern void leveldb_iter_prev(IntPtr /*Iterator*/ iterator); - [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + [DllImport("leveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] public static extern IntPtr leveldb_iter_key(IntPtr /*Iterator*/ iterator, out int length); - [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + [DllImport("leveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] public static extern IntPtr leveldb_iter_value(IntPtr /*Iterator*/ iterator, out int length); - [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + [DllImport("leveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] public static extern void leveldb_iter_get_error(IntPtr /*Iterator*/ iterator, out IntPtr error); #endregion #region Options - [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + [DllImport("leveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] public static extern IntPtr leveldb_options_create(); - [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + [DllImport("leveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] public static extern void leveldb_options_destroy(IntPtr /*Options*/ options); - [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + [DllImport("leveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] public static extern void leveldb_options_set_create_if_missing(IntPtr /*Options*/ options, byte o); - [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + [DllImport("leveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] public static extern void leveldb_options_set_error_if_exists(IntPtr /*Options*/ options, byte o); - [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + [DllImport("leveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] public static extern void leveldb_options_set_info_log(IntPtr /*Options*/ options, IntPtr /* Logger */ logger); - [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + [DllImport("leveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] public static extern void leveldb_options_set_paranoid_checks(IntPtr /*Options*/ options, byte o); - [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + [DllImport("leveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] public static extern void leveldb_options_set_env(IntPtr /*Options*/ options, IntPtr /*Env*/ env); - [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + [DllImport("leveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] public static extern void leveldb_options_set_write_buffer_size(IntPtr /*Options*/ options, long size); - [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + [DllImport("leveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] public static extern void leveldb_options_set_max_open_files(IntPtr /*Options*/ options, int max); - [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + [DllImport("leveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] public static extern void leveldb_options_set_cache(IntPtr /*Options*/ options, IntPtr /*Cache*/ cache); - [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + [DllImport("leveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] public static extern void leveldb_options_set_block_size(IntPtr /*Options*/ options, long size); - [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + [DllImport("leveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] public static extern void leveldb_options_set_block_restart_interval(IntPtr /*Options*/ options, int interval); - [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + [DllImport("leveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] public static extern void leveldb_options_set_compression(IntPtr /*Options*/ options, int level); - [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + [DllImport("leveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] public static extern void leveldb_options_set_filter_policy(IntPtr /*Options*/ options, IntPtr /*FilterPolicy*/ policy); - [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + [DllImport("leveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] public static extern void leveldb_options_set_comparator(IntPtr /*Options*/ options, IntPtr /*Comparator*/ comparer); - [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + [DllImport("leveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] public static extern IntPtr leveldb_filterpolicy_create_bloom(int bits_per_key); #endregion #region ReadOptions - [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + [DllImport("leveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] public static extern IntPtr leveldb_readoptions_create(); - [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + [DllImport("leveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] public static extern void leveldb_readoptions_destroy(IntPtr /*ReadOptions*/ options); - [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + [DllImport("leveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] public static extern void leveldb_readoptions_set_verify_checksums(IntPtr /*ReadOptions*/ options, byte o); - [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + [DllImport("leveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] public static extern void leveldb_readoptions_set_fill_cache(IntPtr /*ReadOptions*/ options, byte o); - [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + [DllImport("leveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] public static extern void leveldb_readoptions_set_snapshot(IntPtr /*ReadOptions*/ options, IntPtr /*SnapShot*/ snapshot); #endregion #region WriteBatch - [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + [DllImport("leveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] public static extern IntPtr leveldb_writebatch_create(); - [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + [DllImport("leveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] public static extern void leveldb_writebatch_destroy(IntPtr /* WriteBatch */ batch); - [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + [DllImport("leveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] public static extern void leveldb_writebatch_clear(IntPtr /* WriteBatch */ batch); - [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + [DllImport("leveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] public static extern void leveldb_writebatch_put(IntPtr /* WriteBatch */ batch, byte[] key, int keylen, byte[] val, int vallen); - [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + [DllImport("leveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] public static extern void leveldb_writebatch_delete(IntPtr /* WriteBatch */ batch, byte[] key, int keylen); - [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + [DllImport("leveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] public static extern void leveldb_writebatch_iterate(IntPtr /* WriteBatch */ batch, object state, Action put, Action deleted); #endregion #region WriteOptions - [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + [DllImport("leveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] public static extern IntPtr leveldb_writeoptions_create(); - [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + [DllImport("leveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] public static extern void leveldb_writeoptions_destroy(IntPtr /*WriteOptions*/ options); - [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + [DllImport("leveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] public static extern void leveldb_writeoptions_set_sync(IntPtr /*WriteOptions*/ options, byte o); #endregion #region Cache - [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + [DllImport("leveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] public static extern IntPtr leveldb_cache_create_lru(int capacity); - [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + [DllImport("leveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] public static extern void leveldb_cache_destroy(IntPtr /*Cache*/ cache); #endregion #region Comparator - [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + [DllImport("leveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] public static extern IntPtr /* leveldb_comparator_t* */ leveldb_comparator_create( IntPtr /* void* */ state, @@ -245,7 +245,7 @@ public static extern IntPtr /* leveldb_comparator_t* */ compare, IntPtr /* const char* (*)(void*) */ name); - [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + [DllImport("leveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] public static extern void leveldb_comparator_destroy(IntPtr /* leveldb_comparator_t* */ cmp); #endregion