From 19e11a58664e44b7210485e651f37d864a0cd339 Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Tue, 21 Jan 2025 09:40:13 +0100 Subject: [PATCH 1/5] Nullable leveldb --- src/Neo/Persistence/IReadOnlyStore.cs | 7 ++++-- .../LevelDBStore/IO/Data/LevelDB/DB.cs | 6 ++--- .../LevelDBStore/IO/Data/LevelDB/Helper.cs | 10 ++++---- .../LevelDBStore/IO/Data/LevelDB/Iterator.cs | 4 ++-- .../LevelDBStore/IO/Data/LevelDB/Native.cs | 23 +++++++++++++++---- src/Plugins/LevelDBStore/LevelDBStore.csproj | 1 + .../LevelDBStore/Plugins/Storage/Snapshot.cs | 9 ++++---- .../LevelDBStore/Plugins/Storage/Store.cs | 7 +++--- 8 files changed, 44 insertions(+), 23 deletions(-) diff --git a/src/Neo/Persistence/IReadOnlyStore.cs b/src/Neo/Persistence/IReadOnlyStore.cs index 134b5b3ade..9432301730 100644 --- a/src/Neo/Persistence/IReadOnlyStore.cs +++ b/src/Neo/Persistence/IReadOnlyStore.cs @@ -9,8 +9,11 @@ // Redistribution and use in source and binary forms with or without // modifications are permitted. +#nullable enable + using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; namespace Neo.Persistence { @@ -33,7 +36,7 @@ public interface IReadOnlyStore /// The key of the entry. /// The data of the entry. Or if it doesn't exist. [Obsolete("use TryGet(byte[] key, [NotNullWhen(true)] out byte[]? value) instead.")] - byte[] TryGet(byte[] key); + byte[]? TryGet(byte[] key); /// /// Reads a specified entry from the database. @@ -41,7 +44,7 @@ public interface IReadOnlyStore /// The key of the entry. /// The data of the entry. /// if the entry exists; otherwise, . - bool TryGet(byte[] key, out byte[] value); + bool TryGet(byte[] key, [NotNullWhen(true)] out byte[]? value); /// /// Determines whether the database contains the specified entry. diff --git a/src/Plugins/LevelDBStore/IO/Data/LevelDB/DB.cs b/src/Plugins/LevelDBStore/IO/Data/LevelDB/DB.cs index 56dfa86431..c1d7a400fb 100644 --- a/src/Plugins/LevelDBStore/IO/Data/LevelDB/DB.cs +++ b/src/Plugins/LevelDBStore/IO/Data/LevelDB/DB.cs @@ -9,8 +9,6 @@ // Redistribution and use in source and binary forms with or without // modifications are permitted. -#nullable enable - using System.Collections; using System.Collections.Generic; using System.IO; @@ -49,7 +47,7 @@ public void Delete(WriteOptions options, byte[] key) /// If the database contains an entry for "key" return the value, /// otherwise return null. /// - public byte[] Get(ReadOptions options, byte[] key) + public byte[]? Get(ReadOptions options, byte[] key) { var value = Native.leveldb_get(Handle, options.Handle, key, (nuint)key.Length, out var length, out var error); try @@ -131,7 +129,7 @@ public IEnumerator> GetEnumerator() { using var iterator = CreateIterator(ReadOptions.Default); for (iterator.SeekToFirst(); iterator.Valid(); iterator.Next()) - yield return new KeyValuePair(iterator.Key(), iterator.Value()); + yield return new KeyValuePair(iterator.Key()!, iterator.Value()!); } IEnumerator IEnumerable.GetEnumerator() => diff --git a/src/Plugins/LevelDBStore/IO/Data/LevelDB/Helper.cs b/src/Plugins/LevelDBStore/IO/Data/LevelDB/Helper.cs index ff15c44377..e38c70e2ea 100644 --- a/src/Plugins/LevelDBStore/IO/Data/LevelDB/Helper.cs +++ b/src/Plugins/LevelDBStore/IO/Data/LevelDB/Helper.cs @@ -18,9 +18,11 @@ namespace Neo.IO.Storage.LevelDB { public static class Helper { - public static IEnumerable<(byte[], byte[])> Seek(this DB db, ReadOptions options, byte[] keyOrPrefix, SeekDirection direction) + public static IEnumerable<(byte[], byte[])> Seek(this DB db, ReadOptions options, byte[]? keyOrPrefix, SeekDirection direction) { - using Iterator it = db.CreateIterator(options); + keyOrPrefix ??= []; + + using var it = db.CreateIterator(options); if (direction == SeekDirection.Forward) { for (it.Seek(keyOrPrefix); it.Valid(); it.Next()) @@ -40,10 +42,10 @@ public static class Helper } } - internal static byte[] ToByteArray(this IntPtr data, UIntPtr length) + internal static byte[]? ToByteArray(this IntPtr data, UIntPtr length) { if (data == IntPtr.Zero) return null; - byte[] buffer = new byte[(int)length]; + var 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 index 0d4ccaa571..1456669aa0 100644 --- a/src/Plugins/LevelDBStore/IO/Data/LevelDB/Iterator.cs +++ b/src/Plugins/LevelDBStore/IO/Data/LevelDB/Iterator.cs @@ -36,7 +36,7 @@ protected override void FreeUnManagedObjects() /// Return the key for the current entry. /// REQUIRES: Valid() /// - public byte[] Key() + public byte[]? Key() { var key = Native.leveldb_iter_key(Handle, out var length); CheckError(); @@ -89,7 +89,7 @@ public bool Valid() return Native.leveldb_iter_valid(Handle); } - public byte[] Value() + public byte[]? Value() { var value = Native.leveldb_iter_value(Handle, out var length); CheckError(); diff --git a/src/Plugins/LevelDBStore/IO/Data/LevelDB/Native.cs b/src/Plugins/LevelDBStore/IO/Data/LevelDB/Native.cs index f489e50a60..63668975bf 100644 --- a/src/Plugins/LevelDBStore/IO/Data/LevelDB/Native.cs +++ b/src/Plugins/LevelDBStore/IO/Data/LevelDB/Native.cs @@ -24,14 +24,17 @@ public enum CompressionType : byte public static class Native { #region Logger + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] public static extern nint leveldb_logger_create(nint /* Action */ logger); [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] public static extern void leveldb_logger_destroy(nint /* logger*/ option); + #endregion #region DB + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] public static extern nint leveldb_open(nint /* Options*/ options, string name, out nint error); @@ -77,19 +80,20 @@ public static class Native public static extern void leveldb_free(nint /* void */ ptr); #endregion - - #endregion #region Env + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] public static extern nint leveldb_create_default_env(); [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] public static extern void leveldb_env_destroy(nint /*Env*/ cache); + #endregion #region Iterator + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] public static extern void leveldb_iter_destroy(nint /*Iterator*/ iterator); @@ -120,9 +124,11 @@ public static class Native [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] public static extern void leveldb_iter_get_error(nint /*Iterator*/ iterator, out nint error); + #endregion #region Options + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] public static extern nint leveldb_options_create(); @@ -170,9 +176,11 @@ public static class Native [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] public static extern nint leveldb_filterpolicy_create_bloom(int bits_per_key); + #endregion #region ReadOptions + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] public static extern nint leveldb_readoptions_create(); @@ -187,9 +195,11 @@ public static class Native [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] public static extern void leveldb_readoptions_set_snapshot(nint /*ReadOptions*/ options, nint /*SnapShot*/ snapshot); + #endregion #region WriteBatch + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] public static extern nint leveldb_writebatch_create(); @@ -207,9 +217,11 @@ public static class Native [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] public static extern void leveldb_writebatch_iterate(nint /* WriteBatch */ batch, object state, Action put, Action deleted); + #endregion #region WriteOptions + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] public static extern nint leveldb_writeoptions_create(); @@ -218,14 +230,17 @@ public static class Native [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] public static extern void leveldb_writeoptions_set_sync(nint /*WriteOptions*/ options, [MarshalAs(UnmanagedType.U1)] bool o); + #endregion #region Cache + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] public static extern nint leveldb_cache_create_lru(int capacity); [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] public static extern void leveldb_cache_destroy(nint /*Cache*/ cache); + #endregion #region Comparator @@ -255,9 +270,9 @@ public static void CheckError(nint error) { if (error != nint.Zero) { - string message = Marshal.PtrToStringAnsi(error); + var message = Marshal.PtrToStringAnsi(error); Native.leveldb_free(error); - throw new LevelDBException(message); + throw new LevelDBException(message ?? string.Empty); } } } diff --git a/src/Plugins/LevelDBStore/LevelDBStore.csproj b/src/Plugins/LevelDBStore/LevelDBStore.csproj index 09e4abb7bd..8f84bed91f 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 + enable ../../../bin/$(PackageId) diff --git a/src/Plugins/LevelDBStore/Plugins/Storage/Snapshot.cs b/src/Plugins/LevelDBStore/Plugins/Storage/Snapshot.cs index be820473c0..f479743dcc 100644 --- a/src/Plugins/LevelDBStore/Plugins/Storage/Snapshot.cs +++ b/src/Plugins/LevelDBStore/Plugins/Storage/Snapshot.cs @@ -13,6 +13,7 @@ using Neo.Persistence; using System.Collections; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using LSnapshot = Neo.IO.Storage.LevelDB.Snapshot; namespace Neo.Plugins.Storage @@ -55,7 +56,7 @@ public void Dispose() } /// - public IEnumerable<(byte[] Key, byte[] Value)> Seek(byte[] keyOrPrefix, SeekDirection direction = SeekDirection.Forward) + public IEnumerable<(byte[] Key, byte[] Value)> Seek(byte[]? keyOrPrefix, SeekDirection direction = SeekDirection.Forward) { return _db.Seek(_readOptions, keyOrPrefix, direction); } @@ -71,12 +72,12 @@ public bool Contains(byte[] key) return _db.Contains(_readOptions, key); } - public byte[] TryGet(byte[] key) + public byte[]? TryGet(byte[] key) { return _db.Get(_readOptions, key); } - public bool TryGet(byte[] key, out byte[] value) + public bool TryGet(byte[] key, [NotNullWhen(true)] out byte[]? value) { value = _db.Get(_readOptions, key); return value != null; @@ -86,7 +87,7 @@ public IEnumerator> GetEnumerator() { using var iterator = _db.CreateIterator(_readOptions); for (iterator.SeekToFirst(); iterator.Valid(); iterator.Next()) - yield return new KeyValuePair(iterator.Key(), iterator.Value()); + yield return new KeyValuePair(iterator.Key()!, iterator.Value()!); } IEnumerator IEnumerable.GetEnumerator() => diff --git a/src/Plugins/LevelDBStore/Plugins/Storage/Store.cs b/src/Plugins/LevelDBStore/Plugins/Storage/Store.cs index c06f2ae07f..db32a92a43 100644 --- a/src/Plugins/LevelDBStore/Plugins/Storage/Store.cs +++ b/src/Plugins/LevelDBStore/Plugins/Storage/Store.cs @@ -13,6 +13,7 @@ using Neo.Persistence; using System.Collections; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; namespace Neo.Plugins.Storage { @@ -58,17 +59,17 @@ public void PutSync(byte[] key, byte[] value) => public bool Contains(byte[] key) => _db.Contains(ReadOptions.Default, key); - public byte[] TryGet(byte[] key) => + public byte[]? TryGet(byte[] key) => _db.Get(ReadOptions.Default, key); - public bool TryGet(byte[] key, out byte[] value) + public bool TryGet(byte[] key, [NotNullWhen(true)] out byte[]? value) { value = _db.Get(ReadOptions.Default, key); return value != null; } /// - public IEnumerable<(byte[], byte[])> Seek(byte[] keyOrPrefix, SeekDirection direction = SeekDirection.Forward) => + public IEnumerable<(byte[], byte[])> Seek(byte[]? keyOrPrefix, SeekDirection direction = SeekDirection.Forward) => _db.Seek(ReadOptions.Default, keyOrPrefix, direction); public IEnumerator> GetEnumerator() => From bbcb3c2fb44521e01d9d2470b5ee69e8972ae1c8 Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Tue, 21 Jan 2025 09:49:34 +0100 Subject: [PATCH 2/5] Add Seek --- src/Neo/Persistence/IReadOnlyStore.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Neo/Persistence/IReadOnlyStore.cs b/src/Neo/Persistence/IReadOnlyStore.cs index 3d23d8ccf5..79ff9099be 100644 --- a/src/Neo/Persistence/IReadOnlyStore.cs +++ b/src/Neo/Persistence/IReadOnlyStore.cs @@ -28,7 +28,7 @@ public interface IReadOnlyStore /// The key(i.e. start key) or prefix to be sought. /// The direction of seek. /// An enumerator containing all the entries after (Forward) or before(Backward) seeking. - IEnumerable<(byte[] Key, byte[] Value)> Seek(byte[] keyOrPrefix, SeekDirection direction); + IEnumerable<(byte[] Key, byte[] Value)> Seek(byte[]? keyOrPrefix, SeekDirection direction); /// /// Reads a specified entry from the database. From 97c4ddd8f476ae086bce78b0ca05bef2ea8e8bd5 Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Tue, 21 Jan 2025 15:23:25 +0100 Subject: [PATCH 3/5] Fix warnings --- src/Neo/Persistence/MemoryStore.cs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/Neo/Persistence/MemoryStore.cs b/src/Neo/Persistence/MemoryStore.cs index d1eb91f8af..483214478a 100644 --- a/src/Neo/Persistence/MemoryStore.cs +++ b/src/Neo/Persistence/MemoryStore.cs @@ -33,9 +33,7 @@ public void Delete(byte[] key) _innerData.TryRemove(key, out _); } - public void Dispose() - { - } + public void Dispose() { } [MethodImpl(MethodImplOptions.AggressiveInlining)] public ISnapshot GetSnapshot() @@ -50,7 +48,7 @@ public void Put(byte[] key, byte[] value) } /// - public IEnumerable<(byte[] Key, byte[] Value)> Seek(byte[] keyOrPrefix, SeekDirection direction = SeekDirection.Forward) + public IEnumerable<(byte[] Key, byte[] Value)> Seek(byte[]? keyOrPrefix, SeekDirection direction = SeekDirection.Forward) { if (direction == SeekDirection.Backward && keyOrPrefix?.Length == 0) yield break; @@ -71,7 +69,7 @@ public void Put(byte[] key, byte[] value) } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool TryGet(byte[] key, [NotNullWhen(true)] out byte[] value) + public bool TryGet(byte[] key, [NotNullWhen(true)] out byte[]? value) { return _innerData.TryGetValue(key, out value); } From 425d6cb80c1cae669e9528c09797156a0180235a Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Tue, 21 Jan 2025 15:25:38 +0100 Subject: [PATCH 4/5] Unify --- src/Neo/Persistence/MemoryStore.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Neo/Persistence/MemoryStore.cs b/src/Neo/Persistence/MemoryStore.cs index 483214478a..05a08e30d9 100644 --- a/src/Neo/Persistence/MemoryStore.cs +++ b/src/Neo/Persistence/MemoryStore.cs @@ -50,11 +50,12 @@ public void Put(byte[] key, byte[] value) /// public IEnumerable<(byte[] Key, byte[] Value)> Seek(byte[]? keyOrPrefix, SeekDirection direction = SeekDirection.Forward) { - if (direction == SeekDirection.Backward && keyOrPrefix?.Length == 0) yield break; + keyOrPrefix ??= []; + if (direction == SeekDirection.Backward && keyOrPrefix.Length == 0) yield break; var comparer = direction == SeekDirection.Forward ? ByteArrayComparer.Default : ByteArrayComparer.Reverse; IEnumerable> records = _innerData; - if (keyOrPrefix?.Length > 0) + if (keyOrPrefix.Length > 0) records = records.Where(p => comparer.Compare(p.Key, keyOrPrefix) >= 0); records = records.OrderBy(p => p.Key, comparer); foreach (var pair in records) From 2891800f894bb4cc4dc5d7e47f838a5ad3fef061 Mon Sep 17 00:00:00 2001 From: Shargon Date: Tue, 21 Jan 2025 17:50:06 +0100 Subject: [PATCH 5/5] Update Helper.cs --- src/Plugins/LevelDBStore/IO/Data/LevelDB/Helper.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Plugins/LevelDBStore/IO/Data/LevelDB/Helper.cs b/src/Plugins/LevelDBStore/IO/Data/LevelDB/Helper.cs index e38c70e2ea..26b4e8b433 100644 --- a/src/Plugins/LevelDBStore/IO/Data/LevelDB/Helper.cs +++ b/src/Plugins/LevelDBStore/IO/Data/LevelDB/Helper.cs @@ -26,7 +26,7 @@ public static class Helper if (direction == SeekDirection.Forward) { for (it.Seek(keyOrPrefix); it.Valid(); it.Next()) - yield return new(it.Key(), it.Value()); + yield return new(it.Key()!, it.Value()!); } else { @@ -38,7 +38,7 @@ public static class Helper it.Prev(); for (; it.Valid(); it.Prev()) - yield return new(it.Key(), it.Value()); + yield return new(it.Key()!, it.Value()!); } }