feat: Phase 16M/17 + promote fixes + testrunner updates

Phase 16M: explicit replica readiness on heartbeat seam
- master.proto: optional bool replica_ready = 19 (proto regenerated on M01)
- block_heartbeat_proto.go: write/read ReplicaReady with presence semantics
- master_block_registry.go: replicaReadyObservedFromHeartbeat prefers
  explicit proto field, falls back to address heuristic when absent
- volume_server_block.go: heartbeat emits ReplicaReady from core projection

Phase 17: host effects extraction + stop line
- phase-17-log.md: Batch 10/11 delivery notes

Promote fixes:
- master_block_failover.go: deterministic replica addrs from path hash
- qa_promote_replication_test.go: address-upgrade trigger test
- qa_promote_rejoin_live_test.go: new live rejoin test

Testrunner:
- devops.go: action improvements
- recovery-baseline-failover.yaml, suite-ha-failover.yaml: scenario updates
- cp11b3-manual-promote.yaml: promote scenario alignment
- fresh_volume_write_test.go: new component test

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
pingqiuandClaude Opus 4.6 committed 2026-04-05 11:38:05 -07:00
1 parent 7855d5240c
commit cf16e53b04
22 files changed
+1204 -82

No files matched your search

+27 -15
View File
@@ -5,6 +5,7 @@ import (
"net/http"
"time"
engine "github.com/seaweedfs/seaweedfs/sw-block/engine/replication"
"github.com/seaweedfs/seaweedfs/weed/storage/blockvol"
)
@@ -17,21 +18,24 @@ type ShipperDebugInfo struct {
// BlockVolumeDebugInfo is the real-time block volume state.
type BlockVolumeDebugInfo struct {
Path string `json:"path"`
Role string `json:"role"`
Mode string `json:"mode,omitempty"`
Epoch uint64 `json:"epoch"`
HeadLSN uint64 `json:"head_lsn"`
Degraded bool `json:"degraded"`
RoleApplied bool `json:"role_applied"`
ReceiverReady bool `json:"receiver_ready"`
ShipperConfigured bool `json:"shipper_configured"`
ShipperConnected bool `json:"shipper_connected"`
ReplicaEligible bool `json:"replica_eligible"`
PublishHealthy bool `json:"publish_healthy"`
PublicationReason string `json:"publication_reason,omitempty"`
Shippers []ShipperDebugInfo `json:"shippers,omitempty"`
Timestamp string `json:"timestamp"`
Path string `json:"path"`
Role string `json:"role"`
Mode string `json:"mode,omitempty"`
Epoch uint64 `json:"epoch"`
HeadLSN uint64 `json:"head_lsn"`
Degraded bool `json:"degraded"`
RoleApplied bool `json:"role_applied"`
ReceiverReady bool `json:"receiver_ready"`
ShipperConfigured bool `json:"shipper_configured"`
ShipperConnected bool `json:"shipper_connected"`
ReplicaEligible bool `json:"replica_eligible"`
PublishHealthy bool `json:"publish_healthy"`
PublicationReason string `json:"publication_reason,omitempty"`
Shippers []ShipperDebugInfo `json:"shippers,omitempty"`
CoreProjection *engine.PublicationProjection `json:"core_projection,omitempty"`
ExecutedCoreCommands []string `json:"executed_core_commands,omitempty"`
ProjectionMismatches []string `json:"projection_mismatches,omitempty"`
Timestamp string `json:"timestamp"`
}
// DebugInfoForVolume returns the current debug surface for one volume. When the
@@ -64,6 +68,14 @@ func (bs *BlockService) DebugInfoForVolume(path string, vol *blockvol.BlockVol)
info.ReplicaEligible = proj.Readiness.ReplicaReady
info.PublishHealthy = proj.Publication.Healthy
info.PublicationReason = proj.Publication.Reason
projCopy := proj
info.CoreProjection = &projCopy
}
if cmds := bs.ExecutedCoreCommands(path); len(cmds) > 0 {
info.ExecutedCoreCommands = cmds
}
if mismatches := bs.CoreProjectionMismatches(path); len(mismatches) > 0 {
info.ProjectionMismatches = mismatches
}
return info
}