github.com/cloudbase/juju-core@v0.0.0-20140504232958-a7271ac7912f/state/apiserver/common/resource.go (about) 1 // Copyright 2013 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package common 5 6 import ( 7 "strconv" 8 "sync" 9 10 "launchpad.net/juju-core/log" 11 ) 12 13 // Resource represents any resource that should be cleaned up when an 14 // API connection terminates. The Stop method will be called when 15 // that happens. 16 type Resource interface { 17 Stop() error 18 } 19 20 // Resources holds all the resources for a connection. 21 // It allows the registration of resources that will be cleaned 22 // up when a connection terminates. 23 type Resources struct { 24 mu sync.Mutex 25 maxId uint64 26 resources map[string]Resource 27 } 28 29 func NewResources() *Resources { 30 return &Resources{ 31 resources: make(map[string]Resource), 32 } 33 } 34 35 // Get returns the resource for the given id, or 36 // nil if there is no such resource. 37 func (rs *Resources) Get(id string) Resource { 38 rs.mu.Lock() 39 defer rs.mu.Unlock() 40 return rs.resources[id] 41 } 42 43 // Register registers the given resource. It returns a unique 44 // identifier for the resource which can then be used in 45 // subsequent API requests to refer to the resource. 46 func (rs *Resources) Register(r Resource) string { 47 rs.mu.Lock() 48 defer rs.mu.Unlock() 49 rs.maxId++ 50 id := strconv.FormatUint(rs.maxId, 10) 51 rs.resources[id] = r 52 return id 53 } 54 55 // Stop stops the resource with the given id and unregisters it. 56 // It returns any error from the underlying Stop call. 57 // It does not return an error if the resource has already 58 // been unregistered. 59 func (rs *Resources) Stop(id string) error { 60 // We don't hold the mutex while calling Stop, because 61 // that might take a while and we don't want to 62 // stop all other resource manipulation while we do so. 63 // If resources.Stop is called concurrently, we'll get 64 // two concurrent calls to Stop, but that should fit 65 // well with the way we invariably implement Stop. 66 r := rs.Get(id) 67 if r == nil { 68 return nil 69 } 70 err := r.Stop() 71 rs.mu.Lock() 72 defer rs.mu.Unlock() 73 delete(rs.resources, id) 74 return err 75 } 76 77 // StopAll stops all the resources. 78 func (rs *Resources) StopAll() { 79 rs.mu.Lock() 80 defer rs.mu.Unlock() 81 for _, r := range rs.resources { 82 if err := r.Stop(); err != nil { 83 log.Errorf("state/api: error stopping %T resource: %v", r, err) 84 } 85 } 86 rs.resources = make(map[string]Resource) 87 } 88 89 // Count returns the number of resources currently held. 90 func (rs *Resources) Count() int { 91 rs.mu.Lock() 92 defer rs.mu.Unlock() 93 return len(rs.resources) 94 }