github.com/zuoyebang/bitalosdb@v1.1.1-0.20240516111551-79a8c4d8ce20/internal/cache/lfucache/cache.go (about) 1 // Copyright 2021 The Bitalosdb author(hustxrb@163.com) and other contributors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package lfucache 16 17 import ( 18 "bytes" 19 "encoding/binary" 20 "sync" 21 "sync/atomic" 22 "time" 23 24 "github.com/zuoyebang/bitalosdb/internal/bytepools" 25 "github.com/zuoyebang/bitalosdb/internal/cache/lfucache/internal/arenaskl" 26 "github.com/zuoyebang/bitalosdb/internal/invariants" 27 "github.com/zuoyebang/bitalosdb/internal/manual" 28 ) 29 30 var ( 31 LFU_FREQ_BUF = [2]uint8{0, 0} 32 LFU_FREQ_LENGTH = 2 33 LFU_TM_LENGTH = 2 34 LFU_META_LENGTH = LFU_FREQ_LENGTH + LFU_TM_LENGTH 35 LFU_FREQ_MAX uint16 = 65535 36 FREQ_TM_STEP = [5]uint16{2, 8, 16, 24, LFU_FREQ_MAX} 37 ) 38 39 const ( 40 FREQ_TM_STEP_LEN = len(FREQ_TM_STEP) 41 FREQ_THRESHOLD_LEN = 2 42 FREQ_LEVEL = 656 43 ) 44 45 type shard struct { 46 atomic struct { 47 memtableID int64 48 arrtableID int64 49 seqNum uint64 50 hits int64 51 misses int64 52 memtableNum int32 53 } 54 55 mu struct { 56 sync.Mutex 57 memMutable *memTable 58 memQueue flushableList 59 arrtable *flushableEntry 60 } 61 62 readState struct { 63 sync.RWMutex 64 val *readState 65 } 66 67 lc *LfuCache 68 index int 69 memSize int 70 maxSize uint64 71 flushCnt int64 72 freqLevelStat [FREQ_TM_STEP_LEN][FREQ_LEVEL]int 73 freqThreshold [FREQ_TM_STEP_LEN][FREQ_THRESHOLD_LEN]uint64 74 } 75 76 func newCache(lc *LfuCache, index int, memSize int, maxSize uint64) *shard { 77 s := &shard{ 78 lc: lc, 79 index: index, 80 memSize: memSize, 81 maxSize: maxSize, 82 freqLevelStat: [FREQ_TM_STEP_LEN][FREQ_LEVEL]int{}, 83 freqThreshold: [FREQ_TM_STEP_LEN][FREQ_THRESHOLD_LEN]uint64{}, 84 } 85 86 s.mu.Lock() 87 defer s.mu.Unlock() 88 89 var entry *flushableEntry 90 s.mu.memMutable, entry = s.newMemTable() 91 s.mu.memQueue = append(s.mu.memQueue, entry) 92 s.updateReadStateLocked() 93 94 return s 95 } 96 97 func (s *shard) exist(key []byte) bool { 98 _, found, closer := s.getInternal(key) 99 defer func() { 100 if closer != nil { 101 closer() 102 } 103 }() 104 105 return found 106 } 107 108 func (s *shard) get(key []byte) ([]byte, func(), bool) { 109 value, found, closer := s.getInternal(key) 110 if found { 111 vLen := len(value) 112 if vLen > LFU_META_LENGTH { 113 freq := binary.BigEndian.Uint16(value[vLen-LFU_FREQ_LENGTH:]) 114 if freq < LFU_FREQ_MAX { 115 freq++ 116 } 117 binary.BigEndian.PutUint16(value[vLen-LFU_FREQ_LENGTH:], freq) 118 binary.BigEndian.PutUint16(value[vLen-LFU_META_LENGTH:], uint16((time.Now().Unix()-s.lc.launchTime)/3600)) 119 120 value = value[:vLen-LFU_META_LENGTH] 121 } 122 atomic.AddInt64(&s.atomic.hits, 1) 123 } else { 124 atomic.AddInt64(&s.atomic.misses, 1) 125 } 126 127 return value, closer, found 128 } 129 130 func (s *shard) getInternal(key []byte) ([]byte, bool, func()) { 131 rs := s.loadReadState() 132 closer := func() { 133 rs.unref() 134 } 135 136 memIndex := len(rs.memtables) - 1 137 for memIndex >= 0 { 138 mt := rs.memtables[memIndex] 139 val, exist, kind := mt.get(key) 140 if exist { 141 if kind == internalKeyKindSet { 142 return val, true, closer 143 } else if kind == internalKeyKindDelete { 144 rs.unref() 145 return nil, false, nil 146 } 147 } 148 149 memIndex-- 150 } 151 152 if rs.arrtable != nil { 153 val, exist, _ := rs.arrtable.get(key) 154 if exist { 155 return val, true, closer 156 } 157 } 158 159 rs.unref() 160 return nil, false, nil 161 } 162 163 func (s *shard) getIter(key []byte) (val []byte, valPool func(), _ bool) { 164 v, iter, found := s.getInternalIter(key) 165 defer func() { 166 if iter != nil { 167 iter.Close() 168 } 169 }() 170 171 if found { 172 vLen := len(v) 173 if vLen > LFU_META_LENGTH { 174 freq := binary.BigEndian.Uint16(v[vLen-LFU_FREQ_LENGTH:]) 175 if freq < LFU_FREQ_MAX { 176 freq++ 177 } 178 binary.BigEndian.PutUint16(v[vLen-LFU_FREQ_LENGTH:], freq) 179 binary.BigEndian.PutUint16(v[vLen-LFU_META_LENGTH:], uint16((time.Now().Unix()-s.lc.launchTime)/3600)) 180 181 v = v[:vLen-LFU_META_LENGTH] 182 183 val, valPool = bytepools.ReaderBytePools.MakeValue(v) 184 } 185 atomic.AddInt64(&s.atomic.hits, 1) 186 } else { 187 atomic.AddInt64(&s.atomic.misses, 1) 188 } 189 190 return val, valPool, found 191 } 192 193 func (s *shard) getInternalIter(key []byte) ([]byte, internalIterator, bool) { 194 var ( 195 iterKey *internalKey 196 iterValue []byte 197 iter internalIterator 198 isSeekAt bool 199 ) 200 201 rs := s.loadReadState() 202 defer rs.unref() 203 204 memIndex := len(rs.memtables) - 1 205 for { 206 if iter != nil { 207 if iterKey != nil && bytes.Equal(key, iterKey.UserKey) { 208 break 209 } 210 _ = iter.Close() 211 iter = nil 212 } 213 214 if memIndex >= 0 { 215 m := rs.memtables[memIndex] 216 iter = m.newIter(nil) 217 iterKey, iterValue = iter.SeekGE(key) 218 memIndex-- 219 continue 220 } 221 222 if !isSeekAt && rs.arrtable != nil { 223 iter = rs.arrtable.newIter(nil) 224 iterKey, iterValue = iter.SeekGE(key) 225 isSeekAt = true 226 continue 227 } 228 229 iterKey = nil 230 iterValue = nil 231 break 232 } 233 234 if iterKey == nil { 235 return nil, iter, false 236 } 237 238 if iterKey.Kind() == internalKeyKindDelete { 239 iterValue = nil 240 } 241 242 return iterValue, iter, true 243 } 244 245 func (s *shard) set(key []byte, value []byte) error { 246 return s.setApply(key, value, internalKeyKindSet) 247 } 248 249 func (s *shard) delete(key []byte) error { 250 return s.setApply(key, nil, internalKeyKindDelete) 251 } 252 253 func (s *shard) setApply(key []byte, value []byte, kind internalKeyKind) error { 254 if kind == internalKeyKindSet && len(value) > 0 { 255 accessTime := [2]uint8{0, 0} 256 binary.BigEndian.PutUint16(accessTime[:], uint16((time.Now().Unix()-s.lc.launchTime)/3600)) 257 value = append(value, accessTime[:]...) 258 value = append(value, LFU_FREQ_BUF[:]...) 259 } 260 261 kvSize := memTableEntrySize(len(key), len(value)) 262 mem, err := s.setPrepare(kvSize) 263 if err != nil { 264 return err 265 } 266 267 mem.writerRef() 268 defer func() { 269 mem.writerUnref() 270 }() 271 seqNum := atomic.AddUint64(&s.atomic.seqNum, 1) 272 273 return mem.add(key, value, seqNum, kind) 274 } 275 276 func (s *shard) setPrepare(size uint64) (*memTable, error) { 277 s.mu.Lock() 278 defer s.mu.Unlock() 279 280 err := s.mu.memMutable.prepare(size) 281 if err == arenaskl.ErrArenaFull { 282 s.makeRoomForWrite() 283 } 284 mem := s.mu.memMutable 285 return mem, nil 286 } 287 288 func (s *shard) makeRoomForWrite() { 289 var entry *flushableEntry 290 immMem := s.mu.memMutable 291 s.mu.memMutable, entry = s.newMemTable() 292 s.mu.memQueue = append(s.mu.memQueue, entry) 293 s.updateReadStateLocked() 294 immMem.writerUnref() 295 } 296 297 func (s *shard) newMemTable() (*memTable, *flushableEntry) { 298 id := atomic.AddInt64(&s.atomic.memtableID, 1) 299 mem := newMemTable(id, s.memSize) 300 301 invariants.SetFinalizer(mem, checkMemTable) 302 303 entry := s.newFlushableEntry(mem) 304 entry.releaseMemAccounting = func() { 305 manual.Free(mem.arenaBuf) 306 mem.arenaBuf = nil 307 } 308 return mem, entry 309 } 310 311 func (s *shard) newArrayTable(size int) (*arrayTable, *flushableEntry) { 312 id := atomic.AddInt64(&s.atomic.arrtableID, 1) 313 at := newArrayTable(id, size) 314 315 invariants.SetFinalizer(at, checkArrayTable) 316 317 entry := s.newFlushableEntry(at) 318 entry.releaseMemAccounting = func() { 319 manual.Free(at.arenaBuf) 320 at.arenaBuf = nil 321 } 322 return at, entry 323 } 324 325 func (s *shard) newFlushableEntry(f flushable) *flushableEntry { 326 return &flushableEntry{ 327 flushable: f, 328 flushed: make(chan struct{}), 329 readerRefs: 1, 330 } 331 } 332 333 func (s *shard) clearFreqLevelStat() { 334 for i := 0; i < FREQ_TM_STEP_LEN; i++ { 335 for j := 0; j < FREQ_LEVEL; j++ { 336 s.freqLevelStat[i][j] = 0 337 } 338 } 339 340 for i := 0; i < FREQ_TM_STEP_LEN; i++ { 341 for j := 0; j < FREQ_THRESHOLD_LEN; j++ { 342 s.freqThreshold[i][j] = 0 343 } 344 } 345 } 346 347 func (s *shard) updateFreqLevelStat(tm uint16, freq uint16, size int) { 348 var i int 349 for i = 0; i < FREQ_TM_STEP_LEN; i++ { 350 if tm <= FREQ_TM_STEP[i] { 351 break 352 } 353 } 354 355 if i == FREQ_TM_STEP_LEN { 356 return 357 } 358 359 for ; i < FREQ_TM_STEP_LEN; i++ { 360 s.freqLevelStat[i][freq/100] += size 361 s.freqThreshold[i][0] += uint64(freq) 362 s.freqThreshold[i][1]++ 363 } 364 } 365 366 func (s *shard) calculateFreqLevel(size int) (uint16, uint16, uint16) { 367 for i := 0; i < FREQ_TM_STEP_LEN; i++ { 368 freqSize := 0 369 j := FREQ_LEVEL - 1 370 for ; j >= 0; j-- { 371 if s.freqLevelStat[i][j] > 0 { 372 freqSize += s.freqLevelStat[i][j] 373 if freqSize >= size { 374 break 375 } 376 } 377 } 378 379 if freqSize >= size { 380 freqThreshold := uint16(0) 381 if j > 0 { 382 freqThreshold = uint16(j * 100) 383 } 384 385 freqAvg := uint16(0) 386 if s.freqThreshold[i][0] > 0 && s.freqThreshold[i][1] > 0 { 387 freqAvg = uint16(s.freqThreshold[i][0] / s.freqThreshold[i][1] / 2) 388 } 389 390 return freqThreshold, FREQ_TM_STEP[i], freqAvg 391 } 392 } 393 394 return 0, 0, 0 395 } 396 397 func (s *shard) close() { 398 s.mu.Lock() 399 defer s.mu.Unlock() 400 s.readState.val.unref() 401 for _, mem := range s.mu.memQueue { 402 mem.readerUnref() 403 } 404 } 405 406 func (s *shard) arrayTableInuseSize() uint64 { 407 var size uint64 408 if s.mu.arrtable != nil { 409 size = s.mu.arrtable.inuseBytes() 410 } 411 return size 412 } 413 414 func (s *shard) arrayTableCount() int { 415 var count int 416 if s.mu.arrtable != nil { 417 count = s.mu.arrtable.count() 418 } 419 return count 420 } 421 422 func (s *shard) memTableCount() int { 423 var count int 424 for i := range s.mu.memQueue { 425 count += s.mu.memQueue[i].count() 426 } 427 return count 428 } 429 430 func (s *shard) memTableInuseSize() uint64 { 431 var size uint64 432 memNum := len(s.mu.memQueue) 433 if memNum > 0 { 434 if memNum > 1 { 435 size += uint64((memNum - 1) * s.memSize) 436 } 437 size += s.mu.memMutable.inuseBytes() 438 } 439 return size 440 } 441 442 func (s *shard) inuseSize() uint64 { 443 s.mu.Lock() 444 defer s.mu.Unlock() 445 return s.inuseSizeLocked() 446 } 447 448 func (s *shard) inuseSizeLocked() uint64 { 449 return s.arrayTableInuseSize() + s.memTableInuseSize() 450 } 451 452 func (s *shard) setMemtableNum(n int32) { 453 atomic.StoreInt32(&s.atomic.memtableNum, n) 454 } 455 456 func (s *shard) getMemtableNum() int32 { 457 return atomic.LoadInt32(&s.atomic.memtableNum) 458 }