Skip to content

Commit

Permalink
Make NuidWriter public (#618)
Browse files Browse the repository at this point in the history
* Make NuidWriter public

* Build fixes

* Build fixes

* Build fixes

* Rename NuidWriter to Nuid

Renamed NuidWriter to Nuid across the codebase for clarity and brevity. Updated all relevant method calls and references to reflect the new naming convention.

* Update src/NATS.Client.Core/Nuid.cs

Co-authored-by: Jasper <jasper-d@users.noreply.github.com>

* Build fix

---------

Co-authored-by: Ziya Suzen <ziya@suzen.net>
Co-authored-by: mtmk <mtmk@mtmk.net>
Co-authored-by: Jasper <jasper-d@users.noreply.github.com>
  • Loading branch information
4 people authored Sep 4, 2024
1 parent 5847cea commit 426ea8c
Show file tree
Hide file tree
Showing 12 changed files with 66 additions and 72 deletions.
10 changes: 2 additions & 8 deletions .github/workflows/perf.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,17 +24,11 @@ jobs:
steps:
- name: Install nats
run: |
rel=$(curl -H 'Authorization: token ${{ secrets.AUTH_TOKEN_FOR_GITHUB_API }}' -s https://api.github.com/repos/nats-io/natscli/releases/latest | jq -r .tag_name | sed s/v//)
rel=$(curl https://api.mtmk.dev/gh/v1/releases/tag/nats-io/natscli/latest | sed s/v//)
wget https://github.com/nats-io/natscli/releases/download/v$rel/nats-$rel-linux-amd64.zip
unzip nats-$rel-linux-amd64.zip
sudo mv nats-$rel-linux-amd64/nats /usr/local/bin
gh_api_url="https://api.github.com/repos/nats-io/nats-server/releases"
branch="${{ matrix.config.branch }}"
if [[ $branch == "v"* ]]; then
branch=$(curl -H 'Authorization: token ${{ secrets.AUTH_TOKEN_FOR_GITHUB_API }}' -s $gh_api_url | jq -r '.[].tag_name' | grep $branch | sort -V | tail -1)
elif [[ $branch == "latest" ]]; then
branch=$(curl -H 'Authorization: token ${{ secrets.AUTH_TOKEN_FOR_GITHUB_API }}' -s $gh_api_url/latest | jq -r .tag_name)
fi
branch=$(curl https://api.mtmk.dev/gh/v1/releases/tag/nats-io/nats-server/${{ matrix.config.branch }})
for i in 1 2 3
do
curl -sf https://binaries.nats.dev/nats-io/nats-server/v2@$branch | PREFIX=. sh && break || sleep 30
Expand Down
16 changes: 2 additions & 14 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,7 @@ jobs:
steps:
- name: Install nats-server
run: |
gh_api_url="https://api.github.com/repos/nats-io/nats-server/releases"
branch="${{ matrix.config.branch }}"
if [[ $branch == "v"* ]]; then
branch=$(curl -H 'Authorization: token ${{ secrets.AUTH_TOKEN_FOR_GITHUB_API }}' -s $gh_api_url | jq -r '.[].tag_name' | grep $branch | sort -V | tail -1)
elif [[ $branch == "latest" ]]; then
branch=$(curl -H 'Authorization: token ${{ secrets.AUTH_TOKEN_FOR_GITHUB_API }}' -s $gh_api_url/latest | jq -r .tag_name)
fi
branch=$(curl https://api.mtmk.dev/gh/v1/releases/tag/nats-io/nats-server/${{ matrix.config.branch }})
for i in 1 2 3
do
curl -sf https://binaries.nats.dev/nats-io/nats-server/v2@$branch | PREFIX=. sh && break || sleep 30
Expand Down Expand Up @@ -119,13 +113,7 @@ jobs:
shell: bash
run: |
mkdir tools-nats-server && cd tools-nats-server
gh_api_url="https://api.github.com/repos/nats-io/nats-server/releases"
branch="${{ matrix.config.branch }}"
if [[ $branch == "v"* ]]; then
branch=$(curl -H 'Authorization: token ${{ secrets.AUTH_TOKEN_FOR_GITHUB_API }}' -s $gh_api_url | jq -r '.[].tag_name' | grep $branch | sort -V | tail -1)
elif [[ $branch == "latest" ]]; then
branch=$(curl -H 'Authorization: token ${{ secrets.AUTH_TOKEN_FOR_GITHUB_API }}' -s $gh_api_url/latest | jq -r .tag_name)
fi
branch=$(curl https://api.mtmk.dev/gh/v1/releases/tag/nats-io/nats-server/${{ matrix.config.branch }})
for i in 1 2 3
do
curl -sf https://binaries.nats.dev/nats-io/nats-server/v2@$branch | PREFIX=. sh && break || sleep 30
Expand Down
4 changes: 2 additions & 2 deletions sandbox/MicroBenchmark/NewInboxBenchmarks.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,14 @@ public class NewInboxBenchmarks
[GlobalSetup]
public void Setup()
{
NuidWriter.TryWriteNuid(new char[100]);
Nuid.TryWriteNuid(new char[100]);
}

[Benchmark(Baseline = true)]
[SkipLocalsInit]
public bool TryWriteNuid()
{
return NuidWriter.TryWriteNuid(_buf);
return Nuid.TryWriteNuid(_buf);
}

[Benchmark]
Expand Down
4 changes: 2 additions & 2 deletions src/NATS.Client.Core/NatsConnection.RequestReply.cs
Original file line number Diff line number Diff line change
Expand Up @@ -112,12 +112,12 @@ static void WriteBuffer(Span<char> buffer, (string prefix, int pfxLen) state)
state.prefix.AsSpan().CopyTo(buffer);
buffer[state.prefix.Length] = '.';
var remaining = buffer.Slice(state.pfxLen);
var didWrite = NuidWriter.TryWriteNuid(remaining);
var didWrite = Nuid.TryWriteNuid(remaining);
Debug.Assert(didWrite, "didWrite");
}

var separatorLength = prefix.Length > 0 ? 1 : 0;
var totalLength = prefix.Length + (int)NuidWriter.NuidLength + separatorLength;
var totalLength = prefix.Length + (int)Nuid.NuidLength + separatorLength;
var totalPrefixLength = prefix.Length + separatorLength;

#if NET6_0_OR_GREATER || NETSTANDARD2_1
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,17 @@
using Random = NATS.Client.Core.Internal.NetStandardExtensions.Random;
#endif

namespace NATS.Client.Core.Internal;

namespace NATS.Client.Core;

/// <summary>
/// Represents a unique identifier generator.
/// </summary>
/// <remarks>
/// The <c>Nuid</c> class generates unique identifiers that can be used
/// to ensure uniqueness in distributed systems.
/// </remarks>
[SkipLocalsInit]
internal sealed class NuidWriter
public sealed class Nuid
{
// NuidLength, PrefixLength, SequentialLength were nuint (System.UIntPtr) in the original code
// however, they were changed to uint to fix the compilation error for IL2CPP Unity projects.
Expand All @@ -25,13 +32,13 @@ internal sealed class NuidWriter
private const int MaxIncrement = 333;

[ThreadStatic]
private static NuidWriter? _writer;
private static Nuid? _writer;

private char[] _prefix;
private ulong _increment;
private ulong _sequential;

private NuidWriter()
private Nuid()
{
Refresh(out _);
}
Expand All @@ -42,25 +49,30 @@ private NuidWriter()
private static ReadOnlySpan<char> Digits => "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
#endif

public static bool TryWriteNuid(Span<char> nuidBuffer)
/// <summary>
/// Generates a new NATS unique identifier (NUID).
/// </summary>
/// <returns>A new NUID as a string.</returns>
/// <exception cref="InvalidOperationException">Thrown when unable to generate the NUID.</exception>
public static string NewNuid()
{
if (_writer is not null)
Span<char> buffer = stackalloc char[(int)NuidLength];
if (TryWriteNuid(buffer))
{
return _writer.TryWriteNuidCore(nuidBuffer);
return buffer.ToString();
}

return InitAndWrite(nuidBuffer);
throw new InvalidOperationException("Internal error: can't generate nuid");
}

public static string NewNuid()
internal static bool TryWriteNuid(Span<char> nuidBuffer)
{
Span<char> buffer = stackalloc char[22];
if (TryWriteNuid(buffer))
if (_writer is not null)
{
return buffer.ToString();
return _writer.TryWriteNuidCore(nuidBuffer);
}

throw new InvalidOperationException("Internal error: can't generate nuid");
return InitAndWrite(nuidBuffer);
}

private static bool TryWriteNuidCore(Span<char> buffer, Span<char> prefix, ulong sequential)
Expand Down Expand Up @@ -140,7 +152,7 @@ private static char[] GetPrefix(RandomNumberGenerator? rng = null)
[MethodImpl(MethodImplOptions.NoInlining)]
private static bool InitAndWrite(Span<char> span)
{
_writer = new NuidWriter();
_writer = new Nuid();
return _writer.TryWriteNuidCore(span);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -390,7 +390,7 @@ await _context.CreateOrUpdateConsumerAsync(
private string NewNuid()
{
Span<char> buffer = stackalloc char[22];
if (NuidWriter.TryWriteNuid(buffer))
if (Nuid.TryWriteNuid(buffer))
{
return buffer.ToString();
}
Expand Down
4 changes: 2 additions & 2 deletions src/NATS.Client.JetStream/NatsJSContext.Consumers.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
using System.Runtime.CompilerServices;
using NATS.Client.Core.Internal;
using NATS.Client.Core;
using NATS.Client.JetStream.Models;

namespace NATS.Client.JetStream;
Expand Down Expand Up @@ -228,7 +228,7 @@ internal ValueTask<ConsumerInfo> CreateOrderedConsumerInternalAsync(
request.Config.FilterSubjects = opts.FilterSubjects;
}

var name = NuidWriter.NewNuid();
var name = Nuid.NewNuid();
var subject = $"{Opts.Prefix}.CONSUMER.CREATE.{stream}.{name}";

return JSRequestResponseAsync<ConsumerCreateRequest, ConsumerInfo>(
Expand Down
2 changes: 1 addition & 1 deletion src/NATS.Client.KeyValueStore/Internal/NatsKVWatcher.cs
Original file line number Diff line number Diff line change
Expand Up @@ -444,7 +444,7 @@ private async ValueTask<INatsJSConsumer> CreatePushConsumer(string origin)
private string NewNuid()
{
Span<char> buffer = stackalloc char[22];
if (NuidWriter.TryWriteNuid(buffer))
if (Nuid.TryWriteNuid(buffer))
{
return buffer.ToString();
}
Expand Down
2 changes: 1 addition & 1 deletion src/NATS.Client.ObjectStore/NatsObjStore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -707,7 +707,7 @@ private async ValueTask PublishMeta(ObjectMetadata meta, CancellationToken cance
private string NewNuid()
{
Span<char> buffer = stackalloc char[22];
if (NuidWriter.TryWriteNuid(buffer))
if (Nuid.TryWriteNuid(buffer))
{
return buffer.ToString();
}
Expand Down
2 changes: 1 addition & 1 deletion src/NATS.Client.Services/NatsSvcServer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public class NatsSvcServer : INatsSvcServer
public NatsSvcServer(NatsConnection nats, NatsSvcConfig config, CancellationToken cancellationToken)
{
_logger = nats.Opts.LoggerFactory.CreateLogger<NatsSvcServer>();
_id = NuidWriter.NewNuid();
_id = Nuid.NewNuid();
_nats = nats;
_config = config;
_cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@

namespace NATS.Client.Core.Tests;

public class NuidWriterTests
public class NuidTests
{
private static readonly Regex NuidRegex = new("[A-z0-9]{22}");

private readonly ITestOutputHelper _outputHelper;

public NuidWriterTests(ITestOutputHelper outputHelper)
public NuidTests(ITestOutputHelper outputHelper)
{
_outputHelper = outputHelper;
}
Expand Down Expand Up @@ -42,7 +42,7 @@ public void GetNextNuid_ReturnsNuidOfLength22_Char()
Span<char> buffer = stackalloc char[44];

// Act
var result = NuidWriter.TryWriteNuid(buffer);
var result = Nuid.TryWriteNuid(buffer);

// Assert
ReadOnlySpan<char> lower = buffer.Slice(0, 22);
Expand All @@ -59,10 +59,10 @@ public void GetNextNuid_ReturnsNuidOfLength22_Char()
public void GetNextNuid_BufferToShort_False_Char()
{
// Arrange
Span<char> nuid = stackalloc char[(int)NuidWriter.NuidLength - 1];
Span<char> nuid = stackalloc char[(int)Nuid.NuidLength - 1];

// Act
var result = NuidWriter.TryWriteNuid(nuid);
var result = Nuid.TryWriteNuid(nuid);

// Assert
Assert.False(result);
Expand All @@ -77,8 +77,8 @@ public void GetNextNuid_ReturnsDifferentNuidEachTime_Char()
Span<char> secondNuid = stackalloc char[22];

// Act
var result = NuidWriter.TryWriteNuid(firstNuid);
result &= NuidWriter.TryWriteNuid(secondNuid);
var result = Nuid.TryWriteNuid(firstNuid);
result &= Nuid.TryWriteNuid(secondNuid);

// Assert
Assert.False(firstNuid.SequenceEqual(secondNuid));
Expand All @@ -93,8 +93,8 @@ public void GetNextNuid_PrefixIsConstant_Char()
Span<char> secondNuid = stackalloc char[22];

// Act
var result = NuidWriter.TryWriteNuid(firstNuid);
result &= NuidWriter.TryWriteNuid(secondNuid);
var result = Nuid.TryWriteNuid(firstNuid);
result &= Nuid.TryWriteNuid(secondNuid);

// Assert
Assert.True(result);
Expand All @@ -108,7 +108,7 @@ public void GetNextNuid_ContainsOnlyValidCharacters_Char()
Span<char> nuid = stackalloc char[22];

// Act
var result = NuidWriter.TryWriteNuid(nuid);
var result = Nuid.TryWriteNuid(nuid);

// Assert
Assert.True(result);
Expand All @@ -129,8 +129,8 @@ public void GetNextNuid_PrefixRenewed_Char()
var maxSequential = 839299365868340224ul - increment - 1;
SetSequentialAndIncrement(maxSequential, increment);

result = NuidWriter.TryWriteNuid(firstNuid);
result &= NuidWriter.TryWriteNuid(secondNuid);
result = Nuid.TryWriteNuid(firstNuid);
result &= Nuid.TryWriteNuid(secondNuid);
});

executionThread.Start();
Expand All @@ -148,7 +148,7 @@ public void GetPrefix_PrefixAsExpected()
var rngBytes = new byte[12] { 0, 1, 2, 3, 4, 5, 6, 7, 11, 253, 254, 255 };
DeterministicRng rng = new(new Queue<byte[]>(new[] { rngBytes, rngBytes }));

var mi = typeof(NuidWriter).GetMethod("GetPrefix", BindingFlags.Static | BindingFlags.NonPublic);
var mi = typeof(Nuid).GetMethod("GetPrefix", BindingFlags.Static | BindingFlags.NonPublic);
var mGetPrefix = mi!.CreateDelegate<Func<RandomNumberGenerator, char[]>>();

// Act
Expand All @@ -166,7 +166,7 @@ public void InitAndWrite_Char()
Thread t = new(() =>
{
var buffer = new char[22];
var didWrite = NuidWriter.TryWriteNuid(buffer);
var didWrite = Nuid.TryWriteNuid(buffer);

var isMatch = NuidRegex.IsMatch(new string(buffer));
Volatile.Write(ref completedSuccessfully, didWrite && isMatch);
Expand All @@ -192,7 +192,7 @@ public void DifferentThreads_DifferentPrefixes()
Thread t = new(() =>
{
var buffer = new char[22];
NuidWriter.TryWriteNuid(buffer);
Nuid.TryWriteNuid(buffer);
nuids.Enqueue((buffer, Environment.CurrentManagedThreadId));
});
t.Start();
Expand Down Expand Up @@ -226,7 +226,7 @@ public void AllNuidsAreUnique()

for (var i = 0; i < count; i++)
{
var didWrite = NuidWriter.TryWriteNuid(buffer);
var didWrite = Nuid.TryWriteNuid(buffer);

if (!didWrite)
{
Expand Down Expand Up @@ -259,7 +259,7 @@ public void AllNuidsAreUnique_SmallSequentials()

for (var i = 0; i < 2048; i++)
{
if (!NuidWriter.TryWriteNuid(buffer))
if (!Nuid.TryWriteNuid(buffer))
{
writeFailed = true;
return;
Expand Down Expand Up @@ -301,7 +301,7 @@ public void AllNuidsAreUnique_ZeroSequential()
Span<char> buffer = new char[22];
for (var i = 0; i < 100_000_000; i++)
{
if (!NuidWriter.TryWriteNuid(buffer))
if (!Nuid.TryWriteNuid(buffer))
{
writeFailed = true;
return;
Expand Down Expand Up @@ -333,11 +333,11 @@ public void Only_last_few_digits_change()
const int tail = 4;
const int head = 22 - tail;

var nuid1 = NuidWriter.NewNuid();
var nuid1 = Nuid.NewNuid();
var head1 = nuid1.Substring(0, head);
var tail1 = nuid1.Substring(head, tail);

var nuid2 = NuidWriter.NewNuid();
var nuid2 = Nuid.NewNuid();
var head2 = nuid2.Substring(0, head);
var tail2 = nuid2.Substring(head, tail);

Expand All @@ -350,17 +350,17 @@ public void Only_last_few_digits_change()
// on separate threads (distinct NuidWriter instances) only.
private static void SetSequentialAndIncrement(ulong sequential, ulong increment)
{
var didWrite = NuidWriter.TryWriteNuid(new char[128]);
var didWrite = Nuid.TryWriteNuid(new char[128]);

Assert.True(didWrite, "didWrite");

var fInstance = typeof(NuidWriter).GetField("_writer", BindingFlags.Static | BindingFlags.NonPublic);
var fInstance = typeof(Nuid).GetField("_writer", BindingFlags.Static | BindingFlags.NonPublic);
var instance = fInstance!.GetValue(null);

var fSequential = typeof(NuidWriter).GetField("_sequential", BindingFlags.Instance | BindingFlags.NonPublic);
var fSequential = typeof(Nuid).GetField("_sequential", BindingFlags.Instance | BindingFlags.NonPublic);
fSequential!.SetValue(instance, sequential);

var fIncrement = typeof(NuidWriter).GetField("_increment", BindingFlags.Instance | BindingFlags.NonPublic);
var fIncrement = typeof(Nuid).GetField("_increment", BindingFlags.Instance | BindingFlags.NonPublic);
fIncrement!.SetValue(instance, increment);
}

Expand Down
2 changes: 1 addition & 1 deletion tests/NATS.Client.KeyValueStore.Tests/KeyValueStoreTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -611,7 +611,7 @@ public async Task Validate_keys()
[Fact]
public async Task TestDirectMessageRepublishedSubject()
{
var streamBucketName = "sb-" + NuidWriter.NewNuid();
var streamBucketName = "sb-" + Nuid.NewNuid();
var subject = "test";
var streamSubject = subject + ".>";
var publishSubject1 = subject + ".one";
Expand Down

0 comments on commit 426ea8c

Please sign in to comment.