From 7727d240464940edcb474ecabf74995cd3a416b2 Mon Sep 17 00:00:00 2001 From: Mogens Heller Grabe Date: Mon, 11 May 2020 09:53:05 +0200 Subject: [PATCH] fix it so that disposing the RocksDb instance twice does not throw AccessViolationException and crash the process --- RocksDbSharp/RocksDb.cs | 19 ++++++++--- tests/RocksDbSharpTest/LifestyleTest.cs | 44 +++++++++++++++++++++++++ 2 files changed, 59 insertions(+), 4 deletions(-) create mode 100644 tests/RocksDbSharpTest/LifestyleTest.cs diff --git a/RocksDbSharp/RocksDb.cs b/RocksDbSharp/RocksDb.cs index 770898b..a97cbdc 100644 --- a/RocksDbSharp/RocksDb.cs +++ b/RocksDbSharp/RocksDb.cs @@ -10,6 +10,8 @@ namespace RocksDbSharp { public class RocksDb : IDisposable { + bool disposed; + internal static ReadOptions DefaultReadOptions { get; } = new ReadOptions(); internal static OptionsHandle DefaultOptions { get; } = new DbOptions(); internal static WriteOptions DefaultWriteOptions { get; } = new WriteOptions(); @@ -31,12 +33,21 @@ private RocksDb(IntPtr handle, dynamic optionsReferences, dynamic cfOptionsRefs, public void Dispose() { - if (columnFamilies != null) + if (disposed) return; + try + { + if (columnFamilies != null) + { + foreach (var cfh in columnFamilies.Values) + cfh.Dispose(); + } + + Native.Instance.rocksdb_close(Handle); + } + finally { - foreach (var cfh in columnFamilies.Values) - cfh.Dispose(); + disposed = true; } - Native.Instance.rocksdb_close(Handle); } public static RocksDb Open(OptionsHandle options, string path) diff --git a/tests/RocksDbSharpTest/LifestyleTest.cs b/tests/RocksDbSharpTest/LifestyleTest.cs new file mode 100644 index 0000000..0e8d78f --- /dev/null +++ b/tests/RocksDbSharpTest/LifestyleTest.cs @@ -0,0 +1,44 @@ +using System; +using System.IO; +using RocksDbSharp; +using Xunit; +// ReSharper disable RedundantArgumentDefaultValue +// ReSharper disable ArgumentsStyleLiteral + +namespace RocksDbSharpTest +{ + public class LifestyleTest + { + [Fact] + public void DoubleDisposableDoesNotThrow() + { + var testdir = Path.Combine(Path.GetTempPath(), "lifestyle_test"); + var testdb = Path.Combine(testdir, "main"); + var path = Environment.ExpandEnvironmentVariables(testdb); + + if (Directory.Exists(testdir)) + { + Directory.Delete(testdir, recursive: true); + } + + Directory.CreateDirectory(testdir); + + var options = new DbOptions().SetCreateIfMissing(true).EnableStatistics(); + + var db = RocksDb.Open(options, path); + + db.Dispose(); + + // throws AccessViolationException, which on my machine crashed the process so hard that XUnit coulnd't cope... + // + db.Dispose(); + // + // got this in Event Viewer though: + // + // Application: dotnet.exe + // CoreCLR Version: 4.6.28619.1 + // Description: The process was terminated due to an internal error in the .NET Runtime at IP 00007FFF39BC5AA3 (00007FFF39A20000) with exit code c0000005. + // + } + } +} \ No newline at end of file