Skip to content

sync: SVS v3 large-group revision (mhash, PARTIAL, announce+pull)#190

Open
Taranum01 wants to merge 19 commits into
named-data:psvsfrom
Taranum01:svs-exploration
Open

sync: SVS v3 large-group revision (mhash, PARTIAL, announce+pull)#190
Taranum01 wants to merge 19 commits into
named-data:psvsfrom
Taranum01:svs-exploration

Conversation

@Taranum01

@Taranum01 Taranum01 commented Jun 29, 2026

Copy link
Copy Markdown

Summary

Implements the SVS v3 large-group revision (approved by Tianyuan Yu): inline FULL/PARTIAL sync, membership hash (mhash), and announce+pull recovery via published full vectors at 32=sv/<version>.

Event size ≤ threshold size > threshold
Publication Inline FULL Inline PARTIAL
Periodic sync Inline FULL Announce + pull
mhash mismatch Pull or sender announce Pull or sender announce

Backward compatible: SyncVectorThreshold defaults to 0 (legacy mode: StateVector-only wire, no mhash/VectorType, no announce+pull recovery — matches pre-revision DV prefix-table SVS). Large-group modes activate when threshold > 0.

Spec: docs/svs-v3-revision.md

Main changes

  • TLV: MemberSetHash, VectorType, SvsDataRef on SvsData (std/ndn/svs/v3)
  • Core: ComputeMhash, PARTIAL encode, publish at 32=sv, announce-only Sync, pull + merge (std/sync)
  • Example: std/examples/svs/large-sync (--threshold)
  • Tests: unit + in-process multi-node integration (std/sync/*_test.go, see svs_mesh_test.go)

Open item

Mixed-version interoperability (revised vs plain SVS v3 peers in one group) — spec §8; not addressed in this PR.

Test plan

  • go test ./std/sync/...
  • GitHub e2e (make e2e, sprint topology)
  • NFD smoke: 3× large-sync --threshold=80 on /ndn/svs/{alice,bob,carol} with multicast on /ndn/svs

Implements the approved large-group SVS revision with backward-compatible
defaults (SyncVectorThreshold=0). Adds mhash and PARTIAL/announce+pull paths,
32=sv publish/pull recovery, tests, and a large-sync example.

Co-authored-by: Cursor <cursoragent@cursor.com>
@Taranum01 Taranum01 changed the base branch from main to psvs June 29, 2026 17:07
Taranum Wasu and others added 6 commits June 29, 2026 22:43
Co-authored-by: Cursor <cursoragent@cursor.com>
Stop blind pulls to unpublished 32=sv prefixes on inline FULL mhash
mismatch (spec §5.6: merge inline first). Clone SvMap before encoding
outside the mutex to avoid concurrent map mutation panics.

Co-authored-by: Cursor <cursoragent@cursor.com>
DV prefix-table SVS uses default SyncVectorThreshold=0. Recovery was
still forcing announce-only sync on mhash mismatch, breaking step-2
prefix propagation while router reachability looked fine. Gate large-group
recovery behind threshold > 0 for true legacy behavior.

Co-authored-by: Cursor <cursoragent@cursor.com>
DV prefix-table sync uses default threshold 0. Emit StateVector-only
SvsData (no mhash/VectorType) so step-2 SVS matches pre-revision behavior
on the wire while large-group features stay behind threshold > 0.

Co-authored-by: Cursor <cursoragent@cursor.com>
Adds topo.min.conf (6 nodes) and make e2e-local for reliable local
validation on Mac Docker/Colima. Full sprint topo remains make e2e for CI.

Co-authored-by: Cursor <cursoragent@cursor.com>
Publish the revision spec alongside the std/sync implementation in PR named-data#190.

Co-authored-by: Cursor <cursoragent@cursor.com>
Comment thread e2e/topo.min.conf Outdated
@@ -0,0 +1,16 @@
# Small topology for local e2e (6 nodes, minimal link delays).

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Can we not introduce new topologies in e2e tests?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Removed in 79b79eetopo.min.conf, make e2e-local, and the docker script were local Mac dev helpers only. CI continues to use topo.sprint.conf.

Comment thread scripts/e2e-local-docker.sh Outdated
@@ -0,0 +1,21 @@
#!/usr/bin/env bash

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Can you explain why we need this extra things?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Removed in 79b79ee for the same reason — not needed in the upstream repo.

Comment thread std/engine/face/multicast_face.go Outdated
@@ -0,0 +1,82 @@
package face

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I am completely lost, we are revising the SVS protocol. Why invent the multicast face here?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Fair point. Removed std/engine/face/multicast_face.go in 79b79ee. The in-process mesh tests now use a test-only multicast hub in svs_mesh_test.go (same coverage, no new production face type).

Comment thread std/sync/svs.go Outdated
}
svsData = buildAnnounceSvsData(stateSnap, ref)
} else {
svsData = buildSvsDataForSend(

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Should use arg struct to avoid long parameter list.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Done in 79b79eebuildSvsDataForSend now takes a svsSendInput struct.

Comment thread std/sync/svs.go Outdated
mtimeSnap,
)
}
logSyncSend(s, reason, svsData)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Is this a leftover from your debugging?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Yes — removed in 79b79ee. Deleted svs_debug.go and the logSyncSend / logSyncRecv calls on the send/recv path.

Comment thread std/sync/svs_announce.go Outdated
}
return exceedsSyncThreshold(threshold, inlineFullSize(state))
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I worry those helper functions are not helping with readability and mainainability.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Addressed in 79b79ee — merged svs_announce.go into svs_pull.go (announce+pull recovery) and svs_encode.go (inline FULL/PARTIAL build) to reduce file sprawl.

Comment thread std/sync/svs_debug.go Outdated
@@ -0,0 +1,89 @@
package sync

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I don't see it is necessary to have this file -- if this is only for debugging.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Removed svs_debug.go entirely in 79b79ee.

Comment thread std/sync/svs_mesh_test.go Outdated
@@ -0,0 +1,157 @@
package sync

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Can you describe what this test is about?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Documented in 79b79ee — renamed to svs_mesh_test.go with a file-level comment. It is an in-process multi-node SVS harness (real engine + SvSync per node, test-only multicast hub) that exercises small-group sync, PARTIAL publication, and announce+pull recovery without mininet/NFD.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I don't see the necessity of this since we already have the e2e tests in CI

Remove local-only e2e topology and docker runner. Drop svs_debug and
production multicast_face; keep mesh integration tests with a test-only
hub in svs_mesh_test.go. Merge announce helpers into svs_pull, use
svsSendInput for buildSvsDataForSend, and remove debug send logging.

Co-authored-by: Cursor <cursoragent@cursor.com>
@Taranum01

Copy link
Copy Markdown
Author

Thanks for the review, @tianyuan129 — addressed in 79b79ee:

  • Removed local-only e2e topology / docker runner (topo.min.conf, e2e-local, e2e-local-docker.sh)
  • Removed production multicast_face; mesh integration tests use a test-only hub in svs_mesh_test.go
  • Removed svs_debug.go and debug send/recv logging
  • buildSvsDataForSend now takes a svsSendInput struct
  • Merged svs_announce.go into svs_pull.go + svs_encode.go

Also updated the PR description: SyncVectorThreshold=0 uses legacy StateVector-only wire (no mhash), which preserves DV prefix-table behavior and is what fixed e2e.

go test ./std/sync/... passes locally; CI should re-run on the new commit.

Remove dead large-sync debug flag and tuName helper, clarify threshold-0
comments, trim pull-path debug logging, rename announce tests to svs_pull_test,
and test pullRefFromSyncDataWire with a signed Sync Data wire.

Co-authored-by: Cursor <cursoragent@cursor.com>
@Taranum01

Copy link
Copy Markdown
Author

Pushed 60474b3 — minor style polish only (no logic changes): aligned `large-sync` with other SVS examples, clarified threshold-0 comments, trimmed pull-path debug logs, renamed `svs_announce_test.go` → `svs_pull_test.go`, and fixed `TestPullRefFromSyncDataWire` to use a real Sync Data wire.

Taranum Wasu and others added 2 commits July 4, 2026 22:53
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
@Taranum01

Copy link
Copy Markdown
Author

@tianyuan129 Pushed ffcc890 — fixes the test/lint failure (goimports column alignment in std/sync/svs_mesh_test.go). Could you re-run CI / re-review when convenient? No logic changes; only the field alignment in meshMulticastFace was touched.

Comment thread std/examples/svs/large-sync/main.go Outdated
@@ -0,0 +1,89 @@
package main

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

If we did not change the Sync API, I do not see the necessity of having a separate example.

Comment thread std/sync/svs.go

// SyncVectorThreshold is the max inline SvsData size (bytes).
// 0 = legacy mode (StateVector-only wire, no mhash or announce+pull recovery).
SyncVectorThreshold int

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

We don't need to be backward compatiable.

Comment thread std/sync/svs.go Outdated

recvSv: make(chan svSyncRecvSvArgs, 128),

fullVectorPrefix: deriveFullVectorPrefix(opts.SyncDataName),

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

The later deriveFullVectorPrefix merely replaces the last name component with another keyword, so I ams thinking about making fullVectorPrefix as another configurable in parallel to SyncDataName.

Comment thread std/sync/svs_encode.go Outdated
Comment on lines +33 to +68
// buildLegacySvsData is the pre-revision SVS v3 wire format used when threshold is 0.
func buildLegacySvsData(state SvMap[uint64]) *spec_svs.SvsData {
sv := state.Encode(func(seq uint64) uint64 { return seq })
return &spec_svs.SvsData{StateVector: sv}
}

// buildInlineSvsData constructs inline SvsData (mhash + VectorType + StateVector).
func buildInlineSvsData(state SvMap[uint64], vectorType uint64, sv *spec_svs.StateVector) *spec_svs.SvsData {
return &spec_svs.SvsData{
MemberSetHash: ComputeMhash(state),
VectorType: optional.Some(vectorType),
StateVector: sv,
}
}

// inlineSvsDataSize returns the encoded byte length of SvsData content.
func inlineSvsDataSize(data *spec_svs.SvsData) int {
return len(data.Encode().Join())
}

// exceedsSyncThreshold reports whether size is over the configured inline budget.
// threshold 0 disables the large-group size limit (legacy mode).
func exceedsSyncThreshold(threshold, size int) bool {
return threshold > 0 && size > threshold
}

// buildInlineFullFromState builds inline FULL SvsData for the complete local state.
func buildInlineFullFromState(state SvMap[uint64]) *spec_svs.SvsData {
sv := state.Encode(func(seq uint64) uint64 { return seq })
return buildInlineSvsData(state, spec_svs.VectorTypeFull, sv)
}

// inlineFullSize returns encoded inline FULL SvsData size for threshold checks.
func inlineFullSize(state SvMap[uint64]) int {
return inlineSvsDataSize(buildInlineFullFromState(state))
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Is there a reason that we must have those tiny helper functions?

I don't know....I prefer inline them for readability.

Comment thread std/sync/svs_mesh_test.go Outdated
@@ -0,0 +1,157 @@
package sync

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I don't see the necessity of this since we already have the e2e tests in CI

Comment thread std/sync/svs_mhash.go Outdated
Comment on lines +10 to +14
// membershipTuple is one (Name, BootstrapTime) pair in the sync group.
type membershipTuple struct {
name enc.Name
boot uint64
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Making this a separate TLV structure

Tuple-T Tuple-L, [Name, Boot]

so that you can use the ndnd standard TLV codec to simplify code.

Comment thread std/sync/svs_pull_test.go Outdated
@@ -0,0 +1,157 @@
package sync

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

We should put all svs related tests into one file.

Taranum Wasu added 8 commits July 9, 2026 12:52
Sync API for SvSync is unchanged; pure-sync suffices for svs examples.
Merge svs_encode_test.go, svs_mhash_test.go, svs_pull_test.go into the
single svs_test.go. svsmap tests remain separate (testing the generic
SvMap type, not the svs protocol). svsmat tests are dropped next.
The mesh-based end-to-end tests in svs_mesh_test.go are redundant with
the GitHub e2e tests (sprint topology) and add an in-process hub plus
test-only face type to the package. Remove them and the helper
functions in svs_test.go that depended on the mesh.
Fold buildLegacySvsData, buildInlineSvsData, inlineSvsDataSize,
exceedsSyncThreshold, buildInlineFullFromState and inlineFullSize into
the call sites that actually use them. The inline FULL/PARTIAL SvsData
structs are now visible at the build sites, matching the rest of the
encode path.
Add SvSyncOpts.FullVectorPrefix next to SyncDataName. When set, it is
used directly as the publish/serve prefix for retrievable FULL
StateVector Data used by announce+pull recovery. When unset, the
previous default (SyncDataName with trailing "32=svs" -> "32=sv") is
preserved.
Introduce spec_svs.MembershipTuple (Tuple-T 0xcc with Name and
BootstrapTime) in the v3 TLV definitions and use the standard TLV
codec in ComputeMhash instead of inlining a bespoke 0xD4 TLV byte.
All Sync messages now carry mhash and VectorType. The legacy
StateVector-only wire (and the threshold-0 paths that guarded it) is
removed from encode, shouldUseAnnouncePull and handleMhashMismatch.

SyncVectorThreshold defaults to 1200 bytes when 0 is supplied; the
gating is preserved for switching between inline FULL / PARTIAL /
announce+pull in large groups. The spec's §4.3 and §8 are updated to
document the no-backward-compat posture.
The previous batch of commits touched svs_test.go and svs_mhash.go but
left them non-canonical for gofmt (trailing blank line in svs_mhash.go)
and goimports (third-party testify imports not separated from local
named-data/ndnd imports in svs_test.go). Apply both.
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.

2 participants