A map using a lock-free concurrency using left-right algo, written in Go

Convert to go2go type parameters

authored by

Johannes Kohnen and committed by joh.dev a6be19c4 aac2b9f9

+70 -74
+4 -5
example_test.go example_test.go2
··· 4 4 "fmt" 5 5 "sort" 6 6 7 - "github.com/jwkohnen/lrmap" 7 + "github.com/jwkohnen/lrmap2" 8 8 ) 9 9 10 10 func ExampleReadHandler_Iterate() { 11 - m := lrmap.New() 11 + m := lrmap2.New[int, int]() 12 12 13 13 for i := 0; i < 10; i++ { 14 - k, v := lrmap.Key(i), lrmap.Value(i) 15 14 m.Set(k, v) 16 15 } 17 16 ··· 23 22 24 23 var values []int 25 24 26 - rh.Iterate(func(_ lrmap.Key, v lrmap.Value) bool { 27 - values = append(values, int(v)) 25 + rh.Iterate(func(_ int, v int) bool { 26 + values = append(values, v) 28 27 29 28 return true 30 29 })
+1 -1
go.mod
··· 1 - module github.com/jwkohnen/lrmap 1 + module github.com/jwkohnen/lrmap2 2 2 3 3 go 1.16
+56 -59
lrmap.go lrmap.go2
··· 10 10 ) 11 11 12 12 type ( 13 - LRMap struct { 13 + LRMap[K comparable, V any] struct { 14 14 mu sync.Mutex 15 - left arena 16 - right arena 15 + left arena[K, V] 16 + right arena[K, V] 17 17 readMap unsafe.Pointer 18 - writeMap *arena 19 - redoLog []operation 20 - readHandlers map[*readHandlerInner]struct{} 18 + writeMap *arena[K, V] 19 + redoLog []operation[K, V] 20 + readHandlers map[*readHandlerInner[K, V]]struct{} 21 21 readHandlerPool sync.Pool 22 22 } 23 23 24 - Key int 25 - Value int 26 - 27 - arena map[Key]Value 24 + arena[K comparable, V any] map[K]V 28 25 ) 29 26 30 - func New() *LRMap { 27 + func New[K comparable, V any]() *LRMap[K, V] { 31 28 // nolint:exhaustivestruct 32 - m := &LRMap{ 33 - left: make(arena), 34 - right: make(arena), 35 - readHandlers: make(map[*readHandlerInner]struct{}), 29 + m := &LRMap[K, V]{ 30 + left: make(arena[K, V]), 31 + right: make(arena[K, V]), 32 + readHandlers: make(map[*readHandlerInner[K, V]]struct{}), 36 33 } 37 34 38 35 m.readHandlerPool.New = func() interface{} { return m.newReadHandler() } ··· 42 39 return m 43 40 } 44 41 45 - func (m *LRMap) Set(k Key, v Value) { 42 + func (m *LRMap[K, V]) Set(k K, v V) { 46 43 m.mu.Lock() 47 44 defer m.mu.Unlock() 48 45 49 46 (*(m.writeMap))[k] = v 50 47 51 - m.redoLog = append(m.redoLog, operation{typ: opSet, key: k, value: &v}) 48 + m.redoLog = append(m.redoLog, operation[K, V]{typ: opSet, key: k, value: &v}) 52 49 } 53 50 54 - func (m *LRMap) Delete(k Key) { 51 + func (m *LRMap[K, V]) Delete(k K) { 55 52 m.mu.Lock() 56 53 defer m.mu.Unlock() 57 54 58 55 delete(*(m.writeMap), k) 59 56 60 57 // nolint:exhaustivestruct 61 - m.redoLog = append(m.redoLog, operation{typ: opDelete, key: k}) 58 + m.redoLog = append(m.redoLog, operation[K, V]{typ: opDelete, key: k}) 62 59 } 63 60 64 - func (m *LRMap) Get(k Key) Value { 61 + func (m *LRMap[K, V]) Get(k K) V { 65 62 v, _ := m.GetOK(k) 66 63 67 64 return v 68 65 } 69 66 70 - func (m *LRMap) GetOK(k Key) (Value, bool) { 67 + func (m *LRMap[K, V]) GetOK(k K) (V, bool) { 71 68 m.mu.Lock() 72 69 defer m.mu.Unlock() 73 70 ··· 76 73 return v, ok 77 74 } 78 75 79 - func (m *LRMap) Flush() { 76 + func (m *LRMap[K, V]) Flush() { 80 77 m.mu.Lock() 81 78 defer m.mu.Unlock() 82 79 ··· 101 98 m.redoLog = nil 102 99 } 103 100 104 - func (m *LRMap) NewReadHandler() *ReadHandler { 105 - rh := m.readHandlerPool.Get().(*ReadHandler) 101 + func (m *LRMap[K, V]) NewReadHandler() *ReadHandler[K, V] { 102 + rh := m.readHandlerPool.Get().(*ReadHandler[K, V]) 106 103 rh.ready = true 107 104 108 105 return rh 109 106 } 110 107 111 - func (m *LRMap) newReadHandler() *ReadHandler { 108 + func (m *LRMap[K, V]) newReadHandler() *ReadHandler[K, V] { 112 109 // Wrap the actual (inner) readHandler in an outer shim and return that shim to the 113 110 // user and only keep a "weak reference" to the inner readHandler, but not the shim. 114 111 // If the user drops any references to the outer shim, (eventually) the runtime runs ··· 122 119 // thus leaking resources through the readHandlers list. 123 120 124 121 // nolint:exhaustivestruct 125 - inner := &readHandlerInner{lrm: m} 122 + inner := &readHandlerInner[K, V]{lrm: m} 126 123 127 124 m.mu.Lock() 128 125 m.readHandlers[inner] = struct{}{} 129 126 m.mu.Unlock() 130 127 131 - outer := &ReadHandler{inner: inner} 132 - runtime.SetFinalizer(outer, func(rh *ReadHandler) { 128 + outer := &ReadHandler[K, V]{inner: inner} 129 + runtime.SetFinalizer(outer, func(rh *ReadHandler[K, V]) { 133 130 rh.ready = false 134 131 rh.inner.close() 135 132 }) ··· 137 134 return outer 138 135 } 139 136 140 - func (m *LRMap) swap() { 137 + func (m *LRMap[K, V]) swap() { 141 138 var ( 142 - read = (*arena)(m.readMap) 143 - write *arena 139 + read = (*arena[K, V])(m.readMap) 140 + write *arena[K, V] 144 141 ) 145 142 146 143 switch read { ··· 163 160 m.writeMap = write 164 161 } 165 162 166 - func (m *LRMap) waitForReaders() { 167 - readers := make(map[*readHandlerInner]uint64) 163 + func (m *LRMap[K, V]) waitForReaders() { 164 + readers := make(map[*readHandlerInner[K, V]]uint64) 168 165 169 166 for rh := range m.readHandlers { 170 167 if epoch := atomic.LoadUint64(&(rh.epoch)); epoch%2 == 1 { ··· 196 193 } 197 194 } 198 195 199 - func (m *LRMap) getArenaAtomic() arena { 200 - return *(*arena)(atomic.LoadPointer(&(m.readMap))) 196 + func (m *LRMap[K, V]) getArenaAtomic() arena[K, V] { 197 + return *(*arena[K, V])(atomic.LoadPointer(&(m.readMap))) 201 198 } 202 199 203 200 type opType int8 ··· 207 204 opDelete 208 205 ) 209 206 210 - type operation struct { 207 + type operation[K comparable, V any] struct { 211 208 typ opType 212 - key Key 213 - value *Value 209 + key K 210 + value *V 214 211 } 215 212 216 - type ReadHandler struct { 217 - inner *readHandlerInner 213 + type ReadHandler[K comparable, V any] struct { 214 + inner *readHandlerInner[K, V] 218 215 ready bool 219 216 } 220 217 221 - func (rh *ReadHandler) Enter() { rh.assertReady(); rh.inner.enter() } 222 - func (rh *ReadHandler) Leave() { rh.assertReady(); rh.inner.leave() } 223 - func (rh *ReadHandler) Get(k Key) Value { rh.assertReady(); return rh.inner.get(k) } 224 - func (rh *ReadHandler) GetOK(k Key) (Value, bool) { rh.assertReady(); return rh.inner.getOK(k) } 225 - func (rh *ReadHandler) Len() int { rh.assertReady(); return rh.inner.len() } 218 + func (rh *ReadHandler[K, V]) Enter() { rh.assertReady(); rh.inner.enter() } 219 + func (rh *ReadHandler[K, V]) Leave() { rh.assertReady(); rh.inner.leave() } 220 + func (rh *ReadHandler[K, V]) Get(k K) V { rh.assertReady(); return rh.inner.get(k) } 221 + func (rh *ReadHandler[K, V]) GetOK(k K) (V, bool) { rh.assertReady(); return rh.inner.getOK(k) } 222 + func (rh *ReadHandler[K, V]) Len() int { rh.assertReady(); return rh.inner.len() } 226 223 227 - func (rh *ReadHandler) Iterate(fn func(k Key, v Value) bool) { 224 + func (rh *ReadHandler[K, V]) Iterate(fn func(k K, v V) bool) { 228 225 rh.assertReady() 229 226 230 227 if !rh.inner.entered() { ··· 238 235 } 239 236 } 240 237 241 - func (rh *ReadHandler) Close() { 238 + func (rh *ReadHandler[K, V]) Close() { 242 239 rh.assertReady() 243 240 244 241 runtime.SetFinalizer(rh, nil) ··· 246 243 rh.inner.close() 247 244 } 248 245 249 - func (rh *ReadHandler) Recycle() { 246 + func (rh *ReadHandler[K, V]) Recycle() { 250 247 if !rh.ready { 251 248 panic("illegal reader state: must not recycle twice") 252 249 } ··· 260 257 rh.inner.lrm.readHandlerPool.Put(rh) 261 258 } 262 259 263 - func (rh *ReadHandler) assertReady() { 260 + func (rh *ReadHandler[K, V]) assertReady() { 264 261 if rh.inner == nil { 265 262 panic("reader illegal state: must create with NewReadHandler()") // TODO 266 263 } ··· 270 267 } 271 268 } 272 269 273 - type readHandlerInner struct { 274 - lrm *LRMap 275 - live arena 270 + type readHandlerInner[K comparable, V any] struct { 271 + lrm *LRMap[K, V] 272 + live arena[K, V] 276 273 epoch uint64 277 274 } 278 275 279 - func (r *readHandlerInner) enter() { 276 + func (r *readHandlerInner[K, V]) enter() { 280 277 if r.entered() { 281 278 panic("reader illegal state: must not Enter() twice") 282 279 } ··· 285 282 r.live = r.lrm.getArenaAtomic() 286 283 } 287 284 288 - func (r *readHandlerInner) leave() { 285 + func (r *readHandlerInner[K, V]) leave() { 289 286 if !r.entered() { 290 287 panic("reader illegal state: must not Leave() twice") 291 288 } ··· 293 290 atomic.AddUint64(&r.epoch, 1) 294 291 } 295 292 296 - func (r *readHandlerInner) get(k Key) Value { 293 + func (r *readHandlerInner[K, V]) get(k K) V { 297 294 v, _ := r.getOK(k) 298 295 299 296 return v 300 297 } 301 298 302 - func (r *readHandlerInner) getOK(k Key) (Value, bool) { 299 + func (r *readHandlerInner[K, V]) getOK(k K) (V, bool) { 303 300 if !r.entered() { 304 301 panic("reader illegal state: must Enter() before operating on data") 305 302 } ··· 309 306 return v, ok 310 307 } 311 308 312 - func (r *readHandlerInner) len() int { 309 + func (r *readHandlerInner[K, V]) len() int { 313 310 if !r.entered() { 314 311 panic("reader illegal state: must Enter() before operation on data") 315 312 } ··· 317 314 return len(r.live) 318 315 } 319 316 320 - func (r *readHandlerInner) close() { 317 + func (r *readHandlerInner[K, V]) close() { 321 318 r.lrm.mu.Lock() 322 319 defer r.lrm.mu.Unlock() 323 320 324 321 delete(r.lrm.readHandlers, r) 325 322 } 326 323 327 - func (r *readHandlerInner) entered() bool { 324 + func (r *readHandlerInner[K, V]) entered() bool { 328 325 return r.epoch%2 == 1 329 326 }
+9 -9
lrmap_test.go lrmap_test.go2
··· 6 6 ) 7 7 8 8 func TestHundred(t *testing.T) { 9 - lrm := New() 9 + lrm := New[int, int]() 10 10 11 11 rh := lrm.NewReadHandler() 12 12 defer rh.Close() 13 13 14 14 for i := 1; i < 100; i += 2 { 15 - k, v := Key(i), Value(i) 15 + k, v := i, i 16 16 17 17 lrm.Set(k, v) 18 18 } ··· 20 20 lrm.Flush() 21 21 22 22 for i := 1; i < 100; i += 2 { 23 - k, v := Key(i), Value(i) 23 + k, v := i, i 24 24 25 25 rh.Enter() 26 26 if _v := rh.Get(k); _v != v { ··· 31 31 } 32 32 33 33 for i := 0; i < 100; i += 2 { 34 - k, v := Key(i), Value(i) 34 + k, v := i, i 35 35 lrm.Set(k, v) 36 36 } 37 37 ··· 39 39 40 40 for i := 0; i < 100; i++ { 41 41 rh.Enter() 42 - k, v := Key(i), Value(i) 42 + k, v := i, i 43 43 44 44 if _v := rh.Get(k); _v != v { 45 45 t.Errorf("Get(%d) want %d, got %d", k, v, _v) ··· 51 51 52 52 rh.Enter() 53 53 for i := 0; i < 100; i++ { 54 - k, v := Key(i), Value(i) 54 + k, v := i, i 55 55 56 56 if _v := rh.Get(k); _v != v { 57 57 t.Errorf("Get(%d) want %d, got %d", k, v, _v) ··· 60 60 rh.Leave() 61 61 62 62 for i := 0; i < 100; i += 2 { 63 - k := Key(i) 63 + k := i 64 64 lrm.Delete(k) 65 65 } 66 66 ··· 68 68 69 69 rh.Enter() 70 70 for i := 0; i < 100; i++ { 71 - k, v := Key(i), Value(i) 71 + k, v := i, i 72 72 73 73 _v, ok := rh.GetOK(k) 74 74 if i%2 == 0 { ··· 87 87 88 88 rh.Enter() 89 89 for i := 0; i < 100; i++ { 90 - k, v := Key(i), Value(i) 90 + k, v := i, i 91 91 92 92 _v, ok := rh.GetOK(k) 93 93 if i%2 == 0 {