| 170 | } |
| 171 | |
| 172 | func (p *_LockStoreImp) lock(key string, method _LockingMethod) { |
| 173 | if p.granularity == PerKeyGranularity { |
| 174 | p.storeLock.Lock() |
| 175 | var lock *_LockImp |
| 176 | var ok bool |
| 177 | |
| 178 | // let's check if we have an existing lock for the key |
| 179 | if lock, ok = p.perKeyLocks[key]; ok { |
| 180 | // let's first make sure if it's alive or not |
| 181 | if atomic.LoadInt32(&lock.count) == 0 { |
| 182 | // we need a new one. Someone has already unlocked it and |
| 183 | // marked it for deletion |
| 184 | lock = newLock(key) |
| 185 | p.perKeyLocks[key] = lock |
| 186 | } |
| 187 | } else { |
| 188 | lock = newLock(key) |
| 189 | p.perKeyLocks[key] = lock |
| 190 | } |
| 191 | |
| 192 | // increment the ref-count |
| 193 | atomic.AddInt32(&lock.count, 1) |
| 194 | p.storeLock.Unlock() |
| 195 | |
| 196 | // this is the blocking call. Do it outside the store lock |
| 197 | switch method { |
| 198 | case _Lock: |
| 199 | lock.Lock() |
| 200 | case _RLock: |
| 201 | lock.RLock() |
| 202 | } |
| 203 | } else if p.granularity == StoreGranularity { |
| 204 | switch method { |
| 205 | case _Lock: |
| 206 | p.storeLock.Lock() |
| 207 | case _RLock: |
| 208 | p.storeLock.RLock() |
| 209 | } |
| 210 | } else if p.granularity == ShardedGranularity { |
| 211 | // hash the key into a bucked and return that lock |
| 212 | shard, err := shardForKey(key, len(p.shardedLocks)) |
| 213 | if err != nil { |
| 214 | panic(err.Error()) |
| 215 | } |
| 216 | switch method { |
| 217 | case _Lock: |
| 218 | p.shardedLocks[shard].Lock() |
| 219 | case _RLock: |
| 220 | p.shardedLocks[shard].RLock() |
| 221 | } |
| 222 | } else { |
| 223 | panic("unexpected granularity") |
| 224 | } |
| 225 | } |
| 226 | |
| 227 | func (p *_LockStoreImp) Unlock(key string) { |
| 228 | p.unlock(key, _Unlock) |