@@ -56,35 +56,16 @@ const (
5656 changeFrontierProcName = `changefntr`
5757)
5858
59- // distChangefeedFlow plans and runs a distributed changefeed.
60- //
61- // One or more ChangeAggregator processors watch table data for changes. These
62- // transform the changed kvs into changed rows and either emit them to a sink
63- // (such as kafka) or, if there is no sink, forward them in columns 1,2,3 (where
64- // they will be eventually returned directly via pgwire). In either case,
65- // periodically a span will become resolved as of some timestamp, meaning that
66- // no new rows will ever be emitted at or below that timestamp. These span-level
67- // resolved timestamps are emitted as a marshaled `jobspb.ResolvedSpan` proto in
68- // column 0.
69- //
70- // The flow will always have exactly one ChangeFrontier processor which all the
71- // ChangeAggregators feed into. It collects all span-level resolved timestamps
72- // and aggregates them into a changefeed-level resolved timestamp, which is the
73- // minimum of the span-level resolved timestamps. This changefeed-level resolved
74- // timestamp is emitted into the changefeed sink (or returned to the gateway if
75- // there is no sink) whenever it advances. ChangeFrontier also updates the
76- // progress of the changefeed's corresponding system job.
77- func distChangefeedFlow (
59+ // computeDistChangefeedTimestamps computes the initialHighWater and schemaTS
60+ // for a changefeed run, and mutates localState.progress when appropriate
61+ // (e.g., to set the high-water if initial scan should be skipped). It also
62+ // invokes testing knobs that observe the initial high-water.
63+ func computeDistChangefeedTimestamps (
7864 ctx context.Context ,
7965 execCtx sql.JobExecContext ,
80- jobID jobspb.JobID ,
8166 details jobspb.ChangefeedDetails ,
82- description string ,
8367 localState * cachedState ,
84- resultsCh chan <- tree.Datums ,
85- onTracingEvent func (ctx context.Context , meta * execinfrapb.TracingAggregatorEvents ),
86- targets changefeedbase.Targets ,
87- ) error {
68+ ) (initialHighWater hlc.Timestamp , schemaTS hlc.Timestamp , _ error ) {
8869 opts := changefeedbase .MakeStatementOptions (details .Opts )
8970 progress := localState .progress
9071
@@ -100,44 +81,38 @@ func distChangefeedFlow(
10081 // cursor but we have a request to not have an initial scan.
10182 initialScanType , err := opts .GetInitialScanType ()
10283 if err != nil {
103- return err
84+ return hlc. Timestamp {}, hlc. Timestamp {}, err
10485 }
10586 if noHighWater && initialScanType == changefeedbase .NoInitialScan {
10687 // If there is a cursor, the statement time has already been set to it.
10788 progress .Progress = & jobspb.Progress_HighWater {HighWater : & details .StatementTime }
10889 }
10990 }
11091
111- var initialHighWater hlc.Timestamp
112- schemaTS := details .StatementTime
113- {
114- if h := progress .GetHighWater (); h != nil && ! h .IsEmpty () {
115- initialHighWater = * h
116- // If we have a high-water set, use it to compute the spans, since the
117- // ones at the statement time may have been garbage collected by now.
118- schemaTS = initialHighWater
119- }
120-
121- // We want to fetch the target spans as of the timestamp following the
122- // highwater unless the highwater corresponds to a timestamp of an initial
123- // scan. This logic is irritatingly complex but extremely important. Namely,
124- // we may be here because the schema changed at the current resolved
125- // timestamp. However, an initial scan should be performed at exactly the
126- // timestamp specified; initial scans can be created at the timestamp of a
127- // schema change and thus should see the side-effect of the schema change.
128- isRestartAfterCheckpointOrNoInitialScan := progress .GetHighWater () != nil
129- if isRestartAfterCheckpointOrNoInitialScan {
130- schemaTS = schemaTS .Next ()
131- }
92+ schemaTS = details .StatementTime
93+ if h := progress .GetHighWater (); h != nil && ! h .IsEmpty () {
94+ initialHighWater = * h
95+ // If we have a high-water set, use it to compute the spans, since the
96+ // ones at the statement time may have been garbage collected by now.
97+ schemaTS = initialHighWater
98+ }
99+ // We want to fetch the target spans as of the timestamp following the
100+ // highwater unless the highwater corresponds to a timestamp of an initial
101+ // scan. This logic is irritatingly complex but extremely important. Namely,
102+ // we may be here because the schema changed at the current resolved
103+ // timestamp. However, an initial scan should be performed at exactly the
104+ // timestamp specified; initial scans can be created at the timestamp of a
105+ // schema change and thus should see the side-effect of the schema change.
106+ if progress .GetHighWater () != nil {
107+ schemaTS = schemaTS .Next ()
132108 }
133109
134110 if knobs , ok := execCtx .ExecCfg ().DistSQLSrv .TestingKnobs .Changefeed .(* TestingKnobs ); ok {
135111 if knobs != nil && knobs .StartDistChangefeedInitialHighwater != nil {
136112 knobs .StartDistChangefeedInitialHighwater (ctx , initialHighWater )
137113 }
138114 }
139- return startDistChangefeed (
140- ctx , execCtx , jobID , schemaTS , details , description , initialHighWater , localState , resultsCh , onTracingEvent , targets )
115+ return initialHighWater , schemaTS , nil
141116}
142117
143118func fetchTableDescriptors (
@@ -225,7 +200,24 @@ func fetchSpansForTables(
225200 sd , tableDescs [0 ], initialHighwater , target , sc )
226201}
227202
228- // startDistChangefeed starts distributed changefeed execution.
203+ // startDistChangefeed plans and runs a distributed changefeed.
204+ //
205+ // One or more ChangeAggregator processors watch table data for changes. These
206+ // transform the changed kvs into changed rows and either emit them to a sink
207+ // (such as kafka) or, if there is no sink, forward them in columns 1,2,3 (where
208+ // they will be eventually returned directly via pgwire). In either case,
209+ // periodically a span will become resolved as of some timestamp, meaning that
210+ // no new rows will ever be emitted at or below that timestamp. These span-level
211+ // resolved timestamps are emitted as a marshaled `jobspb.ResolvedSpan` proto in
212+ // column 0.
213+ //
214+ // The flow will always have exactly one ChangeFrontier processor which all the
215+ // ChangeAggregators feed into. It collects all span-level resolved timestamps
216+ // and aggregates them into a changefeed-level resolved timestamp, which is the
217+ // minimum of the span-level resolved timestamps. This changefeed-level resolved
218+ // timestamp is emitted into the changefeed sink (or returned to the gateway if
219+ // there is no sink) whenever it advances. ChangeFrontier also updates the
220+ // progress of the changefeed's corresponding system job.
229221func startDistChangefeed (
230222 ctx context.Context ,
231223 execCtx sql.JobExecContext ,
@@ -270,7 +262,7 @@ func startDistChangefeed(
270262 }
271263 }
272264 p , planCtx , err := makePlan (execCtx , jobID , details , description , initialHighWater ,
273- trackedSpans , spanLevelCheckpoint , localState .drainingNodes )(ctx , dsp )
265+ trackedSpans , spanLevelCheckpoint , localState .drainingNodes , schemaTS )(ctx , dsp )
274266 if err != nil {
275267 return err
276268 }
@@ -395,6 +387,7 @@ func makePlan(
395387 trackedSpans []roachpb.Span ,
396388 spanLevelCheckpoint * jobspb.TimestampSpansMap ,
397389 drainingNodes []roachpb.NodeID ,
390+ schemaTS hlc.Timestamp ,
398391) func (context.Context , * sql.DistSQLPlanner ) (* sql.PhysicalPlan , * sql.PlanningCtx , error ) {
399392 return func (ctx context.Context , dsp * sql.DistSQLPlanner ) (* sql.PhysicalPlan , * sql.PlanningCtx , error ) {
400393 sv := & execCtx .ExecCfg ().Settings .SV
@@ -535,6 +528,7 @@ func makePlan(
535528 Description : description ,
536529 ProgressConfig : progressConfig ,
537530 ResolvedSpans : resolvedSpans ,
531+ SchemaTS : & schemaTS ,
538532 }
539533 }
540534
@@ -551,6 +545,7 @@ func makePlan(
551545 Description : description ,
552546 ProgressConfig : progressConfig ,
553547 ResolvedSpans : resolvedSpans ,
548+ SchemaTS : & schemaTS ,
554549 }
555550
556551 if haveKnobs && maybeCfKnobs .OnDistflowSpec != nil {
0 commit comments