@@ -54,7 +54,10 @@ func TestFrontier(t *testing.T) {
54
54
55
55
s := srv .ApplicationLayer ()
56
56
sp := func (i int ) roachpb.Span {
57
- return roachpb.Span {Key : s .Codec ().TablePrefix (100 + uint32 (i )), EndKey : s .Codec ().TablePrefix (101 + uint32 (i ))}
57
+ return roachpb.Span {
58
+ Key : s .Codec ().TablePrefix (100 + uint32 (i )),
59
+ EndKey : s .Codec ().TablePrefix (101 + uint32 (i )),
60
+ }
58
61
}
59
62
sp1 , sp2 , sp3 := sp (0 ), sp (1 ), sp (2 )
60
63
@@ -77,6 +80,17 @@ func TestFrontier(t *testing.T) {
77
80
require .Equal (t , 3 , countEntries (loadedFrontier ))
78
81
checkFrontierContainsSpan (t , loadedFrontier , sp1 , ts1 )
79
82
checkFrontierContainsSpan (t , loadedFrontier , sp3 , ts1 )
83
+
84
+ spans , found , err := GetResolvedSpans (ctx , txn , jobID , "basic" )
85
+ require .NoError (t , err )
86
+ require .True (t , found )
87
+ require .ElementsMatch (t ,
88
+ []jobspb.ResolvedSpan {
89
+ {Span : sp1 , Timestamp : ts1 },
90
+ {Span : sp2 },
91
+ {Span : sp3 , Timestamp : ts1 },
92
+ },
93
+ spans )
80
94
},
81
95
},
82
96
{
@@ -86,6 +100,10 @@ func TestFrontier(t *testing.T) {
86
100
_ , found , err := Get (ctx , txn , jobID , "nonexistent" )
87
101
require .NoError (t , err )
88
102
require .False (t , found )
103
+
104
+ _ , found , err = GetResolvedSpans (ctx , txn , jobID , "nonexistent" )
105
+ require .NoError (t , err )
106
+ require .False (t , found )
89
107
},
90
108
},
91
109
{
@@ -106,6 +124,17 @@ func TestFrontier(t *testing.T) {
106
124
checkFrontierContainsSpan (t , loadedFrontier , sp1 , ts1 )
107
125
checkFrontierContainsSpan (t , loadedFrontier , sp2 , ts2 )
108
126
checkFrontierContainsSpan (t , loadedFrontier , sp3 , ts1 )
127
+
128
+ spans , found , err := GetResolvedSpans (ctx , txn , jobID , "multi" )
129
+ require .NoError (t , err )
130
+ require .True (t , found )
131
+ require .ElementsMatch (t ,
132
+ []jobspb.ResolvedSpan {
133
+ {Span : sp1 , Timestamp : ts1 },
134
+ {Span : sp2 , Timestamp : ts2 },
135
+ {Span : sp3 , Timestamp : ts1 },
136
+ },
137
+ spans )
109
138
},
110
139
},
111
140
{
@@ -118,6 +147,10 @@ func TestFrontier(t *testing.T) {
118
147
_ , found , err := Get (ctx , txn , jobID , "deleteme" )
119
148
require .NoError (t , err )
120
149
require .False (t , found )
150
+
151
+ _ , found , err = GetResolvedSpans (ctx , txn , jobID , "deleteme" )
152
+ require .NoError (t , err )
153
+ require .False (t , found )
121
154
},
122
155
},
123
156
{
@@ -135,6 +168,15 @@ func TestFrontier(t *testing.T) {
135
168
require .True (t , found )
136
169
require .Equal (t , 1 , countEntries (loadedFrontier ))
137
170
checkFrontierContainsSpan (t , loadedFrontier , sp2 , ts2 )
171
+
172
+ spans , found , err := GetResolvedSpans (ctx , txn , jobID , "overwrite" )
173
+ require .NoError (t , err )
174
+ require .True (t , found )
175
+ require .ElementsMatch (t ,
176
+ []jobspb.ResolvedSpan {
177
+ {Span : sp2 , Timestamp : ts2 },
178
+ },
179
+ spans )
138
180
},
139
181
},
140
182
}
@@ -261,3 +303,164 @@ func TestStoreChunked(t *testing.T) {
261
303
})
262
304
}
263
305
}
306
+
307
+ func TestGetAllResolvedSpans (t * testing.T ) {
308
+ defer leaktest .AfterTest (t )()
309
+ defer log .Scope (t ).Close (t )
310
+
311
+ ctx := context .Background ()
312
+ srv := serverutils .StartServerOnly (t , base.TestServerArgs {})
313
+ defer srv .Stopper ().Stop (ctx )
314
+
315
+ s := srv .ApplicationLayer ()
316
+ sp := func (i int ) roachpb.Span {
317
+ return roachpb.Span {
318
+ Key : s .Codec ().TablePrefix (100 + uint32 (i )),
319
+ EndKey : s .Codec ().TablePrefix (101 + uint32 (i )),
320
+ }
321
+ }
322
+ sp1 , sp2 , sp3 := sp (0 ), sp (1 ), sp (2 )
323
+
324
+ ts1 , ts2 := hlc.Timestamp {WallTime : 100 , Logical : 1 }, hlc.Timestamp {WallTime : 200 , Logical : 2 }
325
+
326
+ tests := []struct {
327
+ name string
328
+ setup func (t * testing.T , txn isql.Txn , jobID jobspb.JobID )
329
+ expected []jobspb.ResolvedSpan
330
+ }{
331
+ {
332
+ name : "no frontiers" ,
333
+ setup : func (t * testing.T , txn isql.Txn , jobID jobspb.JobID ) {},
334
+ expected : nil ,
335
+ },
336
+ {
337
+ name : "single frontier" ,
338
+ setup : func (t * testing.T , txn isql.Txn , jobID jobspb.JobID ) {
339
+ f , err := span .MakeFrontier (sp1 , sp2 , sp3 )
340
+ require .NoError (t , err )
341
+ _ , err = f .Forward (sp1 , ts1 )
342
+ require .NoError (t , err )
343
+ require .NoError (t , Store (ctx , txn , jobID , "single" , f ))
344
+ },
345
+ expected : []jobspb.ResolvedSpan {
346
+ {Span : sp1 , Timestamp : ts1 },
347
+ {Span : sp2 },
348
+ {Span : sp3 },
349
+ },
350
+ },
351
+ {
352
+ name : "multiple frontiers" ,
353
+ setup : func (t * testing.T , txn isql.Txn , jobID jobspb.JobID ) {
354
+ // First frontier with sp1@ts1 and sp2@zero.
355
+ f1 , err := span .MakeFrontier (sp1 , sp2 )
356
+ require .NoError (t , err )
357
+ _ , err = f1 .Forward (sp1 , ts1 )
358
+ require .NoError (t , err )
359
+ require .NoError (t , Store (ctx , txn , jobID , "frontier1" , f1 ))
360
+
361
+ // Second frontier with sp3@ts2.
362
+ f2 , err := span .MakeFrontier (sp3 )
363
+ require .NoError (t , err )
364
+ _ , err = f2 .Forward (sp3 , ts2 )
365
+ require .NoError (t , err )
366
+ require .NoError (t , Store (ctx , txn , jobID , "frontier2" , f2 ))
367
+ },
368
+ expected : []jobspb.ResolvedSpan {
369
+ {Span : sp1 , Timestamp : ts1 },
370
+ {Span : sp2 },
371
+ {Span : sp3 , Timestamp : ts2 },
372
+ },
373
+ },
374
+ {
375
+ name : "multiple frontiers with overlapping spans" ,
376
+ setup : func (t * testing.T , txn isql.Txn , jobID jobspb.JobID ) {
377
+ // First frontier with sp1@ts1.
378
+ f1 , err := span .MakeFrontier (sp1 )
379
+ require .NoError (t , err )
380
+ _ , err = f1 .Forward (sp1 , ts1 )
381
+ require .NoError (t , err )
382
+ require .NoError (t , Store (ctx , txn , jobID , "overlap1" , f1 ))
383
+
384
+ // Second frontier with sp1@ts2 (different timestamp) and sp2@zero.
385
+ f2 , err := span .MakeFrontier (sp1 , sp2 )
386
+ require .NoError (t , err )
387
+ _ , err = f2 .Forward (sp1 , ts2 )
388
+ require .NoError (t , err )
389
+ require .NoError (t , Store (ctx , txn , jobID , "overlap2" , f2 ))
390
+ },
391
+ expected : []jobspb.ResolvedSpan {
392
+ {Span : sp1 , Timestamp : ts1 },
393
+ {Span : sp1 , Timestamp : ts2 },
394
+ {Span : sp2 },
395
+ },
396
+ },
397
+ {
398
+ name : "multiple frontiers with some deleted" ,
399
+ setup : func (t * testing.T , txn isql.Txn , jobID jobspb.JobID ) {
400
+ // Store first frontier with sp1@ts1.
401
+ f1 , err := span .MakeFrontier (sp1 )
402
+ require .NoError (t , err )
403
+ _ , err = f1 .Forward (sp1 , ts1 )
404
+ require .NoError (t , err )
405
+ require .NoError (t , Store (ctx , txn , jobID , "keep" , f1 ))
406
+
407
+ // Store second frontier with sp2@ts2 then delete it.
408
+ f2 , err := span .MakeFrontier (sp2 )
409
+ require .NoError (t , err )
410
+ _ , err = f2 .Forward (sp2 , ts2 )
411
+ require .NoError (t , err )
412
+ require .NoError (t , Store (ctx , txn , jobID , "delete" , f2 ))
413
+ require .NoError (t , Delete (ctx , txn , jobID , "delete" ))
414
+
415
+ // Store third frontier with sp3@ts1.
416
+ f3 , err := span .MakeFrontier (sp3 )
417
+ require .NoError (t , err )
418
+ _ , err = f3 .Forward (sp3 , ts1 )
419
+ require .NoError (t , err )
420
+ require .NoError (t , Store (ctx , txn , jobID , "also_keep" , f3 ))
421
+ },
422
+ expected : []jobspb.ResolvedSpan {
423
+ {Span : sp1 , Timestamp : ts1 },
424
+ {Span : sp3 , Timestamp : ts1 },
425
+ },
426
+ },
427
+ {
428
+ name : "empty frontiers" ,
429
+ setup : func (t * testing.T , txn isql.Txn , jobID jobspb.JobID ) {
430
+ // Store a frontier with no spans forwarded.
431
+ f , err := span .MakeFrontier (sp1 , sp2 , sp3 )
432
+ require .NoError (t , err )
433
+ require .NoError (t , Store (ctx , txn , jobID , "empty" , f ))
434
+ },
435
+ expected : []jobspb.ResolvedSpan {
436
+ {Span : sp1 },
437
+ {Span : sp2 },
438
+ {Span : sp3 },
439
+ },
440
+ },
441
+ }
442
+
443
+ for i , tc := range tests {
444
+ t .Run (tc .name , func (t * testing.T ) {
445
+ jobID := jobspb .JobID (3000 + i )
446
+
447
+ require .NoError (t , s .InternalDB ().(isql.DB ).Txn (ctx , func (ctx context.Context , txn isql.Txn ) error {
448
+ tc .setup (t , txn , jobID )
449
+ return nil
450
+ }))
451
+
452
+ require .NoError (t , s .InternalDB ().(isql.DB ).Txn (ctx , func (ctx context.Context , txn isql.Txn ) error {
453
+ spans , found , err := GetAllResolvedSpans (ctx , txn , jobID )
454
+ require .NoError (t , err )
455
+ if len (tc .expected ) > 0 {
456
+ require .True (t , found )
457
+ require .ElementsMatch (t , tc .expected , spans )
458
+ } else {
459
+ require .False (t , found )
460
+ require .Empty (t , spans )
461
+ }
462
+ return nil
463
+ }))
464
+ })
465
+ }
466
+ }
0 commit comments