feat: CP13-2 — canonical replica addressing on production truth surface

Problem: StartReplicaReceiver didn't forward advertisedHost to
NewReplicaReceiver, so wildcard-bind listeners relied on outbound-IP
fallback for canonicalization. On multi-NIC hosts this could select
the wrong interface, leaking non-routable addresses into replication
truth.

Fix:
- blockvol.go: StartReplicaReceiver now accepts optional advertisedHost
  variadic param and forwards it to NewReplicaReceiver
- volume_server_block.go: setupReplicaReceiver extracts host from
  localServerID (the canonical VS identity) and passes it as
  advertisedHost — wildcard-bind addresses now resolve to the
  authoritative server IP, not outbound-IP fallback

Proof (sync_all_bug_test.go TestBug3, upgraded from PASS* to PASS):
- fallback: wildcard bind without advertisedHost still produces ip:port
- advertisedHost: explicit host appears in exported DataAddr/CtrlAddr
- StartReplicaReceiver_API: public API forwards advertisedHost correctly

What CP13-2 does NOT change:
- No reconnect handshake changes (CP13-5)
- No retention policy changes (CP13-6)
- No rebuild behavior changes (CP13-7)
- No barrier protocol changes (CP13-3)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
pingqiuandClaude Opus 4.6 committed 2026-04-02 17:45:42 -07:00
1 parent ef740e0ebd
commit 2d47383df7
3 files changed
+89 -36

No files matched your search

+7 -3
View File
@@ -525,11 +525,15 @@ func (bs *BlockService) setupPrimaryReplicationMulti(path string, addrs []blockv
// setupReplicaReceiver starts the replica WAL receiver.
func (bs *BlockService) setupReplicaReceiver(path, dataAddr, ctrlAddr string) {
// Store canonical addresses from the receiver (not raw assignment addresses).
// The receiver canonicalizes wildcard ":port" to "ip:port" via CP13-2.
// CP13-2: Pass the canonical host from localServerID so wildcard-bind
// listeners resolve to the authoritative routable IP, not outbound-IP fallback.
advertisedHost := bs.localServerID
if idx := strings.LastIndex(advertisedHost, ":"); idx >= 0 {
advertisedHost = advertisedHost[:idx]
}
var canonDataAddr, canonCtrlAddr string
if err := bs.blockStore.WithVolume(path, func(vol *blockvol.BlockVol) error {
if err := vol.StartReplicaReceiver(dataAddr, ctrlAddr); err != nil {
if err := vol.StartReplicaReceiver(dataAddr, ctrlAddr, advertisedHost); err != nil {
return err
}
// Read back canonical addresses from the receiver.