From bc14b51a1bc305c163715fffaab7255f62649f9c Mon Sep 17 00:00:00 2001 From: Daniil Porokhnin Date: Thu, 14 May 2026 13:43:51 +0300 Subject: [PATCH 1/2] perf: find `TokenTable` index once --- frac/sealed/token/table_loader.go | 44 ++++++++++++++++++------------- 1 file changed, 26 insertions(+), 18 deletions(-) diff --git a/frac/sealed/token/table_loader.go b/frac/sealed/token/table_loader.go index cd04830b..5cca1a21 100644 --- a/frac/sealed/token/table_loader.go +++ b/frac/sealed/token/table_loader.go @@ -3,6 +3,7 @@ package token import ( "encoding/binary" "slices" + "sync" "unsafe" "go.uber.org/zap" @@ -22,7 +23,9 @@ type TableLoader struct { reader *storage.IndexReader cache *cache.Cache[Table] - i uint32 + once sync.Once + tableIndex uint32 + buf []byte } @@ -47,6 +50,8 @@ func (l *TableLoader) Load() Table { err error ) + l.advanceToTable() + if l.isLegacy { blocks, err = l.loadBlocksLegacy() } else { @@ -98,29 +103,24 @@ func TableFromBlocks(blocks []TableBlock) Table { } func (l *TableLoader) readHeader() storage.IndexBlockHeader { - h, e := l.reader.GetBlockHeader(l.i) + h, e := l.reader.GetBlockHeader(l.tableIndex) if e != nil { logger.Panic("error reading block header", zap.Error(e)) } - l.i++ + l.tableIndex++ return h } func (l *TableLoader) readBlock() ([]byte, error) { - block, _, err := l.reader.ReadIndexBlock(l.i, l.buf) + block, _, err := l.reader.ReadIndexBlock(l.tableIndex, l.buf) l.buf = block - l.i++ + l.tableIndex++ return block, err } func (l *TableLoader) loadBlocksLegacy() ([]TableBlock, error) { - l.i = 1 // Skip info block immediately. - - for h := l.readHeader(); h.Len() > 0; h = l.readHeader() { - // Skip token blocks, go for token table. - } - blocks := make([]TableBlock, 0) + for blockData, err := l.readBlock(); len(blockData) > 0; blockData, err = l.readBlock() { if err != nil { return nil, err @@ -134,19 +134,13 @@ func (l *TableLoader) loadBlocksLegacy() ([]TableBlock, error) { } func (l *TableLoader) loadBlocks() ([]TableBlock, error) { - l.i = 0 - blocksCount, err := l.reader.BlocksCount() if err != nil { return nil, err } - for h := l.readHeader(); h.Len() > 0; h = l.readHeader() { - // Skip token blocks, go for token table. - } - var blocks []TableBlock - for l.i < uint32(blocksCount) { + for l.tableIndex < uint32(blocksCount) { data, err := l.readBlock() if err != nil { return nil, err @@ -161,6 +155,20 @@ func (l *TableLoader) loadBlocks() ([]TableBlock, error) { return blocks, nil } +func (l *TableLoader) advanceToTable() { + l.once.Do(func() { + // This is correct for both legacy and non-legacy sealed fractions: + // - in legacy fractions we have following layout: [info][token][separator][token-table][...]; + // - in non-legacy fraction we have following layout: [token][separator][token-table]; + // As you can see, it is safe to start from 0-th block in both cases. + l.tableIndex = 0 + + for h := l.readHeader(); h.Len() > 0; h = l.readHeader() { + // Skip token blocks, go for token table. + } + }) +} + // TableBlock represents how token.Table is stored on disk type TableBlock struct { FieldsTables []FieldTable From f162f853e8da0bf81448b80636ea1e471d0dc376 Mon Sep 17 00:00:00 2001 From: Daniil Porokhnin Date: Mon, 18 May 2026 15:45:25 +0300 Subject: [PATCH 2/2] fix: use `blockIndex` for iteration --- frac/sealed/token/table_loader.go | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/frac/sealed/token/table_loader.go b/frac/sealed/token/table_loader.go index 5cca1a21..a3fd61c0 100644 --- a/frac/sealed/token/table_loader.go +++ b/frac/sealed/token/table_loader.go @@ -102,32 +102,34 @@ func TableFromBlocks(blocks []TableBlock) Table { return table } -func (l *TableLoader) readHeader() storage.IndexBlockHeader { - h, e := l.reader.GetBlockHeader(l.tableIndex) +func (l *TableLoader) readHeader(idx uint32) storage.IndexBlockHeader { + h, e := l.reader.GetBlockHeader(idx) if e != nil { logger.Panic("error reading block header", zap.Error(e)) } - l.tableIndex++ return h } -func (l *TableLoader) readBlock() ([]byte, error) { - block, _, err := l.reader.ReadIndexBlock(l.tableIndex, l.buf) +func (l *TableLoader) readBlock(idx uint32) ([]byte, error) { + block, _, err := l.reader.ReadIndexBlock(idx, l.buf) l.buf = block - l.tableIndex++ return block, err } func (l *TableLoader) loadBlocksLegacy() ([]TableBlock, error) { blocks := make([]TableBlock, 0) - for blockData, err := l.readBlock(); len(blockData) > 0; blockData, err = l.readBlock() { + blockIndex := l.tableIndex + for blockData, err := l.readBlock(blockIndex); len(blockData) > 0; blockData, err = l.readBlock(blockIndex) { if err != nil { return nil, err } - tb := TableBlock{} + + var tb TableBlock tb.Unpack(blockData) + blocks = append(blocks, tb) + blockIndex += 1 } return blocks, nil @@ -140,8 +142,8 @@ func (l *TableLoader) loadBlocks() ([]TableBlock, error) { } var blocks []TableBlock - for l.tableIndex < uint32(blocksCount) { - data, err := l.readBlock() + for blockIndex := l.tableIndex; blockIndex < uint32(blocksCount); blockIndex++ { + data, err := l.readBlock(blockIndex) if err != nil { return nil, err } @@ -161,11 +163,16 @@ func (l *TableLoader) advanceToTable() { // - in legacy fractions we have following layout: [info][token][separator][token-table][...]; // - in non-legacy fraction we have following layout: [token][separator][token-table]; // As you can see, it is safe to start from 0-th block in both cases. - l.tableIndex = 0 + blockIndex := uint32(0) - for h := l.readHeader(); h.Len() > 0; h = l.readHeader() { + for h := l.readHeader(blockIndex); h.Len() > 0; h = l.readHeader(blockIndex) { // Skip token blocks, go for token table. + blockIndex += 1 } + + // We've stopped iterating on section separator. + // Therefore increment is required to reach index of actual token table. + l.tableIndex = blockIndex + 1 }) }