package csimanager import ( "sync" ) // volumeUsageTracker tracks the allocations that depend on a given volume type volumeUsageTracker struct { // state is a map of volumeUsageKey to a slice of allocation ids state map[volumeUsageKey][]string stateMu sync.Mutex } func newVolumeUsageTracker() *volumeUsageTracker { return &volumeUsageTracker{ state: make(map[volumeUsageKey][]string), } } type volumeUsageKey struct { id string usageOpts UsageOptions } func (v *volumeUsageTracker) allocsForKey(key volumeUsageKey) []string { return v.state[key] } func (v *volumeUsageTracker) appendAlloc(key volumeUsageKey, allocID string) { allocs := v.allocsForKey(key) allocs = append(allocs, allocID) v.state[key] = allocs } func (v *volumeUsageTracker) removeAlloc(key volumeUsageKey, needle string) { allocs := v.allocsForKey(key) var newAllocs []string for _, allocID := range allocs { if allocID != needle { newAllocs = append(newAllocs, allocID) } } if len(newAllocs) == 0 { delete(v.state, key) } else { v.state[key] = newAllocs } } func (v *volumeUsageTracker) Claim(allocID, volID string, usage *UsageOptions) { v.stateMu.Lock() defer v.stateMu.Unlock() key := volumeUsageKey{id: volID, usageOpts: *usage} v.appendAlloc(key, allocID) } // Free removes the allocation from the state list for the given alloc. If the // alloc is the last allocation for the volume then it returns true. func (v *volumeUsageTracker) Free(allocID, volID string, usage *UsageOptions) bool { v.stateMu.Lock() defer v.stateMu.Unlock() key := volumeUsageKey{id: volID, usageOpts: *usage} v.removeAlloc(key, allocID) allocs := v.allocsForKey(key) return len(allocs) == 0 }