Skip to content

Commit 0870503

Browse files
committed
Release 5.24.0
1 parent 42b9240 commit 0870503

File tree

115 files changed

+4260
-894
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

115 files changed

+4260
-894
lines changed

CHANGELOG.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,32 @@
11
Release Notes
22
====
33

4+
# 08-19-2025
5+
<a href="https://www.nuget.org/packages/dotnext/5.24.0">DotNext 5.24.0</a>
6+
* Merged [258](https://github.com/dotnet/dotNext/pull/258)
7+
* Added `CopyTo` extension method overload for [ReadOnlySequence&lt;T&gt;](https://learn.microsoft.com/en-us/dotnet/api/system.buffers.readonlysequence-1) data type that returns the position within the sequence
8+
* Fixed correctness of atomic read/write operations exposed by `Atomic` static class for **double** data type on 32-bit platforms
9+
* `LockAcquisition` static methods are no longer extension methods to avoid ambiguity (see [267](https://github.com/dotnet/dotNext/discussions/267))
10+
11+
<a href="https://www.nuget.org/packages/dotnext.metaprogramming/5.24.0">DotNext.Metaprogramming 5.24.0</a>
12+
* Updated dependencies
13+
14+
<a href="https://www.nuget.org/packages/dotnext.unsafe/5.24.0">DotNext.Unsafe 5.24.0</a>
15+
* Added custom marshallers for `IUnmanagedMemory<T>` interface and `Pointer<T>` data type that are compatible with PInvoke source generator
16+
17+
<a href="https://www.nuget.org/packages/dotnext.threading/5.24.0">DotNext.Threading 5.24.0</a>
18+
* `AsyncLockAcquisition` static methods are no longer extension methods to avoid ambiguity (see [267](https://github.com/dotnet/dotNext/discussions/267))
19+
* Lock contention reported by all async lock primitives is now an up-down counter rather than regular counter
20+
21+
<a href="https://www.nuget.org/packages/dotnext.io/5.24.0">DotNext.IO 5.24.0</a>
22+
* Improved behavioral compatibility with [Pipe](https://learn.microsoft.com/en-us/dotnet/api/system.io.pipelines.pipe) class by extension methods exposed by `PipeExtensions` class
23+
24+
<a href="https://www.nuget.org/packages/dotnext.net.cluster/5.24.0">DotNext.Net.Cluster 5.24.0</a>
25+
* Added `DotNext.Net.Multiplexing` namespace that exposes simple unencrypted multiplexing protocol implementation on top of TCP. The multiplexed channel is exposed as [IDuplexPipe](https://learn.microsoft.com/en-us/dotnet/api/system.io.pipelines.iduplexpipe). The main purpose of this implementation is the efficient communication between nodes within the cluster inside the trusted LAN
26+
27+
<a href="https://www.nuget.org/packages/dotnext.aspnetcore.cluster/5.24.0">DotNext.AspNetCore.Cluster 5.24.0</a>
28+
* Updated dependencies
29+
430
# 06-29-2025
531
<a href="https://www.nuget.org/packages/dotnext/5.23.0">DotNext 5.23.0</a>
632
* Added `Atomic.Read` and `Atomic.Write` methods for **long** and **ulong** data types for cross-architecture support of atomic reads/writes

README.md

Lines changed: 22 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -44,34 +44,38 @@ All these things are implemented in 100% managed code on top of existing .NET AP
4444
* [NuGet Packages](https://www.nuget.org/profiles/rvsakno)
4545

4646
# What's new
47-
Release Date: 06-29-2025
47+
Release Date: 08-19-2025
4848

49-
<a href="https://www.nuget.org/packages/dotnext/5.23.0">DotNext 5.23.0</a>
50-
* Added `Atomic.Read` and `Atomic.Write` methods for **long** and **ulong** data types for cross-architecture support of atomic reads/writes
51-
* Fixed compatibility with 32-bit arch for `Timstamp` data type
49+
<a href="https://www.nuget.org/packages/dotnext/5.24.0">DotNext 5.24.0</a>
50+
* Merged [258](https://github.com/dotnet/dotNext/pull/258)
51+
* Added `CopyTo` extension method overload for [ReadOnlySequence&lt;T&gt;](https://learn.microsoft.com/en-us/dotnet/api/system.buffers.readonlysequence-1) data type that returns the position within the sequence
52+
* Fixed correctness of atomic read/write operations exposed by `Atomic` static class for **double** data type on 32-bit platforms
53+
* `LockAcquisition` static methods are no longer extension methods to avoid ambiguity (see [267](https://github.com/dotnet/dotNext/discussions/267))
5254

53-
<a href="https://www.nuget.org/packages/dotnext.metaprogramming/5.23.0">DotNext.Metaprogramming 5.23.0</a>
55+
<a href="https://www.nuget.org/packages/dotnext.metaprogramming/5.24.0">DotNext.Metaprogramming 5.24.0</a>
5456
* Updated dependencies
5557

56-
<a href="https://www.nuget.org/packages/dotnext.unsafe/5.23.0">DotNext.Unsafe 5.23.0</a>
57-
* Added `UnmanagedMemory<T>` data type that provides allocation of the blittable value in the unmanaged memory in CLS-compliant manner
58-
* Introduced `UnmanagedMemory.Discard` static method for detaching of the physical memory from the virtual memory page
58+
<a href="https://www.nuget.org/packages/dotnext.unsafe/5.24.0">DotNext.Unsafe 5.24.0</a>
59+
* Added custom marshallers for `IUnmanagedMemory<T>` interface and `Pointer<T>` data type that are compatible with PInvoke source generator
5960

60-
<a href="https://www.nuget.org/packages/dotnext.threading/5.23.0">DotNext.Threading 5.23.0</a>
61-
* Fixed compatibility with 32-bit arch for asynchronous primitives and `IndexPool` data type
62-
* Replaced spin wait with the monitor lock for value task sources
61+
<a href="https://www.nuget.org/packages/dotnext.threading/5.24.0">DotNext.Threading 5.24.0</a>
62+
* `AsyncLockAcquisition` static methods are no longer extension methods to avoid ambiguity (see [267](https://github.com/dotnet/dotNext/discussions/267))
63+
* Lock contention reported by all async lock primitives is now an up-down counter rather than regular counter
6364

64-
<a href="https://www.nuget.org/packages/dotnext.io/5.23.0">DotNext.IO 5.23.0</a>
65-
* Updated dependencies
65+
<a href="https://www.nuget.org/packages/dotnext.io/5.24.0">DotNext.IO 5.24.0</a>
66+
* Improved behavioral compatibility with [Pipe](https://learn.microsoft.com/en-us/dotnet/api/system.io.pipelines.pipe) class by extension methods exposed by `PipeExtensions` class
6667

67-
<a href="https://www.nuget.org/packages/dotnext.net.cluster/5.23.0">DotNext.Net.Cluster 5.23.0</a>
68-
* Introduced private memory allocation type for `WriteAheadLog` class
69-
* Added support of Linux Transparent Huge Pages for `WriteAheadLog` class when private memory allocation is enabled
70-
* `WriteAheadLog.FlushAsync` ensures that the background flush is completed
68+
<a href="https://www.nuget.org/packages/dotnext.net.cluster/5.24.0">DotNext.Net.Cluster 5.24.0</a>
69+
* Added `DotNext.Net.Multiplexing` namespace that exposes simple unencrypted multiplexing protocol implementation on top of TCP. The multiplexed channel is exposed as [IDuplexPipe](https://learn.microsoft.com/en-us/dotnet/api/system.io.pipelines.iduplexpipe). The main purpose of this implementation is the efficient communication between nodes within the cluster inside the trusted LAN
7170

72-
<a href="https://www.nuget.org/packages/dotnext.aspnetcore.cluster/5.23.0">DotNext.AspNetCore.Cluster 5.23.0</a>
71+
<a href="https://www.nuget.org/packages/dotnext.aspnetcore.cluster/5.24.0">DotNext.AspNetCore.Cluster 5.24.0</a>
7372
* Updated dependencies
7473

74+
<a href="https://www.nuget.org/packages/dotnext.maintenanceservices/0.6.0">DotNext.MaintenanceServices 0.6.0</a>
75+
* Upgrade to newer `System.CommandLine` library
76+
* Interactive session now prints `>` in the prompt
77+
* Fixed buffer leak caused by interactive session
78+
7579
Changelog for previous versions located [here](./CHANGELOG.md).
7680

7781
# Release & Support Policy

src/Directory.Packages.props

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
<ItemGroup>
1212
<!--System packages-->
1313
<PackageVersion Include="System.Collections.Immutable" Version="8.0.0" />
14-
<PackageVersion Include="System.CommandLine" Version="2.0.0-beta4.22272.1" />
14+
<PackageVersion Include="System.CommandLine" Version="2.0.0-beta5.25306.1" />
1515
<PackageVersion Include="System.IO.Hashing" Version="8.0.0" />
1616
<PackageVersion Include="System.IO.Pipelines" Version="8.0.0" />
1717
<PackageVersion Include="System.Resources.Extensions" Version="8.0.0" />

src/DotNext.Benchmarks.WAL/Program.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
// See https://aka.ms/new-console-template for more information
22

3-
using DotNext;
43
using DotNext.Benchmarks.WAL;
54
using DotNext.Diagnostics;
5+
using DotNext.Hosting;
66
using DotNext.Net.Cluster.Consensus.Raft;
77
using DotNext.Net.Cluster.Consensus.Raft.StateMachine;
88
using FASTER.core;

src/DotNext.IO/DotNext.IO.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
<Authors>.NET Foundation and Contributors</Authors>
1212
<Company />
1313
<Product>.NEXT Family of Libraries</Product>
14-
<VersionPrefix>5.23.0</VersionPrefix>
14+
<VersionPrefix>5.24.0</VersionPrefix>
1515
<VersionSuffix></VersionSuffix>
1616
<AssemblyName>DotNext.IO</AssemblyName>
1717
<PackageLicenseExpression>MIT</PackageLicenseExpression>

src/DotNext.IO/IO/Pipelines/PipeExtensions.Readers.cs

Lines changed: 42 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -253,27 +253,33 @@ private static async ValueTask<TResult> ParseAsync<TResult, TArg>(this PipeReade
253253

254254
static TResult Parse(PipeReader reader, TArg arg, ReadOnlySpanFunc<byte, TArg, TResult> parser, int length, ReadOnlySequence<byte> source)
255255
{
256+
var consumed = source.Start;
256257
try
257258
{
258259
if (source.Length < length)
259260
{
260-
length = (int)source.Length;
261+
consumed = source.End;
261262
throw new EndOfStreamException();
262263
}
263264

264265
if (source.TryGetBlock(length, out var block))
266+
{
267+
consumed = source.GetPosition(block.Length, consumed);
265268
return parser(block.Span, arg);
269+
}
270+
else
271+
{
272+
using var destination = (uint)length <= (uint)SpanOwner<byte>.StackallocThreshold
273+
? stackalloc byte[length]
274+
: new SpanOwner<byte>(length);
266275

267-
using var destination = (uint)length <= (uint)SpanOwner<byte>.StackallocThreshold
268-
? stackalloc byte[length]
269-
: new SpanOwner<byte>(length);
270-
271-
source.CopyTo(destination.Span, out length);
272-
return parser(destination.Span.Slice(0, length), arg);
276+
length = source.CopyTo(destination.Span, out consumed);
277+
return parser(destination.Span.Slice(0, length), arg);
278+
}
273279
}
274280
finally
275281
{
276-
reader.AdvanceTo(source.GetPosition(length));
282+
reader.AdvanceTo(consumed);
277283
}
278284
}
279285
}
@@ -368,8 +374,15 @@ public static async ValueTask CopyToAsync<TConsumer>(this PipeReader reader, TCo
368374
throw new EndOfStreamException();
369375
}
370376

371-
for (ReadOnlyMemory<byte> block; buffer.TryGet(ref consumed, out block, advance: false) && !block.IsEmpty; count -= block.Length, consumed = buffer.GetPosition(block.Length, consumed))
372-
await consumer.Invoke(block, token).ConfigureAwait(false);
377+
for (var position = consumed;
378+
buffer.TryGet(ref position, out var block);
379+
count -= block.Length, consumed = position)
380+
{
381+
if (!block.IsEmpty)
382+
await consumer.Invoke(block, token).ConfigureAwait(false);
383+
}
384+
385+
consumed = buffer.End;
373386
}
374387
finally
375388
{
@@ -415,15 +428,16 @@ public static async ValueTask<int> ReadAtLeastAsync(this PipeReader reader, Memo
415428
static int Read(PipeReader reader, ReadOnlySequence<byte> source, in Memory<byte> destination, int minimumSize)
416429
{
417430
var readCount = 0;
431+
var consumed = source.Start;
418432
try
419433
{
420-
source.CopyTo(destination.Span, out readCount);
434+
readCount = source.CopyTo(destination.Span, out consumed);
421435
if (minimumSize > readCount)
422436
throw new EndOfStreamException();
423437
}
424438
finally
425439
{
426-
reader.AdvanceTo(source.GetPosition(readCount));
440+
reader.AdvanceTo(consumed);
427441
}
428442

429443
return readCount;
@@ -539,8 +553,15 @@ public static async IAsyncEnumerable<ReadOnlyMemory<byte>> ReadAllAsync(this Pip
539553

540554
try
541555
{
542-
for (ReadOnlyMemory<byte> block; buffer.TryGet(ref consumed, out block, advance: false) && !block.IsEmpty; consumed = buffer.GetPosition(block.Length, consumed))
543-
yield return block;
556+
for (var position = consumed;
557+
buffer.TryGet(ref position, out var block);
558+
consumed = position)
559+
{
560+
if (!block.IsEmpty)
561+
yield return block;
562+
}
563+
564+
consumed = buffer.End;
544565
}
545566
finally
546567
{
@@ -581,14 +602,17 @@ static async IAsyncEnumerable<ReadOnlyMemory<byte>> DoReadExactlyAsync(PipeReade
581602

582603
try
583604
{
584-
for (ReadOnlyMemory<byte> block;
585-
length > 0L && buffer.TryGet(ref consumed, out block, advance: false) && !block.IsEmpty;
586-
consumed = buffer.GetPosition(block.Length, consumed),
605+
for (var position = consumed;
606+
length > 0L && buffer.TryGet(ref position, out var block);
607+
consumed = position,
587608
length -= block.Length)
588609
{
589610
block = block.TrimLength(int.CreateSaturating(length));
590-
yield return block;
611+
if (!block.IsEmpty)
612+
yield return block;
591613
}
614+
615+
consumed = buffer.End;
592616
}
593617
finally
594618
{

src/DotNext.MaintenanceServices/DotNext.MaintenanceServices.csproj

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
<Authors>.NET Foundation and Contributors</Authors>
1212
<Company />
1313
<Product>.NEXT Family of Libraries</Product>
14-
<VersionPrefix>0.5.0</VersionPrefix>
14+
<VersionPrefix>0.6.0</VersionPrefix>
1515
<VersionSuffix></VersionSuffix>
1616
<AssemblyName>DotNext.MaintenanceServices</AssemblyName>
1717
<PackageLicenseExpression>MIT</PackageLicenseExpression>
@@ -49,10 +49,6 @@
4949
</ItemGroup>
5050

5151
<ItemGroup>
52-
<EmbeddedResource Include="ExceptionMessages.restext">
53-
<LogicalName>DotNext.ExceptionMessages.resources</LogicalName>
54-
<Generator></Generator>
55-
</EmbeddedResource>
5652
<EmbeddedResource Include="Maintenance/CommandLine/CommandResources.restext">
5753
<LogicalName>DotNext.Maintenance.CommandLine.CommandResources.resources</LogicalName>
5854
<Generator></Generator>

src/DotNext.MaintenanceServices/ExceptionMessages.restext

Whitespace-only changes.

src/DotNext.MaintenanceServices/Maintenance/ApplicationMaintenanceInterfaceHost.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ namespace DotNext.Maintenance;
1010

1111
using Buffers;
1212
using Collections.Specialized;
13+
using Runtime.CompilerServices;
1314
using Security.Principal;
1415
using static IO.TextStreamExtensions;
1516
using static Runtime.InteropServices.UnixDomainSocketInterop;
@@ -211,6 +212,7 @@ private async void ProcessRequestAsync(Socket clientSocket, CancellationToken to
211212
{
212213
clientSocket.Dispose();
213214
inputBuffer?.Dispose();
215+
outputBuffer?.Dispose();
214216
session?.Dispose();
215217
}
216218
}
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
using System.CommandLine;
2+
using System.CommandLine.Invocation;
3+
4+
namespace DotNext.Maintenance.CommandLine;
5+
6+
partial class ApplicationMaintenanceCommand
7+
{
8+
/// <summary>
9+
/// Represents synchronous command handler.
10+
/// </summary>
11+
public abstract class SynchronousAction : SynchronousCommandLineAction
12+
{
13+
/// <summary>
14+
/// Invokes the maintenance command.
15+
/// </summary>
16+
/// <param name="session">The maintenance session.</param>
17+
/// <param name="result">The parsing result.</param>
18+
/// <returns>Exit code.</returns>
19+
protected abstract int Invoke(IMaintenanceSession session, ParseResult result);
20+
21+
/// <inheritdoc />
22+
public sealed override int Invoke(ParseResult result)
23+
=> result.Configuration is CommandContext context ? Invoke(context.Session, result) : -1;
24+
}
25+
26+
private sealed class DelegatingSynchronousAction(Action<IMaintenanceSession, ParseResult> action) : SynchronousAction
27+
{
28+
protected override int Invoke(IMaintenanceSession session, ParseResult result)
29+
{
30+
action(session, result);
31+
return 0;
32+
}
33+
}
34+
35+
/// <summary>
36+
/// Represents asynchronous command handler.
37+
/// </summary>
38+
public abstract class AsynchronousAction : AsynchronousCommandLineAction
39+
{
40+
/// <summary>
41+
/// Invokes the maintenance command.
42+
/// </summary>
43+
/// <param name="session">The maintenance session.</param>
44+
/// <param name="result">The parsing result.</param>
45+
/// <param name="token">The token that can be used to cancel the operation.</param>
46+
/// <returns>Exit code.</returns>
47+
protected abstract Task<int> InvokeAsync(IMaintenanceSession session, ParseResult result, CancellationToken token);
48+
49+
/// <inheritdoc />
50+
public override Task<int> InvokeAsync(ParseResult result, CancellationToken token = default)
51+
=> result.Configuration is CommandContext context ? InvokeAsync(context.Session, result, token) : Task.FromResult(-1);
52+
}
53+
54+
private sealed class DelegatingAsynchronousAction(Func<IMaintenanceSession, ParseResult, CancellationToken, ValueTask> action)
55+
: AsynchronousAction
56+
{
57+
protected override async Task<int> InvokeAsync(IMaintenanceSession session, ParseResult result, CancellationToken token)
58+
{
59+
await action(session, result, token).ConfigureAwait(false);
60+
return 0;
61+
}
62+
}
63+
64+
/// <summary>
65+
/// Sets synchronous command handler.
66+
/// </summary>
67+
/// <param name="handler">The command handler.</param>
68+
/// <exception cref="ArgumentNullException"><paramref name="handler"/> is <see langword="null"/>.</exception>
69+
public void SetAction(Action<IMaintenanceSession, ParseResult> handler)
70+
{
71+
ArgumentNullException.ThrowIfNull(handler);
72+
Action = new DelegatingSynchronousAction(handler);
73+
}
74+
75+
/// <summary>
76+
/// Sets asynchronous command handler.
77+
/// </summary>
78+
/// <param name="handler">The command handler.</param>
79+
/// <exception cref="ArgumentNullException"><paramref name="handler"/> is <see langword="null"/>.</exception>
80+
public void SetAction(Func<IMaintenanceSession, ParseResult, CancellationToken, ValueTask> handler)
81+
{
82+
ArgumentNullException.ThrowIfNull(handler);
83+
Action = new DelegatingAsynchronousAction(handler);
84+
}
85+
}

0 commit comments

Comments
 (0)