github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/cmd/roachtest/namespace_upgrade.go (about) 1 // Copyright 2020 The Cockroach Authors. 2 // 3 // Use of this software is governed by the Business Source License 4 // included in the file licenses/BSL.txt. 5 // 6 // As of the Change Date specified in that file, in accordance with 7 // the Business Source License, use of this software will be governed 8 // by the Apache License, Version 2.0, included in the file 9 // licenses/APL.txt. 10 11 package main 12 13 import ( 14 "context" 15 "fmt" 16 "time" 17 18 "github.com/cockroachdb/cockroach/pkg/util/retry" 19 ) 20 21 func registerNamespaceUpgrade(r *testRegistry) { 22 r.Add(testSpec{ 23 Name: "version/namespace-upgrade", 24 Owner: OwnerSQLSchema, 25 // This test is a regression test designed to test for #49092. 26 // It drops objects from the 19.2 node after the 20.1 node joins the 27 // cluster, and also drops/adds objects in each of the states before, during 28 // and after the migration, making sure results are as we expect. 29 MinVersion: "v20.1.0", 30 Cluster: makeClusterSpec(3), 31 Run: func(ctx context.Context, t *test, c *cluster) { 32 predV, err := PredecessorVersion(r.buildVersion) 33 if err != nil { 34 t.Fatal(err) 35 } 36 runNamespaceUpgrade(ctx, t, c, predV) 37 }, 38 }) 39 } 40 41 func createTableStep(node int, table string) versionStep { 42 return func(ctx context.Context, t *test, u *versionUpgradeTest) { 43 db := u.conn(ctx, t, node) 44 _, err := db.ExecContext(ctx, 45 fmt.Sprintf(`CREATE TABLE %s (a INT)`, table)) 46 if err != nil { 47 t.Fatal(err) 48 } 49 } 50 } 51 52 func createDBStep(node int, name string) versionStep { 53 return func(ctx context.Context, t *test, u *versionUpgradeTest) { 54 db := u.conn(ctx, t, node) 55 _, err := db.ExecContext(ctx, 56 fmt.Sprintf(`CREATE DATABASE %s`, name)) 57 if err != nil { 58 t.Fatal(err) 59 } 60 } 61 } 62 63 func dropTableStep(node int, table string) versionStep { 64 return func(ctx context.Context, t *test, u *versionUpgradeTest) { 65 db := u.conn(ctx, t, node) 66 _, err := db.ExecContext(ctx, 67 fmt.Sprintf(`DROP TABLE %s`, table)) 68 if err != nil { 69 t.Fatal(err) 70 } 71 } 72 } 73 74 func dropDBStep(node int, name string) versionStep { 75 return func(ctx context.Context, t *test, u *versionUpgradeTest) { 76 db := u.conn(ctx, t, node) 77 _, err := db.ExecContext(ctx, 78 fmt.Sprintf(`DROP DATABASE %s`, name)) 79 if err != nil { 80 t.Fatal(err) 81 } 82 } 83 } 84 85 func renameDBStep(node int, oldDB string, newDB string) versionStep { 86 return func(ctx context.Context, t *test, u *versionUpgradeTest) { 87 db := u.conn(ctx, t, node) 88 _, err := db.ExecContext(ctx, 89 fmt.Sprintf(`ALTER DATABASE %s RENAME TO %s`, oldDB, newDB)) 90 if err != nil { 91 t.Fatal(err) 92 } 93 } 94 } 95 96 func renameTableStep(node int, oldTable string, newTable string) versionStep { 97 return func(ctx context.Context, t *test, u *versionUpgradeTest) { 98 db := u.conn(ctx, t, node) 99 _, err := db.ExecContext(ctx, 100 fmt.Sprintf(`ALTER TABLE %s RENAME TO %s`, oldTable, newTable)) 101 if err != nil { 102 t.Fatal(err) 103 } 104 } 105 } 106 107 func truncateTableStep(node int, table string) versionStep { 108 return func(ctx context.Context, t *test, u *versionUpgradeTest) { 109 db := u.conn(ctx, t, node) 110 _, err := db.ExecContext(ctx, 111 fmt.Sprintf(`TRUNCATE %s`, table)) 112 if err != nil { 113 t.Fatal(err) 114 } 115 } 116 } 117 118 func showDatabasesStep(node int) versionStep { 119 return func(ctx context.Context, t *test, u *versionUpgradeTest) { 120 db := u.conn(ctx, t, node) 121 _, err := db.ExecContext(ctx, 122 `SHOW DATABASES`) 123 if err != nil { 124 t.Fatal(err) 125 } 126 } 127 } 128 129 func changeMigrationSetting(node int, enable bool) versionStep { 130 return func(ctx context.Context, t *test, u *versionUpgradeTest) { 131 db := u.conn(ctx, t, node) 132 _, err := db.ExecContext(ctx, `SET CLUSTER SETTING testing.system_namespace_migration.enabled = $1`, enable) 133 if err != nil { 134 t.Fatal(err) 135 } 136 } 137 } 138 139 func verifyNoOrphanedOldEntries(node int) versionStep { 140 return func(ctx context.Context, t *test, u *versionUpgradeTest) { 141 db := u.conn(ctx, t, node) 142 // Check that there are no rows in namespace that aren't in namespace2, 143 // except for the old entry for namespace (descriptor 2) which we don't 144 //copy. 145 row := db.QueryRowContext(ctx, 146 `SELECT count(*) FROM [2 AS namespace] WHERE id != 2 AND id NOT IN (SELECT id FROM [30 as namespace2])`) 147 var count int 148 if err := row.Scan(&count); err != nil { 149 t.Fatal(err) 150 } 151 if count != 0 { 152 t.Fatal("unexpected entries found in namespace but not in namespace2") 153 } 154 } 155 156 } 157 158 func uploadAndStart(nodes nodeListOption, v string) versionStep { 159 return func(ctx context.Context, t *test, u *versionUpgradeTest) { 160 // Put and start the binary. 161 args := u.uploadVersion(ctx, t, nodes, v) 162 // NB: can't start sequentially since cluster already bootstrapped. 163 u.c.Start(ctx, t, nodes, args, startArgsDontEncrypt, roachprodArgOption{"--sequential=false"}) 164 } 165 } 166 167 func runNamespaceUpgrade(ctx context.Context, t *test, c *cluster, predecessorVersion string) { 168 roachNodes := c.All() 169 // An empty string means that the cockroach binary specified by flag 170 // `cockroach` will be used. 171 const mainVersion = "" 172 u := newVersionUpgradeTest(c, 173 uploadAndStart(roachNodes, predecessorVersion), 174 waitForUpgradeStep(roachNodes), 175 preventAutoUpgradeStep(1), 176 177 // Make some objects on node 1. 178 createTableStep(1, "a"), 179 createTableStep(1, "todrop"), 180 createTableStep(1, "torename"), 181 createTableStep(1, "totruncate"), 182 createDBStep(1, "foo"), 183 createDBStep(1, "todrop"), 184 createDBStep(1, "torename"), 185 186 // Upgrade Node 3. 187 binaryUpgradeStep(c.Node(3), mainVersion), 188 189 // Disable the migration. We'll re-enable it later. 190 changeMigrationSetting(3, false), 191 192 // Drop the objects on node 1, which is still on the old version. 193 dropTableStep(1, "a"), 194 dropDBStep(1, "foo"), 195 196 // Verify that the new node can still run SHOW DATABASES. 197 showDatabasesStep(3), 198 // Verify that the new node can recreate the dropped objects. 199 createTableStep(3, "a"), 200 createDBStep(3, "foo"), 201 202 // Drop the objects on node 1 again, which is still on the old version. 203 dropTableStep(1, "a"), 204 dropDBStep(1, "foo"), 205 206 // Upgrade the other 2 nodes. 207 binaryUpgradeStep(c.Node(1), mainVersion), 208 binaryUpgradeStep(c.Node(2), mainVersion), 209 210 // Finalize upgrade. 211 allowAutoUpgradeStep(1), 212 213 waitForUpgradeStep(roachNodes), 214 215 // After finalization, but before upgrade, add a table, drop a table, 216 // rename a table, and truncate a table. 217 createTableStep(1, "fresh"), 218 createDBStep(1, "fresh"), 219 dropTableStep(1, "todrop"), 220 dropDBStep(1, "todrop"), 221 renameTableStep(1, "torename", "new"), 222 renameDBStep(1, "torename", "new"), 223 truncateTableStep(1, "totruncate"), 224 225 // Re-enable the migration. 226 changeMigrationSetting(1, true), 227 228 // Wait for the migration to finish. 229 func(ctx context.Context, t *test, u *versionUpgradeTest) { 230 t.l.Printf("waiting for cluster to finish namespace migration\n") 231 232 for _, i := range roachNodes { 233 err := retry.ForDuration(30*time.Second, func() error { 234 db := u.conn(ctx, t, i) 235 // This is copied from pkg/sqlmigrations/migrations.go. We don't 236 // export it just for this test because it feels unnecessary. 237 const systemNamespaceMigrationName = "upgrade system.namespace post-20.1-finalization" 238 var complete bool 239 if err := db.QueryRowContext(ctx, 240 `SELECT crdb_internal.completed_migrations() @> ARRAY[$1::string]`, 241 systemNamespaceMigrationName, 242 ).Scan(&complete); err != nil { 243 t.Fatal(err) 244 } 245 if !complete { 246 return fmt.Errorf("%d: migration not complete", i) 247 } 248 return nil 249 }) 250 if err != nil { 251 t.Fatal(err) 252 } 253 } 254 }, 255 256 // Verify that there are no remaining entries that only live in the old 257 // namespace table. 258 verifyNoOrphanedOldEntries(1), 259 260 // Verify that the cluster can run SHOW DATABASES and re-use the names. 261 showDatabasesStep(3), 262 createTableStep(1, "a"), 263 createDBStep(1, "foo"), 264 createTableStep(1, "torename"), 265 createDBStep(1, "torename"), 266 createTableStep(1, "todrop"), 267 createDBStep(1, "todrop"), 268 269 verifyNoOrphanedOldEntries(1), 270 ) 271 u.run(ctx, t) 272 273 }