diff --git a/pkg/ccl/backupccl/backup_planning.go b/pkg/ccl/backupccl/backup_planning.go index b12de328c68c..3576ddf02e02 100644 --- a/pkg/ccl/backupccl/backup_planning.go +++ b/pkg/ccl/backupccl/backup_planning.go @@ -1387,8 +1387,23 @@ func getReintroducedSpans( ) ([]roachpb.Span, error) { reintroducedTables := make(map[descpb.ID]struct{}) + // First, create a map that indicates which tables from the previous backup + // were offline when the last backup was taken. To create this map, we must + // iterate two fields in the _last_ backup's manifest: + // + // 1. manifest.Descriptors contains a list of descriptors _explicitly_ + // included in the backup, gathered at backup startTime. + // + // 2. manifest.DescriptorChanges contains a list of descriptor changes tracked + // in the backup. While investigating #88042, it was discovered that + // during revision history backups, a table can get included in + // manifest.DescriptorChanges, causing its spans to get backed up, but _not_ + // in manifest.Descriptors. Therefore, to find all descriptors covered in the + // backup that were offline at backup time, we must find all tables in + // manifest.DescriptorChanges whose last change brought the table offline. offlineInLastBackup := make(map[descpb.ID]struct{}) lastBackup := prevBackups[len(prevBackups)-1] + for _, desc := range lastBackup.Descriptors { // TODO(pbardea): Also check that lastWriteTime is set once those are // populated on the table descriptor. @@ -1397,6 +1412,23 @@ func getReintroducedSpans( } } + latestTableDescChangeInLastBackup := make(map[descpb.ID]*descpb.TableDescriptor) + for _, rev := range lastBackup.DescriptorChanges { + if table, _, _, _, _ := descpb.FromDescriptor(rev.Desc); table != nil { + if trackedRev, ok := latestTableDescChangeInLastBackup[table.GetID()]; !ok { + latestTableDescChangeInLastBackup[table.GetID()] = table + } else if trackedRev.Version < table.Version { + latestTableDescChangeInLastBackup[table.GetID()] = table + } + } + } + + for _, table := range latestTableDescChangeInLastBackup { + if table.Offline() { + offlineInLastBackup[table.GetID()] = struct{}{} + } + } + // If the table was offline in the last backup, but becomes PUBLIC, then it // needs to be re-included since we may have missed non-transactional writes. tablesToReinclude := make([]catalog.TableDescriptor, 0)