Skip to content

Commit

Permalink
sql: add new BACKFILLING mutation state
Browse files Browse the repository at this point in the history
This adds a BACKFILLING mutation state. When an index is in this
state, it is ignored for the purposes of INSERT, UPDATE, and
DELETE. Currently, this state is unused in the actual code.

This new state will eventually be used in the new index backfiller. In
the new backfiller, the bulk-backfill using AddSSTable will occur when
the index is in this state, with concurrent updates being captured by
a temporary index. See
docs/RFCS/20211004_incremental_index_backfiller.md for more details.

Indexes in this state are returned by `(TableDescriptor).AllIndexes`
and `(TableDescriptor).NonDropIndexes`.

Release note: None
  • Loading branch information
stevendanna committed Nov 1, 2021
1 parent a15b840 commit 02d5d80
Show file tree
Hide file tree
Showing 8 changed files with 451 additions and 375 deletions.
723 changes: 369 additions & 354 deletions pkg/sql/catalog/descpb/structured.pb.go

Large diffs are not rendered by default.

13 changes: 13 additions & 0 deletions pkg/sql/catalog/descpb/structured.proto
Original file line number Diff line number Diff line change
Expand Up @@ -723,6 +723,19 @@ message DescriptorMutation {
// (column default or index data) can only be backfilled once
// all nodes have transitioned into the DELETE_AND_WRITE_ONLY state.
DELETE_AND_WRITE_ONLY = 2;

// Operations other than non-transactional backfilling must not
// use this descriptor.
//
// Column: Columns do not use this state. A column descriptor in
// this state is a programming error.
//
// Index: A descriptor in this state is invisible to an INSERT,
// UPDATE, and DELETE.
//
// TODO(ssd): This is currently unused and is being added to
// facilitate the new temporary-index-based backfilling process.
BACKFILLING = 3;
}
optional State state = 3 [(gogoproto.nullable) = false];

Expand Down
5 changes: 3 additions & 2 deletions pkg/sql/catalog/descriptor.go
Original file line number Diff line number Diff line change
Expand Up @@ -374,8 +374,9 @@ type TableDescriptor interface {

// DeletableNonPrimaryIndexes returns a slice of all non-primary indexes
// which allow being deleted from: public + delete-and-write-only +
// delete-only, in their canonical order. This is equivalent to taking
// the slice produced by AllIndexes and removing the primary index.
// delete-only, in their canonical order. This is equivalent to taking
// the slice produced by AllIndexes and removing the primary index and
// backfilling indexes.
DeletableNonPrimaryIndexes() []Index

// DeleteOnlyNonPrimaryIndexes returns a slice of all non-primary indexes
Expand Down
4 changes: 4 additions & 0 deletions pkg/sql/catalog/table_elements.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ type TableElementMaybeMutation interface {
// delete-only state.
DeleteOnly() bool

// Backfilling returns true iff the table element is in a
// mutation in the backfilling state.
Backfilling() bool

// Adding returns true iff the table element is in an add mutation.
Adding() bool

Expand Down
7 changes: 6 additions & 1 deletion pkg/sql/catalog/tabledesc/index.go
Original file line number Diff line number Diff line change
Expand Up @@ -497,7 +497,12 @@ func newIndexCache(desc *descpb.TableDescriptor, mutations *mutationCache) *inde
c.primary = c.all[0]
c.active = c.all[:numPublic]
c.publicNonPrimary = c.active[1:]
c.deletableNonPrimary = c.all[1:]
for _, idx := range c.all[1:] {
if !idx.Backfilling() {
lazyAllocAppendIndex(&c.deletableNonPrimary, idx, len(c.all[1:]))
}
}

if numMutations == 0 {
c.writableNonPrimary = c.publicNonPrimary
} else {
Expand Down
6 changes: 6 additions & 0 deletions pkg/sql/catalog/tabledesc/mutation.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,12 @@ func (mm maybeMutation) DeleteOnly() bool {
return mm.mutationState == descpb.DescriptorMutation_DELETE_ONLY
}

// Backfilling returns true iff the table element is a mutation in the
// backfilling state.
func (mm maybeMutation) Backfilling() bool {
return mm.mutationState == descpb.DescriptorMutation_BACKFILLING
}

// Adding returns true iff the table element is in an add mutation.
func (mm maybeMutation) Adding() bool {
return mm.mutationDirection == descpb.DescriptorMutation_ADD
Expand Down
66 changes: 49 additions & 17 deletions pkg/sql/descriptor_mutation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -529,8 +529,11 @@ CREATE TABLE t.test (k CHAR PRIMARY KEY, v CHAR, INDEX foo (v));
indexQuery := `SELECT v FROM t.test@foo`
for _, useUpsert := range []bool{true, false} {
// See the effect of the operations depending on the state.
for _, state := range []descpb.DescriptorMutation_State{descpb.DescriptorMutation_DELETE_ONLY,
descpb.DescriptorMutation_DELETE_AND_WRITE_ONLY} {
for _, state := range []descpb.DescriptorMutation_State{
descpb.DescriptorMutation_DELETE_ONLY,
descpb.DescriptorMutation_DELETE_AND_WRITE_ONLY,
descpb.DescriptorMutation_BACKFILLING,
} {
// Init table with some entries.
if _, err := sqlDB.Exec(`TRUNCATE TABLE t.test`); err != nil {
t.Fatal(err)
Expand Down Expand Up @@ -573,12 +576,14 @@ CREATE TABLE t.test (k CHAR PRIMARY KEY, v CHAR, INDEX foo (v));

// Make index "foo" live so that we can read it.
mTest.makeMutationsActive(ctx)
if state == descpb.DescriptorMutation_DELETE_ONLY {
switch state {
case descpb.DescriptorMutation_DELETE_ONLY, descpb.DescriptorMutation_BACKFILLING:
// "x" didn't get added to the index.
mTest.CheckQueryResults(t, indexQuery, [][]string{{"y"}, {"z"}})
} else {
default:
// "x" got added to the index.
mTest.CheckQueryResults(t, indexQuery, [][]string{{"x"}, {"y"}, {"z"}})

}

// Make "foo" a mutation.
Expand All @@ -597,11 +602,15 @@ CREATE TABLE t.test (k CHAR PRIMARY KEY, v CHAR, INDEX foo (v));

// Make index "foo" live so that we can read it.
mTest.makeMutationsActive(ctx)
if state == descpb.DescriptorMutation_DELETE_ONLY {
switch state {
case descpb.DescriptorMutation_BACKFILLING:
// Update results in no modifications to index.
mTest.CheckQueryResults(t, indexQuery, [][]string{{"y"}, {"z"}})
case descpb.DescriptorMutation_DELETE_ONLY:
// updating "x" -> "w" will result in "x" being deleted from the index.
// updating "z" -> "z" results in "z" being deleted from the index.
mTest.CheckQueryResults(t, indexQuery, [][]string{{"y"}})
} else {
default:
// updating "x" -> "w" results in the index updating from "x" -> "w",
// updating "z" -> "z" is a noop on the index.
mTest.CheckQueryResults(t, indexQuery, [][]string{{"w"}, {"y"}, {"z"}})
Expand All @@ -618,9 +627,13 @@ CREATE TABLE t.test (k CHAR PRIMARY KEY, v CHAR, INDEX foo (v));
// Updating the primary key for a row when we're in delete-only won't
// create a new index entry, and will delete the old one. Otherwise it'll
// create a new entry and delete the old one.
if state == descpb.DescriptorMutation_DELETE_ONLY {
switch state {
case descpb.DescriptorMutation_BACKFILLING:
// Update results in no modifications to index.
mTest.CheckQueryResults(t, indexQuery, [][]string{{"y"}, {"z"}})
case descpb.DescriptorMutation_DELETE_ONLY:
mTest.CheckQueryResults(t, indexQuery, [][]string{{"y"}})
} else {
default:
mTest.CheckQueryResults(t, indexQuery, [][]string{{"w"}, {"y"}, {"z"}})
}

Expand All @@ -633,9 +646,13 @@ CREATE TABLE t.test (k CHAR PRIMARY KEY, v CHAR, INDEX foo (v));
// Make index "foo" live so that we can read it.
mTest.makeMutationsActive(ctx)
// Deleting row "b" deletes "y" from the index.
if state == descpb.DescriptorMutation_DELETE_ONLY {
switch state {
case descpb.DescriptorMutation_BACKFILLING:
// Update results in no modifications to index.
mTest.CheckQueryResults(t, indexQuery, [][]string{{"y"}, {"z"}})
case descpb.DescriptorMutation_DELETE_ONLY:
mTest.CheckQueryResults(t, indexQuery, [][]string{})
} else {
default:
mTest.CheckQueryResults(t, indexQuery, [][]string{{"w"}, {"z"}})
}
}
Expand Down Expand Up @@ -698,6 +715,7 @@ CREATE INDEX allidx ON t.test (k, v);
for _, idxState := range []descpb.DescriptorMutation_State{
descpb.DescriptorMutation_DELETE_ONLY,
descpb.DescriptorMutation_DELETE_AND_WRITE_ONLY,
descpb.DescriptorMutation_BACKFILLING,
} {
// Ignore the impossible column in DELETE_ONLY state while index
// is in the DELETE_AND_WRITE_ONLY state.
Expand Down Expand Up @@ -748,10 +766,14 @@ CREATE INDEX allidx ON t.test (k, v);
mTest.makeMutationsActive(ctx)
// column "i" has no entry.
mTest.CheckQueryResults(t, starQuery, [][]string{{"a", "z", "q"}, {"b", "y", "r"}, {"c", "x", "NULL"}})
if idxState == descpb.DescriptorMutation_DELETE_ONLY {
switch idxState {
case descpb.DescriptorMutation_DELETE_ONLY:
// No index entry for row "c"
mTest.CheckQueryResults(t, indexQuery, [][]string{{"q"}, {"r"}})
} else {
case descpb.DescriptorMutation_BACKFILLING:
// No index modification
mTest.CheckQueryResults(t, indexQuery, [][]string{{"q"}, {"r"}})
default:
// Index entry for row "c"
mTest.CheckQueryResults(t, indexQuery, [][]string{{"NULL"}, {"q"}, {"r"}})
}
Expand Down Expand Up @@ -809,10 +831,14 @@ CREATE INDEX allidx ON t.test (k, v);
mTest.CheckQueryResults(t, starQuery, [][]string{{"a", "u", "NULL"}, {"b", "y", "r"}, {"c", "x", "NULL"}})
}

if idxState == descpb.DescriptorMutation_DELETE_ONLY {
switch idxState {
case descpb.DescriptorMutation_DELETE_ONLY:
// Index entry for row "a" is deleted.
mTest.CheckQueryResults(t, indexQuery, [][]string{{"r"}})
} else {
case descpb.DescriptorMutation_BACKFILLING:
// No index modification
mTest.CheckQueryResults(t, indexQuery, [][]string{{"q"}, {"r"}})
default:
// Index "foo" has NULL "i" value for row "a".
mTest.CheckQueryResults(t, indexQuery, [][]string{{"NULL"}, {"NULL"}, {"r"}})
}
Expand Down Expand Up @@ -841,10 +867,15 @@ CREATE INDEX allidx ON t.test (k, v);
numKVs++
}

if idxState == descpb.DescriptorMutation_DELETE_ONLY {
switch idxState {
case descpb.DescriptorMutation_DELETE_ONLY:
// Index entry for row "a" is deleted.
mTest.CheckQueryResults(t, indexQuery, [][]string{})
} else {
// No index modification
case descpb.DescriptorMutation_BACKFILLING:
mTest.CheckQueryResults(t, indexQuery, [][]string{{"q"}, {"r"}})
numKVs += 2
default:
// Index entry for row "a" is deleted.
if state == descpb.DescriptorMutation_DELETE_ONLY {
mTest.CheckQueryResults(t, indexQuery, [][]string{{"NULL"}, {"q"}})
Expand All @@ -854,7 +885,6 @@ CREATE INDEX allidx ON t.test (k, v);
// We have two index values.
numKVs += 2
}

// Check that there are no hidden KV values for row "b", and column
// "i" for row "b" was deleted. Also check that the index values are
// all accounted for.
Expand Down Expand Up @@ -1181,6 +1211,8 @@ CREATE TABLE t.test (k CHAR PRIMARY KEY, v CHAR UNIQUE);
actualState = descpb.DescriptorMutation_DELETE_AND_WRITE_ONLY
} else if m.DeleteOnly() {
actualState = descpb.DescriptorMutation_DELETE_ONLY
} else if m.Backfilling() {
actualState = descpb.DescriptorMutation_BACKFILLING
}
if state := expected[i].state; actualState != state {
t.Errorf("%d entry: state %s, expected %s", i, actualState, state)
Expand Down
2 changes: 1 addition & 1 deletion pkg/sql/opt_catalog.go
Original file line number Diff line number Diff line change
Expand Up @@ -1062,7 +1062,7 @@ func (ot *optTable) WritableIndexCount() int {
// DeletableIndexCount is part of the cat.Table interface.
func (ot *optTable) DeletableIndexCount() int {
// Primary index is always present, so count is always >= 1.
return len(ot.desc.AllIndexes())
return len(ot.desc.DeletableNonPrimaryIndexes()) + 1
}

// Index is part of the cat.Table interface.
Expand Down

0 comments on commit 02d5d80

Please sign in to comment.