Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions central/cluster/lifecycle/gate.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,17 +53,18 @@ func (g *Gate) Enter(clusterID string) (active bool, release func()) {
}
}

// BeginDeletion prevents new active writes and waits for existing writes to finish.
// BeginDeletion prevents new active writes and waits for in-flight writes to finish.
// The returned function must be called once cluster cleanup completes.
func (g *Gate) BeginDeletion(clusterID string) func() {
e := g.retain(clusterID)
concurrency.WithLock(&e.stateMu, func() {
e.deleting = true
})
e.mu.Lock()
// Drain in-flight read locks, then release. Cleanup can exceed the dev
// mutex watchdog (10s), which aborts the process on a long exclusive hold.
concurrency.WithLock(&e.mu, func() {})

return func() {
concurrency.UnsafeUnlock(&e.mu)
concurrency.WithLock(&e.stateMu, func() {
e.deleting = false
})
Expand Down
18 changes: 18 additions & 0 deletions central/cluster/lifecycle/gate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,21 @@ func TestGateBlocksDeletionUntilActiveWriteCompletes(t *testing.T) {
require.True(t, active)
release()
}

// TestBeginDeletionDropsWriteLockBeforeCleanup checks that BeginDeletion only
// holds the write lock long enough to drain in-flight leases. The dev mutex
// watchdog aborts the process if that lock stays held through cleanup.
func TestBeginDeletionDropsWriteLockBeforeCleanup(t *testing.T) {
gate := New()
releaseDeletion := gate.BeginDeletion("cluster-id")
t.Cleanup(releaseDeletion)

e := gate.entries["cluster-id"]
require.NotNil(t, e)
require.True(t, e.mu.TryLock(), "write lock still held after BeginDeletion returned")
e.mu.Unlock()

active, release := gate.Enter("cluster-id")
require.False(t, active)
require.Nil(t, release)
}
Loading