@@ -142,7 +142,7 @@ func CanDeleteIncrementalChain(
142
142
if base .Status .IsRunning () {
143
143
return ErrBackupInProgress
144
144
}
145
- if base .Type = = defs .IncrementalBackup {
145
+ if base .Type ! = defs .IncrementalBackup {
146
146
return ErrNonIncrementalBackup
147
147
}
148
148
if base .SrcBackup != "" {
@@ -269,7 +269,8 @@ func isRequiredForOplogSlicing(ctx context.Context, cc connect.Client, lw primit
269
269
if err != nil {
270
270
return false , errors .Wrap (err , "get oplog range from previous backup" )
271
271
}
272
- if len (timelines ) == 1 && timelines [0 ].Start <= prevRestoreTime .T {
272
+ // check if there is a gap (missed ops) in oplog range between previous and following backup restore_to time
273
+ if len (timelines ) != 1 || prevRestoreTime .T >= timelines [0 ].Start {
273
274
return false , nil
274
275
}
275
276
@@ -326,7 +327,11 @@ func ListDeleteBackupBefore(
326
327
}
327
328
328
329
pred := func (m * BackupMeta ) bool { return m .Type == bcpType }
329
- if bcpType == SelectiveBackup {
330
+ if bcpType == defs .LogicalBackup {
331
+ pred = func (m * BackupMeta ) bool {
332
+ return m .Type == defs .LogicalBackup && ! util .IsSelective (m .Namespaces )
333
+ }
334
+ } else if bcpType == SelectiveBackup {
330
335
pred = func (m * BackupMeta ) bool { return util .IsSelective (m .Namespaces ) }
331
336
}
332
337
@@ -345,71 +350,85 @@ func MakeCleanupInfo(ctx context.Context, conn connect.Client, ts primitive.Time
345
350
if err != nil {
346
351
return CleanupInfo {}, errors .Wrap (err , "list backups before" )
347
352
}
348
-
349
- exclude := true
350
- if l := len (backups ) - 1 ; l != - 1 && backups [l ].LastWriteTS .T == ts .T {
351
- // there is a backup at the `ts`
352
- if isValidBaseSnapshot (& backups [l ]) {
353
- // it can be used to fully restore data to the `ts` state.
354
- // no need to exclude any base snapshot and chunks before the `ts`
355
- exclude = false
356
- }
357
- // the backup is not considered to be deleted.
358
- // used only for `exclude` value
359
- backups = backups [:l ]
360
- }
361
-
362
- // exclude the last incremental backups if it is required for following (after the `ts`)
363
- backups , err = extractLastIncrementalChain (ctx , conn , backups )
364
- if err != nil {
365
- return CleanupInfo {}, errors .Wrap (err , "extract last incremental chain" )
366
- }
367
-
368
353
chunks , err := listChunksBefore (ctx , conn , ts )
369
354
if err != nil {
370
355
return CleanupInfo {}, errors .Wrap (err , "list chunks before" )
371
356
}
372
- if ! exclude {
373
- // all chunks can be deleted. there is a backup to fully restore data
357
+ if len (backups ) == 0 {
374
358
return CleanupInfo {Backups : backups , Chunks : chunks }, nil
375
359
}
376
360
377
- // the following check is needed for "delete all" special case.
378
- // if there is no base snapshot after `ts` and PITR is running,
379
- // the last base snapshot before `ts` should be excluded.
380
- // otherwise, it is allowed to delete everything before `ts`
381
- required , err := isRequiredForOplogSlicing (ctx , conn , ts )
382
- if err != nil {
383
- return CleanupInfo {}, err
384
- }
385
- if ! required {
386
- return CleanupInfo {Backups : backups , Chunks : chunks }, nil
361
+ if r := & backups [len (backups )- 1 ]; r .LastWriteTS .T == ts .T {
362
+ // there is a backup at the `ts`
363
+ backups = backups [:len (backups )- 1 ]
364
+
365
+ if isValidBaseSnapshot (r ) {
366
+ // it can be used to fully restore data to the `ts` state.
367
+ // no need to exclude any backups and chunks before the `ts`.
368
+ // except increments that is base for following increment (after `ts`) must be excluded
369
+ backups , err = extractLastIncrementalChain (ctx , conn , backups )
370
+ if err != nil {
371
+ return CleanupInfo {}, errors .Wrap (err , "extract last incremental chain" )
372
+ }
373
+
374
+ return CleanupInfo {Backups : backups , Chunks : chunks }, nil
375
+ }
387
376
}
388
377
389
- // the `baseIndex` could be the base snapshot index for PITR to the `ts`
390
- // or for currently running PITR
391
- baseIndex := findLastBaseSnapshotIndex (backups )
378
+ baseIndex := len (backups ) - 1
379
+ for ; baseIndex != - 1 ; baseIndex -- {
380
+ if isValidBaseSnapshot (& backups [baseIndex ]) {
381
+ break
382
+ }
383
+ }
392
384
if baseIndex == - 1 {
393
- // nothing to keep
385
+ // no valid base snapshot to exclude
394
386
return CleanupInfo {Backups : backups , Chunks : chunks }, nil
395
387
}
396
388
397
- excluded := false
398
- origin := chunks
399
- chunks = []oplog.OplogChunk {}
400
- for i := range origin {
401
- if backups [baseIndex ].LastWriteTS .Compare (origin [i ].EndTS ) != - 1 {
402
- chunks = append (chunks , origin [i ])
389
+ beforeChunks := []oplog.OplogChunk {}
390
+ afterChunks := []oplog.OplogChunk {}
391
+ for _ , chunk := range chunks {
392
+ if chunk .EndTS .Before (backups [baseIndex ].LastWriteTS ) {
393
+ beforeChunks = append (beforeChunks , chunk )
403
394
} else {
404
- excluded = true
395
+ // keep chunks after the last base snapshot restore time
396
+ // the backup may be excluded
397
+ afterChunks = append (afterChunks , chunk )
405
398
}
406
399
}
407
400
408
- // if excluded is false, the last found base snapshot is not used for PITR
409
- // no need to keep it. otherwise, should be excluded
410
- if excluded {
401
+ if oplog . HasSingleTimelineToCover ( afterChunks , backups [ baseIndex ]. LastWriteTS . T , ts . T ) {
402
+ // there is single continuous oplog range between snapshot and ts.
403
+ // keep the backup and chunks to be able to restore to the ts
411
404
copy (backups [baseIndex :], backups [baseIndex + 1 :])
412
405
backups = backups [:len (backups )- 1 ]
406
+ chunks = beforeChunks
407
+ } else {
408
+ // no chunks yet but if PITR is ON, the backup can be base snapshot for it
409
+ enabled , oplogOnly , err := config .IsPITREnabled (ctx , conn )
410
+ if err != nil {
411
+ return CleanupInfo {}, errors .Wrap (err , "get PITR status" )
412
+ }
413
+ if enabled && ! oplogOnly {
414
+ nextRestoreTime , err := FindBaseSnapshotLWAfter (ctx , conn , ts )
415
+ if err != nil {
416
+ return CleanupInfo {}, errors .Wrap (err , "find next snapshot" )
417
+ }
418
+
419
+ if nextRestoreTime .IsZero () {
420
+ // it is not the last base snapshot for PITR
421
+ copy (backups [baseIndex :], backups [baseIndex + 1 :])
422
+ backups = backups [:len (backups )- 1 ]
423
+ chunks = beforeChunks
424
+ }
425
+ }
426
+ }
427
+
428
+ // exclude increments that is base for following increment (after `ts`)
429
+ backups , err = extractLastIncrementalChain (ctx , conn , backups )
430
+ if err != nil {
431
+ return CleanupInfo {}, errors .Wrap (err , "extract last incremental chain" )
413
432
}
414
433
415
434
return CleanupInfo {Backups : backups , Chunks : chunks }, nil
@@ -471,6 +490,10 @@ func extractLastIncrementalChain(
471
490
return bcps , nil
472
491
}
473
492
493
+ return extractIncrementalChain (bcps , i ), nil
494
+ }
495
+
496
+ func extractIncrementalChain (bcps []BackupMeta , i int ) []BackupMeta {
474
497
for base := bcps [i ].Name ; i != - 1 ; i -- {
475
498
if bcps [i ].Status != defs .StatusDone {
476
499
continue
@@ -490,15 +513,5 @@ func extractLastIncrementalChain(
490
513
}
491
514
}
492
515
493
- return bcps , nil
494
- }
495
-
496
- func findLastBaseSnapshotIndex (bcps []BackupMeta ) int {
497
- for i := len (bcps ) - 1 ; i != - 1 ; i -- {
498
- if isValidBaseSnapshot (& bcps [i ]) {
499
- return i
500
- }
501
- }
502
-
503
- return - 1
516
+ return bcps
504
517
}
0 commit comments