github.com/zuoyebang/bitalosdb@v1.1.1-0.20240516111551-79a8c4d8ce20/internal/cache/lfucache/array_table.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  	"fmt"
    21  	"os"
    22  	"sort"
    23  
    24  	"github.com/zuoyebang/bitalosdb/internal/cache/lfucache/internal/arenaskl"
    25  	"github.com/zuoyebang/bitalosdb/internal/manual"
    26  )
    27  
    28  const (
    29  	itemHeaderLen = 2
    30  )
    31  
    32  type arrayTable struct {
    33  	id       int64
    34  	num      int
    35  	index    []uint32
    36  	arenaBuf []byte
    37  	arena    *arenaskl.Arena
    38  }
    39  
    40  func checkArrayTable(obj interface{}) {
    41  	at := obj.(*arrayTable)
    42  	if at.arenaBuf != nil {
    43  		fmt.Fprintf(os.Stderr, "%p: arrayTable(%d) buffer was not freed\n", at.arenaBuf, at.id)
    44  		os.Exit(1)
    45  	}
    46  }
    47  
    48  func newArrayTable(id int64, size int) *arrayTable {
    49  	arenaBuf := manual.New(size + 8)
    50  	at := &arrayTable{
    51  		id:       id,
    52  		num:      0,
    53  		arenaBuf: arenaBuf,
    54  		arena:    arenaskl.NewArena(arenaBuf),
    55  	}
    56  
    57  	return at
    58  }
    59  
    60  func arrayTableEntrySize(keyBytes, valueBytes int) int {
    61  	return keyBytes + valueBytes + itemHeaderLen
    62  }
    63  
    64  func (t *arrayTable) add(key []byte, value []byte) error {
    65  	keySize := len(key)
    66  	valueSize := len(value)
    67  	itemSize := arrayTableEntrySize(keySize, valueSize)
    68  	itemOffset, err := t.arena.AllocNoAlign(uint32(itemSize))
    69  	if err != nil {
    70  		return err
    71  	}
    72  
    73  	binary.BigEndian.PutUint16(t.arena.GetBytes(itemOffset, itemHeaderLen), uint16(keySize))
    74  	copy(t.arena.GetBytes(itemOffset+itemHeaderLen, uint32(keySize)), key)
    75  	copy(t.arena.GetBytes(itemOffset+itemHeaderLen+uint32(keySize), uint32(valueSize)), value)
    76  
    77  	t.index = append(t.index, itemOffset)
    78  	t.num++
    79  
    80  	return nil
    81  }
    82  
    83  func (t *arrayTable) validIndexPos(i int) bool {
    84  	return i >= 0 && i < t.num
    85  }
    86  
    87  func (t *arrayTable) get(key []byte) ([]byte, bool, internalKeyKind) {
    88  	indexPos := sort.Search(t.num, func(i int) bool {
    89  		return bytes.Compare(t.getKey(i), key) != -1
    90  	})
    91  
    92  	k, v := t.getKV(indexPos)
    93  	if k == nil || bytes.Compare(k, key) != 0 {
    94  		return nil, false, internalKeyKindInvalid
    95  	}
    96  
    97  	return v, true, internalKeyKindSet
    98  }
    99  
   100  func (t *arrayTable) getKey(i int) []byte {
   101  	if !t.validIndexPos(i) {
   102  		return nil
   103  	}
   104  
   105  	itemOffset := t.index[i]
   106  	keySize := uint32(binary.BigEndian.Uint16(t.arena.GetBytes(itemOffset, itemHeaderLen)))
   107  	key := t.arena.GetBytes(itemOffset+itemHeaderLen, keySize)
   108  	return key
   109  }
   110  
   111  func (t *arrayTable) getKV(i int) ([]byte, []byte) {
   112  	if !t.validIndexPos(i) {
   113  		return nil, nil
   114  	}
   115  
   116  	var itemSize uint32
   117  	itemOffset := t.index[i]
   118  	if i == t.num-1 {
   119  		itemSize = t.arena.Size() - itemOffset
   120  	} else {
   121  		itemSize = t.index[i+1] - itemOffset
   122  	}
   123  
   124  	keySize := uint32(binary.BigEndian.Uint16(t.arena.GetBytes(itemOffset, itemHeaderLen)))
   125  	key := t.arena.GetBytes(itemOffset+itemHeaderLen, keySize)
   126  	valueSize := itemSize - keySize - itemHeaderLen
   127  	value := t.arena.GetBytes(itemOffset+itemHeaderLen+keySize, valueSize)
   128  
   129  	return key, value
   130  }
   131  
   132  func (t *arrayTable) seek(key []byte) (*internalKey, []byte) {
   133  	iter := t.newIter(nil)
   134  	defer iter.Close()
   135  
   136  	ik, value := iter.SeekGE(key)
   137  	if ik == nil || !bytes.Equal(ik.UserKey, key) {
   138  		return nil, nil
   139  	}
   140  	return ik, value
   141  }
   142  
   143  func (t *arrayTable) newIter(o *iterOptions) internalIterator {
   144  	iter := iterPool.Get().(*arrayTableIterator)
   145  	*iter = arrayTableIterator{
   146  		at:        t,
   147  		indexPos:  0,
   148  		iterKey:   new(internalKey),
   149  		iterValue: nil,
   150  	}
   151  	return iter
   152  }
   153  
   154  func (t *arrayTable) newFlushIter(o *iterOptions, bytesFlushed *uint64) internalIterator {
   155  	iter := &arrayTableFlushIterator{
   156  		arrayTableIterator: arrayTableIterator{at: t, iterKey: new(internalKey)},
   157  		bytesIterated:      bytesFlushed,
   158  	}
   159  	return iter
   160  }
   161  
   162  func (t *arrayTable) inuseBytes() uint64 {
   163  	return uint64(t.arena.Size())
   164  }
   165  
   166  func (t *arrayTable) totalBytes() uint64 {
   167  	return uint64(t.arena.Capacity())
   168  }
   169  
   170  func (t *arrayTable) close() error {
   171  	return nil
   172  }
   173  
   174  func (t *arrayTable) readyForFlush() bool {
   175  	return true
   176  }
   177  
   178  func (t *arrayTable) getID() int64 {
   179  	return t.id
   180  }
   181  
   182  func (t *arrayTable) count() int {
   183  	return t.num
   184  }