Skip to content

Commit 3bf4d17

Browse files
authored
Merge pull request #151080 from dt/backport25.3-151058
release-25.3: backup: fix external storage error propagation
2 parents 4bcc6f0 + ce2adfc commit 3bf4d17

File tree

3 files changed

+51
-1
lines changed

3 files changed

+51
-1
lines changed

pkg/backup/backup_processor.go

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,14 @@ type spanAndTime struct {
292292
finishesSpec bool
293293
}
294294

295+
type errInjectingStorage struct {
296+
cloud.ExternalStorage
297+
}
298+
299+
func (e errInjectingStorage) Writer(_ context.Context, _ string) (io.WriteCloser, error) {
300+
return nil, errors.New("injected error")
301+
}
302+
295303
func runBackupProcessor(
296304
ctx context.Context,
297305
flowCtx *execinfra.FlowCtx,
@@ -393,12 +401,19 @@ func runBackupProcessor(
393401
Settings: &flowCtx.Cfg.Settings.SV,
394402
ElideMode: spec.ElidePrefix,
395403
}
404+
396405
storage, err := flowCtx.Cfg.ExternalStorage(ctx, dest, cloud.WithClientName("backup"))
397406
if err != nil {
398407
return err
399408
}
400409
defer logClose(ctx, storage, "external storage")
401410

411+
if backupKnobs, ok := flowCtx.TestingKnobs().BackupRestoreTestingKnobs.(*sql.BackupRestoreTestingKnobs); ok {
412+
if fn := backupKnobs.InjectErrorsInBackupRowDataStorage; fn != nil && fn() {
413+
storage = errInjectingStorage{storage}
414+
}
415+
}
416+
402417
// Start start a group of goroutines which each pull spans off of `todo` and
403418
// send export requests. Any spans that encounter lock conflict errors during
404419
// Export are put back on the todo queue for later processing.
@@ -683,7 +698,7 @@ func runBackupProcessor(
683698
var writeErr error
684699
resumeSpan.span.Key, writeErr = sink.Write(ctx, ret)
685700
if writeErr != nil {
686-
return err
701+
return writeErr
687702
}
688703
}
689704
// Emit the stats for the processed ExportRequest.

pkg/backup/backup_test.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6321,6 +6321,36 @@ func TestPublicIndexTableSpans(t *testing.T) {
63216321
}
63226322
}
63236323

6324+
// TestBackupStorageErrorPropagates ensures that errors from writing to storage
6325+
// propagate correctly during a backup operation.
6326+
func TestBackupStorageErrorPropagates(t *testing.T) {
6327+
defer leaktest.AfterTest(t)()
6328+
defer log.Scope(t).Close(t)
6329+
6330+
const numAccounts = 1000
6331+
6332+
var fail atomic.Bool
6333+
6334+
params := base.TestClusterArgs{}
6335+
knobs := base.TestingKnobs{
6336+
DistSQL: &execinfra.TestingKnobs{BackupRestoreTestingKnobs: &sql.BackupRestoreTestingKnobs{
6337+
InjectErrorsInBackupRowDataStorage: func() bool { return fail.Load() },
6338+
}},
6339+
}
6340+
params.ServerArgs.Knobs = knobs
6341+
6342+
tc, _, _, cleanupFn := backupRestoreTestSetupWithParams(t, singleNode, numAccounts, InitManualReplication, params)
6343+
defer cleanupFn()
6344+
db := tc.ServerConn(0)
6345+
runner := sqlutils.MakeSQLRunner(db)
6346+
6347+
runner.Exec(t, "BACKUP DATABASE data INTO 'nodelocal://1/success'")
6348+
runner.Exec(t, "RESTORE DATABASE data FROM LATEST IN 'nodelocal://1/success' WITH new_db_name = 'restored'")
6349+
runner.CheckQueryResults(t, "SELECT count(*) FROM restored.bank", [][]string{{"1000"}})
6350+
fail.Store(true)
6351+
runner.ExpectErr(t, "injected", "BACKUP DATABASE data INTO 'nodelocal://1/failure'")
6352+
}
6353+
63246354
// TestRestoreJobErrorPropagates ensures that errors from creating the job
63256355
// record propagate correctly.
63266356
func TestRestoreErrorPropagates(t *testing.T) {

pkg/sql/exec_util_backup.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,11 @@ type BackupRestoreTestingKnobs struct {
4747
// span has been exported.
4848
RunAfterExportingSpanEntry func(ctx context.Context, response *kvpb.ExportResponse)
4949

50+
// InjectErrorsInBackupRowDataStorage, if non-nil and returning true, causes
51+
// errors to be injected when backup processors attempts to write row data to
52+
// the external storage.
53+
InjectErrorsInBackupRowDataStorage func() bool
54+
5055
// BackupMonitor is used to overwrite the monitor used by backup during
5156
// testing. This is typically the bulk mem monitor if not
5257
// specified here.

0 commit comments

Comments
 (0)