diff --git a/src/Nethermind/Nethermind.Db.Rocks/DbOnTheRocks.cs b/src/Nethermind/Nethermind.Db.Rocks/DbOnTheRocks.cs index 2b7b448df76..3d9ca3c9317 100644 --- a/src/Nethermind/Nethermind.Db.Rocks/DbOnTheRocks.cs +++ b/src/Nethermind/Nethermind.Db.Rocks/DbOnTheRocks.cs @@ -5,6 +5,8 @@ using System.Buffers.Binary; using System.Collections.Concurrent; using System.Collections.Generic; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.IO; using System.IO.Abstractions; using System.Linq; @@ -619,22 +621,14 @@ public byte[]? this[ReadOnlySpan key] { if (_readAheadReadOptions is not null && (flags & ReadFlags.HintReadAhead) != 0) { - using IteratorManager.RentWrapper wrapper = iteratorManager.Rent(flags); - Iterator iterator = wrapper.Iterator; - - if (iterator.Valid() && TryCloseReadAhead(iterator, key, out byte[]? closeRes)) + byte[]? result = GetWithIterator(key, cf, iteratorManager, flags, out bool success); + if (success) { - return closeRes; - } - - iterator.Seek(key); - if (iterator.Valid() && Bytes.AreEqual(iterator.GetKeySpan(), key)) - { - return iterator.Value(); + return result; } } - return _db.Get(key, cf, (flags & ReadFlags.HintCacheMiss) != 0 ? _hintCacheMissOptions : _defaultReadOptions); + return Get(key, cf, flags); } catch (RocksDbSharpException e) { @@ -643,6 +637,74 @@ public byte[]? this[ReadOnlySpan key] } } + private unsafe byte[]? GetWithIterator(ReadOnlySpan key, ColumnFamilyHandle? cf, IteratorManager iteratorManager, ReadFlags flags, out bool success) + { + success = true; + + using IteratorManager.RentWrapper wrapper = iteratorManager.Rent(flags); + Iterator iterator = wrapper.Iterator; + + if (iterator.Valid() && TryCloseReadAhead(iterator, key, out byte[]? closeRes)) + { + return closeRes; + } + + iterator.Seek(key); + if (iterator.Valid() && Bytes.AreEqual(iterator.GetKeySpan(), key)) + { + return iterator.Value(); + } + + success = false; + return null; + } + + private unsafe byte[]? Get(ReadOnlySpan key, ColumnFamilyHandle? cf, ReadFlags flags) + { + // TODO: update when merged upstream: https://github.com/curiosity-ai/rocksdb-sharp/pull/61 + // return _db.Get(key, cf, (flags & ReadFlags.HintCacheMiss) != 0 ? _hintCacheMissOptions : _defaultReadOptions); + + nint db = _db.Handle; + nint read_options = ((flags & ReadFlags.HintCacheMiss) != 0 ? _hintCacheMissOptions : _defaultReadOptions).Handle; + UIntPtr skLength = (UIntPtr)key.Length; + IntPtr handle; + IntPtr errPtr; + fixed (byte* ptr = &MemoryMarshal.GetReference(key)) + { + handle = cf is null + ? Native.Instance.rocksdb_get_pinned(db, read_options, ptr, skLength, out errPtr) + : Native.Instance.rocksdb_get_pinned_cf(db, read_options, cf.Handle, ptr, skLength, out errPtr); + } + + if (errPtr != IntPtr.Zero) ThrowRocksDbException(errPtr); + if (handle == IntPtr.Zero) return null; + + try + { + IntPtr valuePtr = Native.Instance.rocksdb_pinnableslice_value(handle, out UIntPtr valueLength); + if (valuePtr == IntPtr.Zero) + { + return null; + } + + int length = (int)valueLength; + byte[] result = new byte[length]; + new ReadOnlySpan((void*)valuePtr, length).CopyTo(new Span(result)); + return result; + } + finally + { + Native.Instance.rocksdb_pinnableslice_destroy(handle); + } + + [DoesNotReturn] + [StackTraceHidden] + static unsafe void ThrowRocksDbException(nint errPtr) + { + throw new RocksDbException(errPtr); + } + } + /// /// iterator.Next() is about 10 to 20 times faster than iterator.Seek(). /// Here we attempt to do that first. To prevent futile attempt some logic is added to approximately detect