Skip to content

Commit 9be8c13

Browse files
committed
Fix it so that disposing the RocksDb instance twice does not throw AccessViolationException and crash the process. Introduce dtor to ensure disposal, even if reference is lost.
1 parent 5b4b0bc commit 9be8c13

File tree

2 files changed

+72
-2
lines changed

2 files changed

+72
-2
lines changed

RocksDbSharp/RocksDb.cs

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,14 @@
55
using System.Runtime.InteropServices;
66
using System.Text;
77
using Transitional;
8+
// ReSharper disable EmptyGeneralCatchClause
89

910
namespace RocksDbSharp
1011
{
1112
public class RocksDb : IDisposable
1213
{
14+
bool disposed;
15+
1316
internal static ReadOptions DefaultReadOptions { get; } = new ReadOptions();
1417
internal static OptionsHandle DefaultOptions { get; } = new DbOptions();
1518
internal static WriteOptions DefaultWriteOptions { get; } = new WriteOptions();
@@ -29,13 +32,36 @@ private RocksDb(IntPtr handle, dynamic optionsReferences, dynamic cfOptionsRefs,
2932
this.columnFamilies = columnFamilies;
3033
}
3134

35+
~RocksDb()
36+
{
37+
ReleaseUnmanagedResources();
38+
}
39+
3240
public void Dispose()
41+
{
42+
if (disposed) return;
43+
44+
try
45+
{
46+
ReleaseUnmanagedResources();
47+
GC.SuppressFinalize(this);
48+
}
49+
finally
50+
{
51+
disposed = true;
52+
}
53+
}
54+
55+
void ReleaseUnmanagedResources()
3356
{
3457
if (columnFamilies != null)
3558
{
3659
foreach (var cfh in columnFamilies.Values)
60+
{
3761
cfh.Dispose();
62+
}
3863
}
64+
3965
Native.Instance.rocksdb_close(Handle);
4066
}
4167

@@ -168,7 +194,7 @@ public long Get(byte[] key, long keyLength, byte[] buffer, long offset, long len
168194
}
169195
}
170196

171-
public KeyValuePair<byte[],byte[]>[] MultiGet(byte[][] keys, ColumnFamilyHandle[] cf = null, ReadOptions readOptions = null)
197+
public KeyValuePair<byte[], byte[]>[] MultiGet(byte[][] keys, ColumnFamilyHandle[] cf = null, ReadOptions readOptions = null)
172198
{
173199
return Native.Instance.rocksdb_multi_get(Handle, (readOptions ?? DefaultReadOptions).Handle, keys);
174200
}
@@ -261,7 +287,7 @@ public void DropColumnFamily(string name)
261287
Native.Instance.rocksdb_drop_column_family(Handle, cf.Handle);
262288
columnFamilies.Remove(name);
263289
}
264-
290+
265291
public ColumnFamilyHandle GetDefaultColumnFamily()
266292
{
267293
return GetColumnFamily(ColumnFamilies.DefaultName);
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
using System;
2+
using System.IO;
3+
using RocksDbSharp;
4+
using Xunit;
5+
// ReSharper disable RedundantArgumentDefaultValue
6+
// ReSharper disable ArgumentsStyleLiteral
7+
8+
namespace RocksDbSharpTest
9+
{
10+
public class LifestyleTest
11+
{
12+
[Fact]
13+
public void DoubleDisposableDoesNotThrow()
14+
{
15+
var testdir = Path.Combine(Path.GetTempPath(), "lifestyle_test");
16+
var testdb = Path.Combine(testdir, "main");
17+
var path = Environment.ExpandEnvironmentVariables(testdb);
18+
19+
if (Directory.Exists(testdir))
20+
{
21+
Directory.Delete(testdir, recursive: true);
22+
}
23+
24+
Directory.CreateDirectory(testdir);
25+
26+
var options = new DbOptions().SetCreateIfMissing(true).EnableStatistics();
27+
28+
var db = RocksDb.Open(options, path);
29+
30+
db.Dispose();
31+
32+
// throws AccessViolationException, which on my machine crashed the process so hard that XUnit coulnd't cope...
33+
//
34+
db.Dispose();
35+
//
36+
// got this in Event Viewer though:
37+
//
38+
// Application: dotnet.exe
39+
// CoreCLR Version: 4.6.28619.1
40+
// Description: The process was terminated due to an internal error in the .NET Runtime at IP 00007FFF39BC5AA3 (00007FFF39A20000) with exit code c0000005.
41+
//
42+
}
43+
}
44+
}

0 commit comments

Comments
 (0)