github.phpd.cn/cilium/cilium@v1.6.12/pkg/allocator/localkeys.go (about) 1 // Copyright 2016-2019 Authors of Cilium 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package allocator 16 17 import ( 18 "fmt" 19 20 "github.com/cilium/cilium/pkg/idpool" 21 "github.com/cilium/cilium/pkg/kvstore" 22 "github.com/cilium/cilium/pkg/lock" 23 24 "github.com/sirupsen/logrus" 25 ) 26 27 type localKey struct { 28 val idpool.ID 29 key AllocatorKey 30 refcnt uint64 31 32 // verified is true when the key has been synced with the kvstore 33 verified bool 34 } 35 36 // localKeys is a map of keys in use locally. Keys can be used multiple times. 37 // A refcnt is managed to know when a key is no longer in use 38 type localKeys struct { 39 lock.RWMutex 40 keys map[string]*localKey 41 ids map[idpool.ID]*localKey 42 } 43 44 func newLocalKeys() *localKeys { 45 return &localKeys{ 46 keys: map[string]*localKey{}, 47 ids: map[idpool.ID]*localKey{}, 48 } 49 } 50 51 // allocate creates an entry for key in localKeys if needed and increments the 52 // refcnt. The value associated with the key must match the local cache or an 53 // error is returned 54 func (lk *localKeys) allocate(keyString string, key AllocatorKey, val idpool.ID) (idpool.ID, error) { 55 lk.Lock() 56 defer lk.Unlock() 57 58 if k, ok := lk.keys[keyString]; ok { 59 if val != k.val { 60 return idpool.NoID, fmt.Errorf("local key already allocated with different value (%s != %s)", val, k.val) 61 } 62 63 k.refcnt++ 64 kvstore.Trace("Incremented local key refcnt", nil, logrus.Fields{fieldKey: keyString, fieldID: val, fieldRefCnt: k.refcnt}) 65 return k.val, nil 66 } 67 68 k := &localKey{key: key, val: val, refcnt: 1} 69 lk.keys[keyString] = k 70 lk.ids[val] = k 71 kvstore.Trace("New local key", nil, logrus.Fields{fieldKey: keyString, fieldID: val, fieldRefCnt: 1}) 72 return val, nil 73 } 74 75 func (lk *localKeys) verify(key string) error { 76 lk.Lock() 77 defer lk.Unlock() 78 79 if k, ok := lk.keys[key]; ok { 80 k.verified = true 81 kvstore.Trace("Local key verified", nil, logrus.Fields{fieldKey: key}) 82 return nil 83 } 84 85 return fmt.Errorf("key %s not found", key) 86 } 87 88 // lookupKey returns the idpool.ID of the key is present in the map of keys. 89 // if it isn't present, returns idpool.NoID 90 func (lk *localKeys) lookupKey(key string) idpool.ID { 91 lk.RLock() 92 defer lk.RUnlock() 93 94 if k, ok := lk.keys[key]; ok { 95 return k.val 96 } 97 98 return idpool.NoID 99 } 100 101 // lookupID returns the key for a given ID or an empty string 102 func (lk *localKeys) lookupID(id idpool.ID) AllocatorKey { 103 lk.RLock() 104 defer lk.RUnlock() 105 106 if k, ok := lk.ids[id]; ok { 107 return k.key 108 } 109 110 return nil 111 } 112 113 // use increments the refcnt of the key and returns its value 114 func (lk *localKeys) use(key string) idpool.ID { 115 lk.Lock() 116 defer lk.Unlock() 117 118 if k, ok := lk.keys[key]; ok { 119 // unverified keys behave as if they do not exist 120 if !k.verified { 121 return idpool.NoID 122 } 123 124 k.refcnt++ 125 kvstore.Trace("Incremented local key refcnt", nil, logrus.Fields{fieldKey: key, fieldID: k.val, fieldRefCnt: k.refcnt}) 126 return k.val 127 } 128 129 return idpool.NoID 130 } 131 132 // release releases the refcnt of a key. It returns the ID associated with the 133 // given key. When the last reference was released, the key is deleted and the 134 // returned lastUse value is true. 135 func (lk *localKeys) release(key string) (lastUse bool, id idpool.ID, err error) { 136 lk.Lock() 137 defer lk.Unlock() 138 if k, ok := lk.keys[key]; ok { 139 k.refcnt-- 140 kvstore.Trace("Decremented local key refcnt", nil, logrus.Fields{fieldKey: key, fieldID: k.val, fieldRefCnt: k.refcnt}) 141 if k.refcnt == 0 { 142 delete(lk.keys, key) 143 delete(lk.ids, k.val) 144 return true, k.val, nil 145 } 146 147 return false, k.val, nil 148 } 149 150 return false, idpool.NoID, fmt.Errorf("unable to find key in local cache") 151 } 152 153 func (lk *localKeys) getVerifiedIDs() map[idpool.ID]AllocatorKey { 154 ids := map[idpool.ID]AllocatorKey{} 155 lk.RLock() 156 for id, localKey := range lk.ids { 157 if localKey.verified { 158 ids[id] = localKey.key 159 } 160 } 161 lk.RUnlock() 162 163 return ids 164 }