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  }