From 1f8cf12d3a71713ed67eb17d42f13f22d9b9c3b6 Mon Sep 17 00:00:00 2001 From: Chris Lu Date: Sun, 18 Oct 2026 21:10:14 -0700 Subject: [PATCH] master: block allocation while the topology id is being minted DeferAllocation only armed after the topology id persisted, so growth requests arriving during init ran ahead of the warmup window. Gate NextVolumeId on an init-pending flag spanning the whole mint. --- weed/server/raft_common.go | 3 +++ weed/topology/topology.go | 13 +++++++++++++ 2 files changed, 16 insertions(+) diff --git a/weed/server/raft_common.go b/weed/server/raft_common.go index 4e4d7afc7d..5c1bd390cc 100644 --- a/weed/server/raft_common.go +++ b/weed/server/raft_common.go @@ -33,6 +33,9 @@ func EnsureTopologyId(topo *topology.Topology, checkLeaderFn func() bool, persis return } + topo.SetTopologyInitPending(true) + defer topo.SetTopologyInitPending(false) + topologyId := uuid.New().String() for { if !checkLeaderFn() { diff --git a/weed/topology/topology.go b/weed/topology/topology.go index e40c429a61..770ed81821 100644 --- a/weed/topology/topology.go +++ b/weed/topology/topology.go @@ -94,6 +94,7 @@ type Topology struct { freezeOnMismatch atomic.Bool stateLossRecoveryWait atomic.Int64 allocationNotBefore atomic.Int64 + topologyInitPending atomic.Bool } func NewTopology(id string, seq sequence.Sequencer, volumeSizeLimit uint64, pulse int, replicationAsMin bool) *Topology { @@ -400,6 +401,12 @@ func (t *Topology) NextVolumeId() (needle.VolumeId, error) { return 0, fmt.Errorf("as leader can not read yet") } + for t.topologyInitPending.Load() { + if !t.IsLeaderAndCanRead() { + return 0, fmt.Errorf("as leader can not read yet") + } + time.Sleep(100 * time.Millisecond) + } if t.IsGrowthFrozen() { return 0, fmt.Errorf("volume growth is frozen after master state loss; verify the cluster inventory, then run: volume.growth.resume") } @@ -1054,6 +1061,12 @@ func (t *Topology) applyGrowthFreeze(frozen bool) { } } +// SetTopologyInitPending gates allocation while a topology id is being +// minted, so growth cannot slip in before the warmup window is installed. +func (t *Topology) SetTopologyInitPending(pending bool) { + t.topologyInitPending.Store(pending) +} + // DeferAllocation holds off new id allocation for d. Called when the leader // mints a fresh topology id: on a rebuilt master that window gives veteran // servers a pulse to raise the bound or trip the freeze.