Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#6816 Akka.DistributedData.LightningDb: move durable folder creation outside of actor constructor #6983

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,8 @@ private WriteBehind() { }
private readonly long _mapSize;

private readonly TimeSpan _writeBehindInterval;
private readonly string _dir;
private readonly string _path;
private string _dir;

private readonly Dictionary<string, DurableDataEnvelope> _pending = new();
private readonly ILoggingAdapter _log;
Expand All @@ -81,17 +82,8 @@ useWriteBehind is "off" or "false" or "no" ?

_mapSize = _config.GetByteSize("map-size") ?? 100 * 1024 * 1024;

var path = _config.GetString("dir");
_dir = path.EndsWith(DatabaseName)
? Path.GetFullPath($"{path}-{Context.System.Name}-{Self.Path.Parent.Name}-{Cluster.Cluster.Get(Context.System).SelfAddress.Port}")
: Path.GetFullPath(path);
_path = _config.GetString("dir");

if (!Directory.Exists(_dir))
{
Directory.CreateDirectory(_dir);
}

_log.Info($"Using durable data in LMDB directory [{_dir}]");
Init();
}

Expand All @@ -108,9 +100,23 @@ protected override void PostStop()
DoWriteBehind();
}

protected override void PreStart()
{
base.PreStart();

_dir = _path.EndsWith(DatabaseName)
? Path.GetFullPath($"{_path}-{Context.System.Name}-{Self.Path.Parent.Name}-{Cluster.Cluster.Get(Context.System).SelfAddress.Port}")
: Path.GetFullPath(_path);
if (!Directory.Exists(_dir))
Directory.CreateDirectory(_dir);

_log.Info($"Using durable data in LMDB directory [{_dir}]");
}

private LightningEnvironment GetLightningEnvironment()
{
var t0 = Stopwatch.StartNew();
var t0 = Stopwatch.StartNew();

var env = new LightningEnvironment(_dir)
{
MapSize = _mapSize,
Expand Down Expand Up @@ -181,13 +187,6 @@ private void Init()
{
Receive<LoadAll>(_ =>
{
if(_dir.Length == 0 || !Directory.Exists(_dir))
{
// no files to load
Sender.Tell(LoadAllCompleted.Instance);
Become(Active);
return;
}

var t0 = Stopwatch.StartNew();

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
//-----------------------------------------------------------------------
// <copyright file="BugFix6816.cs" company="Akka.NET Project">
// Copyright (C) 2009-2023 Lightbend Inc. <http://www.lightbend.com>
// Copyright (C) 2013-2023 .NET Foundation <https://github.com/akkadotnet/akka.net>
// </copyright>
//-----------------------------------------------------------------------

using System;
using System.IO;
using Akka.Actor;
using Akka.Configuration;
using Akka.DistributedData.Durable;
using Akka.DistributedData.LightningDB;
using Akka.Event;
using FluentAssertions;
using Xunit;
using Xunit.Abstractions;

namespace Akka.DistributedData.Tests.LightningDb;

[Collection("DistributedDataSpec")]
public class BugFix6816: Akka.TestKit.Xunit2.TestKit
{
private const string DDataDir = "thatdir";
private static readonly Config BaseConfig = ConfigurationFactory.ParseString(@"
akka.actor.provider = ""Akka.Cluster.ClusterActorRefProvider, Akka.Cluster""
akka.remote.dot-netty.tcp.port = 0")
.WithFallback(DistributedData.DefaultConfig())
.WithFallback(TestKit.Xunit2.TestKit.DefaultConfig);

private static readonly Config LmdbDefaultConfig = ConfigurationFactory.ParseString($@"
lmdb {{
dir = {DDataDir}
map-size = 100 MiB
write-behind-interval = off
}}");

public BugFix6816(ITestOutputHelper output): base(BaseConfig, "LmdbDurableStoreSpec", output)
{
}

[Fact]
public void Lmdb_creates_directory_when_handling_first_message()
{
if (Directory.Exists(DDataDir))
{
var di = new DirectoryInfo(DDataDir);
di.Delete(true);
}

Directory.Exists(DDataDir).Should().BeFalse();
var lmdb = ActorOf(LmdbDurableStore.Props(LmdbDefaultConfig));
lmdb.Tell(LoadAll.Instance);
AwaitCondition(() => HasMessages);
ExpectMsg<LoadAllCompleted>();
Directory.Exists(DDataDir).Should().BeTrue();
}

[Fact]
public void Lmdb_logs_meaningful_error_for_invalid_dir_path()
{
var invalidName = Environment.OSVersion.Platform is PlatformID.Win32NT
? "\"invalid?directory\"" : "/dev/null/illegal";

Directory.Exists(invalidName).Should().BeFalse();

var probe = CreateTestProbe();
Sys.EventStream.Subscribe(probe, typeof(Error));

var lmdb = ActorOf(LmdbDurableStore.Props(ConfigurationFactory.ParseString($@"
lmdb {{
dir = {invalidName}
map-size = 100 MiB
write-behind-interval = off
}}")));

//Expect meaningful error log
var err =probe.ExpectMsg<Error>();
err.Message.ToString().Should()
.NotContain("Error while creating actor instance of type Akka.DistributedData.LightningDB.LmdbDurableStore");
err.Cause.Should().BeOfType<ActorInitializationException>();
err.Cause.InnerException.Should().NotBeNull();
(err.Cause.InnerException is IOException or DirectoryNotFoundException or ArgumentException).Should().BeTrue();

Directory.Exists(invalidName).Should().BeFalse();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,7 @@ public class LmdbDurableStoreSpec
private readonly ITestOutputHelper _output;

private static readonly Config BaseConfig = ConfigurationFactory.ParseString($@"
akka.actor {{
provider=""Akka.Cluster.ClusterActorRefProvider, Akka.Cluster""
}}
akka.actor.provider=""Akka.Cluster.ClusterActorRefProvider, Akka.Cluster""
akka.remote.dot-netty.tcp.port = 0
akka.cluster.distributed-data.durable.lmdb {{
dir = {DDataDir}
Expand All @@ -46,14 +44,12 @@ public void Lmdb_should_not_throw_when_opening_existing_directory()
di.Delete(true);
}
Directory.CreateDirectory(DDataDir);

var testKit = new TestKit.Xunit2.TestKit(BaseConfig, nameof(LmdbDurableStoreSpec), _output);
var probe = testKit.CreateTestProbe();

var config = testKit.Sys.Settings.Config.GetConfig("akka.cluster.distributed-data.durable");
var lmdb = testKit.Sys.ActorOf(LmdbDurableStore.Props(config));
lmdb.Tell(LoadAll.Instance, probe.Ref);

probe.ExpectMsg<LoadAllCompleted>();
}
}
Expand Down