diff --git a/CHANGELOG.md b/CHANGELOG.md
index 50dae742a..fe893b3ce 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,13 @@
Release Notes
====
+# 06-26-2024
+DotNext.Net.Cluster 5.7.1
+* Improved reliability of disk I/O for the new WAL binary format
+
+DotNext.AspNetCore.Cluster 5.7.1
+* Improved reliability of disk I/O for the new WAL binary format
+
# 06-25-2024
DotNext.Threading 5.8.0
* Introduced `WaitAnyAsync` method to wait on a group of cancellation tokens
diff --git a/README.md b/README.md
index 15a141b4e..ecc4146dc 100644
--- a/README.md
+++ b/README.md
@@ -44,11 +44,13 @@ All these things are implemented in 100% managed code on top of existing .NET AP
* [NuGet Packages](https://www.nuget.org/profiles/rvsakno)
# What's new
-Release Date: 06-25-2024
+Release Date: 06-26-2024
-DotNext.Threading 5.8.0
-* Introduced `WaitAnyAsync` method to wait on a group of cancellation tokens
-* Added cancellation support for `WaitAsync` extension method for [WaitHandle](https://learn.microsoft.com/en-us/dotnet/api/system.threading.waithandle) class
+DotNext.Net.Cluster 5.7.1
+* Improved reliability of disk I/O for the new WAL binary format
+
+DotNext.AspNetCore.Cluster 5.7.1
+* Improved reliability of disk I/O for the new WAL binary format
Changelog for previous versions located [here](./CHANGELOG.md).
diff --git a/src/DotNext.Tests/Threading/Leases/LeaseTests.cs b/src/DotNext.Tests/Threading/Leases/LeaseTests.cs
index fc0ea51da..5adf162db 100644
--- a/src/DotNext.Tests/Threading/Leases/LeaseTests.cs
+++ b/src/DotNext.Tests/Threading/Leases/LeaseTests.cs
@@ -94,7 +94,7 @@ public static async Task ConsumerTokenState()
False(consumer.Token.IsCancellationRequested);
False(consumer.Expiration.IsExpired);
- await Task.Delay(150);
+ await Task.Delay(400);
True(consumer.Token.IsCancellationRequested);
False(await consumer.ReleaseAsync());
}
@@ -124,7 +124,7 @@ public static async Task AcquireUsingConsumer()
[Fact]
public static async Task WorkerProtectedWithLease()
{
- var pause = TimeSpan.FromMilliseconds(100);
+ var pause = TimeSpan.FromMilliseconds(500);
using var provider = new TestLeaseProvider(pause);
await using var consumer = new TestLeaseConsumer(provider);
True(await consumer.TryAcquireAsync());
@@ -134,7 +134,7 @@ public static async Task WorkerProtectedWithLease()
static async Task Worker(CancellationToken token)
{
- await Task.Delay(TimeSpan.FromMilliseconds(250), token);
+ await Task.Delay(TimeSpan.FromMilliseconds(1_000), token);
return 42;
}
}
diff --git a/src/cluster/DotNext.AspNetCore.Cluster/DotNext.AspNetCore.Cluster.csproj b/src/cluster/DotNext.AspNetCore.Cluster/DotNext.AspNetCore.Cluster.csproj
index a5c9a3b30..38fd71bbd 100644
--- a/src/cluster/DotNext.AspNetCore.Cluster/DotNext.AspNetCore.Cluster.csproj
+++ b/src/cluster/DotNext.AspNetCore.Cluster/DotNext.AspNetCore.Cluster.csproj
@@ -8,7 +8,7 @@
true
true
nullablePublicOnly
- 5.7.0
+ 5.7.1
.NET Foundation and Contributors
.NEXT Family of Libraries
diff --git a/src/cluster/DotNext.Net.Cluster/DotNext.Net.Cluster.csproj b/src/cluster/DotNext.Net.Cluster/DotNext.Net.Cluster.csproj
index 2d2ec5bc7..3f10699ef 100644
--- a/src/cluster/DotNext.Net.Cluster/DotNext.Net.Cluster.csproj
+++ b/src/cluster/DotNext.Net.Cluster/DotNext.Net.Cluster.csproj
@@ -8,7 +8,7 @@
enable
true
nullablePublicOnly
- 5.7.0
+ 5.7.1
.NET Foundation and Contributors
.NEXT Family of Libraries
diff --git a/src/cluster/DotNext.Net.Cluster/Net/Cluster/Consensus/Raft/PersistentState.Partition.cs b/src/cluster/DotNext.Net.Cluster/Net/Cluster/Consensus/Raft/PersistentState.Partition.cs
index 9969baa9c..dfb072be8 100644
--- a/src/cluster/DotNext.Net.Cluster/Net/Cluster/Consensus/Raft/PersistentState.Partition.cs
+++ b/src/cluster/DotNext.Net.Cluster/Net/Cluster/Consensus/Raft/PersistentState.Partition.cs
@@ -15,12 +15,12 @@ public partial class PersistentState
private protected abstract class Partition : ConcurrentStorageAccess
{
internal const int MaxRecordsPerPartition = int.MaxValue / LogEntryMetadata.Size;
- protected static readonly CacheRecord EmptyRecord = new() { PersistenceMode = CachedLogEntryPersistenceMode.CopyToBuffer };
+ private static readonly CacheRecord EmptyRecord = new() { PersistenceMode = CachedLogEntryPersistenceMode.CopyToBuffer };
internal readonly long FirstIndex, PartitionNumber, LastIndex;
private Partition? previous, next;
private object?[]? context;
- protected MemoryOwner entryCache;
+ private MemoryOwner entryCache;
protected int runningIndex;
protected Partition(DirectoryInfo location, int offset, int bufferSize, int recordsPerPartition, long partitionNumber, in BufferManager manager, int readersCount, WriteMode writeMode, long initialSize, FileAttributes attributes = FileAttributes.NotContentIndexed)
@@ -457,19 +457,6 @@ private sealed class Table : Partition, IReadOnlyList>
{
private const int HeaderSize = 512;
- private static readonly ReadOnlyMemory EmptyMetadata;
- private static readonly ReadOnlyMemory EphemeralMetadata;
-
- static Table()
- {
- EmptyMetadata = new byte[LogEntryMetadata.Size]; // all zeroes
-
- var ephemeral = LogEntryMetadata.Create(LogEntry.Initial, HeaderSize + LogEntryMetadata.Size, length: 0L);
- var buffer = new byte[LogEntryMetadata.Size];
- ephemeral.Format(buffer);
- EphemeralMetadata = buffer;
- }
-
// metadata management
private MemoryOwner header, footer;
private (ReadOnlyMemory, ReadOnlyMemory) bufferTuple;
@@ -485,7 +472,7 @@ internal Table(DirectoryInfo location, int bufferSize, int recordsPerPartition,
// init ephemeral 0 entry
if (PartitionNumber is 0L)
{
- EphemeralMetadata.CopyTo(footer.Memory);
+ LogEntryMetadata.Create(LogEntry.Initial, HeaderSize + LogEntryMetadata.Size, length: 0L).Format(footer.Span);
}
}
@@ -517,6 +504,7 @@ internal override void Initialize()
fileOffset -= footer.Length;
RandomAccess.Read(Handle, footer.Span, fileOffset);
+ runningIndex = int.CreateChecked(LastIndex - FirstIndex);
}
else
{
@@ -534,7 +522,9 @@ internal override void Initialize()
fileOffset = HeaderSize;
}
- for (Span metadataBuffer = stackalloc byte[LogEntryMetadata.Size], metadataTable = footer.Span; footerOffset < footer.Length; footerOffset += LogEntryMetadata.Size)
+ for (Span metadataBuffer = stackalloc byte[LogEntryMetadata.Size], metadataTable = footer.Span;
+ footerOffset < footer.Length;
+ footerOffset += LogEntryMetadata.Size, runningIndex++)
{
var count = RandomAccess.Read(Handle, metadataBuffer, fileOffset);
if (count < LogEntryMetadata.Size)
@@ -696,6 +686,7 @@ private async ValueTask FlushAndSealAsync(CancellationToken token)
await WriteFooterAsync(token).ConfigureAwait(false);
}
+ RandomAccess.FlushToDisk(Handle);
RandomAccess.SetLength(Handle, writer.FilePosition + footer.Length);
IsSealed = true;