Skip to content
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
7 changes: 4 additions & 3 deletions src/NATS.Client.ObjectStore/Models/ObjectMetadata.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,12 @@ public record ObjectMetadata
public string? Nuid { get; set; }

/// <summary>
/// Max chunk size
/// The size of the object in bytes.
/// It only includes the size of the object itself, not the metadata.
/// </summary>
[JsonPropertyName("size")]
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
public int Size { get; set; }
public ulong Size { get; set; }

/// <summary>
/// Modified timestamp
Expand All @@ -53,7 +54,7 @@ public record ObjectMetadata
/// </summary>
[JsonPropertyName("chunks")]
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
public int Chunks { get; set; }
public uint Chunks { get; set; }

@mtmk mtmk Oct 4, 2025

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

turns out this one is not align with the spec either (ADR-20)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have long (int 64) in both java and .net v1. ADR has uint32 so I think this is fine.


/// <summary>
/// Object digest
Expand Down
10 changes: 5 additions & 5 deletions src/NATS.Client.ObjectStore/NatsObjStore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ public async ValueTask<ObjectMetadata> GetAsync(string key, Stream stream, bool

string digest;
var chunks = 0;
var size = 0;
ulong size = 0;
using (var sha256 = SHA256.Create())
{
#if NETSTANDARD2_0
Expand All @@ -107,7 +107,7 @@ public async ValueTask<ObjectMetadata> GetAsync(string key, Stream stream, bool
{
using var memoryOwner = msg.Data;
chunks++;
size += memoryOwner.Memory.Length;
size += (ulong)memoryOwner.Memory.Length;
#if NETSTANDARD2_0
var segment = memoryOwner.DangerousGetArray();
await hashedStream.WriteAsync(segment.Array, segment.Offset, segment.Count, cancellationToken);
Expand Down Expand Up @@ -182,8 +182,8 @@ public async ValueTask<ObjectMetadata> PutAsync(ObjectMetadata meta, Stream stre
meta.Options.MaxChunkSize = DefaultChunkSize;
}

var size = 0;
var chunks = 0;
ulong size = 0;
uint chunks = 0;
var chunkSize = meta.Options.MaxChunkSize.Value;

string digest;
Expand Down Expand Up @@ -250,7 +250,7 @@ public async ValueTask<ObjectMetadata> PutAsync(ObjectMetadata meta, Stream stre

if (currentChunkSize > 0)
{
size += currentChunkSize;
size += (ulong)currentChunkSize;
chunks++;
}

Expand Down
51 changes: 46 additions & 5 deletions tests/NATS.Client.ObjectStore.Tests/ObjectStoreTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ public async Task Put_chunks()

Assert.Equal($"SHA-256={sha}", data.Digest);
Assert.Equal(chunks, data.Chunks);
Assert.Equal(size, data.Size);
Assert.Equal((ulong)size, data.Size);
}

// buffer with smaller last chunk
Expand All @@ -102,7 +102,7 @@ public async Task Put_chunks()

Assert.Equal($"SHA-256={sha}", data.Digest);
Assert.Equal(chunks, data.Chunks);
Assert.Equal(size, data.Size);
Assert.Equal((ulong)size, data.Size);
}

// Object name checks
Expand Down Expand Up @@ -195,7 +195,7 @@ public async Task Delete_object()
await store.PutAsync("k1", new byte[] { 65, 66, 67 }, cancellationToken);

var info = await store.GetInfoAsync("k1", cancellationToken: cancellationToken);
Assert.Equal(3, info.Size);
Assert.Equal(3UL, info.Size);

var bytes = await store.GetBytesAsync("k1", cancellationToken);
Assert.Equal(bytes, new byte[] { 65, 66, 67 });
Expand All @@ -207,8 +207,8 @@ public async Task Delete_object()

var info2 = await store.GetInfoAsync("k1", showDeleted: true, cancellationToken: cancellationToken);
Assert.True(info2.Deleted);
Assert.Equal(0, info2.Size);
Assert.Equal(0, info2.Chunks);
Assert.Equal(0UL, info2.Size);
Assert.Equal(0U, info2.Chunks);
Assert.Equal(string.Empty, info2.Digest);

// Put again
Expand Down Expand Up @@ -622,4 +622,45 @@ await Assert.ThrowsAsync<NatsObjNotFoundException>(async () =>
await b1.GetBytesAsync("name1", cancellationToken: cancellationToken);
});
}

[Fact]
public async Task Metadata_field_types_match_spec()
{
var cts = new CancellationTokenSource(TimeSpan.FromSeconds(10));
var cancellationToken = cts.Token;

await using var server = await NatsServerProcess.StartAsync();
await using var nats = new NatsConnection(new NatsOpts { Url = server.Url });
var js = new NatsJSContext(nats);
var obj = new NatsObjContext(js);

var store = await obj.CreateObjectStoreAsync(new NatsObjConfig("b1"), cancellationToken);

// Test that Size property is ulong (uint64 in NATS spec)
var metadata = new ObjectMetadata { Name = "test" };
metadata.Size = ulong.MaxValue; // Should compile without error
Assert.Equal(18446744073709551615UL, metadata.Size);

// Test that Chunks property is uint (uint32 in NATS spec)
metadata.Chunks = uint.MaxValue; // Should compile without error
Assert.Equal(4294967295U, metadata.Chunks);

// Test with actual object metadata from store
await store.PutAsync("k1", new byte[] { 1, 2, 3 }, cancellationToken: cancellationToken);
var info = await store.GetInfoAsync("k1", cancellationToken: cancellationToken);

// Verify Size is ulong
#pragma warning disable IDE0007
// ReSharper disable once SuggestVarOrType_BuiltInTypes
ulong size = info.Size; // Should compile without error

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

since using large files won't be possible I just check the type here.

#pragma warning restore IDE0007
Assert.Equal(3UL, size);

// Verify Chunks is uint
#pragma warning disable IDE0007
// ReSharper disable once SuggestVarOrType_BuiltInTypes
uint chunks = info.Chunks; // Should compile without error
#pragma warning restore IDE0007
Assert.Equal(1U, chunks);
}
}
2 changes: 1 addition & 1 deletion tests/NATS.Client.ObjectStore.Tests/WatcherTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public async Task Watcher_test()
{
count++;
signal.Pulse();
Assert.Equal(count, info.Size);
Assert.Equal((ulong)count, info.Size);
if (count == 3)
break;
}
Expand Down
Loading