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  }