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 }