- Fix pull consumer fetch: send original stream subject in HMSG (not inbox) so NATS client distinguishes data messages from control messages - Fix MaxAge expiry: add background timer in StreamManager for periodic pruning - Fix JetStream wire format: Go-compatible anonymous objects with string enums, proper offset-based pagination for stream/consumer list APIs - Add 42 E2E black-box tests (core messaging, auth, TLS, accounts, JetStream) - Add ~1000 parity tests across all subsystems (gaps closure) - Update gap inventory docs to reflect implementation status
36 KiB
36 KiB
Internal Data Structures — Gap Analysis
This file tracks what has and hasn't been ported from Go to .NET for the Internal Data Structures module. See stillmissing.md for the full LOC comparison across all modules.
LLM Instructions: How to Analyze This Category
Step 1: Read the Go Reference Files
Read each Go source file listed below. For every file:
- Extract all exported types (structs, interfaces, type aliases)
- Extract all exported methods on those types (receiver functions)
- Extract all exported standalone functions
- Note key constants, enums, and protocol states
- Note important unexported helpers that implement core logic (functions >20 lines)
- Pay attention to concurrency patterns (goroutines, mutexes, channels) — these map to different .NET patterns
Step 2: Read the .NET Implementation Files
Read all .cs files in the .NET directories listed below. For each Go symbol found in Step 1:
- Search for a matching type, method, or function in .NET
- If found, compare the behavior: does it handle the same edge cases? Same error paths?
- If partially implemented, note what's missing
- If not found, note it as MISSING
Step 3: Cross-Reference Tests
Compare Go test functions against .NET test methods:
- For each Go
Test*function, check if a corresponding .NET[Fact]or[Theory]exists - Note which test scenarios are covered and which are missing
- Check the parity DB (
docs/test_parity.db) for existing mappings:sqlite3 docs/test_parity.db "SELECT go_test, dotnet_test, confidence FROM test_mappings tm JOIN go_tests gt ON tm.go_test_id=gt.rowid JOIN dotnet_tests dt ON tm.dotnet_test_id=dt.rowid WHERE gt.go_file LIKE '%PATTERN%'"
Step 4: Classify Each Item
Use these status values:
| Status | Meaning |
|---|---|
| PORTED | Equivalent exists in .NET with matching behavior |
| PARTIAL | .NET implementation exists but is incomplete (missing edge cases, error handling, or features) |
| MISSING | No .NET equivalent found — needs to be ported |
| NOT_APPLICABLE | Go-specific pattern that doesn't apply to .NET (build tags, platform-specific goroutine tricks, etc.) |
| DEFERRED | Intentionally skipped for now (document why) |
Step 5: Fill In the Gap Inventory
Add rows to the Gap Inventory table below. Group by Go source file. Include the Go file and line number so a porting LLM can jump directly to the reference implementation.
Key Porting Notes for Internal Data Structures
- This category is at 105% LOC parity — above Go.
- The subject tree (stree) uses adaptive node sizing (4→10→16→48→256 children) for memory efficiency.
- The AVL tree is used for tracking acknowledged sequences in JetStream consumers.
- The time hash wheel provides O(1) TTL expiration checks.
- PSE (platform-specific extensions) queries process RSS/CPU — may use
System.Diagnostics.Processin .NET. - sysmem queries total system memory — may use
GC.GetGCMemoryInfo()or P/Invoke in .NET. - Many Go files in pse/ and sysmem/ are platform-specific build-tagged files — classify platform-irrelevant ones as NOT_APPLICABLE.
Go Reference Files (Source)
golang/nats-server/server/avl/seqset.go— AVL tree for sparse sequence sets (JetStream ack tracking)golang/nats-server/server/stree/— Subject tree with adaptive nodes (node4, node10, node16, node48, node256) for per-subject state in streams. 11 files.golang/nats-server/server/thw/thw.go— Time hash wheel for efficient TTL expirationgolang/nats-server/server/gsl/gsl.go— Generic subject list, optimized trie variantgolang/nats-server/server/pse/— Platform-specific extensions (proc info: RSS, CPU). 12 files across platforms.golang/nats-server/server/sysmem/— System memory queries. 8 files across platforms.
Go Reference Files (Tests)
golang/nats-server/server/avl/seqset_test.gogolang/nats-server/server/stree/stree_test.gogolang/nats-server/server/thw/thw_test.gogolang/nats-server/server/gsl/gsl_test.go
.NET Implementation Files (Source)
src/NATS.Server/Internal/(all files including subdirectories)src/NATS.Server/Internal/Avl/src/NATS.Server/Internal/Gsl/src/NATS.Server/Internal/SubjectTree/src/NATS.Server/Internal/TimeHashWheel/
.NET Implementation Files (Tests)
tests/NATS.Server.Tests/Internal/(all subdirectories)
Gap Inventory
avl/seqset.go
| Go Symbol | Go File:Line | Status | .NET Equivalent | Notes |
|---|---|---|---|---|
SequenceSet (struct) |
golang/nats-server/server/avl/seqset.go:33 |
PORTED | src/NATS.Server/Internal/Avl/SequenceSet.cs:26 |
Full class with all fields |
SequenceSet.Insert |
golang/nats-server/server/avl/seqset.go:44 |
PORTED | src/NATS.Server/Internal/Avl/SequenceSet.cs:52 |
|
SequenceSet.Exists |
golang/nats-server/server/avl/seqset.go:52 |
PORTED | src/NATS.Server/Internal/Avl/SequenceSet.cs:63 |
|
SequenceSet.SetInitialMin |
golang/nats-server/server/avl/seqset.go:69 |
PORTED | src/NATS.Server/Internal/Avl/SequenceSet.cs:89 |
Go returns error; .NET throws |
SequenceSet.Delete |
golang/nats-server/server/avl/seqset.go:80 |
PORTED | src/NATS.Server/Internal/Avl/SequenceSet.cs:103 |
|
SequenceSet.Size |
golang/nats-server/server/avl/seqset.go:97 |
PORTED | src/NATS.Server/Internal/Avl/SequenceSet.cs:43 |
Property in .NET |
SequenceSet.Nodes |
golang/nats-server/server/avl/seqset.go:102 |
PORTED | src/NATS.Server/Internal/Avl/SequenceSet.cs:46 |
Property in .NET |
SequenceSet.Empty |
golang/nats-server/server/avl/seqset.go:107 |
PORTED | src/NATS.Server/Internal/Avl/SequenceSet.cs:127 |
|
SequenceSet.IsEmpty |
golang/nats-server/server/avl/seqset.go:114 |
PORTED | src/NATS.Server/Internal/Avl/SequenceSet.cs:49 |
Property in .NET |
SequenceSet.Range |
golang/nats-server/server/avl/seqset.go:124 |
PORTED | src/NATS.Server/Internal/Avl/SequenceSet.cs:138 |
|
SequenceSet.Heights |
golang/nats-server/server/avl/seqset.go:129 |
PORTED | src/NATS.Server/Internal/Avl/SequenceSet.cs:141 |
Returns tuple in .NET |
SequenceSet.State |
golang/nats-server/server/avl/seqset.go:143 |
PORTED | src/NATS.Server/Internal/Avl/SequenceSet.cs:153 |
Returns named tuple |
SequenceSet.MinMax |
golang/nats-server/server/avl/seqset.go:152 |
PORTED | src/NATS.Server/Internal/Avl/SequenceSet.cs:166 |
|
clone (unexported) |
golang/nats-server/server/avl/seqset.go:169 |
PORTED | src/NATS.Server/Internal/Avl/SequenceSet.cs:424 |
CloneNode private static method |
SequenceSet.Clone |
golang/nats-server/server/avl/seqset.go:180 |
PORTED | src/NATS.Server/Internal/Avl/SequenceSet.cs:195 |
|
SequenceSet.Union (method) |
golang/nats-server/server/avl/seqset.go:191 |
PORTED | src/NATS.Server/Internal/Avl/SequenceSet.cs:203 |
|
Union (function) |
golang/nats-server/server/avl/seqset.go:208 |
PORTED | src/NATS.Server/Internal/Avl/SequenceSet.cs:228 |
SequenceSet.CreateUnion static method |
SequenceSet.EncodeLen |
golang/nats-server/server/avl/seqset.go:238 |
PORTED | src/NATS.Server/Internal/Avl/SequenceSet.cs:252 |
EncodeLength() in .NET |
SequenceSet.Encode |
golang/nats-server/server/avl/seqset.go:242 |
PORTED | src/NATS.Server/Internal/Avl/SequenceSet.cs:266 |
Added destination-buffer overload (Encode(byte[] destination)) enabling caller buffer reuse parity |
ErrBadEncoding |
golang/nats-server/server/avl/seqset.go:276 |
PORTED | src/NATS.Server/Internal/Avl/SequenceSet.cs:288 |
Thrown as InvalidOperationException |
ErrBadVersion |
golang/nats-server/server/avl/seqset.go:277 |
PORTED | src/NATS.Server/Internal/Avl/SequenceSet.cs:295 |
Thrown as InvalidOperationException |
ErrSetNotEmpty |
golang/nats-server/server/avl/seqset.go:278 |
PORTED | src/NATS.Server/Internal/Avl/SequenceSet.cs:93 |
Thrown as InvalidOperationException |
Decode |
golang/nats-server/server/avl/seqset.go:282 |
PORTED | src/NATS.Server/Internal/Avl/SequenceSet.cs:285 |
Static method, same v1/v2 dispatch |
decodev2 (unexported) |
golang/nats-server/server/avl/seqset.go:298 |
PORTED | src/NATS.Server/Internal/Avl/SequenceSet.cs:300 |
DecodeV2 private static |
decodev1 (unexported) |
golang/nats-server/server/avl/seqset.go:329 |
PORTED | src/NATS.Server/Internal/Avl/SequenceSet.cs:338 |
DecodeV1 private static |
SequenceSet.insertNode (unexported) |
golang/nats-server/server/avl/seqset.go:376 |
PORTED | src/NATS.Server/Internal/Avl/SequenceSet.cs:389 |
InsertNode private method |
node (struct) |
golang/nats-server/server/avl/seqset.go:407 |
PORTED | src/NATS.Server/Internal/Avl/SequenceSet.cs:439 |
Node nested class |
node.set |
golang/nats-server/server/avl/seqset.go:418 |
PORTED | src/NATS.Server/Internal/Avl/SequenceSet.cs:448 |
SetBit |
node.insert |
golang/nats-server/server/avl/seqset.go:428 |
PORTED | src/NATS.Server/Internal/Avl/SequenceSet.cs:521 |
Node.Insert static |
node.rotateL |
golang/nats-server/server/avl/seqset.go:464 |
PORTED | src/NATS.Server/Internal/Avl/SequenceSet.cs:672 |
RotateLeft private static |
node.rotateR |
golang/nats-server/server/avl/seqset.go:478 |
PORTED | src/NATS.Server/Internal/Avl/SequenceSet.cs:692 |
RotateRight private static |
balanceF |
golang/nats-server/server/avl/seqset.go:492 |
PORTED | src/NATS.Server/Internal/Avl/SequenceSet.cs:711 |
BalanceFactor internal static |
maxH |
golang/nats-server/server/avl/seqset.go:506 |
PORTED | src/NATS.Server/Internal/Avl/SequenceSet.cs:724 |
MaxHeight internal static |
node.clear |
golang/nats-server/server/avl/seqset.go:526 |
PORTED | src/NATS.Server/Internal/Avl/SequenceSet.cs:461 |
ClearBit |
node.delete |
golang/nats-server/server/avl/seqset.go:542 |
PORTED | src/NATS.Server/Internal/Avl/SequenceSet.cs:571 |
Node.Delete static |
node.insertNodePrev |
golang/nats-server/server/avl/seqset.go:588 |
PORTED | src/NATS.Server/Internal/Avl/SequenceSet.cs:635 |
InsertNodePrev private static |
node.exists |
golang/nats-server/server/avl/seqset.go:613 |
PORTED | src/NATS.Server/Internal/Avl/SequenceSet.cs:484 |
ExistsBit |
node.min |
golang/nats-server/server/avl/seqset.go:622 |
PORTED | src/NATS.Server/Internal/Avl/SequenceSet.cs:493 |
Min() |
node.max |
golang/nats-server/server/avl/seqset.go:635 |
PORTED | src/NATS.Server/Internal/Avl/SequenceSet.cs:508 |
Max() |
node.nodeIter |
golang/nats-server/server/avl/seqset.go:647 |
PORTED | src/NATS.Server/Internal/Avl/SequenceSet.cs:738 |
NodeIter internal static |
node.iter |
golang/nats-server/server/avl/seqset.go:658 |
PORTED | src/NATS.Server/Internal/Avl/SequenceSet.cs:751 |
Iter internal static |
stree/stree.go
| Go Symbol | Go File:Line | Status | .NET Equivalent | Notes |
|---|---|---|---|---|
SubjectTree[T] (struct) |
golang/nats-server/server/stree/stree.go:28 |
PORTED | src/NATS.Server/Internal/SubjectTree/SubjectTree.cs:9 |
|
NewSubjectTree[T] |
golang/nats-server/server/stree/stree.go:34 |
PORTED | src/NATS.Server/Internal/SubjectTree/SubjectTree.cs:9 |
In .NET, new SubjectTree<T>() used directly |
SubjectTree.Size |
golang/nats-server/server/stree/stree.go:39 |
PORTED | src/NATS.Server/Internal/SubjectTree/SubjectTree.cs:17 |
|
SubjectTree.Empty |
golang/nats-server/server/stree/stree.go:47 |
PORTED | src/NATS.Server/Internal/SubjectTree/SubjectTree.cs:22 |
|
SubjectTree.Insert |
golang/nats-server/server/stree/stree.go:56 |
PORTED | src/NATS.Server/Internal/SubjectTree/SubjectTree.cs:33 |
Signature uses ReadOnlySpan<byte> |
SubjectTree.Find |
golang/nats-server/server/stree/stree.go:74 |
PORTED | src/NATS.Server/Internal/SubjectTree/SubjectTree.cs:52 |
|
SubjectTree.Delete |
golang/nats-server/server/stree/stree.go:106 |
PORTED | src/NATS.Server/Internal/SubjectTree/SubjectTree.cs:97 |
|
SubjectTree.Match |
golang/nats-server/server/stree/stree.go:119 |
PORTED | src/NATS.Server/Internal/SubjectTree/SubjectTree.cs:115 |
|
SubjectTree.MatchUntil |
golang/nats-server/server/stree/stree.go:137 |
PORTED | src/NATS.Server/Internal/SubjectTree/SubjectTree.cs:135 |
|
SubjectTree.IterOrdered |
golang/nats-server/server/stree/stree.go:149 |
PORTED | src/NATS.Server/Internal/SubjectTree/SubjectTree.cs:149 |
|
SubjectTree.IterFast |
golang/nats-server/server/stree/stree.go:158 |
PORTED | src/NATS.Server/Internal/SubjectTree/SubjectTree.cs:158 |
|
SubjectTree.insert (internal) |
golang/nats-server/server/stree/stree.go:169 |
PORTED | src/NATS.Server/Internal/SubjectTree/SubjectTree.cs:170 |
InsertInternal |
SubjectTree.delete (internal) |
golang/nats-server/server/stree/stree.go:253 |
PORTED | src/NATS.Server/Internal/SubjectTree/SubjectTree.cs:286 |
DeleteInternal |
SubjectTree.match (internal) |
golang/nats-server/server/stree/stree.go:318 |
PORTED | src/NATS.Server/Internal/SubjectTree/SubjectTree.cs:383 |
MatchInternal |
SubjectTree.iter (internal) |
golang/nats-server/server/stree/stree.go:418 |
PORTED | src/NATS.Server/Internal/SubjectTree/SubjectTree.cs:512 |
IterInternal |
LazyIntersect[TL,TR] |
golang/nats-server/server/stree/stree.go:463 |
PORTED | src/NATS.Server/Internal/SubjectTree/SubjectTree.cs:584 |
SubjectTreeHelper.LazyIntersect static |
IntersectGSL[T,SL] |
golang/nats-server/server/stree/stree.go:488 |
PORTED | src/NATS.Server/Internal/SubjectTree/SubjectTree.cs:675 |
Added GSL intersection traversal for subject tree entries |
_intersectGSL (internal) |
golang/nats-server/server/stree/stree.go:496 |
PORTED | src/NATS.Server/Internal/SubjectTree/SubjectTree.cs:686 |
Added recursive intersection helper |
hasInterestForTokens (internal) |
golang/nats-server/server/stree/stree.go:521 |
PORTED | src/NATS.Server/Internal/SubjectTree/SubjectTree.cs:717 |
Added token-boundary short-circuit using HasInterestStartingIn |
bytesToString (internal) |
golang/nats-server/server/stree/stree.go:534 |
NOT_APPLICABLE | — | Go unsafe zero-copy string conversion. In .NET, System.Text.Encoding.UTF8.GetString or MemoryMarshal.Cast used instead |
stree/node.go
| Go Symbol | Go File:Line | Status | .NET Equivalent | Notes |
|---|---|---|---|---|
node (interface) |
golang/nats-server/server/stree/node.go:17 |
PORTED | src/NATS.Server/Internal/SubjectTree/Nodes.cs:7 |
INode interface |
meta (struct) |
golang/nats-server/server/stree/node.go:35 |
PORTED | src/NATS.Server/Internal/SubjectTree/Nodes.cs:46 |
NodeMeta class |
meta.isLeaf |
golang/nats-server/server/stree/node.go:40 |
PORTED | src/NATS.Server/Internal/SubjectTree/Nodes.cs:9 |
Via INode.IsLeaf |
meta.base |
golang/nats-server/server/stree/node.go:41 |
PORTED | src/NATS.Server/Internal/SubjectTree/Nodes.cs:10 |
Via INode.Base |
meta.setPrefix |
golang/nats-server/server/stree/node.go:43 |
PORTED | src/NATS.Server/Internal/SubjectTree/Nodes.cs:11 |
Via INode.SetPrefix |
meta.numChildren |
golang/nats-server/server/stree/node.go:47 |
PORTED | src/NATS.Server/Internal/SubjectTree/Nodes.cs:26 |
Via INode.NumChildren |
meta.path |
golang/nats-server/server/stree/node.go:48 |
PORTED | src/NATS.Server/Internal/SubjectTree/Nodes.cs:27 |
Via INode.Path |
meta.matchParts |
golang/nats-server/server/stree/node.go:51 |
PORTED | src/NATS.Server/Internal/SubjectTree/Nodes.cs:22 |
Via INode.MatchParts |
stree/leaf.go
| Go Symbol | Go File:Line | Status | .NET Equivalent | Notes |
|---|---|---|---|---|
leaf[T] (struct) |
golang/nats-server/server/stree/leaf.go:23 |
PORTED | src/NATS.Server/Internal/SubjectTree/Nodes.cs:58 |
Leaf<T> class |
newLeaf[T] |
golang/nats-server/server/stree/leaf.go:30 |
PORTED | src/NATS.Server/Internal/SubjectTree/Nodes.cs:63 |
new Leaf<T>(suffix, value) constructor |
leaf.isLeaf |
golang/nats-server/server/stree/leaf.go:34 |
PORTED | src/NATS.Server/Internal/SubjectTree/Nodes.cs:69 |
|
leaf.base |
golang/nats-server/server/stree/leaf.go:34 |
PORTED | src/NATS.Server/Internal/SubjectTree/Nodes.cs:70 |
Returns null |
leaf.match |
golang/nats-server/server/stree/leaf.go:36 |
PORTED | src/NATS.Server/Internal/SubjectTree/Nodes.cs:75 |
|
leaf.setSuffix |
golang/nats-server/server/stree/leaf.go:37 |
PORTED | src/NATS.Server/Internal/SubjectTree/Nodes.cs:77 |
|
leaf.matchParts |
golang/nats-server/server/stree/leaf.go:39 |
PORTED | src/NATS.Server/Internal/SubjectTree/Nodes.cs:85 |
|
leaf.iter |
golang/nats-server/server/stree/leaf.go:40 |
PORTED | src/NATS.Server/Internal/SubjectTree/Nodes.cs:83 |
No-op on leaf |
leaf.children |
golang/nats-server/server/stree/leaf.go:41 |
PORTED | src/NATS.Server/Internal/SubjectTree/Nodes.cs:81 |
Returns empty array |
leaf.numChildren |
golang/nats-server/server/stree/leaf.go:42 |
PORTED | src/NATS.Server/Internal/SubjectTree/Nodes.cs:72 |
Returns 0 |
leaf.path |
golang/nats-server/server/stree/leaf.go:43 |
PORTED | src/NATS.Server/Internal/SubjectTree/Nodes.cs:79 |
Returns suffix |
stree/node4.go
| Go Symbol | Go File:Line | Status | .NET Equivalent | Notes |
|---|---|---|---|---|
node4 (struct) |
golang/nats-server/server/stree/node4.go:18 |
PORTED | src/NATS.Server/Internal/SubjectTree/Nodes.cs:105 |
Node4 class |
newNode4 |
golang/nats-server/server/stree/node4.go:24 |
PORTED | src/NATS.Server/Internal/SubjectTree/Nodes.cs:111 |
Constructor |
node4.addChild |
golang/nats-server/server/stree/node4.go:31 |
PORTED | src/NATS.Server/Internal/SubjectTree/Nodes.cs:128 |
|
node4.findChild |
golang/nats-server/server/stree/node4.go:40 |
PORTED | src/NATS.Server/Internal/SubjectTree/Nodes.cs:136 |
Returns ChildRef? wrapper |
node4.isFull |
golang/nats-server/server/stree/node4.go:49 |
PORTED | src/NATS.Server/Internal/SubjectTree/Nodes.cs:119 |
|
node4.grow |
golang/nats-server/server/stree/node4.go:51 |
PORTED | src/NATS.Server/Internal/SubjectTree/Nodes.cs:174 |
|
node4.deleteChild |
golang/nats-server/server/stree/node4.go:60 |
PORTED | src/NATS.Server/Internal/SubjectTree/Nodes.cs:149 |
|
node4.shrink |
golang/nats-server/server/stree/node4.go:80 |
PORTED | src/NATS.Server/Internal/SubjectTree/Nodes.cs:184 |
|
node4.iter |
golang/nats-server/server/stree/node4.go:88 |
PORTED | src/NATS.Server/Internal/SubjectTree/Nodes.cs:190 |
|
node4.children |
golang/nats-server/server/stree/node4.go:96 |
PORTED | src/NATS.Server/Internal/SubjectTree/Nodes.cs:198 |
stree/node10.go
| Go Symbol | Go File:Line | Status | .NET Equivalent | Notes |
|---|---|---|---|---|
node10 (struct) |
golang/nats-server/server/stree/node10.go:20 |
PORTED | src/NATS.Server/Internal/SubjectTree/Nodes.cs:217 |
Node10 class |
newNode10 |
golang/nats-server/server/stree/node10.go:26 |
PORTED | src/NATS.Server/Internal/SubjectTree/Nodes.cs:223 |
Constructor |
node10.addChild |
golang/nats-server/server/stree/node10.go:34 |
PORTED | src/NATS.Server/Internal/SubjectTree/Nodes.cs:240 |
|
node10.findChild |
golang/nats-server/server/stree/node10.go:43 |
PORTED | src/NATS.Server/Internal/SubjectTree/Nodes.cs:248 |
|
node10.isFull |
golang/nats-server/server/stree/node10.go:52 |
PORTED | src/NATS.Server/Internal/SubjectTree/Nodes.cs:231 |
|
node10.grow |
golang/nats-server/server/stree/node10.go:54 |
PORTED | src/NATS.Server/Internal/SubjectTree/Nodes.cs:286 |
|
node10.deleteChild |
golang/nats-server/server/stree/node10.go:63 |
PORTED | src/NATS.Server/Internal/SubjectTree/Nodes.cs:258 |
|
node10.shrink |
golang/nats-server/server/stree/node10.go:83 |
PORTED | src/NATS.Server/Internal/SubjectTree/Nodes.cs:295 |
|
node10.iter |
golang/nats-server/server/stree/node10.go:95 |
PORTED | src/NATS.Server/Internal/SubjectTree/Nodes.cs:307 |
|
node10.children |
golang/nats-server/server/stree/node10.go:103 |
PORTED | src/NATS.Server/Internal/SubjectTree/Nodes.cs:315 |
stree/node16.go, stree/node48.go, stree/node256.go
| Go Symbol | Go File:Line | Status | .NET Equivalent | Notes |
|---|---|---|---|---|
node16 (struct) |
golang/nats-server/server/stree/node16.go |
PORTED | src/NATS.Server/Internal/SubjectTree/Nodes.cs:334 |
Node16 class |
node48 (struct) |
golang/nats-server/server/stree/node48.go |
PORTED | src/NATS.Server/Internal/SubjectTree/Nodes.cs:451 |
Node48 class |
node256 (struct) |
golang/nats-server/server/stree/node256.go |
PORTED | src/NATS.Server/Internal/SubjectTree/Nodes.cs:569 |
Node256 class |
stree/parts.go
| Go Symbol | Go File:Line | Status | .NET Equivalent | Notes |
|---|---|---|---|---|
genParts |
golang/nats-server/server/stree/parts.go:23 |
PORTED | src/NATS.Server/Internal/SubjectTree/Parts.cs:57 |
Parts.GenParts static method |
matchParts |
golang/nats-server/server/stree/parts.go:78 |
PORTED | src/NATS.Server/Internal/SubjectTree/Parts.cs:145 |
Parts.MatchPartsAgainstFragment |
stree/util.go
| Go Symbol | Go File:Line | Status | .NET Equivalent | Notes |
|---|---|---|---|---|
pwc, fwc, tsep constants |
golang/nats-server/server/stree/util.go:17 |
PORTED | src/NATS.Server/Internal/SubjectTree/Parts.cs:10 |
Parts.Pwc, Parts.Fwc, Parts.Tsep |
commonPrefixLen |
golang/nats-server/server/stree/util.go:24 |
PORTED | src/NATS.Server/Internal/SubjectTree/Parts.cs:33 |
Parts.CommonPrefixLen |
copyBytes |
golang/nats-server/server/stree/util.go:36 |
PORTED | src/NATS.Server/Internal/SubjectTree/Parts.cs:47 |
Parts.CopyBytes |
position (interface) |
golang/nats-server/server/stree/util.go:45 |
NOT_APPLICABLE | — | Go generic constraint on numeric types; not needed in .NET |
noPivot constant |
golang/nats-server/server/stree/util.go:48 |
PORTED | src/NATS.Server/Internal/SubjectTree/Parts.cs:17 |
Parts.NoPivot |
pivot |
golang/nats-server/server/stree/util.go:52 |
PORTED | src/NATS.Server/Internal/SubjectTree/Parts.cs:23 |
Parts.Pivot |
stree/dump.go
| Go Symbol | Go File:Line | Status | .NET Equivalent | Notes |
|---|---|---|---|---|
SubjectTree.Dump |
golang/nats-server/server/stree/dump.go:23 |
PORTED | src/NATS.Server/Internal/SubjectTree/SubjectTree.cs:172 |
Added debug dump writer with root traversal and trailing newline |
SubjectTree.dump (internal) |
golang/nats-server/server/stree/dump.go:29 |
PORTED | src/NATS.Server/Internal/SubjectTree/SubjectTree.cs:180 |
Added recursive node/leaf dump helper |
dumpPre |
golang/nats-server/server/stree/dump.go:59 |
PORTED | src/NATS.Server/Internal/SubjectTree/SubjectTree.cs:205 |
Added indentation helper matching Go depth formatting |
leaf.kind, node4.kind, etc. |
golang/nats-server/server/stree/dump.go:51 |
PORTED | src/NATS.Server/Internal/SubjectTree/Nodes.cs:21 |
INode.Kind values are now actively consumed by SubjectTree.Dump output |
thw/thw.go
| Go Symbol | Go File:Line | Status | .NET Equivalent | Notes |
|---|---|---|---|---|
ErrTaskNotFound |
golang/nats-server/server/thw/thw.go:25 |
PORTED | src/NATS.Server/Internal/TimeHashWheel/HashWheel.cs:91 |
Returned as false/exception instead of error |
ErrInvalidVersion |
golang/nats-server/server/thw/thw.go:28 |
PORTED | src/NATS.Server/Internal/TimeHashWheel/HashWheel.cs:289 |
Thrown as InvalidOperationException |
slot (struct) |
golang/nats-server/server/thw/thw.go:39 |
PORTED | src/NATS.Server/Internal/TimeHashWheel/HashWheel.cs:406 |
Slot internal class |
HashWheel (struct) |
golang/nats-server/server/thw/thw.go:45 |
PORTED | src/NATS.Server/Internal/TimeHashWheel/HashWheel.cs:17 |
HashWheel class |
HashWheelEntry (struct) |
golang/nats-server/server/thw/thw.go:52 |
PORTED | src/NATS.Server/Internal/TimeHashWheel/HashWheel.cs:407 |
Added HashWheelEntry record struct (Sequence, Expires) |
NewHashWheel |
golang/nats-server/server/thw/thw.go:58 |
PORTED | src/NATS.Server/Internal/TimeHashWheel/HashWheel.cs:34 |
Constructor in .NET |
HashWheel.getPosition (internal) |
golang/nats-server/server/thw/thw.go:66 |
PORTED | src/NATS.Server/Internal/TimeHashWheel/HashWheel.cs:50 |
GetPosition private static |
newSlot (internal) |
golang/nats-server/server/thw/thw.go:71 |
PORTED | src/NATS.Server/Internal/TimeHashWheel/HashWheel.cs:406 |
Inline slot initialization in .NET |
HashWheel.Add |
golang/nats-server/server/thw/thw.go:79 |
PORTED | src/NATS.Server/Internal/TimeHashWheel/HashWheel.cs:60 |
Return type void vs error (never errors in practice) |
HashWheel.Remove |
golang/nats-server/server/thw/thw.go:103 |
PORTED | src/NATS.Server/Internal/TimeHashWheel/HashWheel.cs:91 |
Returns bool instead of error |
HashWheel.Update |
golang/nats-server/server/thw/thw.go:123 |
PORTED | src/NATS.Server/Internal/TimeHashWheel/HashWheel.cs:122 |
|
HashWheel.ExpireTasks |
golang/nats-server/server/thw/thw.go:133 |
PORTED | src/NATS.Server/Internal/TimeHashWheel/HashWheel.cs:135 |
|
HashWheel.expireTasks (internal) |
golang/nats-server/server/thw/thw.go:138 |
PORTED | src/NATS.Server/Internal/TimeHashWheel/HashWheel.cs:148 |
ExpireTasksInternal — public in .NET for testability |
HashWheel.GetNextExpiration |
golang/nats-server/server/thw/thw.go:182 |
PORTED | src/NATS.Server/Internal/TimeHashWheel/HashWheel.cs:219 |
|
HashWheel.Count |
golang/nats-server/server/thw/thw.go:190 |
PORTED | src/NATS.Server/Internal/TimeHashWheel/HashWheel.cs:44 |
Property in .NET |
HashWheel.Encode |
golang/nats-server/server/thw/thw.go:197 |
PORTED | src/NATS.Server/Internal/TimeHashWheel/HashWheel.cs:235 |
|
HashWheel.Decode |
golang/nats-server/server/thw/thw.go:216 |
PORTED | src/NATS.Server/Internal/TimeHashWheel/HashWheel.cs:282 |
Returns (highSeq, bytesRead) tuple; Go returns (uint64, error) |
gsl/gsl.go
| Go Symbol | Go File:Line | Status | .NET Equivalent | Notes |
|---|---|---|---|---|
ErrInvalidSubject |
golang/nats-server/server/gsl/gsl.go:41 |
PORTED | src/NATS.Server/Internal/Gsl/GenericSubjectList.cs:11 |
GslErrors.InvalidSubject |
ErrNotFound |
golang/nats-server/server/gsl/gsl.go:42 |
PORTED | src/NATS.Server/Internal/Gsl/GenericSubjectList.cs:12 |
GslErrors.NotFound |
ErrNilChan |
golang/nats-server/server/gsl/gsl.go:43 |
NOT_APPLICABLE | — | Go channel-specific error; channels don't apply to .NET pattern |
ErrAlreadyRegistered |
golang/nats-server/server/gsl/gsl.go:44 |
NOT_APPLICABLE | — | Used by notification channels in Go; no notification channel pattern in .NET port |
SimpleSublist (type alias) |
golang/nats-server/server/gsl/gsl.go:49 |
PORTED | src/NATS.Server/Internal/Gsl/GenericSubjectList.cs:656 |
SimpleSubjectList now aliases GenericSubjectList<SimpleSublistValue> where marker value mirrors Go's empty struct payload |
NewSimpleSublist |
golang/nats-server/server/gsl/gsl.go:52 |
PORTED | src/NATS.Server/Internal/Gsl/GenericSubjectList.cs:650 |
new SimpleSubjectList() |
GenericSublist[T] (struct) |
golang/nats-server/server/gsl/gsl.go:57 |
PORTED | src/NATS.Server/Internal/Gsl/GenericSubjectList.cs:76 |
GenericSubjectList<T> |
node[T] (struct) |
golang/nats-server/server/gsl/gsl.go:64 |
PORTED | src/NATS.Server/Internal/Gsl/GenericSubjectList.cs:52 |
Node<T> |
level[T] (struct) |
golang/nats-server/server/gsl/gsl.go:71 |
PORTED | src/NATS.Server/Internal/Gsl/GenericSubjectList.cs:19 |
Level<T> |
newNode[T] |
golang/nats-server/server/gsl/gsl.go:77 |
PORTED | src/NATS.Server/Internal/Gsl/GenericSubjectList.cs:52 |
Inline new Node<T>() |
newLevel[T] |
golang/nats-server/server/gsl/gsl.go:82 |
PORTED | src/NATS.Server/Internal/Gsl/GenericSubjectList.cs:19 |
Inline new Level<T>() |
NewSublist[T] |
golang/nats-server/server/gsl/gsl.go:87 |
PORTED | src/NATS.Server/Internal/Gsl/GenericSubjectList.cs:76 |
new GenericSubjectList<T>() constructor |
GenericSublist.Insert |
golang/nats-server/server/gsl/gsl.go:92 |
PORTED | src/NATS.Server/Internal/Gsl/GenericSubjectList.cs:110 |
Throws instead of returning error |
GenericSublist.Match |
golang/nats-server/server/gsl/gsl.go:150 |
PORTED | src/NATS.Server/Internal/Gsl/GenericSubjectList.cs:205 |
|
GenericSublist.MatchBytes |
golang/nats-server/server/gsl/gsl.go:156 |
PORTED | src/NATS.Server/Internal/Gsl/GenericSubjectList.cs:214 |
|
GenericSublist.HasInterest |
golang/nats-server/server/gsl/gsl.go:162 |
PORTED | src/NATS.Server/Internal/Gsl/GenericSubjectList.cs:225 |
|
GenericSublist.NumInterest |
golang/nats-server/server/gsl/gsl.go:168 |
PORTED | src/NATS.Server/Internal/Gsl/GenericSubjectList.cs:234 |
|
GenericSublist.match (internal) |
golang/nats-server/server/gsl/gsl.go:173 |
PORTED | src/NATS.Server/Internal/Gsl/GenericSubjectList.cs:274 |
MatchInternal |
GenericSublist.hasInterest (internal) |
golang/nats-server/server/gsl/gsl.go:198 |
PORTED | src/NATS.Server/Internal/Gsl/GenericSubjectList.cs:295 |
HasInterestInternal |
matchLevelForAny[T] |
golang/nats-server/server/gsl/gsl.go:223 |
PORTED | src/NATS.Server/Internal/Gsl/GenericSubjectList.cs:400 |
MatchLevelForAny private static |
callbacksForResults[T] |
golang/nats-server/server/gsl/gsl.go:266 |
PORTED | src/NATS.Server/Internal/Gsl/GenericSubjectList.cs:448 |
CallbacksForResults private static |
matchLevel[T] |
golang/nats-server/server/gsl/gsl.go:273 |
PORTED | src/NATS.Server/Internal/Gsl/GenericSubjectList.cs:371 |
MatchLevel private static |
lnt[T] (struct) |
golang/nats-server/server/gsl/gsl.go:301 |
PORTED | src/NATS.Server/Internal/Gsl/GenericSubjectList.cs:68 |
Lnt<T> record struct |
GenericSublist.remove (internal) |
golang/nats-server/server/gsl/gsl.go:308 |
PORTED | src/NATS.Server/Internal/Gsl/GenericSubjectList.cs:458 |
RemoveInternal |
GenericSublist.Remove |
golang/nats-server/server/gsl/gsl.go:368 |
PORTED | src/NATS.Server/Internal/Gsl/GenericSubjectList.cs:188 |
|
GenericSublist.HasInterestStartingIn |
golang/nats-server/server/gsl/gsl.go:373 |
PORTED | src/NATS.Server/Internal/Gsl/GenericSubjectList.cs:245 |
|
hasInterestStartingIn[T] (internal) |
golang/nats-server/server/gsl/gsl.go:381 |
PORTED | src/NATS.Server/Internal/Gsl/GenericSubjectList.cs:537 |
HasInterestStartingInLevel private static |
level.pruneNode |
golang/nats-server/server/gsl/gsl.go:403 |
PORTED | src/NATS.Server/Internal/Gsl/GenericSubjectList.cs:37 |
Level<T>.PruneNode |
node.isEmpty |
golang/nats-server/server/gsl/gsl.go:418 |
PORTED | src/NATS.Server/Internal/Gsl/GenericSubjectList.cs:61 |
Node<T>.IsEmpty() |
level.numNodes |
golang/nats-server/server/gsl/gsl.go:423 |
PORTED | src/NATS.Server/Internal/Gsl/GenericSubjectList.cs:25 |
Level<T>.NumNodes() |
GenericSublist.removeFromNode (internal) |
golang/nats-server/server/gsl/gsl.go:438 |
PORTED | src/NATS.Server/Internal/Gsl/GenericSubjectList.cs:527 |
RemoveFromNode private static |
GenericSublist.Count |
golang/nats-server/server/gsl/gsl.go:449 |
PORTED | src/NATS.Server/Internal/Gsl/GenericSubjectList.cs:90 |
|
GenericSublist.numLevels (internal) |
golang/nats-server/server/gsl/gsl.go:457 |
PORTED | src/NATS.Server/Internal/Gsl/GenericSubjectList.cs:264 |
NumLevels() internal |
visitLevel[T] |
golang/nats-server/server/gsl/gsl.go:463 |
PORTED | src/NATS.Server/Internal/Gsl/GenericSubjectList.cs:557 |
VisitLevel private static |
tokenizeSubjectIntoSlice |
golang/nats-server/server/gsl/gsl.go:496 |
PORTED | src/NATS.Server/Internal/Gsl/GenericSubjectList.cs:348 |
TokenizeSubjectIntoSpan |
pse/ (Platform-Specific Extensions)
| Go Symbol | Go File:Line | Status | .NET Equivalent | Notes |
|---|---|---|---|---|
ProcUsage (darwin) |
golang/nats-server/server/pse/pse_darwin.go:83 |
PORTED | src/NATS.Server/Monitoring/VarzHandler.cs:35 |
CPU via Process.TotalProcessorTime; RSS via proc.WorkingSet64. Equivalent behavior in /varz reporting. |
ProcUsage (linux) |
golang/nats-server/server/pse/pse_linux.go |
PORTED | src/NATS.Server/Monitoring/VarzHandler.cs:35 |
Same cross-platform .NET equivalent |
ProcUsage (windows) |
golang/nats-server/server/pse/pse_windows.go |
PORTED | src/NATS.Server/Monitoring/VarzHandler.cs:35 |
Same cross-platform .NET equivalent |
ProcUsage (freebsd/netbsd/openbsd/dragonfly/solaris/zos) |
golang/nats-server/server/pse/pse_*.go |
NOT_APPLICABLE | — | Platform-specific Go build-tagged files. .NET runtime abstracts these OS differences. |
ProcUsage (wasm/rumprun) |
golang/nats-server/server/pse/pse_wasm.go |
NOT_APPLICABLE | — | Stub/no-op implementations for unsupported platforms; not needed in .NET |
updateUsage (darwin, internal) |
golang/nats-server/server/pse/pse_darwin.go:56 |
PORTED | src/NATS.Server/Monitoring/VarzHandler.cs:39 |
CPU sampling logic in VarzHandler |
periodic (darwin, internal) |
golang/nats-server/server/pse/pse_darwin.go:76 |
PORTED | src/NATS.Server/Monitoring/VarzHandler.cs:30 |
Added 1s background timer sampler (SampleCpuUsage) with synchronized cached CPU reads in /varz, matching periodic semantics instead of request-only sampling |
sysmem/ (System Memory Queries)
| Go Symbol | Go File:Line | Status | .NET Equivalent | Notes |
|---|---|---|---|---|
Memory (darwin) |
golang/nats-server/server/sysmem/mem_darwin.go:18 |
PORTED | src/NATS.Server/Internal/SysMem/SystemMemory.cs:12 |
Added cross-platform SystemMemory.Memory() backed by runtime memory info |
Memory (linux) |
golang/nats-server/server/sysmem/mem_linux.go:20 |
PORTED | src/NATS.Server/Internal/SysMem/SystemMemory.cs:12 |
Added cross-platform SystemMemory.Memory() backed by runtime memory info |
Memory (windows) |
golang/nats-server/server/sysmem/mem_windows.go |
PORTED | src/NATS.Server/Internal/SysMem/SystemMemory.cs:12 |
Added cross-platform SystemMemory.Memory() backed by runtime memory info |
Memory (bsd/solaris/wasm/zos) |
golang/nats-server/server/sysmem/mem_bsd.go etc. |
NOT_APPLICABLE | — | Platform-specific stubs; .NET runtime abstracts these. GCMemoryInfo is the cross-platform equivalent. |
sysctlInt64 |
golang/nats-server/server/sysmem/sysctl.go:23 |
NOT_APPLICABLE | — | Darwin/BSD internal helper using unsafe sysctl; .NET abstracts this entirely |
Keeping This File Updated
After porting work is completed:
- Update status: Change
MISSING → PORTEDorPARTIAL → PORTEDfor each item completed - Add .NET path: Fill in the ".NET Equivalent" column with the actual file:line
- Re-count LOC: Update the LOC numbers in
stillmissing.md:# Re-count .NET source LOC for this module find src/NATS.Server/Internal/ -name '*.cs' -type f -exec cat {} + | wc -l # Re-count .NET test LOC for this module find tests/NATS.Server.Tests/Internal/ -name '*.cs' -type f -exec cat {} + | wc -l - Add a changelog entry below with date and summary of what was ported
- Update the parity DB if new test mappings were created:
sqlite3 docs/test_parity.db "INSERT INTO test_mappings (go_test_id, dotnet_test_id, confidence, notes) VALUES (?, ?, 'manual', 'ported in YYYY-MM-DD session')"
Change Log
| Date | Change | By |
|---|---|---|
| 2026-02-25 | File created with LLM analysis instructions | auto |
| 2026-02-25 | Full gap inventory populated: 157 PORTED, 4 PARTIAL, 10 MISSING, 8 NOT_APPLICABLE, 0 DEFERRED | auto |
| 2026-02-25 | Completed periodic PSE parity by moving CPU sampling to a 1s background timer in VarzHandler and adding targeted parity test coverage |
codex |