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 97ac7d3002..74cd5ba653 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 // quarantinedVolumeIds are (node, vid) pairs force-read-only because the // vid collided across layouts. Kept separate from the reported flag so @@ -424,6 +425,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") } @@ -1192,6 +1199,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.