From d8fa1ea1dbcdfc16c404f99fbd508008007f2df2 Mon Sep 17 00:00:00 2001 From: Daniil Porokhnin Date: Tue, 18 Aug 2026 15:12:15 +0300 Subject: [PATCH 1/2] refactor: fair hit-rate for registry --- frac/remote.go | 109 ++++++++++----------- frac/sealed.go | 257 +++++++++++++++++++++++-------------------------- 2 files changed, 168 insertions(+), 198 deletions(-) diff --git a/frac/remote.go b/frac/remote.go index a7a658e0..30f498ab 100644 --- a/frac/remote.go +++ b/frac/remote.go @@ -48,18 +48,13 @@ type Remote struct { legacyFile storage.ImmutableFile legacyReader storage.IndexReader - // Per-section index files and their readers (new split format only). + // Per-section index files (new split format only). infoFile storage.ImmutableFile tokenFile storage.ImmutableFile offsetsFile storage.ImmutableFile idFile storage.ImmutableFile lidFile storage.ImmutableFile - tokenReader storage.IndexReader - offsetsReader storage.IndexReader - idReader storage.IndexReader - lidReader storage.IndexReader - indexCache *IndexCache initMu *sync.RWMutex @@ -171,32 +166,25 @@ func (f *Remote) createDataProvider(ctx context.Context) (*sealedDataProvider, e return nil, err } - tokenReader := &f.tokenReader - lidReader := &f.lidReader - idReader := &f.idReader - - if f.IsLegacy { - tokenReader = &f.legacyReader - lidReader = &f.legacyReader - idReader = &f.legacyReader - } - + ir := f.indexReaders() return &sealedDataProvider{ ctx: ctx, fractionTypeLabel: "remote", - info: f.info, - config: f.Config, - docsReader: &f.docsReader, - blocksOffsets: f.blocksData.BlocksOffsets, - lidsTable: f.blocksData.LIDsTable, - lidsLoader: lids.NewLoader(f.info.BinaryDataVer, lidReader, cache.NewSession(f.indexCache.LIDs)), - tokenBlockLoader: token.NewBlockLoader(f.BaseFileName, f.Info().BinaryDataVer, tokenReader, cache.NewSession(f.indexCache.Tokens)), - tokenTableLoader: token.NewTableLoader(f.BaseFileName, f.Info().BinaryDataVer, f.IsLegacy, tokenReader, cache.NewSession(f.indexCache.TokenTable)), + info: f.info, + config: f.Config, + docsReader: &f.docsReader, + blocksOffsets: f.blocksData.BlocksOffsets, + + lidsTable: f.blocksData.LIDsTable, + lidsLoader: lids.NewLoader(f.info.BinaryDataVer, &ir.LID, cache.NewSession(f.indexCache.LIDs)), + + tokenBlockLoader: token.NewBlockLoader(f.BaseFileName, f.Info().BinaryDataVer, &ir.Token, cache.NewSession(f.indexCache.Tokens)), + tokenTableLoader: token.NewTableLoader(f.BaseFileName, f.Info().BinaryDataVer, f.IsLegacy, &ir.Token, cache.NewSession(f.indexCache.TokenTable)), idsTable: &f.blocksData.IDsTable, idsProvider: seqids.NewProvider( - idReader, + &ir.ID, cache.NewSession(f.indexCache.MIDs), cache.NewSession(f.indexCache.RIDs), cache.NewSession(f.indexCache.Params), @@ -207,6 +195,38 @@ func (f *Remote) createDataProvider(ctx context.Context) (*sealedDataProvider, e }, nil } +func (f *Remote) indexReaders() IndexReaders { + if f.IsLegacy { + r := storage.NewIndexReader( + f.readLimiter, f.legacyFile.Name(), f.legacyFile, + cache.NewSession(f.indexCache.LegacyRegistry), + ) + return IndexReaders{Token: r, Offsets: r, ID: r, LID: r} + } + + return IndexReaders{ + Token: storage.NewIndexReader( + f.readLimiter, f.tokenFile.Name(), f.tokenFile, + cache.NewSession(f.indexCache.TokenRegistry), + ), + + Offsets: storage.NewIndexReader( + f.readLimiter, f.offsetsFile.Name(), f.offsetsFile, + cache.NewSession(f.indexCache.OffsetsRegistry), + ), + + ID: storage.NewIndexReader( + f.readLimiter, f.idFile.Name(), f.idFile, + cache.NewSession(f.indexCache.IDRegistry), + ), + + LID: storage.NewIndexReader( + f.readLimiter, f.lidFile.Name(), f.lidFile, + cache.NewSession(f.indexCache.LIDRegistry), + ), + } +} + func (f *Remote) Info() *common.Info { return f.info } @@ -298,12 +318,7 @@ func (f *Remote) init() error { return nil } - (&Loader{}).Load(&f.blocksData, f.info, IndexReaders{ - Token: f.tokenReader, - Offsets: f.offsetsReader, - ID: f.idReader, - LID: f.lidReader, - }) + (&Loader{}).Load(&f.blocksData, f.info, f.indexReaders()) f.isInited = true return nil @@ -348,13 +363,7 @@ func (f *Remote) openIndex() error { if f.tokenFile == nil { if err := f.openRemoteFile( consts.TokenFileSuffix, - func(file storage.ImmutableFile) { - f.tokenFile = file - f.tokenReader = storage.NewIndexReader( - f.readLimiter, file.Name(), - file, f.indexCache.TokenRegistry, - ) - }, + func(file storage.ImmutableFile) { f.tokenFile = file }, ); err != nil { return err } @@ -363,13 +372,7 @@ func (f *Remote) openIndex() error { if f.offsetsFile == nil { if err := f.openRemoteFile( consts.OffsetsFileSuffix, - func(file storage.ImmutableFile) { - f.offsetsFile = file - f.offsetsReader = storage.NewIndexReader( - f.readLimiter, file.Name(), - file, f.indexCache.OffsetsRegistry, - ) - }, + func(file storage.ImmutableFile) { f.offsetsFile = file }, ); err != nil { return err } @@ -378,13 +381,7 @@ func (f *Remote) openIndex() error { if f.idFile == nil { if err := f.openRemoteFile( consts.IDFileSuffix, - func(file storage.ImmutableFile) { - f.idFile = file - f.idReader = storage.NewIndexReader( - f.readLimiter, file.Name(), - file, f.indexCache.IDRegistry, - ) - }, + func(file storage.ImmutableFile) { f.idFile = file }, ); err != nil { return err } @@ -393,13 +390,7 @@ func (f *Remote) openIndex() error { if f.lidFile == nil { if err := f.openRemoteFile( consts.LIDFileSuffix, - func(file storage.ImmutableFile) { - f.lidFile = file - f.lidReader = storage.NewIndexReader( - f.readLimiter, file.Name(), - file, f.indexCache.LIDRegistry, - ) - }, + func(file storage.ImmutableFile) { f.lidFile = file }, ); err != nil { return err } diff --git a/frac/sealed.go b/frac/sealed.go index 46376c2a..275463d2 100644 --- a/frac/sealed.go +++ b/frac/sealed.go @@ -51,11 +51,6 @@ type Sealed struct { idFile *os.File lidFile *os.File - tokenReader storage.IndexReader - offsetsReader storage.IndexReader - idReader storage.IndexReader - lidReader storage.IndexReader - blocksData sealed.BlocksData indexCache *IndexCache @@ -143,9 +138,12 @@ func NewSealedPreloaded( } // Put token table built during sealing into the cache. - _, _ = indexCache.TokenTable.Get(token.CacheKeyTable, cache.LoaderFunc[token.Table](func(uint32) (token.Table, int, error) { - return preloaded.TokenTable, preloaded.TokenTable.Size(), nil - })) + _, _ = indexCache.TokenTable.Get( + token.CacheKeyTable, + cache.LoaderFunc[token.Table](func(uint32) (token.Table, int, error) { + return preloaded.TokenTable, preloaded.TokenTable.Size(), nil + }), + ) docsCountK := float64(f.info.DocsTotal) / 1000 logger.Info("sealed fraction created from active", @@ -160,94 +158,42 @@ func NewSealedPreloaded( return f } -func (f *Sealed) openInfoLegacy() { - if f.legacyFile != nil { - return - } +func (f *Sealed) openIndex() { + if f.IsLegacy { + // We have exactly one `.index` file for legacy sealed fractions. + // So opening only this file is sufficient. + f.legacyFile = f.openFileIfNeeded(f.legacyFile, f.BaseFileName+consts.IndexFileSuffix) - name := f.BaseFileName + consts.IndexFileSuffix - file, err := os.Open(name) - if err != nil { - logger.Fatal( - "can't open legacy index file", - zap.String("file", name), - zap.Error(err), + f.legacyReader = storage.NewIndexReader( + f.readLimiter, f.legacyFile.Name(), + f.legacyFile, f.indexCache.LegacyRegistry, ) + + return } - f.legacyFile = file - f.legacyReader = storage.NewIndexReader( - f.readLimiter, file.Name(), - file, f.indexCache.LegacyRegistry, - ) + f.infoFile = f.openFileIfNeeded(f.infoFile, f.BaseFileName+consts.InfoFileSuffix) + f.tokenFile = f.openFileIfNeeded(f.tokenFile, f.BaseFileName+consts.TokenFileSuffix) + f.offsetsFile = f.openFileIfNeeded(f.offsetsFile, f.BaseFileName+consts.OffsetsFileSuffix) + f.idFile = f.openFileIfNeeded(f.idFile, f.BaseFileName+consts.IDFileSuffix) + f.lidFile = f.openFileIfNeeded(f.lidFile, f.BaseFileName+consts.LIDFileSuffix) } -func (f *Sealed) openInfo() { - if f.infoFile != nil { - return +func (f *Sealed) openFileIfNeeded(ff *os.File, name string) *os.File { + if ff != nil { + return ff } - name := f.BaseFileName + consts.InfoFileSuffix file, err := os.Open(name) if err != nil { logger.Fatal( - "can't open info file", + "cannot open file", zap.String("file", name), zap.Error(err), ) } - f.infoFile = file -} - -func (f *Sealed) openIndex() { - if f.IsLegacy { - // We have exactly one `.index` file for legacy sealed fractions. - // So opening only this file is sufficient. - f.openInfoLegacy() - return - } - - f.openInfo() - if f.tokenFile == nil { - name := f.BaseFileName + consts.TokenFileSuffix - file, err := os.Open(name) - if err != nil { - logger.Fatal("can't open token file", zap.String("file", name), zap.Error(err)) - } - f.tokenFile = file - f.tokenReader = storage.NewIndexReader(f.readLimiter, file.Name(), file, f.indexCache.TokenRegistry) - } - - if f.offsetsFile == nil { - name := f.BaseFileName + consts.OffsetsFileSuffix - file, err := os.Open(name) - if err != nil { - logger.Fatal("can't open offsets file", zap.String("file", name), zap.Error(err)) - } - f.offsetsFile = file - f.offsetsReader = storage.NewIndexReader(f.readLimiter, file.Name(), file, f.indexCache.OffsetsRegistry) - } - - if f.idFile == nil { - name := f.BaseFileName + consts.IDFileSuffix - file, err := os.Open(name) - if err != nil { - logger.Fatal("can't open id file", zap.String("file", name), zap.Error(err)) - } - f.idFile = file - f.idReader = storage.NewIndexReader(f.readLimiter, file.Name(), file, f.indexCache.IDRegistry) - } - - if f.lidFile == nil { - name := f.BaseFileName + consts.LIDFileSuffix - file, err := os.Open(name) - if err != nil { - logger.Fatal("can't open lid file", zap.String("file", name), zap.Error(err)) - } - f.lidFile = file - f.lidReader = storage.NewIndexReader(f.readLimiter, file.Name(), file, f.indexCache.LIDRegistry) - } + return file } func (f *Sealed) openDocs() { @@ -283,16 +229,30 @@ func (f *Sealed) loadInfo() { var err error if f.IsLegacy { - f.openInfoLegacy() + f.legacyFile = f.openFileIfNeeded(f.legacyFile, f.BaseFileName+consts.IndexFileSuffix) + + f.legacyReader = storage.NewIndexReader( + f.readLimiter, f.legacyFile.Name(), + f.legacyFile, f.indexCache.LegacyRegistry, + ) + if f.info, err = loadInfoLegacy(f.legacyReader); err != nil { - logger.Fatal("error loading Info", zap.String("fraction", f.BaseFileName), zap.Error(err)) + logger.Fatal( + "error loading Info", + zap.String("fraction", f.BaseFileName), + zap.Error(err), + ) } return } - f.openInfo() + f.infoFile = f.openFileIfNeeded(f.infoFile, f.BaseFileName+consts.InfoFileSuffix) if f.info, err = loadInfo(f.infoFile); err != nil { - logger.Fatal("error loading Info", zap.String("fraction", f.BaseFileName), zap.Error(err)) + logger.Fatal( + "error loading Info", + zap.String("fraction", f.BaseFileName), + zap.Error(err), + ) } } @@ -313,13 +273,7 @@ func (f *Sealed) init(full bool) { return } - (&Loader{}).Load(&f.blocksData, f.info, IndexReaders{ - Token: f.tokenReader, - Offsets: f.offsetsReader, - ID: f.idReader, - LID: f.lidReader, - }) - + (&Loader{}).Load(&f.blocksData, f.info, f.indexReaders()) f.isInited = true } @@ -495,32 +449,25 @@ func (f *Sealed) FindLIDs(ctx context.Context, ids []seq.ID) ([]seq.LID, error) func (f *Sealed) createDataProvider(ctx context.Context) *sealedDataProvider { f.init(true) - tokenReader := &f.tokenReader - lidReader := &f.lidReader - idReader := &f.idReader - - if f.IsLegacy { - tokenReader = &f.legacyReader - lidReader = &f.legacyReader - idReader = &f.legacyReader - } - + ir := f.indexReaders() return &sealedDataProvider{ ctx: ctx, fractionTypeLabel: "sealed", - info: f.info, - config: f.Config, - docsReader: &f.docsReader, - blocksOffsets: f.blocksData.BlocksOffsets, - lidsTable: f.blocksData.LIDsTable, - lidsLoader: lids.NewLoader(f.info.BinaryDataVer, lidReader, cache.NewSession(f.indexCache.LIDs)), - tokenBlockLoader: token.NewBlockLoader(f.BaseFileName, f.Info().BinaryDataVer, tokenReader, cache.NewSession(f.indexCache.Tokens)), - tokenTableLoader: token.NewTableLoader(f.BaseFileName, f.Info().BinaryDataVer, f.IsLegacy, tokenReader, cache.NewSession(f.indexCache.TokenTable)), + info: f.info, + config: f.Config, + docsReader: &f.docsReader, + blocksOffsets: f.blocksData.BlocksOffsets, + + lidsTable: f.blocksData.LIDsTable, + lidsLoader: lids.NewLoader(f.info.BinaryDataVer, &ir.LID, cache.NewSession(f.indexCache.LIDs)), + + tokenBlockLoader: token.NewBlockLoader(f.BaseFileName, f.Info().BinaryDataVer, &ir.Token, cache.NewSession(f.indexCache.Tokens)), + tokenTableLoader: token.NewTableLoader(f.BaseFileName, f.Info().BinaryDataVer, f.IsLegacy, &ir.Token, cache.NewSession(f.indexCache.TokenTable)), idsTable: &f.blocksData.IDsTable, idsProvider: seqids.NewProvider( - idReader, + &ir.ID, cache.NewSession(f.indexCache.MIDs), cache.NewSession(f.indexCache.RIDs), cache.NewSession(f.indexCache.Params), @@ -544,41 +491,36 @@ func (f *Sealed) IsIntersecting(from, to seq.MID) bool { return f.info.IsIntersecting(from, to) } -func loadInfoLegacy(infoReader storage.IndexReader) (*common.Info, error) { - block, _, err := infoReader.ReadIndexBlock(0, nil) - if err != nil { - return nil, fmt.Errorf("cannot read info block: %w", err) - } - - var bi sealed.BlockInfo - if err := bi.Unpack(block); err != nil { - return nil, fmt.Errorf("cannot unpack info block: %w", err) +func (f *Sealed) indexReaders() IndexReaders { + if f.IsLegacy { + r := storage.NewIndexReader( + f.readLimiter, f.legacyFile.Name(), f.legacyFile, + cache.NewSession(f.indexCache.LegacyRegistry), + ) + return IndexReaders{Token: r, Offsets: r, ID: r, LID: r} } - return bi.Info, nil -} + return IndexReaders{ + Token: storage.NewIndexReader( + f.readLimiter, f.tokenFile.Name(), f.tokenFile, + cache.NewSession(f.indexCache.TokenRegistry), + ), -func loadInfo(r interface { - io.ReaderAt - Stat() (os.FileInfo, error) -}, -) (*common.Info, error) { - stat, err := r.Stat() - if err != nil { - return nil, fmt.Errorf("cannot stat info file: %w", err) - } + Offsets: storage.NewIndexReader( + f.readLimiter, f.offsetsFile.Name(), f.offsetsFile, + cache.NewSession(f.indexCache.OffsetsRegistry), + ), - block := make([]byte, stat.Size()) - if _, err := r.ReadAt(block, io.SeekStart); err != nil { - return nil, fmt.Errorf("cannot read info block: %w", err) - } + ID: storage.NewIndexReader( + f.readLimiter, f.idFile.Name(), f.idFile, + cache.NewSession(f.indexCache.IDRegistry), + ), - var bi sealed.BlockInfo - if err := bi.Unpack(block); err != nil { - return nil, fmt.Errorf("cannot unpack info block: %w", err) + LID: storage.NewIndexReader( + f.readLimiter, f.lidFile.Name(), f.lidFile, + cache.NewSession(f.indexCache.LIDRegistry), + ), } - - return bi.Info, nil } // computeIndexOnDisk returns the total on-disk size of index files for a local fraction. @@ -611,3 +553,40 @@ func (f *Sealed) computeIndexSize() { f.info.IndexOnDisk += uint64(st.Size()) } } + +func loadInfoLegacy(infoReader storage.IndexReader) (*common.Info, error) { + block, _, err := infoReader.ReadIndexBlock(0, nil) + if err != nil { + return nil, fmt.Errorf("cannot read info block: %w", err) + } + + var bi sealed.BlockInfo + if err := bi.Unpack(block); err != nil { + return nil, fmt.Errorf("cannot unpack info block: %w", err) + } + + return bi.Info, nil +} + +func loadInfo(r interface { + io.ReaderAt + Stat() (os.FileInfo, error) +}, +) (*common.Info, error) { + stat, err := r.Stat() + if err != nil { + return nil, fmt.Errorf("cannot stat info file: %w", err) + } + + block := make([]byte, stat.Size()) + if _, err := r.ReadAt(block, io.SeekStart); err != nil { + return nil, fmt.Errorf("cannot read info block: %w", err) + } + + var bi sealed.BlockInfo + if err := bi.Unpack(block); err != nil { + return nil, fmt.Errorf("cannot unpack info block: %w", err) + } + + return bi.Info, nil +} From 82d19fc5209dcb6ffbc7b14e855b1d6735c90ac2 Mon Sep 17 00:00:00 2001 From: Daniil Porokhnin Date: Fri, 4 Sep 2026 19:08:14 +0300 Subject: [PATCH 2/2] refactor: get rid of reader field --- frac/remote.go | 40 +++++++++++++++++++++++++++++----------- frac/sealed.go | 25 +++++++++++++------------ frac/sealed_source.go | 12 +++--------- 3 files changed, 45 insertions(+), 32 deletions(-) diff --git a/frac/remote.go b/frac/remote.go index 30f498ab..dad0f9ff 100644 --- a/frac/remote.go +++ b/frac/remote.go @@ -44,9 +44,8 @@ type Remote struct { docsReader storage.DocsReader // IsLegacy is true for fractions that use the old single .index file format. - IsLegacy bool - legacyFile storage.ImmutableFile - legacyReader storage.IndexReader + IsLegacy bool + legacyFile storage.ImmutableFile // Per-section index files (new split format only). infoFile storage.ImmutableFile @@ -280,9 +279,20 @@ func (f *Remote) loadInfo() error { if err := f.openInfoLegacy(); err != nil { return err } - if f.info, err = loadInfoLegacy(f.legacyReader); err != nil { - logger.Fatal("error loading Info", zap.String("fraction", f.BaseFileName), zap.Error(err)) + + legacyReader := storage.NewIndexReader( + f.readLimiter, f.legacyFile.Name(), + f.legacyFile, f.indexCache.LegacyRegistry, + ) + + if f.info, err = loadInfoLegacy(legacyReader); err != nil { + logger.Fatal( + "error loading Info", + zap.String("fraction", f.BaseFileName), + zap.Error(err), + ) } + return nil } @@ -291,8 +301,13 @@ func (f *Remote) loadInfo() error { } if f.info, err = loadInfo(f.infoFile); err != nil { - logger.Fatal("error loading Info", zap.String("fraction", f.BaseFileName), zap.Error(err)) + logger.Fatal( + "error loading Info", + zap.String("fraction", f.BaseFileName), + zap.Error(err), + ) } + return nil } @@ -313,7 +328,14 @@ func (f *Remote) init() error { } if f.IsLegacy { - (&LegacyLoader{}).Load(&f.blocksData, f.info, f.legacyReader) + (&LegacyLoader{}).Load( + &f.blocksData, f.info, + storage.NewIndexReader( + f.readLimiter, f.legacyFile.Name(), + f.legacyFile, f.indexCache.LegacyRegistry, + ), + ) + f.isInited = true return nil } @@ -331,10 +353,6 @@ func (f *Remote) openInfoLegacy() error { return f.openRemoteFile(consts.IndexFileSuffix, func(file storage.ImmutableFile) { f.legacyFile = file - f.legacyReader = storage.NewIndexReader( - f.readLimiter, file.Name(), - file, f.indexCache.LegacyRegistry, - ) }) } diff --git a/frac/sealed.go b/frac/sealed.go index 275463d2..6cd8b0e7 100644 --- a/frac/sealed.go +++ b/frac/sealed.go @@ -40,9 +40,8 @@ type Sealed struct { docsReader storage.DocsReader // IsLegacy is true for fractions that use the old single .index file format. - IsLegacy bool - legacyFile *os.File - legacyReader storage.IndexReader + IsLegacy bool + legacyFile *os.File // Per-section index files and their readers (new split format only). infoFile *os.File @@ -163,12 +162,6 @@ func (f *Sealed) openIndex() { // We have exactly one `.index` file for legacy sealed fractions. // So opening only this file is sufficient. f.legacyFile = f.openFileIfNeeded(f.legacyFile, f.BaseFileName+consts.IndexFileSuffix) - - f.legacyReader = storage.NewIndexReader( - f.readLimiter, f.legacyFile.Name(), - f.legacyFile, f.indexCache.LegacyRegistry, - ) - return } @@ -231,18 +224,19 @@ func (f *Sealed) loadInfo() { if f.IsLegacy { f.legacyFile = f.openFileIfNeeded(f.legacyFile, f.BaseFileName+consts.IndexFileSuffix) - f.legacyReader = storage.NewIndexReader( + legacyReader := storage.NewIndexReader( f.readLimiter, f.legacyFile.Name(), f.legacyFile, f.indexCache.LegacyRegistry, ) - if f.info, err = loadInfoLegacy(f.legacyReader); err != nil { + if f.info, err = loadInfoLegacy(legacyReader); err != nil { logger.Fatal( "error loading Info", zap.String("fraction", f.BaseFileName), zap.Error(err), ) } + return } @@ -268,7 +262,14 @@ func (f *Sealed) init(full bool) { } if f.IsLegacy { - (&LegacyLoader{}).Load(&f.blocksData, f.info, f.legacyReader) + (&LegacyLoader{}).Load( + &f.blocksData, f.info, + storage.NewIndexReader( + f.readLimiter, f.legacyFile.Name(), + f.legacyFile, f.indexCache.LegacyRegistry, + ), + ) + f.isInited = true return } diff --git a/frac/sealed_source.go b/frac/sealed_source.go index 2069fd5d..fcffc06c 100644 --- a/frac/sealed_source.go +++ b/frac/sealed_source.go @@ -36,16 +36,10 @@ type SealedSource struct { func NewSealedSource(f *Sealed) *SealedSource { f.init(true) - tokenFile, idFile, lidFile := f.tokenFile, f.idFile, f.lidFile - if f.IsLegacy { - tokenFile, idFile, lidFile = f.legacyFile, f.legacyFile, f.legacyFile - } - + ir := f.indexReaders() s := &SealedSource{ - f: f, - tokenReader: storage.NewIndexReader(f.readLimiter, tokenFile.Name(), tokenFile, cache.NewScan[[]byte]()), - idReader: storage.NewIndexReader(f.readLimiter, idFile.Name(), idFile, cache.NewScan[[]byte]()), - lidReader: storage.NewIndexReader(f.readLimiter, lidFile.Name(), lidFile, cache.NewScan[[]byte]()), + f: f, tokenReader: ir.Token, + idReader: ir.ID, lidReader: ir.LID, } s.idsProvider = seqids.NewProvider(