Skip to main content

table.go

table.go - Overview

This file defines the Table struct and related methods for managing SSTable (Sorted String Table) files in BadgerDB. It includes functionalities for opening, reading, and accessing data within these tables, along with support for encryption, compression, and checksum verification.

Detailed Documentation

Options

type Options struct {
ReadOnly bool
MetricsEnabled bool
TableSize uint64
tableCapacity uint64
ChkMode options.ChecksumVerificationMode
BloomFalsePositive float64
BlockSize int
DataKey *pb.DataKey
Compression options.CompressionType
BlockCache *ristretto.Cache[[]byte, *Block]
IndexCache *ristretto.Cache[uint64, *fb.TableIndex]
AllocPool *z.AllocatorPool
ZSTDCompressionLevel int
}
  • Purpose: Configuration options for opening and building tables.
    • ReadOnly: Opens tables in read-only mode.
    • MetricsEnabled: Enables metrics for the table.
    • TableSize: Maximum size of the table.
    • tableCapacity: 0.9x TableSize.
    • ChkMode: Checksum verification mode.
    • BloomFalsePositive: False positive probability of bloom filter.
    • BlockSize: Size of each block inside SSTable in bytes.
    • DataKey: Key used to decrypt the encrypted text.
    • Compression: Compression algorithm used for block compression.
    • BlockCache: Cache for decompressed and decrypted blocks.
    • IndexCache: Cache for table indexes.
    • AllocPool: Allocator pool.
    • ZSTDCompressionLevel: ZSTD compression level.

TableInterface

type TableInterface interface {
Smallest() []byte
Biggest() []byte
DoesNotHave(hash uint32) bool
MaxVersion() uint64
}
  • Purpose: Interface for testing Table struct.
    • Smallest(): Returns the smallest key in the table.
    • Biggest(): Returns the biggest key in the table.
    • DoesNotHave(hash uint32): Checks if the table does not have the key hash.
    • MaxVersion(): Returns the maximum version across all keys stored in this table.

Table

type Table struct {
sync.Mutex
*z.MmapFile

tableSize int

_index *fb.TableIndex
_cheap *cheapIndex
ref atomic.Int32

smallest, biggest []byte
id uint64

Checksum []byte
CreatedAt time.Time
indexStart int
indexLen int
hasBloomFilter bool

IsInmemory bool
opt *Options
}
  • Purpose: Represents a loaded table file.
    • MmapFile: Mapped file.
    • tableSize: Size of the table.
    • _index: Table index.
    • _cheap: Cheap index for quick access.
    • ref: Reference count for garbage collection.
    • smallest: Smallest key in the table.
    • biggest: Biggest key in the table.
    • id: File ID.
    • Checksum: Checksum of the table.
    • CreatedAt: Time the table was created.
    • indexStart: Start position of the index in the file.
    • indexLen: Length of the index.
    • hasBloomFilter: Indicates if the table has a bloom filter.
    • IsInmemory: Indicates if the table is in memory.
    • opt: Options for the table.

cheapIndex

type cheapIndex struct {
MaxVersion uint64
KeyCount uint32
UncompressedSize uint32
OnDiskSize uint32
BloomFilterLength int
OffsetsLength int
}
  • Purpose: Provides quick access to index metadata.
    • MaxVersion: Maximum version across all keys.
    • KeyCount: Total number of keys.
    • UncompressedSize: Uncompressed size of data.
    • OnDiskSize: On-disk size of key-values.
    • BloomFilterLength: Length of the bloom filter.
    • OffsetsLength: Number of offsets.

(t *Table) cheapIndex() *cheapIndex

func (t *Table) cheapIndex() *cheapIndex {
return t._cheap
}
  • Purpose: Returns the cheap index of the table.
  • Returns: A pointer to the cheapIndex struct.

(t *Table) offsetsLength() int

func (t *Table) offsetsLength() int { return t.cheapIndex().OffsetsLength }
  • Purpose: Returns the length of the offsets in the cheap index.
  • Returns: The OffsetsLength from the cheapIndex.

(t *Table) MaxVersion() uint64

func (t *Table) MaxVersion() uint64 { return t.cheapIndex().MaxVersion }
  • Purpose: Returns the maximum version of keys in the table using the cheap index.
  • Returns: The MaxVersion from the cheapIndex.

(t *Table) BloomFilterSize() int

func (t *Table) BloomFilterSize() int { return t.cheapIndex().BloomFilterLength }
  • Purpose: Returns the size of the bloom filter using the cheap index.
  • Returns: The BloomFilterLength from the cheapIndex.

(t *Table) UncompressedSize() uint32

func (t *Table) UncompressedSize() uint32 { return t.cheapIndex().UncompressedSize }
  • Purpose: Returns the uncompressed size of the data using the cheap index.
  • Returns: The UncompressedSize from the cheapIndex.

(t *Table) KeyCount() uint32

func (t *Table) KeyCount() uint32 { return t.cheapIndex().KeyCount }
  • Purpose: Returns the number of keys in the table using the cheap index.
  • Returns: The KeyCount from the cheapIndex.

(t *Table) OnDiskSize() uint32

func (t *Table) OnDiskSize() uint32 { return t.cheapIndex().OnDiskSize }
  • Purpose: Returns the on-disk size of the key-values using the cheap index.
  • Returns: The OnDiskSize from the cheapIndex.

(t *Table) CompressionType() options.CompressionType

func (t *Table) CompressionType() options.CompressionType {
return t.opt.Compression
}
  • Purpose: Returns the compression type used for the table.
  • Returns: The Compression type from the table's options.

(t *Table) IncrRef()

func (t *Table) IncrRef() {
t.ref.Add(1)
}
  • Purpose: Increments the reference count of the table.

(t *Table) DecrRef() error

func (t *Table) DecrRef() error {
newRef := t.ref.Add(-1)
if newRef == 0 {
for i := 0; i < t.offsetsLength(); i++ {
t.opt.BlockCache.Del(t.blockCacheKey(i))
}
if err := t.Delete(); err != nil {
return err
}
}
return nil
}
  • Purpose: Decrements the reference count of the table and deletes it if the count reaches zero.
  • Returns: An error if deletion fails, nil otherwise.

BlockEvictHandler(b *Block)

func BlockEvictHandler(b *Block) {
b.decrRef()
}
  • Purpose: Handler function called when a block is evicted from the cache. Decrements the reference count of the block.
  • Parameters:
    • b: The block being evicted.

Block

type Block struct {
offset int
data []byte
checksum []byte
entriesIndexStart int
entryOffsets []uint32
chkLen int
freeMe bool
ref atomic.Int32
}
  • Purpose: Represents a block of data within a table.
    • offset: Offset of the block in the file.
    • data: Data within the block.
    • checksum: Checksum of the block.
    • entriesIndexStart: Start index of entryOffsets list.
    • entryOffsets: Offsets of entries within the block.
    • chkLen: Checksum length.
    • freeMe: Indicates if the data needs to be freed.
    • ref: Reference count.

(b *Block) incrRef() bool

func (b *Block) incrRef() bool {
for {
ref := b.ref.Load()
if ref == 0 {
return false
}
if b.ref.CompareAndSwap(ref, ref+1) {
return true
}
}
}
  • Purpose: Atomically increments the reference count of the block.
  • Returns: true if the increment was successful, false otherwise.

(b *Block) decrRef()

func (b *Block) decrRef() {
if b == nil {
return
}

if b.ref.Add(-1) == 0 {
if b.freeMe {
z.Free(b.data)
}
NumBlocks.Add(-1)
}
y.AssertTrue(b.ref.Load() >= 0)
}
  • Purpose: Decrements the reference count of the block and frees the data if the count reaches zero and the freeMe flag is set.

(b *Block) size() int64

func (b *Block) size() int64 {
return int64(3*intSize /* Size of the offset, entriesIndexStart and chkLen */ +
cap(b.data) + cap(b.checksum) + cap(b.entryOffsets)*4)
}
  • Purpose: Calculates the size of the block in bytes.
  • Returns: The calculated size as an int64.

(b *Block) verifyCheckSum() error

func (b *Block) verifyCheckSum() error {
cs := &pb.Checksum{}
if err := proto.Unmarshal(b.checksum, cs); err != nil {
return y.Wrapf(err, "unable to unmarshal checksum for block")
}
return y.VerifyChecksum(b.data, cs)
}
  • Purpose: Verifies the checksum of the block's data.
  • Returns: An error if the checksum verification fails, nil otherwise.

CreateTable(fname string, builder *Builder) (*Table, error)

func CreateTable(fname string, builder *Builder) (*Table, error) {
bd := builder.Done()
mf, err := z.OpenMmapFile(fname, os.O_CREATE|os.O_RDWR|os.O_EXCL, bd.Size)
if err == z.NewFile {
} else if err != nil {
return nil, y.Wrapf(err, "while creating table: %s", fname)
} else {
return nil, fmt.Errorf("file already exists: %s", fname)
}

written := bd.Copy(mf.Data)
y.AssertTrue(written == len(mf.Data))
if err := z.Msync(mf.Data); err != nil {
return nil, y.Wrapf(err, "while calling msync on %s", fname)
}
return OpenTable(mf, *builder.opts)
}
  • Purpose: Creates a new table file from a builder.
  • Parameters:
    • fname: The filename for the new table.
    • builder: The builder containing the table data.
  • Returns: A pointer to the created Table and an error, if any.

OpenTable(mf *z.MmapFile, opts Options) (*Table, error)

func OpenTable(mf *z.MmapFile, opts Options) (*Table, error) {
if opts.BlockSize == 0 && opts.Compression != options.None {
return nil, errors.New("Block size cannot be zero")
}
fileInfo, err := mf.Fd.Stat()
if err != nil {
mf.Close(-1)
return nil, y.Wrap(err, "")
}

filename := fileInfo.Name()
id, ok := ParseFileID(filename)
if !ok {
mf.Close(-1)
return nil, fmt.Errorf("Invalid filename: %s", filename)
}
t := &Table{
MmapFile: mf,
id: id,
opt: &opts,
IsInmemory: false,
tableSize: int(fileInfo.Size()),
CreatedAt: fileInfo.ModTime(),
}
t.ref.Store(1)

if err := t.initBiggestAndSmallest(); err != nil {
return nil, y.Wrapf(err, "failed to initialize table")
}

if opts.ChkMode == options.OnTableRead || opts.ChkMode == options.OnTableAndBlockRead {
if err := t.VerifyChecksum(); err != nil {
mf.Close(-1)
return nil, y.Wrapf(err, "failed to verify checksum")
}
}

return t, nil
}
  • Purpose: Opens an existing table file.
  • Parameters:
    • mf: The mmapped file representing the table.
    • opts: The options for opening the table.
  • Returns: A pointer to the opened Table and an error, if any.

OpenInMemoryTable(data []byte, id uint64, opt *Options) (*Table, error)

func OpenInMemoryTable(data []byte, id uint64, opt *Options) (*Table, error) {
mf := &z.MmapFile{
Data: data,
Fd: nil,
}
t := &Table{
MmapFile: mf,
opt: opt,
tableSize: len(data),
IsInmemory: true,
id: id,
}
t.ref.Store(1)

if err := t.initBiggestAndSmallest(); err != nil {
return nil, err
}
return t, nil
}
  • Purpose: Opens a table from in-memory data.
  • Parameters:
    • data: The byte slice containing the table data.
    • id: The ID of the table.
    • opt: The options for the table.
  • Returns: A pointer to the opened Table and an error, if any.

(t *Table) initBiggestAndSmallest() error

func (t *Table) initBiggestAndSmallest() error {
defer func() {
if r := recover(); r != nil {
var debugBuf bytes.Buffer
defer func() {
panic(fmt.Sprintf("%s\n== Recovered ==\n", debugBuf.String()))
}()

count := 0
for i := len(t.Data) - 1; i >= 0; i-- {
if t.Data[i] != 0 {
break
}
count++
}

fmt.Fprintf(&debugBuf, "\n== Recovering from initIndex crash ==\n")
fmt.Fprintf(&debugBuf, "File Info: [ID: %d, Size: %d, Zeros: %d]\n",
t.id, t.tableSize, count)

fmt.Fprintf(&debugBuf, "isEnrypted: %v ", t.shouldDecrypt())

readPos := t.tableSize

readPos -= 4
buf := t.readNoFail(readPos, 4)
checksumLen := int(y.BytesToU32(buf))
fmt.Fprintf(&debugBuf, "checksumLen: %d ", checksumLen)

checksum := &pb.Checksum{}
readPos -= checksumLen
buf = t.readNoFail(readPos, checksumLen)
_ = proto.Unmarshal(buf, checksum)
fmt.Fprintf(&debugBuf, "checksum: %+v ", checksum)

readPos -= 4
buf = t.readNoFail(readPos, 4)
indexLen := int(y.BytesToU32(buf))
fmt.Fprintf(&debugBuf, "indexLen: %d ", indexLen)

readPos -= t.indexLen
t.indexStart = readPos
indexData := t.readNoFail(readPos, t.indexLen)
fmt.Fprintf(&debugBuf, "index: %v ", indexData)
}
}()

var err error
var ko *fb.BlockOffset
if ko, err = t.initIndex(); err != nil {
return y.Wrapf(err, "failed to read index.")
}

t.smallest = y.Copy(ko.KeyBytes())

it2 := t.NewIterator(REVERSED | NOCACHE)
defer it2.Close()
it2.Rewind()
if !it2.Valid() {
return y.Wrapf(it2.err, "failed to initialize biggest for table %s", t.Filename())
}
t.biggest = y.Copy(it2.Key())
return nil
}
  • Purpose: Initializes the smallest and biggest keys of the table by reading the index.
  • Returns: An error if initialization fails, nil otherwise.

(t *Table) read(off, sz int) ([]byte, error)

func (t *Table) read(off, sz int) ([]byte, error) {
return t.Bytes(off, sz)
}
  • Purpose: Reads a slice of bytes from the table's data.
  • Parameters:
    • off: The offset to start reading from.
    • sz: The number of bytes to read.
  • Returns: A byte slice containing the read data and an error, if any.

(t *Table) readNoFail(off, sz int) []byte

func (t *Table) readNoFail(off, sz int) []byte {
res, err := t.read(off, sz)
y.Check(err)
return res
}
  • Purpose: Reads a slice of bytes from the table's data, panicking on error.
  • Parameters:
    • off: The offset to start reading from.
    • sz: The number of bytes to read.
  • Returns: A byte slice containing the read data.

(t *Table) initIndex() (*fb.BlockOffset, error)

func (t *Table) initIndex() (*fb.BlockOffset, error) {
readPos := t.tableSize

readPos -= 4
buf := t.readNoFail(readPos, 4)
checksumLen := int(y.BytesToU32(buf))
if checksumLen < 0 {
return nil, errors.New("checksum length less than zero. Data corrupted")
}

expectedChk := &pb.Checksum{}
readPos -= checksumLen
buf = t.readNoFail(readPos, checksumLen)
if err := proto.Unmarshal(buf, expectedChk); err != nil {
return nil, err
}

readPos -= 4
buf = t.readNoFail(readPos, 4)
t.indexLen = int(y.BytesToU32(buf))

readPos -= t.indexLen
t.indexStart = readPos
data := t.readNoFail(readPos, t.indexLen)

if err := y.VerifyChecksum(data, expectedChk); err != nil {
return nil, y.Wrapf(err, "failed to verify checksum for table: %s", t.Filename())
}

index, err := t.readTableIndex()
if err != nil {
return nil, err
}
if !t.shouldDecrypt() {
t._index = index
}
t._cheap = &cheapIndex{
MaxVersion: index.MaxVersion(),
KeyCount: index.KeyCount(),
UncompressedSize: index.UncompressedSize(),
OnDiskSize: index.OnDiskSize(),
OffsetsLength: index.OffsetsLength(),
BloomFilterLength: index.BloomFilterLength(),
}

t.hasBloomFilter = len(index.BloomFilterBytes()) > 0

var bo fb.BlockOffset
y.AssertTrue(index.Offsets(&bo, 0))
return &bo, nil
}
  • Purpose: Initializes the table index by reading it from the file.
  • Returns: A pointer to the first BlockOffset and an error, if any.

(t *Table) KeySplits(n int, prefix []byte) []string

func (t *Table) KeySplits(n int, prefix []byte) []string {
if n == 0 {
return nil
}

oLen := t.offsetsLength()
jump := oLen / n
if jump == 0 {
jump = 1
}

var bo fb.BlockOffset
var res []string
for i := 0; i &lt; oLen; i += jump {
if i >= oLen {
i = oLen - 1
}
y.AssertTrue(t.offsets(&bo, i))
if bytes.HasPrefix(bo.KeyBytes(), prefix) {
res = append(res, string(bo.KeyBytes()))
}
}
return res
}
  • Purpose: Splits the table into at least n ranges based on the block offsets, considering a given prefix.
  • Parameters:
    • n: The minimum number of ranges to split into.
    • prefix: Only include keys with this prefix.
  • Returns: A slice of strings representing the split keys.

(t *Table) fetchIndex() *fb.TableIndex

func (t *Table) fetchIndex() *fb.TableIndex {
if !t.shouldDecrypt() {
return t._index
}

if t.opt.IndexCache == nil {
panic("Index Cache must be set for encrypted workloads")
}
if val, ok := t.opt.IndexCache.Get(t.indexKey()); ok && val != nil {
return val
}

index, err := t.readTableIndex()
y.Check(err)
t.opt.IndexCache.Set(t.indexKey(), index, int64(t.indexLen))
return index
}
  • Purpose: Fetches the table index, either from the cache or by reading it from the file.
  • Returns: A pointer to the TableIndex.

(t *Table) offsets(ko *fb.BlockOffset, i int) bool

func (t *Table) offsets(ko *fb.BlockOffset, i int) bool {
return t.fetchIndex().Offsets(ko, i)
}
  • Purpose: Retrieves the block offset at the given index from the table index.
  • Parameters:
    • ko: A pointer to a BlockOffset to store the result.
    • i: The index of the desired block offset.
  • Returns: A boolean indicating success or failure.

(t *Table) block(idx int, useCache bool) (*Block, error)

func (t *Table) block(idx int, useCache bool) (*Block, error) {
y.AssertTruef(idx >= 0, "idx=%d", idx)
if idx >= t.offsetsLength() {
return nil, errors.New("block out of index")
}
if t.opt.BlockCache != nil {
key := t.blockCacheKey(idx)
blk, ok := t.opt.BlockCache.Get(key)
if ok && blk != nil {
if blk.incrRef() {
return blk, nil
}
}
}

var ko fb.BlockOffset
y.AssertTrue(t.offsets(&ko, idx))
blk := &Block{offset: int(ko.Offset())}
blk.ref.Store(1)
defer blk.decrRef()
NumBlocks.Add(1)

var err error
if blk.data, err = t.read(blk.offset, int(ko.Len())); err != nil {
return nil, y.Wrapf(err,
"failed to read from file: %s at offset: %d, len: %d",
t.Fd.Name(), blk.offset, ko.Len())
}

if t.shouldDecrypt() {
if blk.data, err = t.decrypt(blk.data, true); err != nil {
return nil, err
}
blk.freeMe = true
}

if err = t.decompress(blk); err != nil {
return nil, y.Wrapf(err,
"failed to decode compressed data in file: %s at offset: %d, len: %d",
t.Fd.Name(), blk.offset, ko.Len())
}

readPos := len(blk.data) - 4
blk.chkLen = int(y.BytesToU32(blk.data[readPos : readPos+4]))

if blk.chkLen > len(blk.data) {
return nil, errors.New("invalid checksum length. Either the data is " +
"corrupted or the table options are incorrectly set")
}

readPos -= blk.chkLen
blk.checksum = blk.data[readPos : readPos+blk.chkLen]
readPos -= 4
numEntries := int(y.BytesToU32(blk.data[readPos : readPos+4]))
entriesIndexStart := readPos - (numEntries * 4)
entriesIndexEnd := entriesIndexStart + numEntries*4

blk.entryOffsets = y.BytesToU32Slice(blk.data[entriesIndexStart:entriesIndexEnd])

blk.entriesIndexStart = entriesIndexStart

blk.data = blk.data[:readPos+4]

if t.opt.ChkMode == options.OnBlockRead || t.opt.ChkMode == options.OnTableAndBlockRead {
if err = blk.verifyCheckSum(); err != nil {
return nil, err
}
}

blk.incrRef()
if useCache && t.opt.BlockCache != nil {
y.AssertTrue(blk.incrRef())

if !t.opt.BlockCache.Set(key, blk, blk.size()) {
blk.decrRef()
}
}
return blk, nil
}
  • Purpose: Retrieves a block from the table, using the block cache if enabled.
  • Parameters:
    • idx: The index of the block to retrieve.
    • useCache: Whether to use the block cache.
  • Returns: A pointer to the retrieved Block and an error, if any.

(t *Table) blockCacheKey(idx int) []byte

func (t *Table) blockCacheKey(idx int) []byte {
y.AssertTrue(t.id < math.MaxUint32)
y.AssertTrue(uint32(idx) < math.MaxUint32)

buf := make([]byte, 8)
binary.BigEndian.PutUint32(buf[:4], uint32(t.ID()))
binary.BigEndian.PutUint32(buf[4:], uint32(idx))
return buf
}
  • Purpose: Generates a cache key for a block.
  • Parameters:
    • idx: The index of the block.
  • Returns: A byte slice representing the cache key.

(t *Table) indexKey() uint64

func (t *Table) indexKey() uint64 {
return t.id
}
  • Purpose: Returns the cache key for the table index.
  • Returns: The ID of the table as the cache key.

(t *Table) IndexSize() int

func (t *Table) IndexSize() int {
return t.indexLen
}
  • Purpose: Returns the size of the table index.
  • Returns: The indexLen field.

(t *Table) Size() int64

func (t *Table) Size() int64 { return int64(t.tableSize) }
  • Purpose: Returns the size of the table file.
  • Returns: The tableSize field as an int64.

(t *Table) StaleDataSize() uint32

func (t *Table) StaleDataSize() uint32 { return t.fetchIndex().StaleDataSize() }
  • Purpose: Returns the amount of stale data in the table.
  • Returns: The StaleDataSize from the table index.

(t *Table) Smallest() []byte

func (t *Table) Smallest() []byte { return t.smallest }
  • Purpose: Returns the smallest key in the table.
  • Returns: The smallest field.

(t *Table) Biggest() []byte

func (t *Table) Biggest() []byte { return t.biggest }
  • Purpose: Returns the biggest key in the table.
  • Returns: The biggest field.

(t *Table) Filename() string

func (t *Table) Filename() string { return t.Fd.Name() }
  • Purpose: Returns the filename of the table.
  • Returns: The name of the file descriptor.

(t *Table) ID() uint64

func (t *Table) ID() uint64 { return t.id }
  • Purpose: Returns the ID of the table.
  • Returns: The id field.

(t *Table) DoesNotHave(hash uint32) bool

func (t *Table) DoesNotHave(hash uint32) bool {
if !t.hasBloomFilter {
return false
}

y.NumLSMBloomHitsAdd(t.opt.MetricsEnabled, "DoesNotHave_ALL", 1)
index := t.fetchIndex()
bf := index.BloomFilterBytes()
mayContain := y.Filter(bf).MayContain(hash)
if !mayContain {
y.NumLSMBloomHitsAdd(t.opt.MetricsEnabled, "DoesNotHave_HIT", 1)
}
return !mayContain
}
  • Purpose: Checks if the table potentially does not have a key based on the bloom filter.
  • Parameters:
    • hash: The hash of the key.
  • Returns: true if the bloom filter indicates the key is not present, false otherwise.

(t *Table) readTableIndex() (*fb.TableIndex, error)

func (t *Table) readTableIndex() (*fb.TableIndex, error) {
data := t.readNoFail(t.indexStart, t.indexLen)
var err error
if t.shouldDecrypt() {
if data, err = t.decrypt(data, false); err != nil {
return nil, y.Wrapf(err,
"Error while decrypting table index for the table %d in readTableIndex", t.id)
}
}
return fb.GetRootAsTableIndex(data, 0), nil
}
  • Purpose: Reads the table index from the file, decrypting if necessary.
  • Returns: A pointer to the TableIndex and an error, if any.

(t *Table) VerifyChecksum() error

func (t *Table) VerifyChecksum() error {
ti := t.fetchIndex()
for i := 0; i &lt; ti.OffsetsLength(); i++ {
b, err := t.block(i, true)
if err != nil {
return y.Wrapf(err, "checksum validation failed for table: %s, block: %d, offset:%d",
t.Filename(), i, b.offset)
}
defer b.decrRef()
if !(t.opt.ChkMode == options.OnBlockRead || t.opt.ChkMode == options.OnTableAndBlockRead) {
if err = b.verifyCheckSum(); err != nil {
return y.Wrapf(err,
"checksum validation failed for table: %s, block: %d, offset:%d",
t.Filename(), i, b.offset)
}
}
}
return nil
}
  • Purpose: Verifies the checksum of all blocks in the table.
  • Returns: An error if any checksum verification fails, nil otherwise.

(t *Table) shouldDecrypt() bool

func (t *Table) shouldDecrypt() bool {
return t.opt.DataKey != nil
}
  • Purpose: Determines whether the table should be decrypted based on the presence of a data key.
  • Returns: true if a data key is present, false otherwise.

(t *Table) KeyID() uint64

func (t *Table) KeyID() uint64 {
if t.opt.DataKey != nil {
return t.opt.DataKey.KeyId
}
return 0
}
  • Purpose: Returns the ID of the data key used for encryption.
  • Returns: The key ID if a data key is present, 0 otherwise.

(t *Table) decrypt(data []byte, viaCalloc bool) ([]byte, error)

func (t *Table) decrypt(data []byte, viaCalloc bool) ([]byte, error) {
iv := data[len(data)-aes.BlockSize:]