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 }