github.com/hdt3213/godis@v1.2.9/datastruct/lock/lock_map.go (about)

     1  package lock
     2  
     3  import (
     4  	"sort"
     5  	"sync"
     6  )
     7  
     8  const (
     9  	prime32 = uint32(16777619)
    10  )
    11  
    12  // Locks provides rw locks for key
    13  type Locks struct {
    14  	table []*sync.RWMutex
    15  }
    16  
    17  // Make creates a new lock map
    18  func Make(tableSize int) *Locks {
    19  	table := make([]*sync.RWMutex, tableSize)
    20  	for i := 0; i < tableSize; i++ {
    21  		table[i] = &sync.RWMutex{}
    22  	}
    23  	return &Locks{
    24  		table: table,
    25  	}
    26  }
    27  
    28  func fnv32(key string) uint32 {
    29  	hash := uint32(2166136261)
    30  	for i := 0; i < len(key); i++ {
    31  		hash *= prime32
    32  		hash ^= uint32(key[i])
    33  	}
    34  	return hash
    35  }
    36  
    37  func (locks *Locks) spread(hashCode uint32) uint32 {
    38  	if locks == nil {
    39  		panic("dict is nil")
    40  	}
    41  	tableSize := uint32(len(locks.table))
    42  	return (tableSize - 1) & uint32(hashCode)
    43  }
    44  
    45  // Lock obtains exclusive lock for writing
    46  func (locks *Locks) Lock(key string) {
    47  	index := locks.spread(fnv32(key))
    48  	mu := locks.table[index]
    49  	mu.Lock()
    50  }
    51  
    52  // RLock obtains shared lock for reading
    53  func (locks *Locks) RLock(key string) {
    54  	index := locks.spread(fnv32(key))
    55  	mu := locks.table[index]
    56  	mu.RLock()
    57  }
    58  
    59  // UnLock release exclusive lock
    60  func (locks *Locks) UnLock(key string) {
    61  	index := locks.spread(fnv32(key))
    62  	mu := locks.table[index]
    63  	mu.Unlock()
    64  }
    65  
    66  // RUnLock release shared lock
    67  func (locks *Locks) RUnLock(key string) {
    68  	index := locks.spread(fnv32(key))
    69  	mu := locks.table[index]
    70  	mu.RUnlock()
    71  }
    72  
    73  func (locks *Locks) toLockIndices(keys []string, reverse bool) []uint32 {
    74  	indexMap := make(map[uint32]struct{})
    75  	for _, key := range keys {
    76  		index := locks.spread(fnv32(key))
    77  		indexMap[index] = struct{}{}
    78  	}
    79  	indices := make([]uint32, 0, len(indexMap))
    80  	for index := range indexMap {
    81  		indices = append(indices, index)
    82  	}
    83  	sort.Slice(indices, func(i, j int) bool {
    84  		if !reverse {
    85  			return indices[i] < indices[j]
    86  		}
    87  		return indices[i] > indices[j]
    88  	})
    89  	return indices
    90  }
    91  
    92  // Locks obtains multiple exclusive locks for writing
    93  // invoking Lock in loop may cause dead lock, please use Locks
    94  func (locks *Locks) Locks(keys ...string) {
    95  	indices := locks.toLockIndices(keys, false)
    96  	for _, index := range indices {
    97  		mu := locks.table[index]
    98  		mu.Lock()
    99  	}
   100  }
   101  
   102  // RLocks obtains multiple shared locks for reading
   103  // invoking RLock in loop may cause dead lock, please use RLocks
   104  func (locks *Locks) RLocks(keys ...string) {
   105  	indices := locks.toLockIndices(keys, false)
   106  	for _, index := range indices {
   107  		mu := locks.table[index]
   108  		mu.RLock()
   109  	}
   110  }
   111  
   112  // UnLocks releases multiple exclusive locks
   113  func (locks *Locks) UnLocks(keys ...string) {
   114  	indices := locks.toLockIndices(keys, true)
   115  	for _, index := range indices {
   116  		mu := locks.table[index]
   117  		mu.Unlock()
   118  	}
   119  }
   120  
   121  // RUnLocks releases multiple shared locks
   122  func (locks *Locks) RUnLocks(keys ...string) {
   123  	indices := locks.toLockIndices(keys, true)
   124  	for _, index := range indices {
   125  		mu := locks.table[index]
   126  		mu.RUnlock()
   127  	}
   128  }
   129  
   130  // RWLocks locks write keys and read keys together. allow duplicate keys
   131  func (locks *Locks) RWLocks(writeKeys []string, readKeys []string) {
   132  	keys := append(writeKeys, readKeys...)
   133  	indices := locks.toLockIndices(keys, false)
   134  	writeIndexSet := make(map[uint32]struct{})
   135  	for _, wKey := range writeKeys {
   136  		idx := locks.spread(fnv32(wKey))
   137  		writeIndexSet[idx] = struct{}{}
   138  	}
   139  	for _, index := range indices {
   140  		_, w := writeIndexSet[index]
   141  		mu := locks.table[index]
   142  		if w {
   143  			mu.Lock()
   144  		} else {
   145  			mu.RLock()
   146  		}
   147  	}
   148  }
   149  
   150  // RWUnLocks unlocks write keys and read keys together. allow duplicate keys
   151  func (locks *Locks) RWUnLocks(writeKeys []string, readKeys []string) {
   152  	keys := append(writeKeys, readKeys...)
   153  	indices := locks.toLockIndices(keys, true)
   154  	writeIndexSet := make(map[uint32]struct{})
   155  	for _, wKey := range writeKeys {
   156  		idx := locks.spread(fnv32(wKey))
   157  		writeIndexSet[idx] = struct{}{}
   158  	}
   159  	for _, index := range indices {
   160  		_, w := writeIndexSet[index]
   161  		mu := locks.table[index]
   162  		if w {
   163  			mu.Unlock()
   164  		} else {
   165  			mu.RUnlock()
   166  		}
   167  	}
   168  }