package daemon import ( "sync" "time" ) // asyncOp is the protocol shared by the long-running operation state types // (VM create, image build). Each operation has a stable ID, a done flag that // flips to true when its goroutine finishes, an UpdatedAt for pruning, and a // way to signal cancellation to its goroutine. type asyncOp interface { opID() string opIsDone() bool opUpdatedAt() time.Time opCancel() } // opRegistry is a mutex-guarded map of in-flight operations keyed by op ID. // One registry per operation kind; each owns its own lock, so registries do // not contend with each other or with Daemon.mu. type opRegistry[T asyncOp] struct { mu sync.Mutex byID map[string]T } func (r *opRegistry[T]) insert(op T) { r.mu.Lock() defer r.mu.Unlock() if r.byID == nil { r.byID = map[string]T{} } r.byID[op.opID()] = op } func (r *opRegistry[T]) get(id string) (T, bool) { r.mu.Lock() defer r.mu.Unlock() op, ok := r.byID[id] return op, ok } // prune drops completed operations last updated before the cutoff. func (r *opRegistry[T]) prune(before time.Time) { r.mu.Lock() defer r.mu.Unlock() for id, op := range r.byID { if !op.opIsDone() { continue } if op.opUpdatedAt().Before(before) { delete(r.byID, id) } } }