Skip to content

Shipping a major vNext release of SequentialGuid (zero-alloc generation, drop obsolete API, Native AOT) #22

Merged
buvinghausen merged 21 commits into
masterfrom
vNext
May 12, 2026
Merged

Shipping a major vNext release of SequentialGuid (zero-alloc generation, drop obsolete API, Native AOT) #22
buvinghausen merged 21 commits into
masterfrom
vNext

Conversation

@buvinghausen

@buvinghausen buvinghausen commented May 12, 2026

Copy link
Copy Markdown
Owner

Summary

Major release. Three logical phases on vNext:

  1. PerfGuidV4, GuidV7, GuidV8Time use stackalloc byte[16] on NET6+; GuidNameBased digest is stack-allocated; GuidV8Time machine fingerprint hash switched SHA-512 → SHA-256; struct ctors stop the parallel Timestamp read. Generation benchmarks now show Allocated: 0 B on .NET 8/9/10.
  2. Cleanup (breaking) — Removed obsolete SequentialGuidGenerator family and public GuidV{7,8}.Timestamp static properties. Consolidated struct-ctor disambiguation logic into internal SequentialGuidByteOrder.TryDetect. Loosened TicksExtensions.IsDateTime upper bound by 1 s for clock-skew slack.
  3. Native AOTIsAotCompatible=true on all four production projects. New test/SequentialGuid.AotSmokeTest publishes as Native AOT and runs in CI.

Breaking changes

  • SequentialGuidGenerator.Instance.NewGuid()GuidV8Time.NewGuid()
  • SequentialSqlGuidGenerator.Instance.NewSqlGuid()GuidV8Time.NewSqlGuid()
  • GuidV7.Timestamp / GuidV8Time.Timestamp → use DateTime.UtcNow directly
  • SequentialGuid.NodaTime SequentialGuidGeneratorExtensions / SequentialSqlGuidGeneratorExtensions removed; use GuidV8TimeExtensions instead

What's in the diff

20 commits, 34 files changed, net −38 lines.

Phase Commits
Perf ae6df05 Span overloads · 7e33751 GuidV4 stackalloc · 4c550b5 GuidV7 stackalloc · 3151538 GuidV8Time stackalloc · 4b6a2df+15569ad SHA-256 fingerprint · 559a182 GuidNameBased stackalloc · 576134d struct-ctor parallel-read removal · 999fbc8 bench unsealing
Cleanup aac4ce9 TryDetect helper · c0e68a4 struct ctors use TryDetect · 84cb07e IsDateTime slack · 3f4ff5d delete obsolete generators · 6466428 delete Timestamp properties · ae57104 delete Upgrade Guide
AOT 2ce044f IsAotCompatible flags · 17de09f AOT smoke test project · e73f5f9 CI step · ea175c8 README AOT bullet
Polish aceeab8 .gitignore for agent/benchmark artifacts

Test plan

  • dotnet build clean on all 5 TFMs (0 warnings under TreatWarningsAsErrors=true)
  • dotnet test — 25,003 tests pass across net8.0/net9.0/net10.0/net472
  • New TicksExtensionsTests covers the 1 s slack boundary explicitly
  • BenchmarkDotNet generation benchmarks: 0 B allocated for GuidV4, GuidV7, GuidV7.NewSqlGuid, GuidV8Time, GuidV8Time.NewSqlGuid (matches
    Guid.NewGuid baseline)
  • AOT smoke test compiles clean with PublishAot=true and IsAotCompatible=true; JIT run prints AOT smoke test: PASS
  • CI's new AOT publish + run step — verified locally up to the C++ link step (local machine missing the MSVC linker); the runtime check happens on the
    windows-latest runner

Suggested follow-ups (out of scope here)

  • GuidV5.Create(byte[]) and GuidV8Name.Create(byte[]) still allocate ~176 B per call from IncrementalHash + Guid.ToByteArray(true). Could be addressed on
    NET8+ with SHA256.HashData(ReadOnlySpan, ReadOnlySpan, Span) + Guid.TryWriteBytes(span, bigEndian: true).
  • Two-commit history on the V8Time fingerprint hash change (4b6a2df SHA-1 attempt → 15569ad SHA-256 final, reverted because CA5350 flagged SHA-1 as weak).
    Squash-merge cleans this up if you prefer.
  • Add a deterministic test for the SQL-V8 false-positive guard in SequentialGuidByteOrder.TryDetect (the case where a SQL-ordered V8 GUID's b[7] high nibble
    accidentally is 7 or 8).

References

buvinghausen and others added 21 commits May 12, 2026 10:30
CA5350 flagged SHA-1 as weak. SHA-256 gives the same perf win over SHA-512
for a 3-byte fingerprint and clears the analyzer.
…ce methods

BenchmarkDotNet rejects sealed classes and static [Benchmark] methods.
Suppress CA1822 in the benchmark csproj since instance methods are required by BDN.
BREAKING CHANGE: SequentialGuidGenerator and SequentialSqlGuidGenerator are
removed. Use GuidV8Time.NewGuid() / GuidV8Time.NewSqlGuid() instead.
BREAKING CHANGE: GuidV7.Timestamp and GuidV8Time.Timestamp static properties
are removed. Use DateTime.UtcNow directly. The struct constructors decode
their Timestamp property from the generated Value (since v[prior] of PR1).
Exercises every public entry point of the core SequentialGuid package
(GuidV4/V5/V7/V8Time/V8Name factory methods, SequentialGuid and
SequentialSqlGuid struct ctors, SQL byte-order round-trips, JSON
converter registration) and asserts each one returns a usable value.

The project sets PublishAot=true and IsAotCompatible=true so trim/AOT
analyzers run at build time; JSON round-trip uses a source-generated
JsonSerializerContext to stay trimmer- and AOT-safe. Inherited
xunit/Shouldly references from test/Directory.Build.props are stripped
because this is a plain executable, not a test project.

JIT run prints "AOT smoke test: PASS" and exits 0.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@buvinghausen buvinghausen merged commit 27d454a into master May 12, 2026
1 check passed
@buvinghausen buvinghausen deleted the vNext branch May 12, 2026 17:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant