Skip to content

Commit

Permalink
sql: add ForcePut option to indexes
Browse files Browse the repository at this point in the history
This PR adds ForcePut mode to indexes in which all writes are handled
via Put, even in cases where they would typically used CPut or
InitPut.

This change is in support of the mvcc-compatible index backfiller.

As part of the backfill process, newly added indexes will be added in
a BACKFILLING state in which they see no writes or deletes.

However, this would allow for the following sequence of events:

    t0: `CREATE INDEX` creates "new index" in BACKFILLING state
    t1: `INSERT INTO` with a = 1 (new index does not see this write)
    t2: Backfill starts at t1 (a=1 included in backfill, ends up in "new index")
    t3: UPDATE a = 2 where a = 1 (new index still in backfilling does not see these writes)
    t4: Backfilling completes
    t5: "new index" to DELETE-ONLY
    t6: "new index" to DELETE-AND-WRITE-ONLY
    t7: `INSERT INTO` into with a = 1

At t7, the user would encounter an erroneous duplicate key violation
when they attempt their insert because the attempted CPut into "new
index" would fail as there is an existing value (a=1).

The ForcePut mode solves this case.

While use of this option would be unsafe in general because it allows
for writes that violate the unique constraint on the index. However,
when used as part of the index backfilling process it should be safe
because indexes are checked for uniqueness before being made public.

The tests added here are nearly identical to the tests added for
DeletePreservingEncoding.

Release note: None
  • Loading branch information
stevendanna committed Jan 29, 2022
1 parent 4a73be0 commit 50e05a9
Show file tree
Hide file tree
Showing 10 changed files with 416 additions and 26 deletions.
12 changes: 6 additions & 6 deletions pkg/cli/testdata/doctor/test_recreate_zipdir

Large diffs are not rendered by default.

7 changes: 7 additions & 0 deletions pkg/sql/catalog/descpb/structured.proto
Original file line number Diff line number Diff line change
Expand Up @@ -512,6 +512,13 @@ message IndexDescriptor {
// index backfiller
// docs/RFCS/20211004_incremental_index_backfiller.md#new-index-encoding-for-deletions-vs-mvcc
optional bool use_delete_preserving_encoding = 24 [(gogoproto.nullable) = false];

// ForcePut, if true, forces all writes to the the index to
// use Put (rather than CPut or InitPut).
//
// This is used by the MVCC-compatible index backfiller to ensure
// that unique indexes do not produce erroneous conflicts.
optional bool force_put = 25 [(gogoproto.nullable) = false];
}

// ConstraintToUpdate represents a constraint to be added to the table and
Expand Down
18 changes: 18 additions & 0 deletions pkg/sql/catalog/table_elements.go
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,24 @@ type Index interface {
NumCompositeColumns() int
GetCompositeColumnID(compositeColumnOrdinal int) descpb.ColumnID
UseDeletePreservingEncoding() bool
// ForcePut, if true, forces all writes to use Put rather than CPut or InitPut.
//
// Users of this options should take great care as it
// effectively mean unique constraints are not respected.
//
// Currently (2022-01-19) this two users: delete preserving
// indexes and backfilling indexes.
//
// Delete preserving encoding indexes are used only as a log of
// index writes during backfill, thus we can blindly put values into
// them.
//
// Indexes in the backfilling state will be checked for uniqueness
// at the end of the backfilling process and may miss updates during
// the backfilling process that would lead to CPut failures until
// the missed updates are merged into the index. Uniqueness for such indexes
// is checked by the schema changer before they are brought back online.
ForcePut() bool
}

// Column is an interface around the column descriptor types.
Expand Down
7 changes: 7 additions & 0 deletions pkg/sql/catalog/tabledesc/index.go
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,13 @@ func (w index) UseDeletePreservingEncoding() bool {
return w.desc.UseDeletePreservingEncoding
}

// ForcePut returns true if writes to the index should only use Put
// (rather than CPut or InitPut). This is used by indexes currently
// being backfilled by the MVCC-compliant index backfiller.
func (w index) ForcePut() bool {
return w.desc.ForcePut || w.desc.UseDeletePreservingEncoding
}

// partitioning is the backing struct for a catalog.Partitioning interface.
type partitioning struct {
desc *descpb.PartitioningDescriptor
Expand Down
1 change: 1 addition & 0 deletions pkg/sql/catalog/tabledesc/validate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,7 @@ var validationMap = []struct {
"GeoConfig": {status: thisFieldReferencesNoObjects},
"Predicate": {status: iSolemnlySwearThisFieldIsValidated},
"UseDeletePreservingEncoding": {status: thisFieldReferencesNoObjects},
"ForcePut": {status: thisFieldReferencesNoObjects},
},
},
{
Expand Down
61 changes: 61 additions & 0 deletions pkg/sql/opt/exec/execbuilder/testdata/force_put_index
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# LogicTest: local !metamorphic

# ---------------------------------------------------------
# Ensure ForcePut indexes forces Puts even on unique indexes.
# ---------------------------------------------------------
statement ok
CREATE TABLE ti (
a INT PRIMARY KEY,
b INT,
FAMILY (a, b),
UNIQUE INDEX (b)
);

let $t_id
SELECT id FROM system.namespace WHERE name = 'ti'

let $updated_t_jsonb
WITH
descs
AS (
SELECT
id,
crdb_internal.pb_to_json(
'cockroach.sql.sqlbase.Descriptor',
descriptor
)
AS descriptor
FROM
system.descriptor
)
SELECT
CAST (json_set(descriptor, ARRAY['table', 'indexes', '0', 'forcePut'], 'true') AS STRING)
FROM
descs WHERE id = $t_id;

statement ok
SELECT * FROM crdb_internal.unsafe_upsert_descriptor($t_id, crdb_internal.json_to_pb('cockroach.sql.sqlbase.Descriptor',$$ $updated_t_jsonb $$), true)

statement ok
INSERT INTO ti VALUES (1, 1), (2, 2)

# Test that it's okay to insert into the unique
# force put index.
query T kvtrace
INSERT INTO ti VALUES (3, 1)
----
CPut /Table/56/1/3/0 -> /TUPLE/2:2:Int/1
Put /Table/56/2/1/0 -> /BYTES/0x8b

# Test that Put's triggered but update that should fail, continue to
# work.
statement ok
INSERT INTO ti VALUES (4, 4)

query T kvtrace
UPDATE ti SET b = 2 WHERE a = 4
----
Scan /Table/56/1/4/0
Put /Table/56/1/4/0 -> /TUPLE/2:2:Int/2
Del /Table/56/2/4/0
Put /Table/56/2/2/0 -> /BYTES/0x8c
12 changes: 6 additions & 6 deletions pkg/sql/opt/exec/execbuilder/testdata/show_trace_nonmetamorphic

Large diffs are not rendered by default.

Loading

0 comments on commit 50e05a9

Please sign in to comment.