github.com/authzed/spicedb@v1.32.1-0.20240520085336-ebda56537386/internal/datastore/postgres/migrations/zz_migration.0011_backfill_xid_add_indices.go (about) 1 package migrations 2 3 import ( 4 "context" 5 "fmt" 6 7 "github.com/jackc/pgx/v5" 8 "github.com/jackc/pgx/v5/pgconn" 9 10 log "github.com/authzed/spicedb/internal/logging" 11 "github.com/authzed/spicedb/pkg/migrate" 12 ) 13 14 var ( 15 addRelationTupleDefault = ` 16 ALTER TABLE relation_tuple 17 ALTER COLUMN created_xid SET DEFAULT (pg_current_xact_id());` 18 19 addNamepsaceDefault = ` 20 ALTER TABLE namespace_config 21 ALTER COLUMN created_xid SET DEFAULT (pg_current_xact_id());` 22 23 addCaveatDefault = ` 24 ALTER TABLE caveat 25 ALTER COLUMN created_xid SET DEFAULT (pg_current_xact_id());` 26 ) 27 28 var addBackfillIndices = []string{ 29 addRelationTupleDefault, 30 addNamepsaceDefault, 31 addCaveatDefault, 32 `CREATE INDEX CONCURRENTLY IF NOT EXISTS ix_backfill_rtt_temp 33 ON relation_tuple_transaction ( (snapshot IS NULL) )`, 34 `CREATE INDEX CONCURRENTLY IF NOT EXISTS ix_backfill_ns_temp 35 ON namespace_config ( (created_xid IS NULL) )`, 36 `CREATE INDEX CONCURRENTLY IF NOT EXISTS ix_backfill_tuple_temp 37 ON relation_tuple ( (created_xid IS NULL) )`, 38 `CREATE INDEX CONCURRENTLY IF NOT EXISTS ix_backfill_caveat_temp 39 ON caveat ( (created_xid IS NULL) )`, 40 } 41 42 var backfills = []string{ 43 `UPDATE relation_tuple_transaction 44 SET xid = id::text::xid8, snapshot = CONCAT(id, ':', id, ':')::pg_snapshot 45 WHERE id IN ( 46 SELECT id FROM relation_tuple_transaction 47 WHERE snapshot IS NULL 48 LIMIT %d 49 FOR UPDATE 50 );`, 51 `UPDATE relation_tuple 52 SET deleted_xid = deleted_transaction::text::xid8, 53 created_xid = created_transaction::text::xid8 54 WHERE (namespace, object_id, relation, userset_namespace, userset_object_id, 55 userset_relation, created_transaction, deleted_transaction 56 ) IN ( 57 SELECT namespace, object_id, relation, userset_namespace, userset_object_id, 58 userset_relation, created_transaction, deleted_transaction 59 FROM relation_tuple 60 WHERE created_xid IS NULL 61 LIMIT %d 62 FOR UPDATE 63 );`, 64 `UPDATE namespace_config 65 SET deleted_xid = deleted_transaction::text::xid8, 66 created_xid = created_transaction::text::xid8 67 WHERE (namespace, created_transaction, deleted_transaction) IN ( 68 SELECT namespace, created_transaction, deleted_transaction 69 FROM namespace_config 70 WHERE created_xid IS NULL 71 LIMIT %d 72 FOR UPDATE 73 );`, 74 `UPDATE caveat 75 SET deleted_xid = deleted_transaction::text::xid8, 76 created_xid = created_transaction::text::xid8 77 WHERE (name, created_transaction, deleted_transaction) IN ( 78 SELECT name, created_transaction, deleted_transaction 79 FROM caveat 80 WHERE created_xid IS NULL 81 LIMIT %d 82 FOR UPDATE 83 );`, 84 } 85 86 var addXIDIndices = []string{ 87 // Replace the indices that are inherent from having a primary key constraint 88 `CREATE UNIQUE INDEX CONCURRENTLY IF NOT EXISTS ix_rttx_oldpk 89 ON relation_tuple_transaction (id)`, 90 `CREATE UNIQUE INDEX CONCURRENTLY IF NOT EXISTS ix_namespace_config_oldpk 91 ON namespace_config (id)`, 92 93 // Add indices that will eventually back our new constraints 94 `CREATE UNIQUE INDEX CONCURRENTLY IF NOT EXISTS ix_rttx_pk 95 ON relation_tuple_transaction (xid);`, 96 `CREATE UNIQUE INDEX CONCURRENTLY IF NOT EXISTS ix_namespace_config_pk 97 ON namespace_config (namespace, created_xid, deleted_xid);`, 98 `CREATE UNIQUE INDEX CONCURRENTLY IF NOT EXISTS ix_namespace_config_living 99 ON namespace_config (namespace, deleted_xid);`, 100 `CREATE UNIQUE INDEX CONCURRENTLY IF NOT EXISTS ix_relation_tuple_pk 101 ON relation_tuple (namespace, object_id, relation, userset_namespace, userset_object_id, 102 userset_relation, created_xid, deleted_xid);`, 103 `CREATE UNIQUE INDEX CONCURRENTLY IF NOT EXISTS ix_relation_tuple_living 104 ON relation_tuple (namespace, object_id, relation, userset_namespace, userset_object_id, 105 userset_relation, deleted_xid);`, 106 `CREATE UNIQUE INDEX CONCURRENTLY IF NOT EXISTS ix_caveat_unique 107 ON caveat (name, created_xid, deleted_xid);`, 108 `CREATE UNIQUE INDEX CONCURRENTLY IF NOT EXISTS ix_caveat_living 109 ON caveat (name, deleted_xid);`, 110 } 111 112 var dropBackfillIndices = []string{ 113 "DROP INDEX ix_backfill_rtt_temp", 114 "DROP INDEX ix_backfill_ns_temp", 115 "DROP INDEX ix_backfill_tuple_temp", 116 "DROP INDEX ix_backfill_caveat_temp", 117 } 118 119 func init() { 120 if err := DatabaseMigrations.Register("backfill-xid-add-indices", "add-xid-columns", 121 func(ctx context.Context, conn *pgx.Conn) error { 122 for _, stmt := range addBackfillIndices { 123 if _, err := conn.Exec(ctx, stmt); err != nil { 124 return err 125 } 126 } 127 128 batchSize := ctx.Value(migrate.BackfillBatchSize).(uint64) 129 for _, stmt := range backfills { 130 concreteStmt := fmt.Sprintf(stmt, batchSize) 131 132 log.Ctx(ctx).Info().Str("statement", concreteStmt).Msg("starting backfill") 133 134 var r pgconn.CommandTag 135 var err error 136 137 for r, err = conn.Exec(ctx, concreteStmt); err == nil && r.RowsAffected() > 0; r, err = conn.Exec(ctx, concreteStmt) { 138 log.Ctx(ctx).Debug().Int64("count", r.RowsAffected()).Msg("updated rows") 139 } 140 if err != nil { 141 return err 142 } 143 } 144 145 for _, stmt := range append(addXIDIndices, dropBackfillIndices...) { 146 if _, err := conn.Exec(ctx, stmt); err != nil { 147 return err 148 } 149 } 150 151 return nil 152 }, 153 noTxMigration, 154 ); err != nil { 155 panic("failed to register migration: " + err.Error()) 156 } 157 }