From 4fa070a54b4c5ecc8c9effc7bcd01b07488aceeb Mon Sep 17 00:00:00 2001 From: Ben Adams Date: Sun, 23 Feb 2025 00:56:17 +0000 Subject: [PATCH 1/3] Use get_pinned for gets to reduce copies --- csharp/src/Native.Marshaled.cs | 80 ++++++++++++++++++++-------------- 1 file changed, 47 insertions(+), 33 deletions(-) diff --git a/csharp/src/Native.Marshaled.cs b/csharp/src/Native.Marshaled.cs index 80b447f..f849a45 100644 --- a/csharp/src/Native.Marshaled.cs +++ b/csharp/src/Native.Marshaled.cs @@ -225,27 +225,33 @@ public unsafe byte[] rocksdb_get( ColumnFamilyHandle cf = null) { UIntPtr skLength = (UIntPtr)key.Length; - IntPtr resultPtr; - UIntPtr valueLength; + IntPtr handle; fixed (byte* ptr = &MemoryMarshal.GetReference(key)) { - resultPtr = cf is null - ? rocksdb_get(db, read_options, ptr, skLength, out valueLength, out errptr) - : rocksdb_get_cf(db, read_options, cf.Handle, ptr, skLength, out valueLength, out errptr); + handle = cf is null + ? rocksdb_get_pinned(db, read_options, ptr, skLength, out errptr) + : rocksdb_get_pinned_cf(db, read_options, cf.Handle, ptr, skLength, out errptr); } if (errptr != IntPtr.Zero) { return null; } - if (resultPtr == IntPtr.Zero) + if (handle == IntPtr.Zero) { return null; } - var result = new byte[(ulong)valueLength]; - Marshal.Copy(resultPtr, result, 0, (int)valueLength); - rocksdb_free(resultPtr); + IntPtr valuePtr = rocksdb_pinnableslice_value(handle, out UIntPtr valueLength); + if (valuePtr == IntPtr.Zero) + { + return null; + } + + int length = (int)valueLength; + byte[] result = new byte[length]; + Marshal.Copy(handle, result, 0, length); + rocksdb_pinnableslice_destroy(handle); return result; } @@ -257,13 +263,12 @@ public unsafe bool rocksdb_has_key( ColumnFamilyHandle cf = null) { UIntPtr skLength = (UIntPtr)key.Length; - IntPtr resultPtr; - UIntPtr valueLength; + IntPtr handle; fixed (byte* ptr = &MemoryMarshal.GetReference(key)) { - resultPtr = cf is null - ? rocksdb_get(db, read_options, ptr, skLength, out valueLength, out errptr) - : rocksdb_get_cf(db, read_options, cf.Handle, ptr, skLength, out valueLength, out errptr); + handle = cf is null + ? rocksdb_get_pinned(db, read_options, ptr, skLength, out errptr) + : rocksdb_get_pinned_cf(db, read_options, cf.Handle, ptr, skLength, out errptr); } if (errptr != IntPtr.Zero) @@ -271,12 +276,12 @@ public unsafe bool rocksdb_has_key( return false; } - if (resultPtr == IntPtr.Zero) + if (handle == IntPtr.Zero) { return false; } - - rocksdb_free(resultPtr); + + rocksdb_pinnableslice_destroy(handle); return true; } @@ -290,32 +295,37 @@ public unsafe T rocksdb_get( ColumnFamilyHandle cf = null) { UIntPtr skLength = (UIntPtr)key.Length; - IntPtr resultPtr; - UIntPtr valueLength; + IntPtr handle; fixed (byte* ptr = &MemoryMarshal.GetReference(key)) { - resultPtr = cf is null - ? rocksdb_get(db, read_options, ptr, skLength, out valueLength, out errptr) - : rocksdb_get_cf(db, read_options, cf.Handle, ptr, skLength, out valueLength, out errptr); + handle = cf is null + ? rocksdb_get_pinned(db, read_options, ptr, skLength, out errptr) + : rocksdb_get_pinned_cf(db, read_options, cf.Handle, ptr, skLength, out errptr); } if (errptr != IntPtr.Zero) { return default(T); } - if (resultPtr == IntPtr.Zero) + if (handle == IntPtr.Zero) + { + return default(T); + } + + IntPtr valuePtr = rocksdb_pinnableslice_value(handle, out UIntPtr valueLength); + if (valuePtr == IntPtr.Zero) { return default(T); } - var span = new ReadOnlySpan((void*)resultPtr, (int)valueLength); + var span = new ReadOnlySpan((void*)valuePtr, (int)valueLength); try { return deserializer.Deserialize(span); } finally { - rocksdb_free(resultPtr); + rocksdb_pinnableslice_destroy(handle); } } @@ -328,32 +338,36 @@ public unsafe T rocksdb_get( ColumnFamilyHandle cf = null) { UIntPtr skLength = (UIntPtr)key.Length; - IntPtr resultPtr; - UIntPtr valueLength; + IntPtr handle; fixed (byte* ptr = &MemoryMarshal.GetReference(key)) { - resultPtr = cf is null - ? rocksdb_get(db, read_options, ptr, skLength, out valueLength, out errptr) - : rocksdb_get_cf(db, read_options, cf.Handle, ptr, skLength, out valueLength, out errptr); + handle = cf is null + ? rocksdb_get_pinned(db, read_options, ptr, skLength, out errptr) + : rocksdb_get_pinned_cf(db, read_options, cf.Handle, ptr, skLength, out errptr); } if (errptr != IntPtr.Zero) { return default(T); } - if (resultPtr == IntPtr.Zero) + if (handle == IntPtr.Zero) { return default(T); } + IntPtr valuePtr = rocksdb_pinnableslice_value(handle, out UIntPtr valueLength); + if (valuePtr == IntPtr.Zero) + { + return default(T); + } try { - using var stream = new UnmanagedMemoryStream((byte*)resultPtr, (long)valueLength); + using var stream = new UnmanagedMemoryStream((byte*)valuePtr, (long)valueLength); return deserializer(stream); } finally { - rocksdb_free(resultPtr); + rocksdb_pinnableslice_destroy(handle); } } #endif From c122d4bd568f4329bd9b171bc1967831ac1649b7 Mon Sep 17 00:00:00 2001 From: Ben Adams Date: Sun, 23 Feb 2025 01:17:02 +0000 Subject: [PATCH 2/3] Use correct pointer --- csharp/src/Native.Marshaled.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/csharp/src/Native.Marshaled.cs b/csharp/src/Native.Marshaled.cs index f849a45..700c9ee 100644 --- a/csharp/src/Native.Marshaled.cs +++ b/csharp/src/Native.Marshaled.cs @@ -250,7 +250,7 @@ public unsafe byte[] rocksdb_get( int length = (int)valueLength; byte[] result = new byte[length]; - Marshal.Copy(handle, result, 0, length); + Marshal.Copy(valuePtr, result, 0, length); rocksdb_pinnableslice_destroy(handle); return result; } @@ -280,6 +280,11 @@ public unsafe bool rocksdb_has_key( { return false; } + IntPtr valuePtr = rocksdb_pinnableslice_value(handle, out UIntPtr _); + if (valuePtr == IntPtr.Zero) + { + return false; + } rocksdb_pinnableslice_destroy(handle); From 668e7a641894f4af2026cd175a324b6079542549 Mon Sep 17 00:00:00 2001 From: Ben Adams Date: Mon, 24 Feb 2025 04:04:59 +0000 Subject: [PATCH 3/3] Throw exception on error --- csharp/src/Native.Marshaled.cs | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/csharp/src/Native.Marshaled.cs b/csharp/src/Native.Marshaled.cs index 700c9ee..1d003c1 100644 --- a/csharp/src/Native.Marshaled.cs +++ b/csharp/src/Native.Marshaled.cs @@ -5,6 +5,10 @@ This is kept separate so that the lowest level imports can be kept as close as p */ using System; using System.Collections.Generic; +#if NET6_0_OR_GREATER +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +#endif using System.IO; using System.Runtime.InteropServices; using System.Text; @@ -232,9 +236,10 @@ public unsafe byte[] rocksdb_get( ? rocksdb_get_pinned(db, read_options, ptr, skLength, out errptr) : rocksdb_get_pinned_cf(db, read_options, cf.Handle, ptr, skLength, out errptr); } + if (errptr != IntPtr.Zero) { - return null; + ThrowRocksDbException(errptr); } if (handle == IntPtr.Zero) @@ -273,7 +278,7 @@ public unsafe bool rocksdb_has_key( if (errptr != IntPtr.Zero) { - return false; + ThrowRocksDbException(errptr); } if (handle == IntPtr.Zero) @@ -307,9 +312,10 @@ public unsafe T rocksdb_get( ? rocksdb_get_pinned(db, read_options, ptr, skLength, out errptr) : rocksdb_get_pinned_cf(db, read_options, cf.Handle, ptr, skLength, out errptr); } + if (errptr != IntPtr.Zero) { - return default(T); + ThrowRocksDbException(errptr); } if (handle == IntPtr.Zero) @@ -350,9 +356,10 @@ public unsafe T rocksdb_get( ? rocksdb_get_pinned(db, read_options, ptr, skLength, out errptr) : rocksdb_get_pinned_cf(db, read_options, cf.Handle, ptr, skLength, out errptr); } + if (errptr != IntPtr.Zero) { - return default(T); + ThrowRocksDbException(errptr); } if (handle == IntPtr.Zero) @@ -375,6 +382,15 @@ public unsafe T rocksdb_get( rocksdb_pinnableslice_destroy(handle); } } + +#if NET6_0_OR_GREATER + [DoesNotReturn] + [StackTraceHidden] +#endif + static unsafe void ThrowRocksDbException(nint errPtr) + { + throw new RocksDbException(errPtr); + } #endif ///