Some checks failed
Go Tests / Run Tests (1.24.2) (push) Has been cancelled
Adds a complete LSM-based storage engine with these features: - Single-writer based architecture for the storage engine - WAL for durability, and hey it's configurable - MemTable with skip list implementation for fast read/writes - SSTable with block-based structure for on-disk level-based storage - Background compaction with tiered strategy - ACID transactions - Good documentation (I hope)
73 lines
1.8 KiB
Go
73 lines
1.8 KiB
Go
package block
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"fmt"
|
|
|
|
"github.com/cespare/xxhash/v2"
|
|
)
|
|
|
|
// Reader provides methods to read data from a serialized block
|
|
type Reader struct {
|
|
data []byte
|
|
restartPoints []uint32
|
|
numRestarts uint32
|
|
checksum uint64
|
|
}
|
|
|
|
// NewReader creates a new block reader
|
|
func NewReader(data []byte) (*Reader, error) {
|
|
if len(data) < BlockFooterSize {
|
|
return nil, fmt.Errorf("block data too small: %d bytes", len(data))
|
|
}
|
|
|
|
// Read footer
|
|
footerOffset := len(data) - BlockFooterSize
|
|
numRestarts := binary.LittleEndian.Uint32(data[footerOffset : footerOffset+4])
|
|
checksum := binary.LittleEndian.Uint64(data[footerOffset+4:])
|
|
|
|
// Verify checksum - the checksum covers everything except the checksum itself
|
|
computedChecksum := xxhash.Sum64(data[:len(data)-8])
|
|
if computedChecksum != checksum {
|
|
return nil, fmt.Errorf("block checksum mismatch: expected %d, got %d",
|
|
checksum, computedChecksum)
|
|
}
|
|
|
|
// Read restart points
|
|
restartOffset := footerOffset - int(numRestarts)*4
|
|
if restartOffset < 0 {
|
|
return nil, fmt.Errorf("invalid restart points offset")
|
|
}
|
|
|
|
restartPoints := make([]uint32, numRestarts)
|
|
for i := uint32(0); i < numRestarts; i++ {
|
|
restartPoints[i] = binary.LittleEndian.Uint32(
|
|
data[restartOffset+int(i)*4:])
|
|
}
|
|
|
|
reader := &Reader{
|
|
data: data,
|
|
restartPoints: restartPoints,
|
|
numRestarts: numRestarts,
|
|
checksum: checksum,
|
|
}
|
|
|
|
return reader, nil
|
|
}
|
|
|
|
// Iterator returns an iterator for the block
|
|
func (r *Reader) Iterator() *Iterator {
|
|
// Calculate the data end position (everything before the restart points array)
|
|
dataEnd := len(r.data) - BlockFooterSize - 4*len(r.restartPoints)
|
|
|
|
return &Iterator{
|
|
reader: r,
|
|
currentPos: 0,
|
|
currentKey: nil,
|
|
currentVal: nil,
|
|
restartIdx: 0,
|
|
initialized: false,
|
|
dataEnd: uint32(dataEnd),
|
|
}
|
|
}
|