Skip to content

Commit 0619316

Browse files
authored
MDB throws a MDB_NOTFOUND exception when the database directory already exists (#5424)
* Add failing spec * Rearrange try..catch so that it catches errors in the initializer code. Try to recreate the database even when directory exists. * Fix spec, just delete test folder if it exists. * Clean up spec * Add platform target hint in csproj to make sure that the right LMDB files were copied over
1 parent 1cf4156 commit 0619316

File tree

3 files changed

+104
-55
lines changed

3 files changed

+104
-55
lines changed

src/contrib/cluster/Akka.DistributedData.LightningDB/LmdbDurableStore.cs

+43-55
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,6 @@ private WriteBehind() { }
5757

5858
private readonly TimeSpan _writeBehindInterval;
5959
private readonly string _dir;
60-
private bool _dirExists;
6160

6261
private readonly Dictionary<string, DurableDataEnvelope> _pending = new Dictionary<string, DurableDataEnvelope>();
6362
private readonly ILoggingAdapter _log;
@@ -89,8 +88,11 @@ public LmdbDurableStore(Config config)
8988
? Path.GetFullPath($"{path}-{Context.System.Name}-{Self.Path.Parent.Name}-{Cluster.Cluster.Get(Context.System).SelfAddress.Port}")
9089
: Path.GetFullPath(path);
9190

92-
_dirExists = Directory.Exists(_dir);
93-
91+
if (!Directory.Exists(_dir))
92+
{
93+
Directory.CreateDirectory(_dir);
94+
}
95+
9496
_log.Info($"Using durable data in LMDB directory [{_dir}]");
9597
Init();
9698
}
@@ -110,41 +112,24 @@ protected override void PostStop()
110112

111113
private LightningEnvironment GetLightningEnvironment()
112114
{
113-
LightningEnvironment env;
114-
115-
if (!_dirExists)
115+
var t0 = Stopwatch.StartNew();
116+
var env = new LightningEnvironment(_dir)
116117
{
117-
var t0 = Stopwatch.StartNew();
118-
Directory.CreateDirectory(_dir);
119-
_dirExists = true;
120-
121-
env = new LightningEnvironment(_dir)
122-
{
123-
MapSize = _mapSize,
124-
MaxDatabases = 1
125-
};
126-
env.Open(EnvironmentOpenFlags.NoLock);
118+
MapSize = _mapSize,
119+
MaxDatabases = 1
120+
};
121+
env.Open(EnvironmentOpenFlags.NoLock);
127122

128-
using (var tx = env.BeginTransaction())
129-
using (tx.OpenDatabase(DatabaseName, new DatabaseConfiguration { Flags = DatabaseOpenFlags.Create }))
130-
{
131-
tx.Commit();
132-
}
133-
134-
t0.Stop();
135-
if (_log.IsDebugEnabled)
136-
_log.Debug($"Init of LMDB in directory [{_dir}] took [{t0.ElapsedMilliseconds} ms]");
137-
}
138-
else
123+
using (var tx = env.BeginTransaction())
124+
using (tx.OpenDatabase(DatabaseName, new DatabaseConfiguration { Flags = DatabaseOpenFlags.Create }))
139125
{
140-
env = new LightningEnvironment(_dir)
141-
{
142-
MapSize = _mapSize,
143-
MaxDatabases = 1
144-
};
145-
env.Open(EnvironmentOpenFlags.NoLock);
126+
tx.Commit();
146127
}
147128

129+
t0.Stop();
130+
if (_log.IsDebugEnabled)
131+
_log.Debug($"Init of LMDB in directory [{_dir}] took [{t0.ElapsedMilliseconds} ms]");
132+
148133
return env;
149134
}
150135

@@ -207,12 +192,13 @@ private void Init()
207192
}
208193

209194
var t0 = Stopwatch.StartNew();
210-
using (var env = GetLightningEnvironment())
211-
using (var tx = env.BeginTransaction(TransactionBeginFlags.ReadOnly))
212-
using(var db = tx.OpenDatabase(DatabaseName))
213-
using(var cursor = tx.CreateCursor(db))
195+
196+
try
214197
{
215-
try
198+
using (var env = GetLightningEnvironment())
199+
using (var tx = env.BeginTransaction(TransactionBeginFlags.ReadOnly))
200+
using(var db = tx.OpenDatabase(DatabaseName))
201+
using(var cursor = tx.CreateCursor(db))
216202
{
217203
var data = cursor.AsEnumerable().Select((x, i)
218204
=> {
@@ -236,11 +222,11 @@ private void Init()
236222

237223
Become(Active);
238224
}
239-
catch (Exception e)
240-
{
241-
if (t0.IsRunning) t0.Stop();
242-
throw new LoadFailedException("failed to load durable distributed-data", e);
243-
}
225+
}
226+
catch (Exception e)
227+
{
228+
if (t0.IsRunning) t0.Stop();
229+
throw new LoadFailedException("failed to load durable distributed-data", e);
244230
}
245231
});
246232
}
@@ -251,23 +237,25 @@ private void DoWriteBehind()
251237
{
252238
var t0 = Stopwatch.StartNew();
253239
using (var env = GetLightningEnvironment())
254-
using(var tx = env.BeginTransaction())
255-
using (var db = tx.OpenDatabase(DatabaseName))
240+
using (var tx = env.BeginTransaction())
256241
{
257242
try
258243
{
259-
foreach (var entry in _pending)
244+
using (var db = tx.OpenDatabase(DatabaseName))
260245
{
261-
var byteKey = Encoding.UTF8.GetBytes(entry.Key);
262-
var byteValue = _serializer.ToBinary(entry.Value);
263-
tx.Put(db, byteKey, byteValue);
264-
}
265-
tx.Commit();
246+
foreach (var entry in _pending)
247+
{
248+
var byteKey = Encoding.UTF8.GetBytes(entry.Key);
249+
var byteValue = _serializer.ToBinary(entry.Value);
250+
tx.Put(db, byteKey, byteValue);
251+
}
252+
tx.Commit();
266253

267-
t0.Stop();
268-
if (_log.IsDebugEnabled)
269-
{
270-
_log.Debug($"store and commit of [{_pending.Count}] entries took {t0.ElapsedMilliseconds} ms");
254+
t0.Stop();
255+
if (_log.IsDebugEnabled)
256+
{
257+
_log.Debug($"store and commit of [{_pending.Count}] entries took {t0.ElapsedMilliseconds} ms");
258+
}
271259
}
272260
}
273261
catch (Exception cause)

src/contrib/cluster/Akka.DistributedData.Tests/Akka.DistributedData.Tests.csproj

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
<PropertyGroup>
66
<AssemblyTitle>Akka.DistributedData.Tests</AssemblyTitle>
77
<TargetFrameworks>$(NetFrameworkTestVersion);$(NetTestVersion);$(NetCoreTestVersion)</TargetFrameworks>
8+
<PlatformTarget>x64</PlatformTarget>
89
</PropertyGroup>
910

1011
<ItemGroup>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
// //-----------------------------------------------------------------------
2+
// // <copyright file="LmdbSpec.cs" company="Akka.NET Project">
3+
// // Copyright (C) 2009-2021 Lightbend Inc. <http://www.lightbend.com>
4+
// // Copyright (C) 2013-2021 .NET Foundation <https://github.com/akkadotnet/akka.net>
5+
// // </copyright>
6+
// //-----------------------------------------------------------------------
7+
8+
using System.IO;
9+
using Akka.Actor;
10+
using Akka.Configuration;
11+
using Akka.DistributedData.Durable;
12+
using Akka.DistributedData.LightningDB;
13+
using Xunit;
14+
using Xunit.Abstractions;
15+
16+
namespace Akka.DistributedData.Tests.LightningDb
17+
{
18+
public class LmdbDurableStoreSpec
19+
{
20+
private const string DDataDir = "thisdir";
21+
private readonly ITestOutputHelper _output;
22+
23+
private static readonly Config BaseConfig = ConfigurationFactory.ParseString($@"
24+
akka.actor {{
25+
provider=""Akka.Cluster.ClusterActorRefProvider, Akka.Cluster""
26+
}}
27+
akka.remote.dot-netty.tcp.port = 0
28+
akka.cluster.distributed-data.durable.lmdb {{
29+
dir = {DDataDir}
30+
map-size = 100 MiB
31+
write-behind-interval = off
32+
}}").WithFallback(DistributedData.DefaultConfig())
33+
.WithFallback(TestKit.Xunit2.TestKit.DefaultConfig);
34+
35+
public LmdbDurableStoreSpec(ITestOutputHelper output)
36+
{
37+
_output = output;
38+
}
39+
40+
[Fact]
41+
public void Lmdb_should_not_throw_when_opening_existing_directory()
42+
{
43+
if(Directory.Exists(DDataDir))
44+
{
45+
var di = new DirectoryInfo(DDataDir);
46+
di.Delete(true);
47+
}
48+
Directory.CreateDirectory(DDataDir);
49+
50+
var testKit = new TestKit.Xunit2.TestKit(BaseConfig, nameof(LmdbDurableStoreSpec), _output);
51+
var probe = testKit.CreateTestProbe();
52+
53+
var config = testKit.Sys.Settings.Config.GetConfig("akka.cluster.distributed-data.durable");
54+
var lmdb = testKit.Sys.ActorOf(LmdbDurableStore.Props(config));
55+
lmdb.Tell(LoadAll.Instance, probe.Ref);
56+
57+
probe.ExpectMsg<LoadAllCompleted>();
58+
}
59+
}
60+
}

0 commit comments

Comments
 (0)