forked from cockroachdb/cockroach
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
storage: handle range keys in readAsOfIterator
Previously, the readAsOfIterator used in RESTORE could not handle range keys. This PR implements the new SimpleMVCCIterator methods that handle range keys. Further, this patch ensures the readAsOfIterator skips over point keys shadowed by range keys at or below the caller's specified asOf timestamp. Next, Backup needs to be tought about RangeKeys. Informs cockroachdb#71155 Release note: none
- Loading branch information
Showing
3 changed files
with
267 additions
and
24 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
168 changes: 168 additions & 0 deletions
168
pkg/storage/testdata/mvcc_histories/range_key_iter_read_as_of
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,168 @@ | ||
# Tests range key handling in ReadAsOfIterator. Note that the iterator assumes it will not see an | ||
# intent. | ||
# | ||
# Sets up the following dataset, where x is tombstone, o-o is range tombstone | ||
# | ||
# 6 f6 | ||
# 5 o---------------o k5 | ||
# 4 x x d4 f4 g4 x | ||
# 3 o-------o e3 o-------oh3 o---o | ||
# 2 a2 f2 g2 | ||
# 1 o---------------------------------------o | ||
# a b c d e f g h i j k l m n o | ||
# | ||
run ok | ||
put_rangekey k=a end=k ts=1 | ||
put k=a ts=2 v=a2 | ||
del k=a ts=4 | ||
put_rangekey k=b end=d ts=3 | ||
del k=b ts=4 | ||
put k=d ts=4 v=d4 | ||
put k=e ts=3 v=e3 | ||
put k=f ts=2 v=f2 | ||
put k=g ts=2 v=g2 | ||
put_rangekey k=f end=h ts=3 | ||
put k=f ts=4 v=f4 | ||
put_rangekey k=c end=g ts=5 | ||
put k=f ts=6 v=f6 | ||
put k=g ts=4 v=g4 | ||
put k=h ts=3 v=h3 | ||
del k=h ts=4 | ||
put k=k ts=5 v=k5 | ||
put_rangekey k=m end=n ts=3 localTs=2 | ||
---- | ||
>> at end: | ||
rangekey: {a-b}/[1.000000000,0=/<empty>] | ||
rangekey: {b-c}/[3.000000000,0=/<empty> 1.000000000,0=/<empty>] | ||
rangekey: {c-d}/[5.000000000,0=/<empty> 3.000000000,0=/<empty> 1.000000000,0=/<empty>] | ||
rangekey: {d-f}/[5.000000000,0=/<empty> 1.000000000,0=/<empty>] | ||
rangekey: {f-g}/[5.000000000,0=/<empty> 3.000000000,0=/<empty> 1.000000000,0=/<empty>] | ||
rangekey: {g-h}/[3.000000000,0=/<empty> 1.000000000,0=/<empty>] | ||
rangekey: {h-k}/[1.000000000,0=/<empty>] | ||
rangekey: {m-n}/[3.000000000,0={localTs=2.000000000,0}/<empty>] | ||
data: "a"/4.000000000,0 -> /<empty> | ||
data: "a"/2.000000000,0 -> /BYTES/a2 | ||
data: "b"/4.000000000,0 -> /<empty> | ||
data: "d"/4.000000000,0 -> /BYTES/d4 | ||
data: "e"/3.000000000,0 -> /BYTES/e3 | ||
data: "f"/6.000000000,0 -> /BYTES/f6 | ||
data: "f"/4.000000000,0 -> /BYTES/f4 | ||
data: "f"/2.000000000,0 -> /BYTES/f2 | ||
data: "g"/4.000000000,0 -> /BYTES/g4 | ||
data: "g"/2.000000000,0 -> /BYTES/g2 | ||
data: "h"/4.000000000,0 -> /<empty> | ||
data: "h"/3.000000000,0 -> /BYTES/h3 | ||
data: "k"/5.000000000,0 -> /BYTES/k5 | ||
|
||
# test range keys are ignored if above asOf, even with multiple range keys | ||
run ok | ||
iter_new_read_as_of asOfTs=2 | ||
iter_seek_ge k=a | ||
iter_scan | ||
---- | ||
iter_seek_ge: "a"/2.000000000,0=/BYTES/a2 | ||
iter_scan: "a"/2.000000000,0=/BYTES/a2 | ||
iter_scan: "f"/2.000000000,0=/BYTES/f2 | ||
iter_scan: "g"/2.000000000,0=/BYTES/g2 | ||
iter_scan: . | ||
|
||
# test range key at or below asOf properly shadows keys | ||
run ok | ||
iter_new_read_as_of asOfTs=3 | ||
iter_seek_ge k=a | ||
iter_scan | ||
---- | ||
iter_seek_ge: "a"/2.000000000,0=/BYTES/a2 | ||
iter_scan: "a"/2.000000000,0=/BYTES/a2 | ||
iter_scan: "e"/3.000000000,0=/BYTES/e3 | ||
iter_scan: "h"/3.000000000,0=/BYTES/h3 | ||
iter_scan: . | ||
|
||
# iterate over a few point tombstones at the asOf time | ||
run ok | ||
iter_new_read_as_of asOfTs=4 | ||
iter_seek_ge k=a | ||
iter_scan | ||
---- | ||
iter_seek_ge: "d"/4.000000000,0=/BYTES/d4 | ||
iter_scan: "d"/4.000000000,0=/BYTES/d4 | ||
iter_scan: "e"/3.000000000,0=/BYTES/e3 | ||
iter_scan: "f"/4.000000000,0=/BYTES/f4 | ||
iter_scan: "g"/4.000000000,0=/BYTES/g4 | ||
iter_scan: . | ||
|
||
# iterate over ts 5-7 because the test is cheap | ||
run ok | ||
iter_new_read_as_of asOfTs=5 | ||
iter_seek_ge k=a | ||
iter_scan | ||
---- | ||
iter_seek_ge: "g"/4.000000000,0=/BYTES/g4 | ||
iter_scan: "g"/4.000000000,0=/BYTES/g4 | ||
iter_scan: "k"/5.000000000,0=/BYTES/k5 | ||
iter_scan: . | ||
|
||
# iterate over ts 5-7 because the test is cheap | ||
run ok | ||
iter_new_read_as_of asOfTs=6 | ||
iter_seek_ge k=a | ||
iter_scan | ||
---- | ||
iter_seek_ge: "f"/6.000000000,0=/BYTES/f6 | ||
iter_scan: "f"/6.000000000,0=/BYTES/f6 | ||
iter_scan: "g"/4.000000000,0=/BYTES/g4 | ||
iter_scan: "k"/5.000000000,0=/BYTES/k5 | ||
iter_scan: . | ||
|
||
# iterate over ts 5-7 for completeness | ||
run ok | ||
iter_new_read_as_of asOfTs=7 | ||
iter_seek_ge k=a | ||
iter_scan | ||
---- | ||
iter_seek_ge: "f"/6.000000000,0=/BYTES/f6 | ||
iter_scan: "f"/6.000000000,0=/BYTES/f6 | ||
iter_scan: "g"/4.000000000,0=/BYTES/g4 | ||
iter_scan: "k"/5.000000000,0=/BYTES/k5 | ||
iter_scan: . | ||
|
||
|
||
# test range key handling when asOf is empty | ||
run ok | ||
iter_new_read_as_of | ||
iter_seek_ge k=a | ||
iter_scan | ||
---- | ||
iter_seek_ge: "f"/6.000000000,0=/BYTES/f6 | ||
iter_scan: "f"/6.000000000,0=/BYTES/f6 | ||
iter_scan: "g"/4.000000000,0=/BYTES/g4 | ||
iter_scan: "k"/5.000000000,0=/BYTES/k5 | ||
iter_scan: . | ||
|
||
# seek to a point key shadowed by a range key | ||
run ok | ||
iter_new_read_as_of asOfTs=5 | ||
iter_seek_ge k=d | ||
---- | ||
iter_seek_ge: "g"/4.000000000,0=/BYTES/g4 | ||
|
||
# seek to the start of a range key | ||
run ok | ||
iter_new_read_as_of asOfTs=5 | ||
iter_seek_ge k=c | ||
---- | ||
iter_seek_ge: "g"/4.000000000,0=/BYTES/g4 | ||
|
||
# seek to the same point key, with AsOf empty | ||
run ok | ||
iter_new_read_as_of | ||
iter_seek_ge k=d | ||
---- | ||
iter_seek_ge: "f"/6.000000000,0=/BYTES/f6 | ||
|
||
# attempt seek to the same point key, but ignore the range key because its above AsOf | ||
run ok | ||
iter_new_read_as_of asOfTs=4 | ||
iter_seek_ge k=d | ||
---- | ||
iter_seek_ge: "d"/4.000000000,0=/BYTES/d4 |