@@ -25,6 +25,7 @@ import (
2525 "github.com/cockroachdb/cockroach/pkg/sql/types"
2626 "github.com/cockroachdb/cockroach/pkg/util/admission/admissionpb"
2727 "github.com/cockroachdb/cockroach/pkg/util/ctxgroup"
28+ "github.com/cockroachdb/cockroach/pkg/util/errorutil/unimplemented"
2829 "github.com/cockroachdb/cockroach/pkg/util/hlc"
2930 "github.com/cockroachdb/cockroach/pkg/util/log"
3031 "github.com/cockroachdb/cockroach/pkg/util/mon"
@@ -48,6 +49,8 @@ type indexBackfiller struct {
4849 processorID int32
4950
5051 filter backfill.MutationFilter
52+
53+ bulkAdderFactory indexBackfillBulkAdderFactory
5154}
5255
5356var _ execinfra.Processor = & indexBackfiller {}
@@ -86,6 +89,40 @@ var indexBackfillElasticCPUControlEnabled = settings.RegisterBoolSetting(
8689 false , // TODO(dt): enable this by default after more benchmarking.
8790)
8891
92+ // indexBackfillSink abstracts the destination for index backfill output so the
93+ // ingestion pipeline can route built KVs either to the legacy BulkAdder path or
94+ // to future sinks (e.g. distributed-merge SST writers) without rewriting the
95+ // DistSQL processor. All sinks share the same Add/Flush/progress contract.
96+ type indexBackfillSink interface {
97+ // Add enqueues a single KV pair for eventual persistence in the sink-specific
98+ // backing store.
99+ Add (ctx context.Context , key roachpb.Key , value []byte ) error
100+ // Flush forces any buffered state to be persisted.
101+ Flush (ctx context.Context ) error
102+ // Close releases resources owned by the sink. Implementations should be
103+ // idempotent and safe to call even if Flush returns an error.
104+ Close (ctx context.Context )
105+ // SetOnFlush installs a callback that is invoked after the sink writes a
106+ // batch (mirrors kvserverbase.BulkAdder semantics so existing progress
107+ // plumbing can be reused).
108+ SetOnFlush (func (summary kvpb.BulkOpSummary ))
109+ }
110+
111+ // indexBackfillBulkAdderFactory mirrors kvserverbase.BulkAdderFactory but is
112+ // injected so tests can swap in fakes and future sinks can reuse the backfiller
113+ // without referencing execinfra.ServerConfig directly.
114+ type indexBackfillBulkAdderFactory func (
115+ ctx context.Context , writeAsOf hlc.Timestamp , opts kvserverbase.BulkAdderOptions ,
116+ ) (kvserverbase.BulkAdder , error )
117+
118+ // bulkAdderIndexBackfillSink is the default sink implementation backed by
119+ // kvserverbase.BulkAdder.
120+ type bulkAdderIndexBackfillSink struct {
121+ kvserverbase.BulkAdder
122+ }
123+
124+ var _ indexBackfillSink = (* bulkAdderIndexBackfillSink )(nil )
125+
89126func newIndexBackfiller (
90127 ctx context.Context ,
91128 flowCtx * execinfra.FlowCtx ,
@@ -101,6 +138,11 @@ func newIndexBackfiller(
101138 flowCtx : flowCtx ,
102139 processorID : processorID ,
103140 filter : backfill .IndexMutationFilter ,
141+ bulkAdderFactory : func (
142+ ctx context.Context , writeAsOf hlc.Timestamp , opts kvserverbase.BulkAdderOptions ,
143+ ) (kvserverbase.BulkAdder , error ) {
144+ return flowCtx .Cfg .BulkAdder (ctx , flowCtx .Cfg .DB .KV (), writeAsOf , opts )
145+ },
104146 }
105147
106148 if err := ib .IndexBackfiller .InitForDistributedUse (
@@ -257,15 +299,16 @@ func (ib *indexBackfiller) maybeReencodeAndWriteVectorIndexEntry(
257299 return true , nil
258300}
259301
260- // ingestIndexEntries adds the batches of built index entries to the buffering
261- // adder and reports progress back to the coordinator node.
262- func (ib * indexBackfiller ) ingestIndexEntries (
263- ctx context.Context ,
264- indexEntryCh <- chan indexEntryBatch ,
265- progCh chan execinfrapb.RemoteProducerMetadata_BulkProcessorProgress ,
266- ) error {
267- ctx , span := tracing .ChildSpan (ctx , "ingestIndexEntries" )
268- defer span .Finish ()
302+ // makeIndexBackfillSink materializes whatever sink the current backfill should
303+ // use (legacy BulkAdder or distributed-merge sink). The choice is driven by
304+ // execinfrapb.BackfillerSpec.
305+ func (ib * indexBackfiller ) makeIndexBackfillSink (ctx context.Context ) (indexBackfillSink , error ) {
306+ if ib .spec .UseDistributedMergeSink {
307+ return nil , unimplemented .New (
308+ "distributed merge index backfill sink" ,
309+ "index backfill distributed merge sink is not implemented yet" ,
310+ )
311+ }
269312
270313 minBufferSize := backfillerBufferSize .Get (& ib .flowCtx .Cfg .Settings .SV )
271314 maxBufferSize := func () int64 { return backfillerMaxBufferSize .Get (& ib .flowCtx .Cfg .Settings .SV ) }
@@ -278,11 +321,33 @@ func (ib *indexBackfiller) ingestIndexEntries(
278321 InitialSplitsIfUnordered : int (ib .spec .InitialSplits ),
279322 WriteAtBatchTimestamp : ib .spec .WriteAtBatchTimestamp ,
280323 }
281- adder , err := ib .flowCtx .Cfg .BulkAdder (ctx , ib .flowCtx .Cfg .DB .KV (), ib .spec .WriteAsOf , opts )
324+
325+ adderFactory := ib .bulkAdderFactory
326+ if adderFactory == nil {
327+ return nil , errors .AssertionFailedf ("index backfiller bulk adder factory must be configured" )
328+ }
329+ adder , err := adderFactory (ctx , ib .spec .WriteAsOf , opts )
330+ if err != nil {
331+ return nil , err
332+ }
333+ return & bulkAdderIndexBackfillSink {BulkAdder : adder }, nil
334+ }
335+
336+ // ingestIndexEntries adds the batches of built index entries to the buffering
337+ // adder and reports progress back to the coordinator node.
338+ func (ib * indexBackfiller ) ingestIndexEntries (
339+ ctx context.Context ,
340+ indexEntryCh <- chan indexEntryBatch ,
341+ progCh chan execinfrapb.RemoteProducerMetadata_BulkProcessorProgress ,
342+ ) error {
343+ ctx , span := tracing .ChildSpan (ctx , "ingestIndexEntries" )
344+ defer span .Finish ()
345+
346+ sink , err := ib .makeIndexBackfillSink (ctx )
282347 if err != nil {
283348 return err
284349 }
285- defer adder .Close (ctx )
350+ defer sink .Close (ctx )
286351
287352 // Synchronizes read and write access on completedSpans which is updated on a
288353 // BulkAdder flush, but is read when progress is being sent back to the
@@ -302,7 +367,7 @@ func (ib *indexBackfiller) ingestIndexEntries(
302367 mu .completedSpans = append (mu .completedSpans , mu .addedSpans ... )
303368 mu .addedSpans = nil
304369 }
305- adder .SetOnFlush (flushAddedSpans )
370+ sink .SetOnFlush (flushAddedSpans )
306371
307372 pushProgress := func () {
308373 mu .Lock ()
@@ -365,7 +430,7 @@ func (ib *indexBackfiller) ingestIndexEntries(
365430 }
366431 }
367432
368- if err := adder .Add (ctx , indexEntry .Key , indexEntry .Value .RawBytes ); err != nil {
433+ if err := sink .Add (ctx , indexEntry .Key , indexEntry .Value .RawBytes ); err != nil {
369434 return ib .wrapDupError (ctx , err )
370435 }
371436 }
@@ -391,7 +456,7 @@ func (ib *indexBackfiller) ingestIndexEntries(
391456
392457 knobs := & ib .flowCtx .Cfg .TestingKnobs
393458 if knobs .BulkAdderFlushesEveryBatch {
394- if err := adder .Flush (ctx ); err != nil {
459+ if err := sink .Flush (ctx ); err != nil {
395460 return ib .wrapDupError (ctx , err )
396461 }
397462 pushProgress ()
@@ -412,7 +477,7 @@ func (ib *indexBackfiller) ingestIndexEntries(
412477 if err := g .Wait (); err != nil {
413478 return err
414479 }
415- if err := adder .Flush (ctx ); err != nil {
480+ if err := sink .Flush (ctx ); err != nil {
416481 return ib .wrapDupError (ctx , err )
417482 }
418483
0 commit comments