github.com/rosedblabs/rosedb/v2@v2.3.7-0.20240423093736-a89ea823e5b9/record.go (about)

     1  package rosedb
     2  
     3  import (
     4  	"encoding/binary"
     5  	"github.com/rosedblabs/wal"
     6  	"github.com/valyala/bytebufferpool"
     7  )
     8  
     9  // LogRecordType is the type of the log record.
    10  type LogRecordType = byte
    11  
    12  const (
    13  	// LogRecordNormal is the normal log record type.
    14  	LogRecordNormal LogRecordType = iota
    15  	// LogRecordDeleted is the deleted log record type.
    16  	LogRecordDeleted
    17  	// LogRecordBatchFinished is the batch finished log record type.
    18  	LogRecordBatchFinished
    19  )
    20  
    21  // type batchId keySize valueSize expire
    22  //
    23  //	1  +  10  +   5   +   5   +    10  = 31
    24  const maxLogRecordHeaderSize = binary.MaxVarintLen32*2 + binary.MaxVarintLen64*2 + 1
    25  
    26  // LogRecord is the log record of the key/value pair.
    27  // It contains the key, the value, the record type and the batch id
    28  // It will be encoded to byte slice and written to the wal.
    29  type LogRecord struct {
    30  	Key     []byte
    31  	Value   []byte
    32  	Type    LogRecordType
    33  	BatchId uint64
    34  	Expire  int64
    35  }
    36  
    37  // IsExpired checks whether the log record is expired.
    38  func (lr *LogRecord) IsExpired(now int64) bool {
    39  	return lr.Expire > 0 && lr.Expire <= now
    40  }
    41  
    42  // IndexRecord is the index record of the key.
    43  // It contains the key, the record type and the position of the record in the wal.
    44  // Only used in start up to rebuild the index.
    45  type IndexRecord struct {
    46  	key        []byte
    47  	recordType LogRecordType
    48  	position   *wal.ChunkPosition
    49  }
    50  
    51  // +-------------+-------------+-------------+--------------+---------------+---------+--------------+
    52  // |    type     |  batch id   |   key size  |   value size |     expire    |  key    |      value   |
    53  // +-------------+-------------+-------------+--------------+---------------+--------+--------------+
    54  //
    55  //	1 byte	      varint(max 10) varint(max 5)  varint(max 5) varint(max 10)  varint      varint
    56  func encodeLogRecord(logRecord *LogRecord, header []byte, buf *bytebufferpool.ByteBuffer) []byte {
    57  	header[0] = logRecord.Type
    58  	var index = 1
    59  
    60  	// batch id
    61  	index += binary.PutUvarint(header[index:], logRecord.BatchId)
    62  	// key size
    63  	index += binary.PutVarint(header[index:], int64(len(logRecord.Key)))
    64  	// value size
    65  	index += binary.PutVarint(header[index:], int64(len(logRecord.Value)))
    66  	// expire
    67  	index += binary.PutVarint(header[index:], logRecord.Expire)
    68  
    69  	// copy header
    70  	_, _ = buf.Write(header[:index])
    71  	// copy key
    72  	_, _ = buf.Write(logRecord.Key)
    73  	// copy value
    74  	_, _ = buf.Write(logRecord.Value)
    75  
    76  	return buf.Bytes()
    77  }
    78  
    79  // decodeLogRecord decodes the log record from the given byte slice.
    80  func decodeLogRecord(buf []byte) *LogRecord {
    81  	recordType := buf[0]
    82  
    83  	var index uint32 = 1
    84  	// batch id
    85  	batchId, n := binary.Uvarint(buf[index:])
    86  	index += uint32(n)
    87  
    88  	// key size
    89  	keySize, n := binary.Varint(buf[index:])
    90  	index += uint32(n)
    91  
    92  	// value size
    93  	valueSize, n := binary.Varint(buf[index:])
    94  	index += uint32(n)
    95  
    96  	// expire
    97  	expire, n := binary.Varint(buf[index:])
    98  	index += uint32(n)
    99  
   100  	// copy key
   101  	key := make([]byte, keySize)
   102  	copy(key[:], buf[index:index+uint32(keySize)])
   103  	index += uint32(keySize)
   104  
   105  	// copy value
   106  	value := make([]byte, valueSize)
   107  	copy(value[:], buf[index:index+uint32(valueSize)])
   108  
   109  	return &LogRecord{Key: key, Value: value, Expire: expire,
   110  		BatchId: batchId, Type: recordType}
   111  }
   112  
   113  func encodeHintRecord(key []byte, pos *wal.ChunkPosition) []byte {
   114  	// SegmentId BlockNumber ChunkOffset ChunkSize
   115  	//    5          5           10          5      =    25
   116  	// see binary.MaxVarintLen64 and binary.MaxVarintLen32
   117  	buf := make([]byte, 25)
   118  	var idx = 0
   119  
   120  	// SegmentId
   121  	idx += binary.PutUvarint(buf[idx:], uint64(pos.SegmentId))
   122  	// BlockNumber
   123  	idx += binary.PutUvarint(buf[idx:], uint64(pos.BlockNumber))
   124  	// ChunkOffset
   125  	idx += binary.PutUvarint(buf[idx:], uint64(pos.ChunkOffset))
   126  	// ChunkSize
   127  	idx += binary.PutUvarint(buf[idx:], uint64(pos.ChunkSize))
   128  
   129  	// key
   130  	result := make([]byte, idx+len(key))
   131  	copy(result, buf[:idx])
   132  	copy(result[idx:], key)
   133  	return result
   134  }
   135  
   136  func decodeHintRecord(buf []byte) ([]byte, *wal.ChunkPosition) {
   137  	var idx = 0
   138  	// SegmentId
   139  	segmentId, n := binary.Uvarint(buf[idx:])
   140  	idx += n
   141  	// BlockNumber
   142  	blockNumber, n := binary.Uvarint(buf[idx:])
   143  	idx += n
   144  	// ChunkOffset
   145  	chunkOffset, n := binary.Uvarint(buf[idx:])
   146  	idx += n
   147  	// ChunkSize
   148  	chunkSize, n := binary.Uvarint(buf[idx:])
   149  	idx += n
   150  	// Key
   151  	key := buf[idx:]
   152  
   153  	return key, &wal.ChunkPosition{
   154  		SegmentId:   wal.SegmentID(segmentId),
   155  		BlockNumber: uint32(blockNumber),
   156  		ChunkOffset: int64(chunkOffset),
   157  		ChunkSize:   uint32(chunkSize),
   158  	}
   159  }
   160  
   161  func encodeMergeFinRecord(segmentId wal.SegmentID) []byte {
   162  	buf := make([]byte, 4)
   163  	binary.LittleEndian.PutUint32(buf, segmentId)
   164  	return buf
   165  }