Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
78430: backupccl: datadrivenify the restore OnFailOrCancel tests r=msbutler a=adityamaru

This change ports all the "cleanup on failed or canceled restore"
tests to the datadriven framework. To make this possible new instructions
have been added to the datadriven framework, please refer to the header
comment for details about each one.

Informs: #77129

Release note: None

79167: bazel: update arguments passed to `configure` for dev macOS arm builds r=mari-crl a=rickystewart

Release note: None

79236: dev: `lint` should honor the number of CPUs when building cockroach r=irfansharif a=rickystewart

Release note: None

79242: docs: generate swagger docs w/ bazel r=mari-crl,rail a=rickystewart

Also build in CI as well as `dev generate docs`.

Closes #77395.

Release note: None

Co-authored-by: Aditya Maru <[email protected]>
Co-authored-by: Ricky Stewart <[email protected]>
  • Loading branch information
3 people committed Apr 1, 2022
5 parents 0d10296 + 1ba873a + c7b82dc + ea619e1 + d52f609 commit 675eb23
Show file tree
Hide file tree
Showing 16 changed files with 694 additions and 328 deletions.
11 changes: 11 additions & 0 deletions build/toolchains/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,17 @@ config_setting(
},
)

config_setting(
name = "is_dev_macos_arm64",
constraint_values = [
"@io_bazel_rules_go//go/toolchain:darwin",
"@platforms//cpu:aarch64",
],
flag_values = {
":dev_flag": "true",
},
)

config_setting(
name = "is_cross_linux",
constraint_values = [
Expand Down
11 changes: 10 additions & 1 deletion c-deps/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,16 @@ configure_make(
"--enable-prof",
] + select({
"@io_bazel_rules_go//go/platform:windows": ["--host=x86_64-w64-mingw32"],
"@io_bazel_rules_go//go/platform:darwin": ["--host=x86_64-apple-darwin19"],
"@io_bazel_rules_go//go/platform:darwin_amd64": ["--host=x86_64-apple-darwin19"],
"@io_bazel_rules_go//go/platform:darwin_arm64": ["--host=aarch64-apple-darwin19"],
# NB: Normally host detection is handled by configure, but the version
# of jemalloc we have vendored is pretty ancient and can't handle some
# of the newer M1 Macs. This arm of the select() can probably be deleted
# when we bump the vendored version.
"//build/toolchains:is_dev_macos_arm64": [
"--host=aarch64-apple-darwin19",
"--build=aarch64-apple-darwin19",
],
"@io_bazel_rules_go//go/platform:linux_arm64": ["--host=aarch64-unknown-linux-gnu"],
"//conditions:default": [],
}),
Expand Down
1 change: 1 addition & 0 deletions docs/generated/bazel_targets.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@ documentation. Lines not beginning with // should be ignored.
//docs/generated/settings:settings_for_tenants
//docs/generated/sql
//docs/generated/sql/bnf
//docs/generated/swagger
26 changes: 26 additions & 0 deletions docs/generated/swagger/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
load("@io_bazel_rules_go//go:def.bzl", "go_path")

genrule(
name = "swagger",
srcs = [
":swagger_go_path",
],
outs = ["spec.json"],
cmd = """
GO_REL_PATH=`dirname $(location @go_sdk//:bin/go)`
GO_ABS_PATH=`cd $$GO_REL_PATH && pwd`
env PATH=$$GO_ABS_PATH HOME=$(GENDIR) GOPATH=$$(cd $(location :swagger_go_path) && pwd) GO111MODULE=off \
$(location @com_github_go_swagger_go_swagger//cmd/swagger) generate spec -w $(location :swagger_go_path)/src/github.com/cockroachdb/cockroach/pkg --scan-models -t bazel -o $@
""",
exec_tools = [
"@com_github_go_swagger_go_swagger//cmd/swagger",
"@go_sdk//:bin/go",
],
)

go_path(
name = "swagger_go_path",
deps = [
"//pkg/server",
],
)
279 changes: 0 additions & 279 deletions pkg/ccl/backupccl/backup_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1870,285 +1870,6 @@ func TestBackupRestoreControlJob(t *testing.T) {
})
}

func TestRestoreFailCleansUpTTLSchedules(t *testing.T) {
defer leaktest.AfterTest(t)()
defer log.Scope(t).Close(t)

injectedErr := errors.New("injected error")
testCases := []struct {
desc string
beforePublishingDescriptors func() error
afterPublishingDescriptors func() error
}{
{
desc: "error before publishing descriptors",
beforePublishingDescriptors: func() error {
return injectedErr
},
},
{
desc: "error after publishing descriptors",
afterPublishingDescriptors: func() error {
return injectedErr
},
},
}

ctx := context.Background()

for _, tc := range testCases {
t.Run(tc.desc, func(t *testing.T) {
c, sqlDB, _, cleanup := backupRestoreTestSetup(t, singleNode, 0, InitManualReplication)
defer cleanup()
for _, server := range c.Servers {
registry := server.JobRegistry().(*jobs.Registry)
registry.TestingResumerCreationKnobs = map[jobspb.Type]func(raw jobs.Resumer) jobs.Resumer{
jobspb.TypeRestore: func(raw jobs.Resumer) jobs.Resumer {
r := raw.(*restoreResumer)
r.testingKnobs.beforePublishingDescriptors = tc.beforePublishingDescriptors
r.testingKnobs.afterPublishingDescriptors = tc.afterPublishingDescriptors
return r
},
}
}

// Create a database with a TTL table.
sqlDB.Exec(t, `
CREATE DATABASE d;
CREATE TABLE d.tb (id INT PRIMARY KEY) WITH (ttl_expire_after = '10 minutes')
`)

// Backup d.tb.
sqlDB.Exec(t, `BACKUP DATABASE d TO $1`, localFoo)

// Drop d so that it can be restored.
sqlDB.Exec(t, `DROP DATABASE d`)

// Attempt the restore and check it fails.
_, err := sqlDB.DB.ExecContext(ctx, `RESTORE DATABASE d FROM $1`, localFoo)
require.Error(t, err)
require.Regexp(t, injectedErr.Error(), err.Error())

var count int
sqlDB.QueryRow(t, `SELECT count(1) FROM [SHOW SCHEDULES] WHERE label LIKE 'row-level-ttl-%'`).Scan(&count)
require.Equal(t, 0, count)
})
}
}

func TestRestoreFailCleansUpTypeBackReferences(t *testing.T) {
defer leaktest.AfterTest(t)()
defer log.Scope(t).Close(t)

_, sqlDB, dir, cleanup := backupRestoreTestSetup(t, singleNode, 0, InitManualReplication)
defer cleanup()

dir = dir + "/foo"

// Create a database with a type and table.
sqlDB.Exec(t, `
CREATE DATABASE d;
CREATE TYPE d.ty AS ENUM ('hello');
CREATE TABLE d.tb (x d.ty);
INSERT INTO d.tb VALUES ('hello'), ('hello');
`)

// Backup d.tb.
sqlDB.Exec(t, `BACKUP TABLE d.tb TO $1`, localFoo)

// Drop d.tb so that it can be restored.
sqlDB.Exec(t, `DROP TABLE d.tb`)

// Bugger the backup by removing the SST files.
if err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
if err != nil {
t.Fatal(err)
}
if info.Name() == backupManifestName || !strings.HasSuffix(path, ".sst") {
return nil
}
return os.Remove(path)
}); err != nil {
t.Fatal(err)
}

// We should get an error when restoring the table.
sqlDB.ExpectErr(t, "sst: no such file", `RESTORE d.tb FROM $1`, localFoo)

// The failed restore should clean up type back references so that we are able
// to drop d.ty.
sqlDB.Exec(t, `DROP TYPE d.ty`)
}

// TestRestoreFailCleanup tests that a failed RESTORE is cleaned up.
func TestRestoreFailCleanup(t *testing.T) {
defer leaktest.AfterTest(t)()
defer log.Scope(t).Close(t)

params := base.TestServerArgs{}
// Disable GC job so that the final check of crdb_internal.tables is
// guaranteed to not be cleaned up. Although this was never observed by a
// stress test, it is here for safety.
blockGC := make(chan struct{})
params.Knobs.GCJob = &sql.GCJobTestingKnobs{
RunBeforeResume: func(_ jobspb.JobID) error {
<-blockGC
return nil
},
}

const numAccounts = 1000
tc, sqlDB, dir, cleanup := backupRestoreTestSetupWithParams(t, singleNode, numAccounts,
InitManualReplication, base.TestClusterArgs{ServerArgs: params})
defer cleanup()
kvDB := tc.Server(0).DB()

dir = dir + "/foo"

sqlDB.Exec(t, `CREATE DATABASE restore`)

// Create a user defined type and check that it is cleaned up after the
// failed restore.
sqlDB.Exec(t, `CREATE TYPE data.myenum AS ENUM ('hello')`)
// Do the same with a user defined schema.
sqlDB.Exec(t, `USE data; CREATE SCHEMA myschema`)

sqlDB.Exec(t, `BACKUP DATABASE data TO $1`, localFoo)
// Bugger the backup by removing the SST files.
if err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
if err != nil {
t.Fatal(err)
}
if info.Name() == backupManifestName || !strings.HasSuffix(path, ".sst") {
return nil
}
return os.Remove(path)
}); err != nil {
t.Fatal(err)
}
sqlDB.ExpectErr(
t, "sst: no such file",
`RESTORE data.* FROM $1 WITH OPTIONS (into_db='restore')`, localFoo,
)
// Verify the failed RESTORE added some DROP tables.
sqlDB.CheckQueryResults(t,
`SELECT name FROM crdb_internal.tables WHERE database_name = 'restore' AND state = 'DROP'`,
[][]string{{"bank"}},
)

// Verify that `myenum` was cleaned out from the failed restore. There should
// only be one namespace entry (data.myenum).
sqlDB.CheckQueryResults(t, `SELECT count(*) FROM system.namespace WHERE name = 'myenum'`, [][]string{{"1"}})
// Check the same for data.myschema.
sqlDB.CheckQueryResults(t, `SELECT count(*) FROM system.namespace WHERE name = 'myschema'`, [][]string{{"1"}})

// Verify that the only schema that appears is the public schema
dbDesc := desctestutils.TestingGetDatabaseDescriptor(kvDB, keys.SystemSQLCodec, "restore")
require.Equal(t, len(dbDesc.DatabaseDesc().Schemas), 1)
if _, found := dbDesc.DatabaseDesc().Schemas[tree.PublicSchema]; !found {
t.Error("public schema not found")
}
}

// TestRestoreFailDatabaseCleanup tests that a failed RESTORE is cleaned up
// when restoring an entire database.
func TestRestoreFailDatabaseCleanup(t *testing.T) {
defer leaktest.AfterTest(t)()
defer log.Scope(t).Close(t)

params := base.TestServerArgs{}
const numAccounts = 1000
_, sqlDB, dir, cleanup := backupRestoreTestSetupWithParams(t, singleNode, numAccounts,
InitManualReplication, base.TestClusterArgs{ServerArgs: params})
defer cleanup()

dir = dir + "/foo"

// Create a user defined type and check that it is cleaned up after the
// failed restore.
sqlDB.Exec(t, `CREATE TYPE data.myenum AS ENUM ('hello')`)
// Do the same with a user defined schema.
sqlDB.Exec(t, `USE data; CREATE SCHEMA myschema`)

sqlDB.Exec(t, `BACKUP DATABASE data TO $1`, localFoo)
// Bugger the backup by removing the SST files.
if err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
if err != nil {
t.Fatal(err)
}
if info.Name() == backupManifestName || !strings.HasSuffix(path, ".sst") {
return nil
}
return os.Remove(path)
}); err != nil {
t.Fatal(err)
}
sqlDB.Exec(t, `DROP DATABASE data`)
sqlDB.ExpectErr(
t, "sst: no such file",
`RESTORE DATABASE data FROM $1`, localFoo,
)
sqlDB.ExpectErr(
t, `database "data" does not exist`,
`DROP DATABASE data`,
)
}

func TestRestoreFailCleansUpTempSystemDatabase(t *testing.T) {
defer leaktest.AfterTest(t)()
defer log.Scope(t).Close(t)

_, sqlDB, dir, cleanup := backupRestoreTestSetup(t, singleNode, 0, InitManualReplication)
defer cleanup()

// Create a database with a type and table.
sqlDB.Exec(t, `
CREATE DATABASE d;
CREATE TYPE d.ty AS ENUM ('hello');
CREATE TABLE d.tb (x d.ty);
INSERT INTO d.tb VALUES ('hello'), ('hello');
`)

// Cluster BACKUP.
sqlDB.Exec(t, `BACKUP TO $1`, localFoo)

// Bugger the backup by removing the SST files.
if err := filepath.Walk(dir+"/foo", func(path string, info os.FileInfo, err error) error {
if err != nil {
t.Fatal(err)
}
if info.Name() == backupManifestName || !strings.HasSuffix(path, ".sst") {
return nil
}
return os.Remove(path)
}); err != nil {
t.Fatal(err)
}

_, sqlDBRestore, cleanupRestore := backupRestoreTestSetupEmpty(t, singleNode, dir, InitManualReplication,
base.TestClusterArgs{})
defer cleanupRestore()
var defaultDBID int
sqlDBRestore.QueryRow(
t, "SELECT id FROM system.namespace WHERE name = 'defaultdb'",
).Scan(&defaultDBID)

// We should get an error when restoring the table.
sqlDBRestore.ExpectErr(t, "sst: no such file", `RESTORE FROM $1`, localFoo)

// Make sure the temp system db is not present.
row := sqlDBRestore.QueryStr(t, fmt.Sprintf(`SELECT * FROM [SHOW DATABASES] WHERE database_name = '%s'`, restoreTempSystemDB))
require.Equal(t, 0, len(row))

// Make sure defaultdb and postgres are recreated with new IDs.
sqlDBRestore.CheckQueryResults(t,
fmt.Sprintf(`
SELECT name
FROM system.namespace
WHERE "parentID" = 0 AND id > %d`, defaultDBID,
), [][]string{{"defaultdb"}, {"postgres"}})
}

func TestBackupRestoreUserDefinedSchemas(t *testing.T) {
defer leaktest.AfterTest(t)()
defer log.Scope(t).Close(t)
Expand Down
Loading

0 comments on commit 675eb23

Please sign in to comment.