github.com/aacfactory/rings@v1.1.2/hashed.go (about) 1 package rings 2 3 import ( 4 "fmt" 5 "github.com/cespare/xxhash/v2" 6 "sort" 7 "sync" 8 ) 9 10 const ( 11 maxEntries = uint64(256) 12 ) 13 14 type HashRingEntry[E Entry] struct { 15 Entry E 16 Active bool 17 Low uint64 18 High uint64 19 } 20 21 func (entry *HashRingEntry[E]) String() (s string) { 22 active := "F" 23 if entry.Active { 24 active = "T" 25 } 26 s = fmt.Sprintf("{%s:[%d, %d) (%s)}", entry.Entry.Key(), entry.Low, entry.High, active) 27 return 28 } 29 30 func (entry *HashRingEntry[E]) Less(o *HashRingEntry[E]) bool { 31 if entry.High < o.High { 32 return true 33 } 34 return entry.High == o.High && entry.Low < o.Low 35 } 36 37 func (entry *HashRingEntry[E]) RangeSize() uint64 { 38 return entry.High - entry.Low 39 } 40 41 type RangeSizeSortedHashRingEntries[E Entry] []*HashRingEntry[E] 42 43 func (entries RangeSizeSortedHashRingEntries[E]) Len() int { 44 return len(entries) 45 } 46 47 func (entries RangeSizeSortedHashRingEntries[E]) Less(i, j int) bool { 48 return entries[i].RangeSize() < entries[j].RangeSize() && entries[j].Active 49 } 50 51 func (entries RangeSizeSortedHashRingEntries[E]) Swap(i, j int) { 52 entries[i], entries[j] = entries[j], entries[i] 53 return 54 } 55 56 type HashRingEntries[E Entry] []*HashRingEntry[E] 57 58 func (entries HashRingEntries[E]) Len() int { 59 return len(entries) 60 } 61 62 func (entries HashRingEntries[E]) Less(i, j int) bool { 63 return entries[i].Less(entries[j]) 64 } 65 66 func (entries HashRingEntries[E]) Swap(i, j int) { 67 entries[i], entries[j] = entries[j], entries[i] 68 return 69 } 70 71 func (entries HashRingEntries[E]) BiggestRangeAndActiveOne() (entry *HashRingEntry[E]) { 72 sorted := RangeSizeSortedHashRingEntries[E](entries) 73 sort.Sort(sorted) 74 target := sorted[sorted.Len()-1] 75 sort.Sort(entries) 76 if !target.Active { 77 return 78 } 79 entry = target 80 return 81 } 82 83 func (entries HashRingEntries[E]) Get(n uint64) (entry *HashRingEntry[E], has bool) { 84 idx := -1 85 for i, hashed := range entries { 86 if hashed.Low <= n && hashed.High > n { 87 entry = hashed 88 idx = i 89 break 90 } 91 } 92 entry = entries[idx] 93 if entry.Active { 94 has = true 95 return 96 } 97 for { 98 idx-- 99 if idx < 0 { 100 break 101 } 102 entry = entries[idx] 103 if entry.Active { 104 has = true 105 return 106 } 107 } 108 return 109 } 110 111 func NewHashed[E Entry](entries ...E) (v *HashRing[E]) { 112 hashedEntries := make([]*HashRingEntry[E], 0, 1) 113 if entries != nil && len(entries) > 0 { 114 for _, entry := range entries { 115 hashedEntries = append(hashedEntries, &HashRingEntry[E]{ 116 Entry: entry, 117 Active: true, 118 Low: 0, 119 High: 0, 120 }) 121 } 122 span := maxEntries / uint64(len(hashedEntries)) 123 for i, entry := range hashedEntries { 124 entry.Low = span * uint64(i) 125 entry.High = span * uint64(i+1) 126 } 127 hashedEntries[len(entries)-1].High = maxEntries 128 } 129 v = &HashRing[E]{ 130 locker: sync.RWMutex{}, 131 entries: hashedEntries, 132 } 133 return 134 } 135 136 type HashRing[E Entry] struct { 137 locker sync.RWMutex 138 entries HashRingEntries[E] 139 } 140 141 func (r *HashRing[E]) Get(key []byte) (entry E, has bool) { 142 r.locker.RLock() 143 idx := xxhash.Sum64(key) % maxEntries 144 hashed, hasHashed := r.entries.Get(idx) 145 if !hasHashed { 146 r.locker.RUnlock() 147 return 148 } 149 entry = hashed.Entry 150 has = true 151 r.locker.RUnlock() 152 return 153 } 154 155 func (r *HashRing[E]) Add(entry E) (prevActive E, cLow uint64, cHigh uint64, active func(), cancel func(), ok bool) { 156 r.locker.Lock() 157 defer r.locker.Unlock() 158 if uint64(r.entries.Len()) >= maxEntries { 159 return 160 } 161 var prevActiveHashed *HashRingEntry[E] 162 hashed := &HashRingEntry[E]{ 163 Entry: entry, 164 Active: false, 165 Low: 0, 166 High: maxEntries, 167 } 168 if r.entries.Len() == 0 { 169 r.entries = append(r.entries, hashed) 170 } else { 171 prevActiveHashed = r.entries.BiggestRangeAndActiveOne() 172 if prevActiveHashed == nil { 173 return 174 } 175 hashed.Low = (prevActiveHashed.High-prevActiveHashed.Low)/2 + prevActiveHashed.Low 176 hashed.High = prevActiveHashed.High 177 prevActiveHashed.High = hashed.Low 178 prevActive = prevActiveHashed.Entry 179 r.entries = append(r.entries, hashed) 180 sort.Sort(r.entries) 181 } 182 cLow = hashed.Low 183 cHigh = hashed.High 184 active = func() { 185 r.locker.Lock() 186 hashed.Active = true 187 r.locker.Unlock() 188 } 189 cancel = func() { 190 r.locker.Lock() 191 if prevActiveHashed != nil { 192 prevActiveHashed.High = hashed.High 193 } 194 entries := make([]*HashRingEntry[E], 0, r.entries.Len()-1) 195 for _, hashedEntry := range r.entries { 196 if hashedEntry.Entry.Key() == entry.Key() { 197 continue 198 } 199 entries = append(entries, hashedEntry) 200 } 201 r.entries = entries 202 sort.Sort(r.entries) 203 r.locker.Unlock() 204 } 205 ok = true 206 return 207 } 208 209 func (r *HashRing[E]) AddDeclared(entry E, low uint64, high uint64) (ok bool) { 210 r.locker.Lock() 211 defer r.locker.Unlock() 212 if uint64(r.entries.Len()) >= maxEntries { 213 return 214 } 215 hashed := &HashRingEntry[E]{ 216 Entry: entry, 217 Active: true, 218 Low: low, 219 High: high, 220 } 221 if r.entries.Len() == 0 { 222 r.entries = append(r.entries, hashed) 223 } else { 224 for _, e := range r.entries { 225 if intersect(e.Low, e.High, low, high) { 226 return 227 } 228 } 229 r.entries = append(r.entries, hashed) 230 sort.Sort(r.entries) 231 } 232 ok = true 233 return 234 } 235 236 func (r *HashRing[E]) Size() (n int) { 237 n = len(r.entries) 238 return 239 } 240 241 func (r *HashRing[E]) State(key string) (active bool, low uint64, high uint64, has bool) { 242 for _, entry := range r.entries { 243 if entry.Entry.Key() == key { 244 active = entry.Active 245 low = entry.Low 246 high = entry.High 247 has = true 248 return 249 } 250 } 251 return 252 } 253 254 func (r *HashRing[E]) States(fn func(key string, active bool, low uint64, high uint64) bool) { 255 for _, entry := range r.entries { 256 if !fn(entry.Entry.Key(), entry.Active, entry.Low, entry.High) { 257 break 258 } 259 } 260 return 261 } 262 263 func (r *HashRing[E]) String() (s string) { 264 for _, entry := range r.entries { 265 s = s + ", " + entry.String() 266 } 267 if s != "" { 268 s = s[2:] 269 } 270 s = "[" + s + "]" 271 return 272 } 273 274 func intersect(sLow uint64, sHigh uint64, tLow uint64, tHigh uint64) (ok bool) { 275 for s := sLow; s < sHigh; s++ { 276 for t := tLow; t < tHigh; t++ { 277 if s == t { 278 ok = true 279 return 280 } 281 } 282 } 283 return 284 }