github.com/hashicorp/vault/sdk@v0.11.0/helper/locksutil/locks.go (about) 1 // Copyright (c) HashiCorp, Inc. 2 // SPDX-License-Identifier: MPL-2.0 3 4 package locksutil 5 6 import ( 7 "sync" 8 9 "github.com/hashicorp/vault/sdk/helper/cryptoutil" 10 ) 11 12 const ( 13 LockCount = 256 14 ) 15 16 type LockEntry struct { 17 sync.RWMutex 18 } 19 20 // CreateLocks returns an array so that the locks can be iterated over in 21 // order. 22 // 23 // This is only threadsafe if a process is using a single lock, or iterating 24 // over the entire lock slice in order. Using a consistent order avoids 25 // deadlocks because you can never have the following: 26 // 27 // Lock A, Lock B 28 // Lock B, Lock A 29 // 30 // Where process 1 is now deadlocked trying to lock B, and process 2 deadlocked trying to lock A 31 func CreateLocks() []*LockEntry { 32 ret := make([]*LockEntry, LockCount) 33 for i := range ret { 34 ret[i] = new(LockEntry) 35 } 36 return ret 37 } 38 39 func LockIndexForKey(key string) uint8 { 40 return uint8(cryptoutil.Blake2b256Hash(key)[0]) 41 } 42 43 func LockForKey(locks []*LockEntry, key string) *LockEntry { 44 return locks[LockIndexForKey(key)] 45 } 46 47 func LocksForKeys(locks []*LockEntry, keys []string) []*LockEntry { 48 lockIndexes := make(map[uint8]struct{}, len(keys)) 49 for _, k := range keys { 50 lockIndexes[LockIndexForKey(k)] = struct{}{} 51 } 52 53 locksToReturn := make([]*LockEntry, 0, len(keys)) 54 for i, l := range locks { 55 if _, ok := lockIndexes[uint8(i)]; ok { 56 locksToReturn = append(locksToReturn, l) 57 } 58 } 59 60 return locksToReturn 61 }