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