From ec8e63caed508a40d92a3a9d750f4ce022f908b1 Mon Sep 17 00:00:00 2001 From: Marcus Gartner Date: Tue, 7 Jun 2022 16:48:18 -0400 Subject: [PATCH 1/3] opt: fix inverted key column type in testcat Previously, inverted key columns in the test catalog were incorrectly given the type of their source column. Now they have the correct type, `types.EncodedKey`. Release note: None --- pkg/sql/catalog/tabledesc/index.go | 2 +- .../opt/memo/testdata/stats/inverted-array | 10 ++-- pkg/sql/opt/memo/testdata/stats/inverted-geo | 8 +-- .../testdata/stats/inverted-geo-multi-column | 12 ++--- pkg/sql/opt/memo/testdata/stats/inverted-json | 52 +++++++++---------- .../memo/testdata/stats/partial-index-scan | 16 +++--- pkg/sql/opt/memo/testdata/stats/scan | 2 +- .../opt/optbuilder/testdata/inverted-indexes | 4 +- pkg/sql/opt/testutils/testcat/create_table.go | 19 ++++--- pkg/sql/opt/testutils/testcat/testdata/index | 20 +++---- pkg/sql/opt/testutils/testcat/testdata/table | 16 +++--- pkg/sql/opt_catalog.go | 4 +- 12 files changed, 81 insertions(+), 84 deletions(-) diff --git a/pkg/sql/catalog/tabledesc/index.go b/pkg/sql/catalog/tabledesc/index.go index 88863192f447..f8287f8e9f37 100644 --- a/pkg/sql/catalog/tabledesc/index.go +++ b/pkg/sql/catalog/tabledesc/index.go @@ -170,7 +170,7 @@ func (w index) InvertedColumnName() string { } // InvertedColumnKeyType returns the type of the data element that is encoded -// as the inverted index key. This is currently always Bytes. +// as the inverted index key. This is currently always EncodedKey. // // Panics if the index is not inverted. func (w index) InvertedColumnKeyType() *types.T { diff --git a/pkg/sql/opt/memo/testdata/stats/inverted-array b/pkg/sql/opt/memo/testdata/stats/inverted-array index f8e6e144cf76..840bec2d5b89 100644 --- a/pkg/sql/opt/memo/testdata/stats/inverted-array +++ b/pkg/sql/opt/memo/testdata/stats/inverted-array @@ -72,7 +72,7 @@ index-join t ├── stats: [rows=1020] ├── key: (1) └── scan t@a_idx - ├── columns: k:1(int!null) a_inverted_key:5(int[]!null) + ├── columns: k:1(int!null) a_inverted_key:5(encodedkey!null) ├── inverted constraint: /5/1 │ └── spans: ["", ""] ├── flags: force-index=a_idx @@ -120,7 +120,7 @@ index-join t ├── stats: [rows=20] ├── key: (1) └── scan t@a_idx - ├── columns: k:1(int!null) a_inverted_key:5(int[]!null) + ├── columns: k:1(int!null) a_inverted_key:5(encodedkey!null) ├── inverted constraint: /5/1 │ └── spans: ["\x8a", "\x8c") ├── stats: [rows=20, distinct(1)=19.6078, null(1)=0, avgsize(1)=4, distinct(5)=2, null(5)=0, avgsize(5)=4] @@ -183,7 +183,7 @@ select │ ├── stats: [rows=20] │ ├── key: (1) │ └── scan t@a_idx - │ ├── columns: k:1(int!null) a_inverted_key:5(int[]!null) + │ ├── columns: k:1(int!null) a_inverted_key:5(encodedkey!null) │ ├── inverted constraint: /5/1 │ │ └── spans │ │ ├── ["C", "C"] @@ -222,7 +222,7 @@ select │ ├── stats: [rows=30] │ ├── key: (1) │ └── scan t@a_idx - │ ├── columns: k:1(int!null) a_inverted_key:5(int[]!null) + │ ├── columns: k:1(int!null) a_inverted_key:5(encodedkey!null) │ ├── inverted constraint: /5/1 │ │ └── spans │ │ ├── ["C", "C"] @@ -267,7 +267,7 @@ select │ ├── stats: [rows=30] │ ├── key: (1) │ └── scan t@a_idx - │ ├── columns: k:1(int!null) a_inverted_key:5(int[]!null) + │ ├── columns: k:1(int!null) a_inverted_key:5(encodedkey!null) │ ├── inverted constraint: /5/1 │ │ └── spans │ │ ├── ["C", "C"] diff --git a/pkg/sql/opt/memo/testdata/stats/inverted-geo b/pkg/sql/opt/memo/testdata/stats/inverted-geo index c77cc75b9d22..d65b8aee74ef 100644 --- a/pkg/sql/opt/memo/testdata/stats/inverted-geo +++ b/pkg/sql/opt/memo/testdata/stats/inverted-geo @@ -181,7 +181,7 @@ project │ │ ├── stats: [rows=1.4e-06] │ │ ├── key: (3) │ │ └── scan t@t_g_idx - │ │ ├── columns: rowid:3(int!null) g_inverted_key:6(geometry!null) + │ │ ├── columns: rowid:3(int!null) g_inverted_key:6(encodedkey!null) │ │ ├── inverted constraint: /6/3 │ │ │ └── spans: ["B\xfd\xff\xff\xff\xff\xff\xff\xff\xff", "B\xfd\xff\xff\xff\xff\xff\xff\xff\xff"] │ │ ├── stats: [rows=1.4e-06, distinct(3)=4e-07, null(3)=0, avgsize(3)=4, distinct(6)=1.4e-06, null(6)=0, avgsize(6)=4] @@ -401,7 +401,7 @@ project │ │ ├── stats: [rows=1.42e-06] │ │ ├── key: (3) │ │ └── scan t@t_g_idx - │ │ ├── columns: rowid:3(int!null) g_inverted_key:6(geometry!null) + │ │ ├── columns: rowid:3(int!null) g_inverted_key:6(encodedkey!null) │ │ ├── inverted constraint: /6/3 │ │ │ └── spans: ["B\xfd\xff\xff\xff\xff\xff\xff\xff\xff", "B\xfd\xff\xff\xff\xff\xff\xff\xff\xff"] │ │ ├── stats: [rows=1.42e-06, distinct(3)=4e-07, null(3)=0, avgsize(3)=4, distinct(6)=1.42e-06, null(6)=0, avgsize(6)=4] @@ -480,7 +480,7 @@ select │ ├── stats: [rows=100] │ ├── key: (3) │ └── scan t@t_g_idx - │ ├── columns: rowid:3(int!null) g_inverted_key:6(geometry!null) + │ ├── columns: rowid:3(int!null) g_inverted_key:6(encodedkey!null) │ ├── inverted constraint: /6/3 │ │ └── spans │ │ ├── ["B\xfd\x10\x00\x00\x00\x00\x00\x00\x00", "B\xfd\x10\x00\x00\x00\x00\x00\x00\x00"] @@ -522,7 +522,7 @@ project │ ├── stats: [rows=100] │ ├── key: (3) │ └── scan t@t_g_idx - │ ├── columns: rowid:3(int!null) g_inverted_key:6(geometry!null) + │ ├── columns: rowid:3(int!null) g_inverted_key:6(encodedkey!null) │ ├── inverted constraint: /6/3 │ │ └── spans │ │ ├── ["B\xfd\x10\x00\x00\x00\x00\x00\x00\x00", "B\xfd\x10\x00\x00\x00\x00\x00\x00\x00"] diff --git a/pkg/sql/opt/memo/testdata/stats/inverted-geo-multi-column b/pkg/sql/opt/memo/testdata/stats/inverted-geo-multi-column index 74fb44c21fa1..4da3ab18a238 100644 --- a/pkg/sql/opt/memo/testdata/stats/inverted-geo-multi-column +++ b/pkg/sql/opt/memo/testdata/stats/inverted-geo-multi-column @@ -99,7 +99,7 @@ project │ ├── stats: [rows=60.78475] │ ├── key: (1) │ └── scan t@m - │ ├── columns: k:1(int!null) g_inverted_key:7(geometry!null) + │ ├── columns: k:1(int!null) g_inverted_key:7(encodedkey!null) │ ├── constraint: /3: [/'banana' - /'banana'] │ ├── inverted constraint: /7/1 │ │ └── spans @@ -151,7 +151,7 @@ project │ ├── stats: [rows=60.78475] │ ├── key: (1) │ └── scan t@p,partial - │ ├── columns: k:1(int!null) g_inverted_key:8(geometry!null) + │ ├── columns: k:1(int!null) g_inverted_key:8(encodedkey!null) │ ├── inverted constraint: /8/1 │ │ └── spans │ │ ├── ["B\xfd\x10\x00\x00\x00\x00\x00\x00\x00", "B\xfd\x10\x00\x00\x00\x00\x00\x00\x00"] @@ -214,7 +214,7 @@ project │ ├── stats: [rows=121.5695] │ ├── key: (1) │ └── scan t@m - │ ├── columns: k:1(int!null) g_inverted_key:7(geometry!null) + │ ├── columns: k:1(int!null) g_inverted_key:7(encodedkey!null) │ ├── constraint: /3 │ │ ├── [/'apple' - /'apple'] │ │ ├── [/'banana' - /'banana'] @@ -269,7 +269,7 @@ project │ ├── stats: [rows=121.5695] │ ├── key: (1) │ └── scan t@p,partial - │ ├── columns: k:1(int!null) g_inverted_key:9(geometry!null) + │ ├── columns: k:1(int!null) g_inverted_key:9(encodedkey!null) │ ├── inverted constraint: /9/1 │ │ └── spans │ │ ├── ["B\xfd\x10\x00\x00\x00\x00\x00\x00\x00", "B\xfd\x10\x00\x00\x00\x00\x00\x00\x00"] @@ -332,7 +332,7 @@ project │ ├── stats: [rows=5.512417] │ ├── key: (1) │ └── scan t@mp,partial - │ ├── columns: k:1(int!null) g_inverted_key:10(geometry!null) + │ ├── columns: k:1(int!null) g_inverted_key:10(encodedkey!null) │ ├── constraint: /4: [/400 - /400] │ ├── inverted constraint: /10/1 │ │ └── spans @@ -388,7 +388,7 @@ project │ ├── stats: [rows=14.82863] │ ├── key: (1) │ └── scan t@mp,partial - │ ├── columns: k:1(int!null) g_inverted_key:10(geometry!null) + │ ├── columns: k:1(int!null) g_inverted_key:10(encodedkey!null) │ ├── constraint: /4 │ │ ├── [/200 - /200] │ │ ├── [/300 - /300] diff --git a/pkg/sql/opt/memo/testdata/stats/inverted-json b/pkg/sql/opt/memo/testdata/stats/inverted-json index f79985c68820..c9c0a45e0006 100644 --- a/pkg/sql/opt/memo/testdata/stats/inverted-json +++ b/pkg/sql/opt/memo/testdata/stats/inverted-json @@ -100,7 +100,7 @@ index-join t ├── stats: [rows=1110] ├── key: (1) └── scan t@j_idx - ├── columns: k:1(int!null) j_inverted_key:5(jsonb!null) + ├── columns: k:1(int!null) j_inverted_key:5(encodedkey!null) ├── inverted constraint: /5/1 │ └── spans │ ├── ["7\x00\x019", "7\x00\x019"] @@ -172,7 +172,7 @@ index-join t ├── stats: [rows=110] ├── key: (1) └── scan t@j_idx - ├── columns: k:1(int!null) j_inverted_key:5(jsonb!null) + ├── columns: k:1(int!null) j_inverted_key:5(encodedkey!null) ├── inverted constraint: /5/1 │ └── spans │ ├── ["7c\x00\x01\x12d\x00\x01", "7c\x00\x01\x12d\x00\x01"] @@ -203,7 +203,7 @@ index-join t ├── stats: [rows=1110] ├── key: (1) └── scan t@j_idx - ├── columns: k:1(int!null) j_inverted_key:5(jsonb!null) + ├── columns: k:1(int!null) j_inverted_key:5(encodedkey!null) ├── inverted constraint: /5/1 │ └── spans │ ├── ["7\x00\x018", "7\x00\x018"] @@ -255,7 +255,7 @@ index-join t ├── stats: [rows=110] ├── key: (1) └── scan t@j_idx - ├── columns: k:1(int!null) j_inverted_key:5(jsonb!null) + ├── columns: k:1(int!null) j_inverted_key:5(encodedkey!null) ├── inverted constraint: /5/1 │ └── spans │ ├── ["7\x00\x03\x00\x01*\x04\x00", "7\x00\x03\x00\x01*\x04\x00"] @@ -346,7 +346,7 @@ select │ ├── stats: [rows=110] │ ├── key: (1) │ └── scan t@j_idx - │ ├── columns: k:1(int!null) j_inverted_key:5(jsonb!null) + │ ├── columns: k:1(int!null) j_inverted_key:5(encodedkey!null) │ ├── inverted constraint: /5/1 │ │ └── spans │ │ ├── ["7\x00\x019", "7\x00\x019"] @@ -386,7 +386,7 @@ select │ ├── stats: [rows=120] │ ├── key: (1) │ └── scan t@j_idx - │ ├── columns: k:1(int!null) j_inverted_key:5(jsonb!null) + │ ├── columns: k:1(int!null) j_inverted_key:5(encodedkey!null) │ ├── inverted constraint: /5/1 │ │ └── spans │ │ ├── ["7\x00\x019", "7\x00\x019"] @@ -431,7 +431,7 @@ select │ ├── stats: [rows=120] │ ├── key: (1) │ └── scan t@j_idx - │ ├── columns: k:1(int!null) j_inverted_key:5(jsonb!null) + │ ├── columns: k:1(int!null) j_inverted_key:5(encodedkey!null) │ ├── inverted constraint: /5/1 │ │ └── spans │ │ ├── ["7\x00\x019", "7\x00\x019"] @@ -473,7 +473,7 @@ select │ ├── stats: [rows=110] │ ├── key: (1) │ └── scan t@j_idx - │ ├── columns: k:1(int!null) j_inverted_key:5(jsonb!null) + │ ├── columns: k:1(int!null) j_inverted_key:5(encodedkey!null) │ ├── inverted constraint: /5/1 │ │ └── spans │ │ ├── ["7\x00\x01*\x04\x00", "7\x00\x01*\x04\x00"] @@ -516,7 +516,7 @@ select │ ├── stats: [rows=120] │ ├── key: (1) │ └── scan t@j_idx - │ ├── columns: k:1(int!null) j_inverted_key:5(jsonb!null) + │ ├── columns: k:1(int!null) j_inverted_key:5(encodedkey!null) │ ├── inverted constraint: /5/1 │ │ └── spans │ │ ├── ["7\x00\x01*\x04\x00", "7\x00\x01*\x04\x00"] @@ -567,7 +567,7 @@ select │ ├── stats: [rows=120] │ ├── key: (1) │ └── scan t@j_idx - │ ├── columns: k:1(int!null) j_inverted_key:5(jsonb!null) + │ ├── columns: k:1(int!null) j_inverted_key:5(encodedkey!null) │ ├── inverted constraint: /5/1 │ │ └── spans │ │ ├── ["7\x00\x01*\x04\x00", "7\x00\x01*\x04\x00"] @@ -659,7 +659,7 @@ index-join t ├── stats: [rows=100] ├── key: (1) └── scan t@j_idx - ├── columns: k:1(int!null) j_inverted_key:5(jsonb!null) + ├── columns: k:1(int!null) j_inverted_key:5(encodedkey!null) ├── inverted constraint: /5/1 │ └── spans │ ├── ["7\x00\x019", "7\x00\x019"] @@ -691,7 +691,7 @@ index-join t ├── stats: [rows=100] ├── key: (1) └── scan t@j_idx - ├── columns: k:1(int!null) j_inverted_key:5(jsonb!null) + ├── columns: k:1(int!null) j_inverted_key:5(encodedkey!null) ├── inverted constraint: /5/1 │ └── spans │ ├── ["7\x00\x018", "7\x00\x018"] @@ -786,7 +786,7 @@ select │ ├── stats: [rows=4e-07] │ ├── key: (1) │ └── scan t@j_idx - │ ├── columns: k:1(int!null) j_inverted_key:5(jsonb!null) + │ ├── columns: k:1(int!null) j_inverted_key:5(encodedkey!null) │ ├── inverted constraint: /5/1 │ │ └── spans │ │ ├── ["7a\x00\x02b\x00\x01\x12c\x00\x01", "7a\x00\x02b\x00\x01\x12c\x00\x01"] @@ -843,7 +843,7 @@ select │ ├── stats: [rows=4e-07] │ ├── key: (1) │ └── scan t@j_idx - │ ├── columns: k:1(int!null) j_inverted_key:5(jsonb!null) + │ ├── columns: k:1(int!null) j_inverted_key:5(encodedkey!null) │ ├── inverted constraint: /5/1 │ │ └── spans │ │ ├── ["7a\x00\x02\x00\x03\x00\x01\x12b\x00\x01", "7a\x00\x02\x00\x03\x00\x01\x12b\x00\x01"] @@ -896,7 +896,7 @@ select │ ├── stats: [rows=4e-07] │ ├── key: (1) │ └── scan t@j_idx - │ ├── columns: k:1(int!null) j_inverted_key:5(jsonb!null) + │ ├── columns: k:1(int!null) j_inverted_key:5(encodedkey!null) │ ├── inverted constraint: /5/1 │ │ └── spans │ │ ├── ["7a\x00\x02b\x00\x02\x00\x03\x00\x01\x12c\x00\x01", "7a\x00\x02b\x00\x02\x00\x03\x00\x01\x12c\x00\x01"] @@ -935,7 +935,7 @@ select │ ├── stats: [rows=4e-07] │ ├── key: (1) │ └── scan t@j_idx - │ ├── columns: k:1(int!null) j_inverted_key:5(jsonb!null) + │ ├── columns: k:1(int!null) j_inverted_key:5(encodedkey!null) │ ├── inverted constraint: /5/1 │ │ └── spans │ │ ├── ["7a\x00\x018", "7a\x00\x018"] @@ -973,7 +973,7 @@ select │ ├── stats: [rows=4e-07] │ ├── key: (1) │ └── scan t@j_idx - │ ├── columns: k:1(int!null) j_inverted_key:5(jsonb!null) + │ ├── columns: k:1(int!null) j_inverted_key:5(encodedkey!null) │ ├── inverted constraint: /5/1 │ │ └── spans │ │ ├── ["7a\x00\x019", "7a\x00\x019"] @@ -1005,7 +1005,7 @@ index-join t ├── stats: [rows=4e-07] ├── key: (1) └── scan t@j_idx - ├── columns: k:1(int!null) j_inverted_key:5(jsonb!null) + ├── columns: k:1(int!null) j_inverted_key:5(encodedkey!null) ├── inverted constraint: /5/1 │ └── spans │ ├── ["7a\x00\x01*\x02\x00", "7a\x00\x01*\x02\x00"] @@ -1041,7 +1041,7 @@ select │ ├── stats: [rows=100] │ ├── key: (1) │ └── scan t@j_idx - │ ├── columns: k:1(int!null) j_inverted_key:5(jsonb!null) + │ ├── columns: k:1(int!null) j_inverted_key:5(encodedkey!null) │ ├── inverted constraint: /5/1 │ │ └── spans │ │ ├── ["7\x00\x019", "7\x00\x019"] @@ -1074,7 +1074,7 @@ index-join t ├── stats: [rows=4e-07] ├── key: (1) └── scan t@j_idx - ├── columns: k:1(int!null) j_inverted_key:5(jsonb!null) + ├── columns: k:1(int!null) j_inverted_key:5(encodedkey!null) ├── inverted constraint: /5/1 │ └── spans │ ├── ["7a\x00\x02b\x00\x01\x12c\x00\x01", "7a\x00\x02b\x00\x01\x12c\x00\x01"] @@ -1111,7 +1111,7 @@ select │ ├── stats: [rows=100] │ ├── key: (1) │ └── scan t@j_idx - │ ├── columns: k:1(int!null) j_inverted_key:5(jsonb!null) + │ ├── columns: k:1(int!null) j_inverted_key:5(encodedkey!null) │ ├── inverted constraint: /5/1 │ │ └── spans │ │ ├── ["7\x00\x019", "7\x00\x019"] @@ -1171,7 +1171,7 @@ select │ ├── stats: [rows=100] │ ├── key: (1) │ └── scan t@j_idx - │ ├── columns: k:1(int!null) j_inverted_key:5(jsonb!null) + │ ├── columns: k:1(int!null) j_inverted_key:5(encodedkey!null) │ ├── inverted constraint: /5/1 │ │ └── spans │ │ ├── ["7\x00\x019", "7\x00\x019"] @@ -1216,7 +1216,7 @@ select │ ├── stats: [rows=4e-07] │ ├── key: (1) │ └── scan t@j_idx - │ ├── columns: k:1(int!null) j_inverted_key:5(jsonb!null) + │ ├── columns: k:1(int!null) j_inverted_key:5(encodedkey!null) │ ├── inverted constraint: /5/1 │ │ └── spans │ │ ├── ["7a\x00\x02\x00\x03\x00\x01*\x02\x00", "7a\x00\x02\x00\x03\x00\x01*\x02\x00"] @@ -1258,7 +1258,7 @@ select │ ├── stats: [rows=100] │ ├── key: (1) │ └── scan t@j_idx - │ ├── columns: k:1(int!null) j_inverted_key:5(jsonb!null) + │ ├── columns: k:1(int!null) j_inverted_key:5(encodedkey!null) │ ├── inverted constraint: /5/1 │ │ └── spans │ │ ├── ["7\x00\x019", "7\x00\x019"] @@ -1296,7 +1296,7 @@ index-join t ├── stats: [rows=4e-07] ├── key: (1) └── scan t@j_idx - ├── columns: k:1(int!null) j_inverted_key:5(jsonb!null) + ├── columns: k:1(int!null) j_inverted_key:5(encodedkey!null) ├── inverted constraint: /5/1 │ └── spans │ ├── ["7a\x00\x02b\x00\x01\x12c\x00\x01", "7a\x00\x02b\x00\x01\x12c\x00\x01"] @@ -1337,7 +1337,7 @@ select │ ├── stats: [rows=100] │ ├── key: (1) │ └── scan t@j_idx - │ ├── columns: k:1(int!null) j_inverted_key:5(jsonb!null) + │ ├── columns: k:1(int!null) j_inverted_key:5(encodedkey!null) │ ├── inverted constraint: /5/1 │ │ └── spans │ │ ├── ["7\x00\x019", "7\x00\x019"] diff --git a/pkg/sql/opt/memo/testdata/stats/partial-index-scan b/pkg/sql/opt/memo/testdata/stats/partial-index-scan index 277d5e2a71e2..0f16a67005d7 100644 --- a/pkg/sql/opt/memo/testdata/stats/partial-index-scan +++ b/pkg/sql/opt/memo/testdata/stats/partial-index-scan @@ -1245,7 +1245,7 @@ project │ ├── stats: [rows=16.66667] │ ├── key: (1) │ └── scan spatial@p,partial - │ ├── columns: k:1(int!null) g_inverted_key:7(geometry!null) + │ ├── columns: k:1(int!null) g_inverted_key:7(encodedkey!null) │ ├── inverted constraint: /7/1 │ │ └── spans │ │ ├── ["B\xfd\x10\x00\x00\x00\x00\x00\x00\x00", "B\xfd\x10\x00\x00\x00\x00\x00\x00\x00"] @@ -1291,7 +1291,7 @@ project │ ├── stats: [rows=16.66667] │ ├── key: (1) │ └── scan spatial@p,partial - │ ├── columns: k:1(int!null) g_inverted_key:7(geometry!null) + │ ├── columns: k:1(int!null) g_inverted_key:7(encodedkey!null) │ ├── inverted constraint: /7/1 │ │ └── spans │ │ ├── ["B\xfd\x10\x00\x00\x00\x00\x00\x00\x00", "B\xfd\x10\x00\x00\x00\x00\x00\x00\x00"] @@ -1358,7 +1358,7 @@ project │ ├── stats: [rows=8.547009] │ ├── key: (1) │ └── scan spatial@p,partial - │ ├── columns: k:1(int!null) g_inverted_key:7(geometry!null) + │ ├── columns: k:1(int!null) g_inverted_key:7(encodedkey!null) │ ├── inverted constraint: /7/1 │ │ └── spans │ │ ├── ["B\xfd\x10\x00\x00\x00\x00\x00\x00\x00", "B\xfd\x10\x00\x00\x00\x00\x00\x00\x00"] @@ -1402,7 +1402,7 @@ project │ ├── stats: [rows=8.547009] │ ├── key: (1) │ └── scan spatial@p,partial - │ ├── columns: k:1(int!null) g_inverted_key:7(geometry!null) + │ ├── columns: k:1(int!null) g_inverted_key:7(encodedkey!null) │ ├── inverted constraint: /7/1 │ │ └── spans │ │ ├── ["B\xfd\x10\x00\x00\x00\x00\x00\x00\x00", "B\xfd\x10\x00\x00\x00\x00\x00\x00\x00"] @@ -1492,7 +1492,7 @@ project │ ├── stats: [rows=118.7568] │ ├── key: (1) │ └── scan spatial@p,partial - │ ├── columns: k:1(int!null) g_inverted_key:7(geometry!null) + │ ├── columns: k:1(int!null) g_inverted_key:7(encodedkey!null) │ ├── inverted constraint: /7/1 │ │ └── spans │ │ ├── ["B\xfd\x10\x00\x00\x00\x00\x00\x00\x00", "B\xfd\x10\x00\x00\x00\x00\x00\x00\x00"] @@ -1544,7 +1544,7 @@ project │ ├── stats: [rows=118.7568] │ ├── key: (1) │ └── scan spatial@p,partial - │ ├── columns: k:1(int!null) g_inverted_key:7(geometry!null) + │ ├── columns: k:1(int!null) g_inverted_key:7(encodedkey!null) │ ├── inverted constraint: /7/1 │ │ └── spans │ │ ├── ["B\xfd\x10\x00\x00\x00\x00\x00\x00\x00", "B\xfd\x10\x00\x00\x00\x00\x00\x00\x00"] @@ -1632,7 +1632,7 @@ project │ ├── stats: [rows=121.5695] │ ├── key: (1) │ └── scan spatial@p,partial - │ ├── columns: k:1(int!null) g_inverted_key:7(geometry!null) + │ ├── columns: k:1(int!null) g_inverted_key:7(encodedkey!null) │ ├── inverted constraint: /7/1 │ │ └── spans │ │ ├── ["B\xfd\x10\x00\x00\x00\x00\x00\x00\x00", "B\xfd\x10\x00\x00\x00\x00\x00\x00\x00"] @@ -1682,7 +1682,7 @@ project │ ├── stats: [rows=121.5695] │ ├── key: (1) │ └── scan spatial@p,partial - │ ├── columns: k:1(int!null) g_inverted_key:7(geometry!null) + │ ├── columns: k:1(int!null) g_inverted_key:7(encodedkey!null) │ ├── inverted constraint: /7/1 │ │ └── spans │ │ ├── ["B\xfd\x10\x00\x00\x00\x00\x00\x00\x00", "B\xfd\x10\x00\x00\x00\x00\x00\x00\x00"] diff --git a/pkg/sql/opt/memo/testdata/stats/scan b/pkg/sql/opt/memo/testdata/stats/scan index ff4e93d12fc8..282344a420ea 100644 --- a/pkg/sql/opt/memo/testdata/stats/scan +++ b/pkg/sql/opt/memo/testdata/stats/scan @@ -2235,7 +2235,7 @@ select │ ├── stats: [rows=1] │ ├── key: (2) │ └── scan tab@tab_geom_idx - │ ├── columns: rowid:2(int!null) geom_inverted_key:5(geometry!null) + │ ├── columns: rowid:2(int!null) geom_inverted_key:5(encodedkey!null) │ ├── inverted constraint: /5/2 │ │ └── spans │ │ ├── ["B\xfd\x10\x00\x00\x00\x00\x00\x00\x00", "B\xfd\x10\x00\x00\x00\x00\x00\x00\x00"] diff --git a/pkg/sql/opt/optbuilder/testdata/inverted-indexes b/pkg/sql/opt/optbuilder/testdata/inverted-indexes index 9b168c703c88..480f7815e9bd 100644 --- a/pkg/sql/opt/optbuilder/testdata/inverted-indexes +++ b/pkg/sql/opt/optbuilder/testdata/inverted-indexes @@ -26,11 +26,11 @@ TABLE kj ├── j jsonb ├── crdb_internal_mvcc_timestamp decimal [hidden] [system] ├── tableoid oid [hidden] [system] - ├── j_inverted_key jsonb not null [inverted] + ├── j_inverted_key encodedkey not null [inverted] ├── PRIMARY INDEX kj_pkey │ └── k int not null └── INVERTED INDEX kj_j_idx - ├── j_inverted_key jsonb not null [inverted] + ├── j_inverted_key encodedkey not null [inverted] └── k int not null build diff --git a/pkg/sql/opt/testutils/testcat/create_table.go b/pkg/sql/opt/testutils/testcat/create_table.go index edf04f121e50..820d7067aa6a 100644 --- a/pkg/sql/opt/testutils/testcat/create_table.go +++ b/pkg/sql/opt/testutils/testcat/create_table.go @@ -1028,18 +1028,15 @@ func (ti *Index) addColumn( } if ti.Inverted && isLastIndexCol { - // The last column of an inverted index is special: the index key does not - // contain values from the column itself, but contains inverted index - // entries derived from that column. Create a virtual column to be able to - // refer to it separately. + // The last column of an inverted index is special: the index key does + // not contain values from the column itself, but contains inverted + // index entries derived from that column. Create a virtual column to be + // able to refer to it separately with the special type EncodedKey. var col cat.Column - // TODO(radu,mjibson): update this when the corresponding type in the real - // catalog is fixed (see sql.newOptTable). - typ := tt.Columns[ordinal].DatumType() col.InitInverted( len(tt.Columns), colName+"_inverted_key", - typ, + types.EncodedKey, false, /* nullable */ ordinal, /* invertedSourceColumnOrdinal */ ) @@ -1104,10 +1101,12 @@ func (ti *Index) addColumnByOrdinal( if colType == keyCol || colType == strictKeyCol { typ := col.DatumType() if col.Kind() == cat.Inverted { - if !colinfo.ColumnTypeIsInvertedIndexable(typ) { + srcCol := tt.Column(col.InvertedSourceColumnOrdinal()) + srcColType := srcCol.DatumType() + if !colinfo.ColumnTypeIsInvertedIndexable(srcColType) { panic(fmt.Errorf( "column %s of type %s is not allowed as the last column of an inverted index", - col.ColName(), typ, + col.ColName(), srcColType, )) } } else if !colinfo.ColumnTypeIsIndexable(typ) { diff --git a/pkg/sql/opt/testutils/testcat/testdata/index b/pkg/sql/opt/testutils/testcat/testdata/index index 2aa11c5a38d5..700cbbadad8b 100644 --- a/pkg/sql/opt/testutils/testcat/testdata/index +++ b/pkg/sql/opt/testutils/testcat/testdata/index @@ -83,18 +83,18 @@ TABLE g ├── geog geography ├── crdb_internal_mvcc_timestamp decimal [hidden] [system] ├── tableoid oid [hidden] [system] - ├── geog_inverted_key geography not null [inverted] - ├── geog_inverted_key geography not null [inverted] + ├── geog_inverted_key encodedkey not null [inverted] + ├── geog_inverted_key encodedkey not null [inverted] ├── PRIMARY INDEX g_pkey │ └── k int not null ├── INVERTED INDEX g_a_geog_idx │ ├── a int - │ ├── geog_inverted_key geography not null [inverted] + │ ├── geog_inverted_key encodedkey not null [inverted] │ └── k int not null └── INVERTED INDEX g_a_b_geog_idx ├── a int ├── b int - ├── geog_inverted_key geography not null [inverted] + ├── geog_inverted_key encodedkey not null [inverted] └── k int not null # Test for expression index columns. @@ -133,10 +133,10 @@ TABLE xyz ├── crdb_internal_idx_expr string as (lower(z)) virtual [inaccessible] ├── crdb_internal_idx_expr_1 int as (y + 1) virtual [inaccessible] ├── crdb_internal_idx_expr_2 jsonb as (j->'a') virtual [inaccessible] - ├── crdb_internal_idx_expr_2_inverted_key jsonb not null [inverted] - ├── crdb_internal_idx_expr_2_inverted_key jsonb not null [inverted] + ├── crdb_internal_idx_expr_2_inverted_key encodedkey not null [inverted] + ├── crdb_internal_idx_expr_2_inverted_key encodedkey not null [inverted] ├── crdb_internal_idx_expr_3 int as (x + y) virtual [inaccessible] - ├── crdb_internal_idx_expr_2_inverted_key jsonb not null [inverted] + ├── crdb_internal_idx_expr_2_inverted_key encodedkey not null [inverted] ├── PRIMARY INDEX xyz_pkey │ └── x int not null ├── INDEX idx1 @@ -151,12 +151,12 @@ TABLE xyz │ ├── crdb_internal_idx_expr string as (lower(z)) virtual [inaccessible] │ └── x int not null ├── INVERTED INDEX idx4 - │ ├── crdb_internal_idx_expr_2_inverted_key jsonb not null [inverted] + │ ├── crdb_internal_idx_expr_2_inverted_key encodedkey not null [inverted] │ └── x int not null ├── INVERTED INDEX idx5 │ ├── y int │ ├── z string - │ ├── crdb_internal_idx_expr_2_inverted_key jsonb not null [inverted] + │ ├── crdb_internal_idx_expr_2_inverted_key encodedkey not null [inverted] │ └── x int not null ├── INDEX idx6 │ ├── crdb_internal_idx_expr_3 int as (x + y) virtual [inaccessible] @@ -166,6 +166,6 @@ TABLE xyz │ └── WHERE v > 1 └── INVERTED INDEX idx7 ├── crdb_internal_idx_expr_3 int as (x + y) virtual [inaccessible] - ├── crdb_internal_idx_expr_2_inverted_key jsonb not null [inverted] + ├── crdb_internal_idx_expr_2_inverted_key encodedkey not null [inverted] ├── x int not null └── WHERE v > 1 diff --git a/pkg/sql/opt/testutils/testcat/testdata/table b/pkg/sql/opt/testutils/testcat/testdata/table index 0b481ac7f79b..23fa4eaad7d2 100644 --- a/pkg/sql/opt/testutils/testcat/testdata/table +++ b/pkg/sql/opt/testutils/testcat/testdata/table @@ -204,15 +204,15 @@ TABLE inv ├── g geometry ├── crdb_internal_mvcc_timestamp decimal [hidden] [system] ├── tableoid oid [hidden] [system] - ├── j_inverted_key jsonb not null [inverted] - ├── g_inverted_key geometry not null [inverted] + ├── j_inverted_key encodedkey not null [inverted] + ├── g_inverted_key encodedkey not null [inverted] ├── PRIMARY INDEX inv_pkey │ └── k int not null ├── INVERTED INDEX inv_j_idx - │ ├── j_inverted_key jsonb not null [inverted] + │ ├── j_inverted_key encodedkey not null [inverted] │ └── k int not null └── INVERTED INDEX inv_g_idx - ├── g_inverted_key geometry not null [inverted] + ├── g_inverted_key encodedkey not null [inverted] └── k int not null # Table with inverted indexes and implicit primary index. @@ -236,15 +236,15 @@ TABLE inv2 ├── rowid int not null default (unique_rowid()) [hidden] ├── crdb_internal_mvcc_timestamp decimal [hidden] [system] ├── tableoid oid [hidden] [system] - ├── j_inverted_key jsonb not null [inverted] - ├── g_inverted_key geometry not null [inverted] + ├── j_inverted_key encodedkey not null [inverted] + ├── g_inverted_key encodedkey not null [inverted] ├── PRIMARY INDEX inv2_pkey │ └── rowid int not null default (unique_rowid()) [hidden] ├── INVERTED INDEX inv2_j_idx - │ ├── j_inverted_key jsonb not null [inverted] + │ ├── j_inverted_key encodedkey not null [inverted] │ └── rowid int not null default (unique_rowid()) [hidden] └── INVERTED INDEX inv2_g_idx - ├── g_inverted_key geometry not null [inverted] + ├── g_inverted_key encodedkey not null [inverted] └── rowid int not null default (unique_rowid()) [hidden] # Table with unique constraints. diff --git a/pkg/sql/opt_catalog.go b/pkg/sql/opt_catalog.go index aedf02926313..138fd78ad971 100644 --- a/pkg/sql/opt_catalog.go +++ b/pkg/sql/opt_catalog.go @@ -892,10 +892,8 @@ func newOptTable( invertedSourceColOrdinal, _ := ot.lookupColumnOrdinal(invertedColumnID) - // Add a inverted column that refers to the inverted index key. + // Add an inverted column that refers to the inverted index key. invertedCol, invertedColOrd := newColumn() - - // All inverted columns have type bytes. invertedCol.InitInverted( invertedColOrd, tree.Name(invertedColumnName+"_inverted_key"), From d07bf3a120fe5798f9e3bb446228a90b6cd17d0e Mon Sep 17 00:00:00 2001 From: Erik Grinaker Date: Sat, 28 May 2022 12:14:47 +0000 Subject: [PATCH 2/3] storage: add MVCC point synthesizing iterator This patch adds `pointSynthesizingIter`, an MVCC iterator which wraps an arbitrary MVCC iterator and synthesizes point keys for range keys at their start key and where they overlap point keys. It can optionally synthesize around the SeekGE seek key too, which is useful for point operations like `MVCCGet` where we may want to return a synthetic tombstone for an MVCC range tombstone if there is no existing point key. This will primarily be used to handle MVCC range tombstones in MVCC scans and gets, as well as during MVCC conflict checks, which allows much of this logic to remain unchanged and simplified (in particular, `pebbleMVCCScanner` will not need any changes). However, this patch does not make use of the iterator yet, since both it and Pebble will need further performance optimizations for use in hot paths. For now, correctness is sufficient, and only basic attempts at performance optimization have been made. Release note: None --- pkg/storage/BUILD.bazel | 1 + pkg/storage/mvcc_history_test.go | 5 +- pkg/storage/mvcc_key.go | 6 + pkg/storage/point_synthesizing_iter.go | 696 +++++++++++ .../mvcc_histories/range_key_point_synthesis | 1042 +++++++++++++++++ 5 files changed, 1749 insertions(+), 1 deletion(-) create mode 100644 pkg/storage/point_synthesizing_iter.go create mode 100644 pkg/storage/testdata/mvcc_histories/range_key_point_synthesis diff --git a/pkg/storage/BUILD.bazel b/pkg/storage/BUILD.bazel index 2a8ec647e8e6..84ac19caed44 100644 --- a/pkg/storage/BUILD.bazel +++ b/pkg/storage/BUILD.bazel @@ -29,6 +29,7 @@ go_library( "pebble_iterator.go", "pebble_merge.go", "pebble_mvcc_scanner.go", + "point_synthesizing_iter.go", "read_as_of_iterator.go", "replicas_storage.go", "resource_limiter.go", diff --git a/pkg/storage/mvcc_history_test.go b/pkg/storage/mvcc_history_test.go index 372562c6d3e2..5595bcc07918 100644 --- a/pkg/storage/mvcc_history_test.go +++ b/pkg/storage/mvcc_history_test.go @@ -69,7 +69,7 @@ import ( // get [t=] [ts=[,]] [resolve [status=]] k= [inconsistent] [tombstones] [failOnMoreRecent] [localUncertaintyLimit=[,]] [globalUncertaintyLimit=[,]] // scan [t=] [ts=[,]] [resolve [status=]] k= [end=] [inconsistent] [tombstones] [reverse] [failOnMoreRecent] [localUncertaintyLimit=[,]] [globalUncertaintyLimit=[,]] [max=] [targetbytes=] [avoidExcess] [allowEmpty] // -// iter_new [k=] [end=] [prefix] [kind=key|keyAndIntents] [types=pointsOnly|pointsWithRanges|pointsAndRanges|rangesOnly] [maskBelow=[,]] +// iter_new [k=] [end=] [prefix] [kind=key|keyAndIntents] [types=pointsOnly|pointsWithRanges|pointsAndRanges|rangesOnly] [pointSynthesis [emitOnSeekGE]] [maskBelow=[,]] // iter_seek_ge k= [ts=[,]] // iter_seek_lt k= [ts=[,]] // iter_seek_intent_ge k= txn= @@ -1027,6 +1027,9 @@ func cmdIterNew(e *evalCtx) error { MVCCIterator: r.NewMVCCIterator(kind, opts), closeReader: closeReader, } + if e.hasArg("pointSynthesis") { + e.iter = newPointSynthesizingIter(e.iter, e.hasArg("emitOnSeekGE")) + } return nil } diff --git a/pkg/storage/mvcc_key.go b/pkg/storage/mvcc_key.go index e59ffe52be4d..f128b69c77cd 100644 --- a/pkg/storage/mvcc_key.go +++ b/pkg/storage/mvcc_key.go @@ -68,6 +68,12 @@ func (k MVCCKey) Next() MVCCKey { } } +// Clone returns a copy of the key. +func (k MVCCKey) Clone() MVCCKey { + k.Key = k.Key.Clone() + return k +} + // Compare returns -1 if this key is less than the given key, 0 if they're // equal, or 1 if this is greater. Comparison is by key,timestamp, where larger // timestamps sort before smaller ones except empty ones which sort first (like diff --git a/pkg/storage/point_synthesizing_iter.go b/pkg/storage/point_synthesizing_iter.go new file mode 100644 index 000000000000..557d79765c53 --- /dev/null +++ b/pkg/storage/point_synthesizing_iter.go @@ -0,0 +1,696 @@ +// Copyright 2022 The Cockroach Authors. +// +// Use of this software is governed by the Business Source License +// included in the file licenses/BSL.txt. +// +// As of the Change Date specified in that file, in accordance with +// the Business Source License, use of this software will be governed +// by the Apache License, Version 2.0, included in the file +// licenses/APL.txt. + +package storage + +import ( + "sort" + "sync" + + "github.com/cockroachdb/cockroach/pkg/roachpb" + "github.com/cockroachdb/cockroach/pkg/storage/enginepb" + "github.com/cockroachdb/cockroach/pkg/util" + "github.com/cockroachdb/cockroach/pkg/util/hlc" + "github.com/cockroachdb/cockroach/pkg/util/protoutil" + "github.com/cockroachdb/cockroach/pkg/util/uuid" + "github.com/cockroachdb/errors" +) + +// pointSynthesizingIterPool reuses pointSynthesizingIters to avoid allocations. +var pointSynthesizingIterPool = sync.Pool{ + New: func() interface{} { + return &pointSynthesizingIter{} + }, +} + +// pointSynthesizingIter wraps an MVCCIterator, and synthesizes MVCC point keys +// for MVCC range keys above/below existing point keys, and at the start of +// range keys (truncated to iterator bounds). If emitOnSeekGE is set, it will +// also unconditionally synthesize point keys around a SeekGE seek key if it +// overlaps an MVCC range key. +// +// It does not emit MVCC range keys at all, since these would appear to conflict +// with the synthesized point keys. +// +// During iteration, any range keys overlapping the current iterator position +// are kept in rangeKeys. When atPoint is true, the iterator is positioned on a +// real point key in the underlying iterator. Otherwise, it is positioned on a +// synthetic point key given by rangeKeysPos and rangeKeys[rangeKeysIdx]. +// +// The relative positioning of pointSynthesizingIter and the underlying iterator +// is as follows in the forward direction: +// +// - atPoint=true: rangeKeysIdx points to a range key following the point key, +// or beyond the slice bounds when there are no further range keys at this +// key position. +// +// - atPoint=false: the underlying iterator is on a following key or exhausted. +// This can either be a different version of the current key or a different +// point/range key. +// +// This positioning is mirrored in the reverse direction. For example, when +// atPoint=true and rangeKeys are exhausted, rangeKeysIdx will be len(rangeKeys) +// in the forward direction and -1 in the reverse direction. Similarly, the +// underlying iterator is always >= rangeKeysPos in the forward direction and <= +// in reverse. +// +// See also assertInvariants() which asserts positioning invariants. +type pointSynthesizingIter struct { + iter MVCCIterator + + // rangeKeys contains any range keys that overlap the current key position, + // for which points will be synthesized. + rangeKeys []MVCCRangeKeyValue + + // rangeKeysPos is the current key (along the rangeKeys span) that points will + // be synthesized for. It is only set if rangeKeys is non-empty, and may + // differ from the underlying iterator position. + rangeKeysPos roachpb.Key + + // rangeKeysIdx is the rangeKeys index of the current/pending range key + // to synthesize a point for. See struct comment for details. + rangeKeysIdx int + + // rangeKeysStart contains the start key of the current rangeKeys stack. It is + // only used to memoize rangeKeys for adjacent keys. + rangeKeysStart roachpb.Key + + // atPoint is true if the synthesizing iterator is positioned on a real point + // key in the underlying iterator. See struct comment for details. + atPoint bool + + // reverse is true when the current iterator direction is in reverse, i.e. + // following a SeekLT or Prev call. + reverse bool + + // emitOnSeekGE will synthesize point keys for the SeekGE seek key if it + // overlaps with a range key even if no point key exists. The primary use-case + // is to synthesize point keys for e.g. an MVCCGet that does not match a point + // key but overlaps a range key, which is necessary for conflict checks. + // + // This is optional, because e.g. pebbleMVCCScanner often uses seeks as an + // optimization to skip over old versions of a key, and we don't want to keep + // synthesizing point keys every time it skips ahead. + // + // TODO(erikgrinaker): This could instead check for prefix iterators, or a + // separate SeekPrefixGE() method, but we don't currently have APIs for it. + emitOnSeekGE bool +} + +var _ MVCCIterator = new(pointSynthesizingIter) + +// newPointSynthesizingIter creates a new pointSynthesizingIter, or gets one +// from the pool. +func newPointSynthesizingIter(parent MVCCIterator, emitOnSeekGE bool) *pointSynthesizingIter { + iter := pointSynthesizingIterPool.Get().(*pointSynthesizingIter) + *iter = pointSynthesizingIter{ + iter: parent, + emitOnSeekGE: emitOnSeekGE, + // Reuse pooled byte slices. + rangeKeysPos: iter.rangeKeysPos, + rangeKeysStart: iter.rangeKeysStart, + } + return iter +} + +// Close implements MVCCIterator. +// +// Close will also close the underlying iterator. Use release() to release it +// back to the pool without closing the parent iterator. +func (i *pointSynthesizingIter) Close() { + i.iter.Close() + i.release() +} + +// release releases the iterator back into the pool. +func (i *pointSynthesizingIter) release() { + *i = pointSynthesizingIter{ + // Reuse byte slices. + rangeKeysPos: i.rangeKeysPos[:0], + rangeKeysStart: i.rangeKeysStart[:0], + } + pointSynthesizingIterPool.Put(i) +} + +// updateRangeKeys updates i.rangeKeys and related fields with range keys from +// the underlying iterator. rangeKeysIdx is reset to the first/last range key. +func (i *pointSynthesizingIter) updateRangeKeys() { + if _, hasRange := i.iter.HasPointAndRange(); hasRange { + i.rangeKeysPos = append(i.rangeKeysPos[:0], i.iter.UnsafeKey().Key...) + if rangeStart := i.iter.RangeBounds().Key; !rangeStart.Equal(i.rangeKeysStart) { + i.rangeKeysStart = append(i.rangeKeysStart[:0], rangeStart...) + i.rangeKeys = i.rangeKeys[:0] + for _, rk := range i.iter.RangeKeys() { + // TODO(erikgrinaker): We should optimize the clone cost. + i.rangeKeys = append(i.rangeKeys, rk.Clone()) + } + } + } else if len(i.rangeKeys) != 0 { + i.rangeKeys = i.rangeKeys[:0] + i.rangeKeysPos = i.rangeKeysPos[:0] + i.rangeKeysStart = i.rangeKeysStart[:0] + } + if !i.reverse { + i.rangeKeysIdx = 0 + } else { + i.rangeKeysIdx = len(i.rangeKeys) - 1 // NB: -1 is correct with no range keys + } +} + +// clearRangeKeys resets the iterator by clearing out all range key state. +// gcassert:inline +func (i *pointSynthesizingIter) clearRangeKeys() { + if len(i.rangeKeys) != 0 { + i.rangeKeys = i.rangeKeys[:0] + i.rangeKeysPos = i.rangeKeysPos[:0] + i.rangeKeysStart = i.rangeKeysStart[:0] + } + if !i.reverse { + i.rangeKeysIdx = 0 + } else { + i.rangeKeysIdx = -1 + } +} + +// updateAtPoint updates i.atPoint according to whether the synthesizing +// iterator is positioned on the real point key in the underlying iterator. +// Requires i.rangeKeys to have been positioned first. +func (i *pointSynthesizingIter) updateAtPoint() { + if hasPoint, _ := i.iter.HasPointAndRange(); !hasPoint { + i.atPoint = false + } else if len(i.rangeKeys) == 0 { + i.atPoint = true + } else if point := i.iter.UnsafeKey(); !point.Key.Equal(i.rangeKeysPos) { + i.atPoint = false + } else if !i.reverse { + i.atPoint = i.rangeKeysIdx >= len(i.rangeKeys) || + !point.Timestamp.IsSet() || + i.rangeKeys[i.rangeKeysIdx].RangeKey.Timestamp.LessEq(point.Timestamp) + } else { + i.atPoint = i.rangeKeysIdx < 0 || (point.Timestamp.IsSet() && + point.Timestamp.LessEq(i.rangeKeys[i.rangeKeysIdx].RangeKey.Timestamp)) + } +} + +// updatePosition updates the synthesizing iterator with the position of the +// underlying iterator. This may step the underlying iterator to position it +// correctly relative to bare range keys. +func (i *pointSynthesizingIter) updatePosition() { + if hasPoint, hasRange := i.iter.HasPointAndRange(); !hasRange { + // Fast path: no range keys, so just clear range keys and bail out. + i.atPoint = hasPoint + i.clearRangeKeys() + + } else if !i.reverse { + // If we're on a bare range key in the forward direction, we populate the + // range keys but then step iter ahead before updating the point position. + // The next position may be a point key with the same key as the current + // range key, which must be interleaved with the synthetic points. + i.updateRangeKeys() + if hasRange && !hasPoint { + i.iter.Next() + } + i.updateAtPoint() + + } else { + // If we're on a bare range key in the reverse direction, and we've already + // emitted synthetic points for this key (as evidenced by rangeKeysPos), + // then we skip over the bare range key to avoid duplicates. + if hasRange && !hasPoint && i.iter.UnsafeKey().Key.Equal(i.rangeKeysPos) { + i.iter.Prev() + } + i.updateRangeKeys() + i.updateAtPoint() + } +} + +// SeekGE implements MVCCIterator. +func (i *pointSynthesizingIter) SeekGE(seekKey MVCCKey) { + i.reverse = false + i.iter.SeekGE(seekKey) + + // Fast path: no range key, so just reset the iterator and bail out. + hasPoint, hasRange := i.iter.HasPointAndRange() + if !hasRange { + i.atPoint = hasPoint + i.clearRangeKeys() + return + } + + // If we land in the middle of a bare range key and emitOnSeekGE is disabled, + // then skip over it to the next point/range key -- we're only supposed to + // synthesize at the range key start bound and at existing points. + // + // However, if we're seeking to a specific version and don't find an older + // point key at the seek key, then we also need to peek backwards for an + // existing point key above us, which would mandate that we synthesize point + // keys here after all. + // + // TODO(erikgrinaker): It might be faster to first do an unversioned seek to + // look for previous points and then a versioned seek. We can also omit this + // if there are no range keys below the seek timestamp. + // + // TODO(erikgrinaker): We could avoid this in the SeekGE case if we only + // synthesize points above existing points, except in the emitOnSeeGE case + // where no existing point exists. That could also result in fewer synthetic + // points overall. Do we need to synthesize older points? + var positioned bool + if !i.emitOnSeekGE && hasRange && !hasPoint && + !i.iter.RangeBounds().Key.Equal(i.iter.UnsafeKey().Key) { + i.iter.Next() + + if seekKey.Timestamp.IsSet() { + ok, err := i.iter.Valid() + if err == nil && (!ok || !seekKey.Key.Equal(i.iter.UnsafeKey().Key)) { + i.iter.Prev() + if hasP, _ := i.iter.HasPointAndRange(); hasP && seekKey.Key.Equal(i.iter.UnsafeKey().Key) { + i.updateRangeKeys() + positioned = true + } + i.iter.Next() + } + } + hasPoint, hasRange = i.iter.HasPointAndRange() + } + + if !positioned { + i.updateRangeKeys() + + // If we're now at a bare range key, we must either be at the start of it, + // or in the middle with emitOnSeekGE enabled. In either case, we want to + // move the iterator ahead to look for a point key with the same key as the + // start/seek key in order to interleave it. + if hasRange && !hasPoint { + i.iter.Next() + } + } + + // If we're seeking to a specific version, skip newer range keys. + if len(i.rangeKeys) > 0 && seekKey.Timestamp.IsSet() && seekKey.Key.Equal(i.rangeKeysPos) { + i.rangeKeysIdx = sort.Search(len(i.rangeKeys), func(idx int) bool { + return i.rangeKeys[idx].RangeKey.Timestamp.LessEq(seekKey.Timestamp) + }) + } + + i.updateAtPoint() + + // It's possible that we seeked past all of the range key versions. In this + // case, we have to reposition on the next key (current iter key). + if !i.atPoint && i.rangeKeysIdx >= len(i.rangeKeys) { + i.updatePosition() + } +} + +// SeekIntentGE implements MVCCIterator. +func (i *pointSynthesizingIter) SeekIntentGE(seekKey roachpb.Key, txnUUID uuid.UUID) { + i.reverse = false + i.iter.SeekIntentGE(seekKey, txnUUID) + + // Fast path: no range key, so just reset the iterator and bail out. + hasPoint, hasRange := i.iter.HasPointAndRange() + if !hasRange { + i.atPoint = hasPoint + i.clearRangeKeys() + return + } + + // If we land in the middle of a bare range key and emitOnSeekGE is disabled, + // then skip over it to the next point/range key. + if !i.emitOnSeekGE && hasRange && !hasPoint && + !i.iter.RangeBounds().Key.Equal(i.iter.UnsafeKey().Key) { + i.iter.Next() + } + + i.updatePosition() +} + +// Next implements MVCCIterator. +func (i *pointSynthesizingIter) Next() { + // When changing direction, flip the relative positioning with iter. + if i.reverse { + i.reverse = false + if !i.atPoint && len(i.rangeKeys) == 0 { // iterator was exhausted + i.iter.Next() + i.updatePosition() + return + } else if i.atPoint { + i.rangeKeysIdx++ + } else { + i.iter.Next() + } + } + + // Step off the current point, either real or synthetic. + if i.atPoint { + i.iter.Next() + } else { + i.rangeKeysIdx++ + } + i.updateAtPoint() + + // If we've exhausted the current range keys, update with the underlying + // iterator position (which must now be at a later key). + if !i.atPoint && i.rangeKeysIdx >= len(i.rangeKeys) { + i.updatePosition() + } +} + +// NextKey implements MVCCIterator. +func (i *pointSynthesizingIter) NextKey() { + // When changing direction, flip the relative positioning with iter. + // + // NB: This isn't really supported by the MVCCIterator interface, but we have + // best-effort handling in e.g. `pebbleIterator` and it's simple enough to + // implement, so we may as well. + if i.reverse { + i.reverse = false + if !i.atPoint { + i.iter.Next() + } + } + // Don't call NextKey() if the underlying iterator is already on the next key. + if i.atPoint || i.rangeKeysPos.Equal(i.iter.UnsafeKey().Key) { + i.iter.NextKey() + } + i.updatePosition() +} + +// SeekLT implements MVCCIterator. +func (i *pointSynthesizingIter) SeekLT(seekKey MVCCKey) { + i.reverse = true + i.iter.SeekLT(seekKey) + + // Fast path: no range key, so just reset the iterator and bail out. + hasPoint, hasRange := i.iter.HasPointAndRange() + if !hasRange { + i.atPoint = hasPoint + i.clearRangeKeys() + return + } + + // If we did a versioned seek and find a range key that overlaps the seek key, + // we may have skipped over existing point key versions of the seek key. These + // would mandate that we synthesize point keys for the seek key after all, so + // we peek ahead to check for them. + // + // TODO(erikgrinaker): It might be faster to do an unversioned seek from the + // next key first to look for points. + var positioned bool + if seekKey.Timestamp.IsSet() && hasRange && + (!hasPoint || !i.iter.UnsafeKey().Key.Equal(seekKey.Key)) && + seekKey.Key.Compare(i.iter.RangeBounds().EndKey) < 0 { + i.iter.Next() + if hasP, _ := i.iter.HasPointAndRange(); hasP && i.iter.UnsafeKey().Key.Equal(seekKey.Key) { + i.updateRangeKeys() + positioned = true + } + i.iter.Prev() + } + + if !positioned { + i.updateRangeKeys() + } + + // If we're seeking to a specific version, skip over older range keys. + if seekKey.Timestamp.IsSet() && seekKey.Key.Equal(i.rangeKeysPos) { + i.rangeKeysIdx = sort.Search(len(i.rangeKeys), func(idx int) bool { + return i.rangeKeys[idx].RangeKey.Timestamp.LessEq(seekKey.Timestamp) + }) - 1 + } + + i.updateAtPoint() + + // It's possible that we seeked past all of the range key versions. In this + // case, we have to reposition on the previous key (current iter key). + if !i.atPoint && i.rangeKeysIdx < 0 { + i.updatePosition() + } +} + +// Prev implements MVCCIterator. +func (i *pointSynthesizingIter) Prev() { + // When changing direction, flip the relative positioning with iter. + if !i.reverse { + i.reverse = true + if !i.atPoint && len(i.rangeKeys) == 0 { // iterator was exhausted + i.iter.Prev() + i.updatePosition() + return + } else if i.atPoint { + i.rangeKeysIdx-- + } else { + i.iter.Prev() + } + } + + // Step off the current point key (real or synthetic). + if i.atPoint { + i.iter.Prev() + } else { + i.rangeKeysIdx-- + } + i.updateAtPoint() + + // If we've exhausted the current range keys, and we're not positioned on a + // point key at the current range key position, then update with the + // underlying iter position (which must be before the current key). + if i.rangeKeysIdx < 0 && (!i.atPoint || !i.rangeKeysPos.Equal(i.iter.UnsafeKey().Key)) { + i.updatePosition() + } +} + +// Valid implements MVCCIterator. +func (i *pointSynthesizingIter) Valid() (bool, error) { + if util.RaceEnabled { + if err := i.assertInvariants(); err != nil { + panic(err) + } + } + if !i.atPoint && i.rangeKeysIdx >= 0 && i.rangeKeysIdx < len(i.rangeKeys) { + return true, nil // on synthetic point key + } + return i.iter.Valid() +} + +// Key implements MVCCIterator. +func (i *pointSynthesizingIter) Key() MVCCKey { + return i.UnsafeKey().Clone() +} + +// UnsafeKey implements MVCCIterator. +func (i *pointSynthesizingIter) UnsafeKey() MVCCKey { + if i.atPoint { + return i.iter.UnsafeKey() + } + if i.rangeKeysIdx >= len(i.rangeKeys) || i.rangeKeysIdx < 0 { + return MVCCKey{} + } + return MVCCKey{ + Key: i.rangeKeysPos, + Timestamp: i.rangeKeys[i.rangeKeysIdx].RangeKey.Timestamp, + } +} + +// UnsafeRawKey implements MVCCIterator. +func (i *pointSynthesizingIter) UnsafeRawKey() []byte { + if i.atPoint { + return i.iter.UnsafeRawKey() + } + return EncodeMVCCKeyPrefix(i.rangeKeysPos) +} + +// UnsafeRawMVCCKey implements MVCCIterator. +func (i *pointSynthesizingIter) UnsafeRawMVCCKey() []byte { + if i.atPoint { + return i.iter.UnsafeRawMVCCKey() + } + return EncodeMVCCKey(i.UnsafeKey()) +} + +// Value implements MVCCIterator. +func (i *pointSynthesizingIter) Value() []byte { + if v := i.UnsafeValue(); v != nil { + return append([]byte{}, v...) + } + return nil +} + +// UnsafeValue implements MVCCIterator. +func (i *pointSynthesizingIter) UnsafeValue() []byte { + if i.atPoint { + return i.iter.UnsafeValue() + } + if i.rangeKeysIdx >= len(i.rangeKeys) || i.rangeKeysIdx < 0 { + return nil + } + return i.rangeKeys[i.rangeKeysIdx].Value +} + +// ValueProto implements MVCCIterator. +func (i *pointSynthesizingIter) ValueProto(msg protoutil.Message) error { + return protoutil.Unmarshal(i.UnsafeValue(), msg) +} + +// HasPointAndRange implements MVCCIterator. +func (i *pointSynthesizingIter) HasPointAndRange() (bool, bool) { + ok, err := i.Valid() + return ok && err == nil, false +} + +// RangeBounds implements MVCCIterator. +func (i *pointSynthesizingIter) RangeBounds() roachpb.Span { + return roachpb.Span{} +} + +// RangeKeys implements MVCCIterator. +func (i *pointSynthesizingIter) RangeKeys() []MVCCRangeKeyValue { + return []MVCCRangeKeyValue{} +} + +// ComputeStats implements MVCCIterator. +func (i *pointSynthesizingIter) ComputeStats( + start, end roachpb.Key, nowNanos int64, +) (enginepb.MVCCStats, error) { + return i.iter.ComputeStats(start, end, nowNanos) +} + +// FindSplitKey implements MVCCIterator. +func (i *pointSynthesizingIter) FindSplitKey( + start, end, minSplitKey roachpb.Key, targetSize int64, +) (MVCCKey, error) { + return i.iter.FindSplitKey(start, end, minSplitKey, targetSize) +} + +// Stats implements MVCCIterator. +func (i *pointSynthesizingIter) Stats() IteratorStats { + return i.iter.Stats() +} + +// SupportsPrev implements MVCCIterator. +func (i *pointSynthesizingIter) SupportsPrev() bool { + return i.iter.SupportsPrev() +} + +// assertInvariants asserts iterator invariants. +func (i *pointSynthesizingIter) assertInvariants() error { + // If the underlying iterator has errored, make sure we're not positioned on a + // synthetic point such that Valid() will surface the error. + if _, err := i.iter.Valid(); err != nil { + if !i.atPoint && i.rangeKeysIdx >= 0 && i.rangeKeysIdx < len(i.rangeKeys) { + return errors.NewAssertionErrorWithWrappedErrf(err, "iterator error with synthetic point %s", + i.rangeKeysPos) + } + return nil + } + + // When atPoint is true, the underlying iterator must be valid and on a point. + if i.atPoint { + if ok, _ := i.iter.Valid(); !ok { + return errors.AssertionFailedf("atPoint with invalid iter") + } + if hasPoint, _ := i.iter.HasPointAndRange(); !hasPoint { + return errors.AssertionFailedf("atPoint at non-point position %s", i.iter.UnsafeKey()) + } + } + + // rangeKeysIdx is never more than 1 outside of the slice bounds, and the + // excess depends on the direction: len(rangeKeys) in the forward direction, + // -1 in the reverse. + if i.rangeKeysIdx < 0 || i.rangeKeysIdx >= len(i.rangeKeys) { + if (!i.reverse && i.rangeKeysIdx != len(i.rangeKeys)) || (i.reverse && i.rangeKeysIdx != -1) { + return errors.AssertionFailedf("invalid rangeKeysIdx %d with length %d and reverse=%t", + i.rangeKeysIdx, len(i.rangeKeys), i.reverse) + } + } + + // If rangeKeys is empty, atPoint is true unless exhausted and other state is + // cleared. In this case, there's nothing more to check. + if len(i.rangeKeys) == 0 { + if ok, _ := i.iter.Valid(); ok && !i.atPoint { + return errors.AssertionFailedf("no rangeKeys nor atPoint") + } + if len(i.rangeKeysPos) > 0 { + return errors.AssertionFailedf("no rangeKeys but rangeKeysPos %s", i.rangeKeysPos) + } + if len(i.rangeKeysStart) > 0 { + return errors.AssertionFailedf("no rangeKeys but rangeKeysStart %s", i.rangeKeysStart) + } + return nil + } + + // rangeKeysStart must be set, and rangeKeysPos must be at or after it. This + // implies that rangeKeysPos must also be set. + if len(i.rangeKeysStart) == 0 { + return errors.AssertionFailedf("no rangeKeysStart at %s", i.iter.UnsafeKey()) + } + if i.rangeKeysPos.Compare(i.rangeKeysStart) < 0 { + return errors.AssertionFailedf("rangeKeysPos %s not after rangeKeysStart %s", + i.rangeKeysPos, i.rangeKeysStart) + } + + // rangeKeysIdx must be valid if we're not on a point. + if !i.atPoint && (i.rangeKeysIdx < 0 || i.rangeKeysIdx >= len(i.rangeKeys)) { + return errors.AssertionFailedf("not atPoint with invalid rangeKeysIdx %d at %s", + i.rangeKeysIdx, i.rangeKeysPos) + } + + // If the underlying iterator is exhausted, then there's nothing more to + // check. We must either be on a synthetic point key or exhausted iterator. + if ok, _ := i.iter.Valid(); !ok { + return nil + } + + // We now have range keys and a non-exhausted iterator. Check their relative + // positioning as minimum and maximum iter keys (in MVCC order). We can assume + // that overlapping range keys and point keys don't have the same timestamp, + // since this is enforced by MVCC mutations. + var minKey, maxKey MVCCKey + + // The iterator should never lag behind the range key position. + if !i.reverse { + minKey = MVCCKey{Key: i.rangeKeysPos} + } else { + maxKey = MVCCKey{Key: i.rangeKeysPos, Timestamp: hlc.MinTimestamp} + } + + // If we're not at a real point, then the iterator must be ahead of the + // current synthesized point. If we are on a point, then it must lie between + // the surrounding range keys (if they exist). + minIdx, maxIdx := -1, -1 + if !i.atPoint { + if !i.reverse { + minIdx = i.rangeKeysIdx + } else { + maxIdx = i.rangeKeysIdx + } + } else if !i.reverse { + minIdx = i.rangeKeysIdx - 1 + maxIdx = i.rangeKeysIdx + } else { + minIdx = i.rangeKeysIdx + maxIdx = i.rangeKeysIdx + 1 + } + if minIdx >= 0 && minIdx < len(i.rangeKeys) { + minKey = MVCCKey{Key: i.rangeKeysPos, Timestamp: i.rangeKeys[minIdx].RangeKey.Timestamp} + } + if maxIdx >= 0 && maxIdx < len(i.rangeKeys) { + maxKey = MVCCKey{Key: i.rangeKeysPos, Timestamp: i.rangeKeys[maxIdx].RangeKey.Timestamp} + } + + iterKey := i.iter.Key() + if minKey.Key != nil && iterKey.Compare(minKey) < 0 { + return errors.AssertionFailedf("iter %s below minimum key %s", iterKey, minKey) + } + if maxKey.Key != nil && iterKey.Compare(maxKey) > 0 { + return errors.AssertionFailedf("iter %s above maximum key %s", iterKey, maxKey) + } + + return nil +} diff --git a/pkg/storage/testdata/mvcc_histories/range_key_point_synthesis b/pkg/storage/testdata/mvcc_histories/range_key_point_synthesis new file mode 100644 index 000000000000..682c4053ddd4 --- /dev/null +++ b/pkg/storage/testdata/mvcc_histories/range_key_point_synthesis @@ -0,0 +1,1042 @@ +# Tests pointSynthesizingIter. +# +# Sets up following dataset, where x is tombstone, o-o is range tombstone, [] is intent. +# +# T +# 7 [d7] [j7] +# 6 f6 +# 5 o---------------o k5 o-----------o +# 4 x x d4 f4 g4 +# 3 o-------o e3 o-------oh3 o---o +# 2 a2 f2 g2 +# 1 o-------------------o o-----------o +# a b c d e f g h i j k l m n o p +# +run ok +put_rangekey k=a end=f ts=1 +put_rangekey k=h end=k ts=1 +put_rangekey k=b end=d ts=3 +put_rangekey k=n end=o ts=3 +put_rangekey k=l end=o ts=5 +put k=a ts=2 v=a2 +del k=a ts=4 +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 localTs=4 +put k=f ts=4 v=f4 +put k=f ts=6 v=f6 +put k=g ts=4 v=g4 +put_rangekey k=c end=g ts=5 +put k=h ts=3 v=h3 +put k=k ts=5 v=k5 +with t=A + txn_begin ts=7 + put k=d v=d7 + put k=j v=j7 +---- +>> at end: +txn: "A" meta={id=00000000 key=/Min pri=0.00000000 epo=0 ts=7.000000000,0 min=0,0 seq=0} lock=true stat=PENDING rts=7.000000000,0 wto=false gul=0,0 +rangekey: {a-b}/[1.000000000,0=/] +rangekey: {b-c}/[3.000000000,0=/ 1.000000000,0=/] +rangekey: {c-d}/[5.000000000,0=/ 3.000000000,0=/ 1.000000000,0=/] +rangekey: {d-f}/[5.000000000,0=/ 1.000000000,0=/] +rangekey: {f-g}/[5.000000000,0=/ 3.000000000,0=vheader{ localTs=4.000000000,0 } /] +rangekey: {g-h}/[3.000000000,0=vheader{ localTs=4.000000000,0 } /] +rangekey: {h-k}/[1.000000000,0=/] +rangekey: {l-n}/[5.000000000,0=/] +rangekey: {n-o}/[5.000000000,0=/ 3.000000000,0=/] +data: "a"/4.000000000,0 -> / +data: "a"/2.000000000,0 -> /BYTES/a2 +data: "b"/4.000000000,0 -> / +meta: "d"/0,0 -> txn={id=00000000 key=/Min pri=0.00000000 epo=0 ts=7.000000000,0 min=0,0 seq=0} ts=7.000000000,0 del=false klen=12 vlen=7 mergeTs= txnDidNotUpdateMeta=true +data: "d"/7.000000000,0 -> /BYTES/d7 +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"/3.000000000,0 -> /BYTES/h3 +meta: "j"/0,0 -> txn={id=00000000 key=/Min pri=0.00000000 epo=0 ts=7.000000000,0 min=0,0 seq=0} ts=7.000000000,0 del=false klen=12 vlen=7 mergeTs= txnDidNotUpdateMeta=true +data: "j"/7.000000000,0 -> /BYTES/j7 +data: "k"/5.000000000,0 -> /BYTES/k5 + +# Iterate across the entire span, forward and reverse. +run ok +iter_new types=pointsAndRanges pointSynthesis +iter_seek_ge k=a +iter_scan +---- +iter_seek_ge: "a"/4.000000000,0=/ +iter_scan: "a"/4.000000000,0=/ +iter_scan: "a"/2.000000000,0=/BYTES/a2 +iter_scan: "a"/1.000000000,0=/ +iter_scan: "b"/4.000000000,0=/ +iter_scan: "b"/3.000000000,0=/ +iter_scan: "b"/1.000000000,0=/ +iter_scan: "c"/5.000000000,0=/ +iter_scan: "c"/3.000000000,0=/ +iter_scan: "c"/1.000000000,0=/ +iter_scan: "d"/0,0=txn={id=00000000 key=/Min pri=0.00000000 epo=0 ts=7.000000000,0 min=0,0 seq=0} ts=7.000000000,0 del=false klen=12 vlen=7 mergeTs= txnDidNotUpdateMeta=true +iter_scan: "d"/7.000000000,0=/BYTES/d7 +iter_scan: "d"/5.000000000,0=/ +iter_scan: "d"/4.000000000,0=/BYTES/d4 +iter_scan: "d"/1.000000000,0=/ +iter_scan: "e"/5.000000000,0=/ +iter_scan: "e"/3.000000000,0=/BYTES/e3 +iter_scan: "e"/1.000000000,0=/ +iter_scan: "f"/6.000000000,0=/BYTES/f6 +iter_scan: "f"/5.000000000,0=/ +iter_scan: "f"/4.000000000,0=/BYTES/f4 +iter_scan: "f"/3.000000000,0=vheader{ localTs=4.000000000,0 } / +iter_scan: "f"/2.000000000,0=/BYTES/f2 +iter_scan: "g"/4.000000000,0=/BYTES/g4 +iter_scan: "g"/3.000000000,0=vheader{ localTs=4.000000000,0 } / +iter_scan: "g"/2.000000000,0=/BYTES/g2 +iter_scan: "h"/3.000000000,0=/BYTES/h3 +iter_scan: "h"/1.000000000,0=/ +iter_scan: "j"/0,0=txn={id=00000000 key=/Min pri=0.00000000 epo=0 ts=7.000000000,0 min=0,0 seq=0} ts=7.000000000,0 del=false klen=12 vlen=7 mergeTs= txnDidNotUpdateMeta=true +iter_scan: "j"/7.000000000,0=/BYTES/j7 +iter_scan: "j"/1.000000000,0=/ +iter_scan: "k"/5.000000000,0=/BYTES/k5 +iter_scan: "l"/5.000000000,0=/ +iter_scan: "n"/5.000000000,0=/ +iter_scan: "n"/3.000000000,0=/ +iter_scan: . + +run ok +iter_new types=pointsAndRanges pointSynthesis +iter_seek_lt k=z +iter_scan reverse +---- +iter_seek_lt: "n"/3.000000000,0=/ +iter_scan: "n"/3.000000000,0=/ +iter_scan: "n"/5.000000000,0=/ +iter_scan: "l"/5.000000000,0=/ +iter_scan: "k"/5.000000000,0=/BYTES/k5 +iter_scan: "j"/1.000000000,0=/ +iter_scan: "j"/7.000000000,0=/BYTES/j7 +iter_scan: "j"/0,0=txn={id=00000000 key=/Min pri=0.00000000 epo=0 ts=7.000000000,0 min=0,0 seq=0} ts=7.000000000,0 del=false klen=12 vlen=7 mergeTs= txnDidNotUpdateMeta=true +iter_scan: "h"/1.000000000,0=/ +iter_scan: "h"/3.000000000,0=/BYTES/h3 +iter_scan: "g"/2.000000000,0=/BYTES/g2 +iter_scan: "g"/3.000000000,0=vheader{ localTs=4.000000000,0 } / +iter_scan: "g"/4.000000000,0=/BYTES/g4 +iter_scan: "f"/2.000000000,0=/BYTES/f2 +iter_scan: "f"/3.000000000,0=vheader{ localTs=4.000000000,0 } / +iter_scan: "f"/4.000000000,0=/BYTES/f4 +iter_scan: "f"/5.000000000,0=/ +iter_scan: "f"/6.000000000,0=/BYTES/f6 +iter_scan: "e"/1.000000000,0=/ +iter_scan: "e"/3.000000000,0=/BYTES/e3 +iter_scan: "e"/5.000000000,0=/ +iter_scan: "d"/1.000000000,0=/ +iter_scan: "d"/4.000000000,0=/BYTES/d4 +iter_scan: "d"/5.000000000,0=/ +iter_scan: "d"/7.000000000,0=/BYTES/d7 +iter_scan: "d"/0,0=txn={id=00000000 key=/Min pri=0.00000000 epo=0 ts=7.000000000,0 min=0,0 seq=0} ts=7.000000000,0 del=false klen=12 vlen=7 mergeTs= txnDidNotUpdateMeta=true +iter_scan: "c"/1.000000000,0=/ +iter_scan: "c"/3.000000000,0=/ +iter_scan: "c"/5.000000000,0=/ +iter_scan: "b"/1.000000000,0=/ +iter_scan: "b"/3.000000000,0=/ +iter_scan: "b"/4.000000000,0=/ +iter_scan: "a"/1.000000000,0=/ +iter_scan: "a"/2.000000000,0=/BYTES/a2 +iter_scan: "a"/4.000000000,0=/ +iter_scan: . + +# Iterate across the entire span using NextKey(). +run ok +iter_new types=pointsAndRanges pointSynthesis +iter_seek_ge k=a +iter_next_key +iter_next_key +iter_next_key +iter_next_key +iter_next_key +iter_next_key +iter_next_key +iter_next_key +iter_next_key +iter_next_key +iter_next_key +iter_next_key +---- +iter_seek_ge: "a"/4.000000000,0=/ +iter_next_key: "b"/4.000000000,0=/ +iter_next_key: "c"/5.000000000,0=/ +iter_next_key: "d"/0,0=txn={id=00000000 key=/Min pri=0.00000000 epo=0 ts=7.000000000,0 min=0,0 seq=0} ts=7.000000000,0 del=false klen=12 vlen=7 mergeTs= txnDidNotUpdateMeta=true +iter_next_key: "e"/5.000000000,0=/ +iter_next_key: "f"/6.000000000,0=/BYTES/f6 +iter_next_key: "g"/4.000000000,0=/BYTES/g4 +iter_next_key: "h"/3.000000000,0=/BYTES/h3 +iter_next_key: "j"/0,0=txn={id=00000000 key=/Min pri=0.00000000 epo=0 ts=7.000000000,0 min=0,0 seq=0} ts=7.000000000,0 del=false klen=12 vlen=7 mergeTs= txnDidNotUpdateMeta=true +iter_next_key: "k"/5.000000000,0=/BYTES/k5 +iter_next_key: "l"/5.000000000,0=/ +iter_next_key: "n"/5.000000000,0=/ +iter_next_key: . + +# Unversioned seeks. +run ok +iter_new types=pointsAndRanges pointSynthesis +iter_seek_ge k=a +iter_seek_ge k=b +iter_seek_ge k=c +iter_seek_ge k=d +iter_seek_ge k=e +iter_seek_ge k=f +iter_seek_ge k=g +iter_seek_ge k=h +iter_seek_ge k=i +iter_seek_ge k=j +iter_seek_ge k=k +iter_seek_ge k=l +iter_seek_ge k=m +iter_seek_ge k=n +iter_seek_ge k=o +---- +iter_seek_ge: "a"/4.000000000,0=/ +iter_seek_ge: "b"/4.000000000,0=/ +iter_seek_ge: "c"/5.000000000,0=/ +iter_seek_ge: "d"/0,0=txn={id=00000000 key=/Min pri=0.00000000 epo=0 ts=7.000000000,0 min=0,0 seq=0} ts=7.000000000,0 del=false klen=12 vlen=7 mergeTs= txnDidNotUpdateMeta=true +iter_seek_ge: "e"/5.000000000,0=/ +iter_seek_ge: "f"/6.000000000,0=/BYTES/f6 +iter_seek_ge: "g"/4.000000000,0=/BYTES/g4 +iter_seek_ge: "h"/3.000000000,0=/BYTES/h3 +iter_seek_ge: "j"/0,0=txn={id=00000000 key=/Min pri=0.00000000 epo=0 ts=7.000000000,0 min=0,0 seq=0} ts=7.000000000,0 del=false klen=12 vlen=7 mergeTs= txnDidNotUpdateMeta=true +iter_seek_ge: "j"/0,0=txn={id=00000000 key=/Min pri=0.00000000 epo=0 ts=7.000000000,0 min=0,0 seq=0} ts=7.000000000,0 del=false klen=12 vlen=7 mergeTs= txnDidNotUpdateMeta=true +iter_seek_ge: "k"/5.000000000,0=/BYTES/k5 +iter_seek_ge: "l"/5.000000000,0=/ +iter_seek_ge: "n"/5.000000000,0=/ +iter_seek_ge: "n"/5.000000000,0=/ +iter_seek_ge: . + +run ok +iter_new types=pointsAndRanges pointSynthesis emitOnSeekGE +iter_seek_ge k=a +iter_seek_ge k=b +iter_seek_ge k=c +iter_seek_ge k=d +iter_seek_ge k=e +iter_seek_ge k=f +iter_seek_ge k=g +iter_seek_ge k=h +iter_seek_ge k=i +iter_seek_ge k=j +iter_seek_ge k=k +iter_seek_ge k=l +iter_seek_ge k=m +iter_seek_ge k=n +iter_seek_ge k=o +---- +iter_seek_ge: "a"/4.000000000,0=/ +iter_seek_ge: "b"/4.000000000,0=/ +iter_seek_ge: "c"/5.000000000,0=/ +iter_seek_ge: "d"/0,0=txn={id=00000000 key=/Min pri=0.00000000 epo=0 ts=7.000000000,0 min=0,0 seq=0} ts=7.000000000,0 del=false klen=12 vlen=7 mergeTs= txnDidNotUpdateMeta=true +iter_seek_ge: "e"/5.000000000,0=/ +iter_seek_ge: "f"/6.000000000,0=/BYTES/f6 +iter_seek_ge: "g"/4.000000000,0=/BYTES/g4 +iter_seek_ge: "h"/3.000000000,0=/BYTES/h3 +iter_seek_ge: "i"/1.000000000,0=/ +iter_seek_ge: "j"/0,0=txn={id=00000000 key=/Min pri=0.00000000 epo=0 ts=7.000000000,0 min=0,0 seq=0} ts=7.000000000,0 del=false klen=12 vlen=7 mergeTs= txnDidNotUpdateMeta=true +iter_seek_ge: "k"/5.000000000,0=/BYTES/k5 +iter_seek_ge: "l"/5.000000000,0=/ +iter_seek_ge: "m"/5.000000000,0=/ +iter_seek_ge: "n"/5.000000000,0=/ +iter_seek_ge: . + +run ok +iter_new types=pointsAndRanges pointSynthesis +iter_seek_lt k=o +iter_seek_lt k=n +iter_seek_lt k=m +iter_seek_lt k=l +iter_seek_lt k=k +iter_seek_lt k=j +iter_seek_lt k=i +iter_seek_lt k=h +iter_seek_lt k=g +iter_seek_lt k=f +iter_seek_lt k=e +iter_seek_lt k=d +iter_seek_lt k=c +iter_seek_lt k=b +iter_seek_lt k=a +---- +iter_seek_lt: "n"/3.000000000,0=/ +iter_seek_lt: "l"/5.000000000,0=/ +iter_seek_lt: "l"/5.000000000,0=/ +iter_seek_lt: "k"/5.000000000,0=/BYTES/k5 +iter_seek_lt: "j"/1.000000000,0=/ +iter_seek_lt: "h"/1.000000000,0=/ +iter_seek_lt: "h"/1.000000000,0=/ +iter_seek_lt: "g"/2.000000000,0=/BYTES/g2 +iter_seek_lt: "f"/2.000000000,0=/BYTES/f2 +iter_seek_lt: "e"/1.000000000,0=/ +iter_seek_lt: "d"/1.000000000,0=/ +iter_seek_lt: "c"/1.000000000,0=/ +iter_seek_lt: "b"/1.000000000,0=/ +iter_seek_lt: "a"/1.000000000,0=/ +iter_seek_lt: . + +run ok +iter_new types=pointsAndRanges pointSynthesis +iter_seek_intent_ge k=a txn=A +iter_seek_intent_ge k=b txn=A +iter_seek_intent_ge k=c txn=A +iter_seek_intent_ge k=d txn=A +iter_seek_intent_ge k=e txn=A +iter_seek_intent_ge k=f txn=A +iter_seek_intent_ge k=g txn=A +iter_seek_intent_ge k=h txn=A +iter_seek_intent_ge k=i txn=A +iter_seek_intent_ge k=j txn=A +iter_seek_intent_ge k=k txn=A +iter_seek_intent_ge k=l txn=A +iter_seek_intent_ge k=m txn=A +iter_seek_intent_ge k=n txn=A +iter_seek_intent_ge k=o txn=A +---- +iter_seek_intent_ge: "a"/4.000000000,0=/ +iter_seek_intent_ge: "b"/4.000000000,0=/ +iter_seek_intent_ge: "c"/5.000000000,0=/ +iter_seek_intent_ge: "d"/0,0=txn={id=00000000 key=/Min pri=0.00000000 epo=0 ts=7.000000000,0 min=0,0 seq=0} ts=7.000000000,0 del=false klen=12 vlen=7 mergeTs= txnDidNotUpdateMeta=true +iter_seek_intent_ge: "e"/5.000000000,0=/ +iter_seek_intent_ge: "f"/6.000000000,0=/BYTES/f6 +iter_seek_intent_ge: "g"/4.000000000,0=/BYTES/g4 +iter_seek_intent_ge: "h"/3.000000000,0=/BYTES/h3 +iter_seek_intent_ge: "j"/0,0=txn={id=00000000 key=/Min pri=0.00000000 epo=0 ts=7.000000000,0 min=0,0 seq=0} ts=7.000000000,0 del=false klen=12 vlen=7 mergeTs= txnDidNotUpdateMeta=true +iter_seek_intent_ge: "j"/0,0=txn={id=00000000 key=/Min pri=0.00000000 epo=0 ts=7.000000000,0 min=0,0 seq=0} ts=7.000000000,0 del=false klen=12 vlen=7 mergeTs= txnDidNotUpdateMeta=true +iter_seek_intent_ge: "k"/5.000000000,0=/BYTES/k5 +iter_seek_intent_ge: "l"/5.000000000,0=/ +iter_seek_intent_ge: "n"/5.000000000,0=/ +iter_seek_intent_ge: "n"/5.000000000,0=/ +iter_seek_intent_ge: . + +run ok +iter_new types=pointsAndRanges pointSynthesis emitOnSeekGE +iter_seek_intent_ge k=a txn=A +iter_seek_intent_ge k=b txn=A +iter_seek_intent_ge k=c txn=A +iter_seek_intent_ge k=d txn=A +iter_seek_intent_ge k=e txn=A +iter_seek_intent_ge k=f txn=A +iter_seek_intent_ge k=g txn=A +iter_seek_intent_ge k=h txn=A +iter_seek_intent_ge k=i txn=A +iter_seek_intent_ge k=j txn=A +iter_seek_intent_ge k=k txn=A +iter_seek_intent_ge k=l txn=A +iter_seek_intent_ge k=m txn=A +iter_seek_intent_ge k=n txn=A +iter_seek_intent_ge k=o txn=A +---- +iter_seek_intent_ge: "a"/4.000000000,0=/ +iter_seek_intent_ge: "b"/4.000000000,0=/ +iter_seek_intent_ge: "c"/5.000000000,0=/ +iter_seek_intent_ge: "d"/0,0=txn={id=00000000 key=/Min pri=0.00000000 epo=0 ts=7.000000000,0 min=0,0 seq=0} ts=7.000000000,0 del=false klen=12 vlen=7 mergeTs= txnDidNotUpdateMeta=true +iter_seek_intent_ge: "e"/5.000000000,0=/ +iter_seek_intent_ge: "f"/6.000000000,0=/BYTES/f6 +iter_seek_intent_ge: "g"/4.000000000,0=/BYTES/g4 +iter_seek_intent_ge: "h"/3.000000000,0=/BYTES/h3 +iter_seek_intent_ge: "i"/1.000000000,0=/ +iter_seek_intent_ge: "j"/0,0=txn={id=00000000 key=/Min pri=0.00000000 epo=0 ts=7.000000000,0 min=0,0 seq=0} ts=7.000000000,0 del=false klen=12 vlen=7 mergeTs= txnDidNotUpdateMeta=true +iter_seek_intent_ge: "k"/5.000000000,0=/BYTES/k5 +iter_seek_intent_ge: "l"/5.000000000,0=/ +iter_seek_intent_ge: "m"/5.000000000,0=/ +iter_seek_intent_ge: "n"/5.000000000,0=/ +iter_seek_intent_ge: . + +# Versioned seeks. +run ok +iter_new types=pointsAndRanges pointSynthesis +iter_seek_ge k=a ts=5 +iter_seek_ge k=a ts=4 +iter_seek_ge k=a ts=3 +iter_seek_ge k=a ts=2 +iter_seek_ge k=a ts=1 +---- +iter_seek_ge: "a"/4.000000000,0=/ +iter_seek_ge: "a"/4.000000000,0=/ +iter_seek_ge: "a"/2.000000000,0=/BYTES/a2 +iter_seek_ge: "a"/2.000000000,0=/BYTES/a2 +iter_seek_ge: "a"/1.000000000,0=/ + +run ok +iter_new types=pointsAndRanges pointSynthesis +iter_seek_ge k=b ts=5 +iter_seek_ge k=b ts=4 +iter_seek_ge k=b ts=3 +iter_seek_ge k=b ts=2 +iter_seek_ge k=b ts=1 +---- +iter_seek_ge: "b"/4.000000000,0=/ +iter_seek_ge: "b"/4.000000000,0=/ +iter_seek_ge: "b"/3.000000000,0=/ +iter_seek_ge: "b"/1.000000000,0=/ +iter_seek_ge: "b"/1.000000000,0=/ + +run ok +iter_new types=pointsAndRanges pointSynthesis +iter_seek_ge k=c ts=6 +iter_seek_ge k=c ts=5 +iter_seek_ge k=c ts=4 +iter_seek_ge k=c ts=3 +iter_seek_ge k=c ts=2 +iter_seek_ge k=c ts=1 +---- +iter_seek_ge: "c"/5.000000000,0=/ +iter_seek_ge: "c"/5.000000000,0=/ +iter_seek_ge: "c"/3.000000000,0=/ +iter_seek_ge: "c"/3.000000000,0=/ +iter_seek_ge: "c"/1.000000000,0=/ +iter_seek_ge: "c"/1.000000000,0=/ + +run ok +iter_new types=pointsAndRanges pointSynthesis +iter_seek_ge k=d ts=0 +iter_seek_ge k=d ts=8 +iter_seek_ge k=d ts=7 +iter_seek_ge k=d ts=6 +iter_seek_ge k=d ts=5 +iter_seek_ge k=d ts=4 +iter_seek_ge k=d ts=3 +iter_seek_ge k=d ts=2 +iter_seek_ge k=d ts=1 +---- +iter_seek_ge: "d"/0,0=txn={id=00000000 key=/Min pri=0.00000000 epo=0 ts=7.000000000,0 min=0,0 seq=0} ts=7.000000000,0 del=false klen=12 vlen=7 mergeTs= txnDidNotUpdateMeta=true +iter_seek_ge: "d"/7.000000000,0=/BYTES/d7 +iter_seek_ge: "d"/7.000000000,0=/BYTES/d7 +iter_seek_ge: "d"/5.000000000,0=/ +iter_seek_ge: "d"/5.000000000,0=/ +iter_seek_ge: "d"/4.000000000,0=/BYTES/d4 +iter_seek_ge: "d"/1.000000000,0=/ +iter_seek_ge: "d"/1.000000000,0=/ +iter_seek_ge: "d"/1.000000000,0=/ + +run ok +iter_new types=pointsAndRanges pointSynthesis +iter_seek_ge k=e ts=6 +iter_seek_ge k=e ts=5 +iter_seek_ge k=e ts=4 +iter_seek_ge k=e ts=3 +iter_seek_ge k=e ts=2 +iter_seek_ge k=e ts=1 +---- +iter_seek_ge: "e"/5.000000000,0=/ +iter_seek_ge: "e"/5.000000000,0=/ +iter_seek_ge: "e"/3.000000000,0=/BYTES/e3 +iter_seek_ge: "e"/3.000000000,0=/BYTES/e3 +iter_seek_ge: "e"/1.000000000,0=/ +iter_seek_ge: "e"/1.000000000,0=/ + +run ok +iter_new types=pointsAndRanges pointSynthesis +iter_seek_ge k=f ts=7 +iter_seek_ge k=f ts=6 +iter_seek_ge k=f ts=5 +iter_seek_ge k=f ts=4 +iter_seek_ge k=f ts=3 +iter_seek_ge k=f ts=2 +iter_seek_ge k=f ts=1 +---- +iter_seek_ge: "f"/6.000000000,0=/BYTES/f6 +iter_seek_ge: "f"/6.000000000,0=/BYTES/f6 +iter_seek_ge: "f"/5.000000000,0=/ +iter_seek_ge: "f"/4.000000000,0=/BYTES/f4 +iter_seek_ge: "f"/3.000000000,0=vheader{ localTs=4.000000000,0 } / +iter_seek_ge: "f"/2.000000000,0=/BYTES/f2 +iter_seek_ge: "g"/4.000000000,0=/BYTES/g4 + +run ok +iter_new types=pointsAndRanges pointSynthesis +iter_seek_ge k=g ts=6 +iter_seek_ge k=g ts=5 +iter_seek_ge k=g ts=4 +iter_seek_ge k=g ts=3 +iter_seek_ge k=g ts=2 +iter_seek_ge k=g ts=1 +---- +iter_seek_ge: "g"/4.000000000,0=/BYTES/g4 +iter_seek_ge: "g"/4.000000000,0=/BYTES/g4 +iter_seek_ge: "g"/4.000000000,0=/BYTES/g4 +iter_seek_ge: "g"/3.000000000,0=vheader{ localTs=4.000000000,0 } / +iter_seek_ge: "g"/2.000000000,0=/BYTES/g2 +iter_seek_ge: "h"/3.000000000,0=/BYTES/h3 + +run ok +iter_new types=pointsAndRanges pointSynthesis +iter_seek_ge k=h ts=4 +iter_seek_ge k=h ts=3 +iter_seek_ge k=h ts=2 +iter_seek_ge k=h ts=1 +---- +iter_seek_ge: "h"/3.000000000,0=/BYTES/h3 +iter_seek_ge: "h"/3.000000000,0=/BYTES/h3 +iter_seek_ge: "h"/1.000000000,0=/ +iter_seek_ge: "h"/1.000000000,0=/ + +run ok +iter_new types=pointsAndRanges pointSynthesis +iter_seek_ge k=i ts=2 +iter_seek_ge k=i ts=1 +---- +iter_seek_ge: "j"/0,0=txn={id=00000000 key=/Min pri=0.00000000 epo=0 ts=7.000000000,0 min=0,0 seq=0} ts=7.000000000,0 del=false klen=12 vlen=7 mergeTs= txnDidNotUpdateMeta=true +iter_seek_ge: "j"/0,0=txn={id=00000000 key=/Min pri=0.00000000 epo=0 ts=7.000000000,0 min=0,0 seq=0} ts=7.000000000,0 del=false klen=12 vlen=7 mergeTs= txnDidNotUpdateMeta=true + +run ok +iter_new types=pointsAndRanges pointSynthesis +iter_seek_ge k=j ts=8 +iter_seek_ge k=j ts=7 +iter_seek_ge k=j ts=6 +iter_seek_ge k=j ts=1 +---- +iter_seek_ge: "j"/7.000000000,0=/BYTES/j7 +iter_seek_ge: "j"/7.000000000,0=/BYTES/j7 +iter_seek_ge: "j"/1.000000000,0=/ +iter_seek_ge: "j"/1.000000000,0=/ + +run ok +iter_new types=pointsAndRanges pointSynthesis +iter_seek_ge k=k ts=6 +iter_seek_ge k=k ts=5 +iter_seek_ge k=k ts=4 +---- +iter_seek_ge: "k"/5.000000000,0=/BYTES/k5 +iter_seek_ge: "k"/5.000000000,0=/BYTES/k5 +iter_seek_ge: "l"/5.000000000,0=/ + +run ok +iter_new types=pointsAndRanges pointSynthesis +iter_seek_ge k=l ts=6 +iter_seek_ge k=l ts=5 +iter_seek_ge k=l ts=4 +---- +iter_seek_ge: "l"/5.000000000,0=/ +iter_seek_ge: "l"/5.000000000,0=/ +iter_seek_ge: "n"/5.000000000,0=/ + +run ok +iter_new types=pointsAndRanges pointSynthesis +iter_seek_ge k=m ts=6 +iter_seek_ge k=m ts=5 +iter_seek_ge k=m ts=4 +---- +iter_seek_ge: "n"/5.000000000,0=/ +iter_seek_ge: "n"/5.000000000,0=/ +iter_seek_ge: "n"/5.000000000,0=/ + +run ok +iter_new types=pointsAndRanges pointSynthesis +iter_seek_ge k=n ts=6 +iter_seek_ge k=n ts=5 +iter_seek_ge k=n ts=4 +iter_seek_ge k=n ts=3 +iter_seek_ge k=n ts=2 +---- +iter_seek_ge: "n"/5.000000000,0=/ +iter_seek_ge: "n"/5.000000000,0=/ +iter_seek_ge: "n"/3.000000000,0=/ +iter_seek_ge: "n"/3.000000000,0=/ +iter_seek_ge: . + +run ok +iter_new types=pointsAndRanges pointSynthesis +iter_seek_ge k=o ts=6 +iter_seek_ge k=o ts=5 +iter_seek_ge k=o ts=4 +iter_seek_ge k=o ts=3 +---- +iter_seek_ge: . +iter_seek_ge: . +iter_seek_ge: . +iter_seek_ge: . + +# Versioned seeks with emitOnSeekGE. +run ok +iter_new types=pointsAndRanges pointSynthesis emitOnSeekGE +iter_seek_ge k=l ts=6 +iter_seek_ge k=l ts=5 +iter_seek_ge k=l ts=4 +---- +iter_seek_ge: "l"/5.000000000,0=/ +iter_seek_ge: "l"/5.000000000,0=/ +iter_seek_ge: "n"/5.000000000,0=/ + +run ok +iter_new types=pointsAndRanges pointSynthesis emitOnSeekGE +iter_seek_ge k=m ts=6 +iter_seek_ge k=m ts=5 +iter_seek_ge k=m ts=4 +---- +iter_seek_ge: "m"/5.000000000,0=/ +iter_seek_ge: "m"/5.000000000,0=/ +iter_seek_ge: "n"/5.000000000,0=/ + +run ok +iter_new types=pointsAndRanges pointSynthesis emitOnSeekGE +iter_seek_ge k=n ts=6 +iter_seek_ge k=n ts=5 +iter_seek_ge k=n ts=4 +iter_seek_ge k=n ts=3 +---- +iter_seek_ge: "n"/5.000000000,0=/ +iter_seek_ge: "n"/5.000000000,0=/ +iter_seek_ge: "n"/3.000000000,0=/ +iter_seek_ge: "n"/3.000000000,0=/ + +run ok +iter_new types=pointsAndRanges pointSynthesis emitOnSeekGE +iter_seek_ge k=o ts=6 +iter_seek_ge k=o ts=5 +iter_seek_ge k=o ts=4 +---- +iter_seek_ge: . +iter_seek_ge: . +iter_seek_ge: . + +# Versioned reverse seeks. +run ok +iter_new types=pointsAndRanges pointSynthesis +iter_seek_lt k=a ts=1 +iter_seek_lt k=a ts=2 +iter_seek_lt k=a ts=3 +iter_seek_lt k=a ts=4 +iter_seek_lt k=a ts=5 +---- +iter_seek_lt: "a"/2.000000000,0=/BYTES/a2 +iter_seek_lt: "a"/4.000000000,0=/ +iter_seek_lt: "a"/4.000000000,0=/ +iter_seek_lt: . +iter_seek_lt: . + +run ok +iter_new types=pointsAndRanges pointSynthesis +iter_seek_lt k=b ts=1 +iter_seek_lt k=b ts=2 +iter_seek_lt k=b ts=3 +iter_seek_lt k=b ts=4 +iter_seek_lt k=b ts=5 +---- +iter_seek_lt: "b"/3.000000000,0=/ +iter_seek_lt: "b"/3.000000000,0=/ +iter_seek_lt: "b"/4.000000000,0=/ +iter_seek_lt: "a"/1.000000000,0=/ +iter_seek_lt: "a"/1.000000000,0=/ + +run ok +iter_new types=pointsAndRanges pointSynthesis +iter_seek_lt k=c ts=1 +iter_seek_lt k=c ts=2 +iter_seek_lt k=c ts=3 +iter_seek_lt k=c ts=4 +iter_seek_lt k=c ts=5 +iter_seek_lt k=c ts=6 +---- +iter_seek_lt: "c"/3.000000000,0=/ +iter_seek_lt: "c"/3.000000000,0=/ +iter_seek_lt: "c"/5.000000000,0=/ +iter_seek_lt: "c"/5.000000000,0=/ +iter_seek_lt: "b"/1.000000000,0=/ +iter_seek_lt: "b"/1.000000000,0=/ + +run ok +iter_new types=pointsAndRanges pointSynthesis +iter_seek_lt k=d ts=1 +iter_seek_lt k=d ts=2 +iter_seek_lt k=d ts=3 +iter_seek_lt k=d ts=4 +iter_seek_lt k=d ts=5 +iter_seek_lt k=d ts=6 +iter_seek_lt k=d ts=7 +iter_seek_lt k=d ts=8 +---- +iter_seek_lt: "d"/4.000000000,0=/BYTES/d4 +iter_seek_lt: "d"/4.000000000,0=/BYTES/d4 +iter_seek_lt: "d"/4.000000000,0=/BYTES/d4 +iter_seek_lt: "d"/5.000000000,0=/ +iter_seek_lt: "d"/7.000000000,0=/BYTES/d7 +iter_seek_lt: "d"/7.000000000,0=/BYTES/d7 +iter_seek_lt: "d"/0,0=txn={id=00000000 key=/Min pri=0.00000000 epo=0 ts=7.000000000,0 min=0,0 seq=0} ts=7.000000000,0 del=false klen=12 vlen=7 mergeTs= txnDidNotUpdateMeta=true +iter_seek_lt: "d"/0,0=txn={id=00000000 key=/Min pri=0.00000000 epo=0 ts=7.000000000,0 min=0,0 seq=0} ts=7.000000000,0 del=false klen=12 vlen=7 mergeTs= txnDidNotUpdateMeta=true + +run ok +iter_new types=pointsAndRanges pointSynthesis +iter_seek_lt k=e ts=1 +iter_seek_lt k=e ts=2 +iter_seek_lt k=e ts=3 +iter_seek_lt k=e ts=4 +iter_seek_lt k=e ts=5 +iter_seek_lt k=e ts=6 +---- +iter_seek_lt: "e"/3.000000000,0=/BYTES/e3 +iter_seek_lt: "e"/3.000000000,0=/BYTES/e3 +iter_seek_lt: "e"/5.000000000,0=/ +iter_seek_lt: "e"/5.000000000,0=/ +iter_seek_lt: "d"/1.000000000,0=/ +iter_seek_lt: "d"/1.000000000,0=/ + +run ok +iter_new types=pointsAndRanges pointSynthesis +iter_seek_lt k=f ts=1 +iter_seek_lt k=f ts=2 +iter_seek_lt k=f ts=3 +iter_seek_lt k=f ts=4 +iter_seek_lt k=f ts=5 +iter_seek_lt k=f ts=6 +iter_seek_lt k=f ts=7 +---- +iter_seek_lt: "f"/2.000000000,0=/BYTES/f2 +iter_seek_lt: "f"/3.000000000,0=vheader{ localTs=4.000000000,0 } / +iter_seek_lt: "f"/4.000000000,0=/BYTES/f4 +iter_seek_lt: "f"/5.000000000,0=/ +iter_seek_lt: "f"/6.000000000,0=/BYTES/f6 +iter_seek_lt: "e"/1.000000000,0=/ +iter_seek_lt: "e"/1.000000000,0=/ + +run ok +iter_new types=pointsAndRanges pointSynthesis +iter_seek_lt k=g ts=1 +iter_seek_lt k=g ts=2 +iter_seek_lt k=g ts=3 +iter_seek_lt k=g ts=4 +iter_seek_lt k=g ts=5 +iter_seek_lt k=g ts=6 +---- +iter_seek_lt: "g"/2.000000000,0=/BYTES/g2 +iter_seek_lt: "g"/3.000000000,0=vheader{ localTs=4.000000000,0 } / +iter_seek_lt: "g"/4.000000000,0=/BYTES/g4 +iter_seek_lt: "f"/2.000000000,0=/BYTES/f2 +iter_seek_lt: "f"/2.000000000,0=/BYTES/f2 +iter_seek_lt: "f"/2.000000000,0=/BYTES/f2 + +run ok +iter_new types=pointsAndRanges pointSynthesis +iter_seek_lt k=h ts=1 +iter_seek_lt k=h ts=2 +iter_seek_lt k=h ts=3 +iter_seek_lt k=h ts=4 +---- +iter_seek_lt: "h"/3.000000000,0=/BYTES/h3 +iter_seek_lt: "h"/3.000000000,0=/BYTES/h3 +iter_seek_lt: "g"/2.000000000,0=/BYTES/g2 +iter_seek_lt: "g"/2.000000000,0=/BYTES/g2 + +run ok +iter_new types=pointsAndRanges pointSynthesis +iter_seek_lt k=i ts=1 +iter_seek_lt k=i ts=2 +---- +iter_seek_lt: "h"/1.000000000,0=/ +iter_seek_lt: "h"/1.000000000,0=/ + +run ok +iter_new types=pointsAndRanges pointSynthesis +iter_seek_lt k=j ts=1 +iter_seek_lt k=j ts=6 +iter_seek_lt k=j ts=7 +iter_seek_lt k=j ts=8 +---- +iter_seek_lt: "j"/7.000000000,0=/BYTES/j7 +iter_seek_lt: "j"/7.000000000,0=/BYTES/j7 +iter_seek_lt: "j"/0,0=txn={id=00000000 key=/Min pri=0.00000000 epo=0 ts=7.000000000,0 min=0,0 seq=0} ts=7.000000000,0 del=false klen=12 vlen=7 mergeTs= txnDidNotUpdateMeta=true +iter_seek_lt: "j"/0,0=txn={id=00000000 key=/Min pri=0.00000000 epo=0 ts=7.000000000,0 min=0,0 seq=0} ts=7.000000000,0 del=false klen=12 vlen=7 mergeTs= txnDidNotUpdateMeta=true + +run ok +iter_new types=pointsAndRanges pointSynthesis +iter_seek_lt k=k ts=1 +iter_seek_lt k=k ts=4 +iter_seek_lt k=k ts=5 +iter_seek_lt k=k ts=6 +---- +iter_seek_lt: "k"/5.000000000,0=/BYTES/k5 +iter_seek_lt: "k"/5.000000000,0=/BYTES/k5 +iter_seek_lt: "j"/1.000000000,0=/ +iter_seek_lt: "j"/1.000000000,0=/ + +run ok +iter_new types=pointsAndRanges pointSynthesis +iter_seek_lt k=l ts=4 +iter_seek_lt k=l ts=5 +iter_seek_lt k=l ts=6 +---- +iter_seek_lt: "l"/5.000000000,0=/ +iter_seek_lt: "k"/5.000000000,0=/BYTES/k5 +iter_seek_lt: "k"/5.000000000,0=/BYTES/k5 + +run ok +iter_new types=pointsAndRanges pointSynthesis +iter_seek_lt k=l ts=4 +iter_seek_lt k=l ts=5 +iter_seek_lt k=l ts=6 +---- +iter_seek_lt: "l"/5.000000000,0=/ +iter_seek_lt: "k"/5.000000000,0=/BYTES/k5 +iter_seek_lt: "k"/5.000000000,0=/BYTES/k5 + +run ok +iter_new types=pointsAndRanges pointSynthesis +iter_seek_lt k=m ts=4 +iter_seek_lt k=m ts=5 +iter_seek_lt k=m ts=6 +---- +iter_seek_lt: "l"/5.000000000,0=/ +iter_seek_lt: "l"/5.000000000,0=/ +iter_seek_lt: "l"/5.000000000,0=/ + +run ok +iter_new types=pointsAndRanges pointSynthesis +iter_seek_lt k=n ts=2 +iter_seek_lt k=n ts=3 +iter_seek_lt k=n ts=4 +iter_seek_lt k=n ts=5 +iter_seek_lt k=n ts=6 +---- +iter_seek_lt: "n"/3.000000000,0=/ +iter_seek_lt: "n"/5.000000000,0=/ +iter_seek_lt: "n"/5.000000000,0=/ +iter_seek_lt: "l"/5.000000000,0=/ +iter_seek_lt: "l"/5.000000000,0=/ + +run ok +iter_new types=pointsAndRanges pointSynthesis +iter_seek_lt k=o ts=1 +---- +iter_seek_lt: "n"/3.000000000,0=/ + +# Seeks with opposite scans. +run ok +iter_new types=pointsAndRanges pointSynthesis +iter_seek_ge k=d +iter_scan reverse +---- +iter_seek_ge: "d"/0,0=txn={id=00000000 key=/Min pri=0.00000000 epo=0 ts=7.000000000,0 min=0,0 seq=0} ts=7.000000000,0 del=false klen=12 vlen=7 mergeTs= txnDidNotUpdateMeta=true +iter_scan: "d"/0,0=txn={id=00000000 key=/Min pri=0.00000000 epo=0 ts=7.000000000,0 min=0,0 seq=0} ts=7.000000000,0 del=false klen=12 vlen=7 mergeTs= txnDidNotUpdateMeta=true +iter_scan: "c"/1.000000000,0=/ +iter_scan: "c"/3.000000000,0=/ +iter_scan: "c"/5.000000000,0=/ +iter_scan: "b"/1.000000000,0=/ +iter_scan: "b"/3.000000000,0=/ +iter_scan: "b"/4.000000000,0=/ +iter_scan: "a"/1.000000000,0=/ +iter_scan: "a"/2.000000000,0=/BYTES/a2 +iter_scan: "a"/4.000000000,0=/ +iter_scan: . + +run ok +iter_new types=pointsAndRanges pointSynthesis +iter_seek_ge k=d ts=5 +iter_scan reverse +---- +iter_seek_ge: "d"/5.000000000,0=/ +iter_scan: "d"/5.000000000,0=/ +iter_scan: "d"/7.000000000,0=/BYTES/d7 +iter_scan: "d"/0,0=txn={id=00000000 key=/Min pri=0.00000000 epo=0 ts=7.000000000,0 min=0,0 seq=0} ts=7.000000000,0 del=false klen=12 vlen=7 mergeTs= txnDidNotUpdateMeta=true +iter_scan: "c"/1.000000000,0=/ +iter_scan: "c"/3.000000000,0=/ +iter_scan: "c"/5.000000000,0=/ +iter_scan: "b"/1.000000000,0=/ +iter_scan: "b"/3.000000000,0=/ +iter_scan: "b"/4.000000000,0=/ +iter_scan: "a"/1.000000000,0=/ +iter_scan: "a"/2.000000000,0=/BYTES/a2 +iter_scan: "a"/4.000000000,0=/ +iter_scan: . + +run ok +iter_new types=pointsAndRanges pointSynthesis +iter_seek_lt k=g +iter_scan +---- +iter_seek_lt: "f"/2.000000000,0=/BYTES/f2 +iter_scan: "f"/2.000000000,0=/BYTES/f2 +iter_scan: "g"/4.000000000,0=/BYTES/g4 +iter_scan: "g"/3.000000000,0=vheader{ localTs=4.000000000,0 } / +iter_scan: "g"/2.000000000,0=/BYTES/g2 +iter_scan: "h"/3.000000000,0=/BYTES/h3 +iter_scan: "h"/1.000000000,0=/ +iter_scan: "j"/0,0=txn={id=00000000 key=/Min pri=0.00000000 epo=0 ts=7.000000000,0 min=0,0 seq=0} ts=7.000000000,0 del=false klen=12 vlen=7 mergeTs= txnDidNotUpdateMeta=true +iter_scan: "j"/7.000000000,0=/BYTES/j7 +iter_scan: "j"/1.000000000,0=/ +iter_scan: "k"/5.000000000,0=/BYTES/k5 +iter_scan: "l"/5.000000000,0=/ +iter_scan: "n"/5.000000000,0=/ +iter_scan: "n"/3.000000000,0=/ +iter_scan: . + +run ok +iter_new types=pointsAndRanges pointSynthesis +iter_seek_lt k=g ts=2 +iter_scan +---- +iter_seek_lt: "g"/3.000000000,0=vheader{ localTs=4.000000000,0 } / +iter_scan: "g"/3.000000000,0=vheader{ localTs=4.000000000,0 } / +iter_scan: "g"/2.000000000,0=/BYTES/g2 +iter_scan: "h"/3.000000000,0=/BYTES/h3 +iter_scan: "h"/1.000000000,0=/ +iter_scan: "j"/0,0=txn={id=00000000 key=/Min pri=0.00000000 epo=0 ts=7.000000000,0 min=0,0 seq=0} ts=7.000000000,0 del=false klen=12 vlen=7 mergeTs= txnDidNotUpdateMeta=true +iter_scan: "j"/7.000000000,0=/BYTES/j7 +iter_scan: "j"/1.000000000,0=/ +iter_scan: "k"/5.000000000,0=/BYTES/k5 +iter_scan: "l"/5.000000000,0=/ +iter_scan: "n"/5.000000000,0=/ +iter_scan: "n"/3.000000000,0=/ +iter_scan: . + +# Try some direction changes. +run ok +iter_new types=pointsAndRanges pointSynthesis +iter_seek_ge k=e ts=4 +iter_prev +iter_next +iter_next +iter_prev +---- +iter_seek_ge: "e"/3.000000000,0=/BYTES/e3 +iter_prev: "e"/5.000000000,0=/ +iter_next: "e"/3.000000000,0=/BYTES/e3 +iter_next: "e"/1.000000000,0=/ +iter_prev: "e"/3.000000000,0=/BYTES/e3 + +run ok +iter_new types=pointsAndRanges pointSynthesis +iter_seek_lt k=e ts=4 +iter_next +iter_prev +iter_prev +iter_next +---- +iter_seek_lt: "e"/5.000000000,0=/ +iter_next: "e"/3.000000000,0=/BYTES/e3 +iter_prev: "e"/5.000000000,0=/ +iter_prev: "d"/1.000000000,0=/ +iter_next: "e"/5.000000000,0=/ + +run ok +iter_new kind=keys types=pointsAndRanges pointSynthesis +iter_seek_ge k=e ts=4 +iter_prev +iter_prev +iter_next_key +iter_next +iter_next_key +iter_prev +iter_prev +iter_next_key +iter_next +---- +iter_seek_ge: "e"/3.000000000,0=/BYTES/e3 +iter_prev: "e"/5.000000000,0=/ +iter_prev: "d"/1.000000000,0=/ +iter_next_key: "e"/5.000000000,0=/ +iter_next: "e"/3.000000000,0=/BYTES/e3 +iter_next_key: "f"/6.000000000,0=/BYTES/f6 +iter_prev: "e"/1.000000000,0=/ +iter_prev: "e"/3.000000000,0=/BYTES/e3 +iter_next_key: "f"/6.000000000,0=/BYTES/f6 +iter_next: "f"/5.000000000,0=/ + +run ok +iter_new kind=keys types=pointsAndRanges pointSynthesis +iter_seek_ge k=k ts=4 +iter_next_key +iter_prev +iter_next_key +iter_next +iter_prev +---- +iter_seek_ge: "l"/5.000000000,0=/ +iter_next_key: "n"/5.000000000,0=/ +iter_prev: "l"/5.000000000,0=/ +iter_next_key: "n"/5.000000000,0=/ +iter_next: "n"/3.000000000,0=/ +iter_prev: "n"/5.000000000,0=/ + +run ok +iter_new kind=keys types=pointsAndRanges pointSynthesis +iter_seek_ge k=e ts=3 +iter_prev +iter_next_key +---- +iter_seek_ge: "e"/3.000000000,0=/BYTES/e3 +iter_prev: "e"/5.000000000,0=/ +iter_next_key: "f"/6.000000000,0=/BYTES/f6 + +# Exhausting the iterator then reversing should work in both directions, +# both after a seek and after a step. +run ok +iter_new types=pointsAndRanges pointSynthesis +iter_seek_lt k=a +iter_next +---- +iter_seek_lt: . +iter_next: "a"/4.000000000,0=/ + +run ok +iter_new kind=keys types=pointsAndRanges pointSynthesis +iter_seek_lt k=a +iter_next_key +---- +iter_seek_lt: . +iter_next_key: "a"/4.000000000,0=/ + +run ok +iter_new types=pointsAndRanges pointSynthesis +iter_seek_ge k=z +iter_prev +---- +iter_seek_ge: . +iter_prev: "n"/3.000000000,0=/ + +run ok +iter_new types=pointsAndRanges pointSynthesis +iter_seek_lt k=z +iter_next +iter_next +iter_prev +---- +iter_seek_lt: "n"/3.000000000,0=/ +iter_next: . +iter_next: . +iter_prev: "n"/3.000000000,0=/ + +run ok +iter_new kind=keys types=pointsAndRanges pointSynthesis +iter_seek_lt k=z +iter_next_key +iter_next_key +iter_prev +---- +iter_seek_lt: "n"/3.000000000,0=/ +iter_next_key: . +iter_next_key: . +iter_prev: "n"/3.000000000,0=/ + +run ok +iter_new types=pointsAndRanges pointSynthesis +iter_seek_ge k=a +iter_prev +iter_prev +iter_next +---- +iter_seek_ge: "a"/4.000000000,0=/ +iter_prev: . +iter_prev: . +iter_next: "a"/4.000000000,0=/ + +run ok +iter_new kind=keys types=pointsAndRanges pointSynthesis +iter_seek_ge k=a +iter_prev +iter_prev +iter_next_key +---- +iter_seek_ge: "a"/4.000000000,0=/ +iter_prev: . +iter_prev: . +iter_next_key: "a"/4.000000000,0=/ From 7dfd13265c400f822d3a93f33998a14a4482a34e Mon Sep 17 00:00:00 2001 From: irfan sharif Date: Wed, 8 Jun 2022 17:47:16 -0400 Subject: [PATCH 3/3] bazel: unlist unsupported os+arch combos We don't support these for CRDB builds. Even windows is experimental, but lets keep that around anyway since we publish binaries for it. Release note: None --- WORKSPACE | 7 ------- build/bazelutil/distdir_files.bzl | 7 ------- 2 files changed, 14 deletions(-) diff --git a/WORKSPACE b/WORKSPACE index 6fdc12466ca1..13b53ee14433 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -160,17 +160,10 @@ go_download_sdk( sdks = { "darwin_amd64": ("go1.17.10.darwin-amd64.tar.gz", "84979d5985c70cee6f303050a7e811440aad7f304efdf28665b200f096b01945"), "darwin_arm64": ("go1.17.10.darwin-arm64.tar.gz", "32098bea40117ea1ec23e7124cd188db6bdddd0ea41e2ec9bea3ba35a487e39c"), - "freebsd_386": ("go1.17.10.freebsd-386.tar.gz", "37f005846d70f477e89fcf7279f8869c28ba1d266cebf794d2f7a79a1e2127ec"), "freebsd_amd64": ("go1.17.10.freebsd-amd64.tar.gz", "33794d96f58608fdc023c5114ae9baeeb4111a74720c8830ff25029debe508f0"), - "linux_386": ("go1.17.10.linux-386.tar.gz", "5c45aad27c3091b07517ed57df5650dad5b3b71111cebdf83153878f140ad981"), "linux_amd64": ("go1.17.10.linux-amd64.tar.gz", "87fc728c9c731e2f74e4a999ef53cf07302d7ed3504b0839027bd9c10edaa3fd"), "linux_arm64": ("go1.17.10.linux-arm64.tar.gz", "649141201efa7195403eb1301b95dc79c5b3e65968986a391da1370521701b0c"), - "linux_armv6l": ("go1.17.10.linux-armv6l.tar.gz", "ad2d9053011c24be07c39f337f4a31987381d905874acbf2570511e050418dd3"), - "linux_ppc64le": ("go1.17.10.linux-ppc64le.tar.gz", "4e2310864fa9d5a4e2d589dbc5fcd98ce8c4cd25320b335efed04dc67765e66c"), - "linux_s390x": ("go1.17.10.linux-s390x.tar.gz", "e1df61f29fb0962b89d7bfe18b7db45eee003d5f8a1a7ff4d9e54616689076bf"), - "windows_386": ("go1.17.10.windows-386.zip", "60840a079a04c838dc44b7d48f74ac37506298d34d2a002ced48831ccce6bdae"), "windows_amd64": ("go1.17.10.windows-amd64.zip", "ba9198a29fa5c4f322212d21569e8507165c3b34e1ed1f1f9cf6dfb71ddcdeb2"), - "windows_arm64": ("go1.17.10.windows-arm64.zip", "9d06da8d3e9c3f4a5905c4ea9cb271294e2ff956926380322feb2561e84b4d68"), }, urls = ["https://storage.googleapis.com/public-bazel-artifacts/go/{}"], version = "1.17.10", diff --git a/build/bazelutil/distdir_files.bzl b/build/bazelutil/distdir_files.bzl index b241c9b69fb3..d3d750437e2b 100644 --- a/build/bazelutil/distdir_files.bzl +++ b/build/bazelutil/distdir_files.bzl @@ -975,17 +975,10 @@ DISTDIR_FILES = { "https://storage.googleapis.com/public-bazel-artifacts/c-deps/20220520-181309/libproj_foreign.windows.20220520-181309.tar.gz": "4d935601d1b989ff020c66011355a0e2985abacf36f9d952f7f1ce34d54684ad", "https://storage.googleapis.com/public-bazel-artifacts/go/go1.17.10.darwin-amd64.tar.gz": "84979d5985c70cee6f303050a7e811440aad7f304efdf28665b200f096b01945", "https://storage.googleapis.com/public-bazel-artifacts/go/go1.17.10.darwin-arm64.tar.gz": "32098bea40117ea1ec23e7124cd188db6bdddd0ea41e2ec9bea3ba35a487e39c", - "https://storage.googleapis.com/public-bazel-artifacts/go/go1.17.10.freebsd-386.tar.gz": "37f005846d70f477e89fcf7279f8869c28ba1d266cebf794d2f7a79a1e2127ec", "https://storage.googleapis.com/public-bazel-artifacts/go/go1.17.10.freebsd-amd64.tar.gz": "33794d96f58608fdc023c5114ae9baeeb4111a74720c8830ff25029debe508f0", - "https://storage.googleapis.com/public-bazel-artifacts/go/go1.17.10.linux-386.tar.gz": "5c45aad27c3091b07517ed57df5650dad5b3b71111cebdf83153878f140ad981", "https://storage.googleapis.com/public-bazel-artifacts/go/go1.17.10.linux-amd64.tar.gz": "87fc728c9c731e2f74e4a999ef53cf07302d7ed3504b0839027bd9c10edaa3fd", "https://storage.googleapis.com/public-bazel-artifacts/go/go1.17.10.linux-arm64.tar.gz": "649141201efa7195403eb1301b95dc79c5b3e65968986a391da1370521701b0c", - "https://storage.googleapis.com/public-bazel-artifacts/go/go1.17.10.linux-armv6l.tar.gz": "ad2d9053011c24be07c39f337f4a31987381d905874acbf2570511e050418dd3", - "https://storage.googleapis.com/public-bazel-artifacts/go/go1.17.10.linux-ppc64le.tar.gz": "4e2310864fa9d5a4e2d589dbc5fcd98ce8c4cd25320b335efed04dc67765e66c", - "https://storage.googleapis.com/public-bazel-artifacts/go/go1.17.10.linux-s390x.tar.gz": "e1df61f29fb0962b89d7bfe18b7db45eee003d5f8a1a7ff4d9e54616689076bf", - "https://storage.googleapis.com/public-bazel-artifacts/go/go1.17.10.windows-386.zip": "60840a079a04c838dc44b7d48f74ac37506298d34d2a002ced48831ccce6bdae", "https://storage.googleapis.com/public-bazel-artifacts/go/go1.17.10.windows-amd64.zip": "ba9198a29fa5c4f322212d21569e8507165c3b34e1ed1f1f9cf6dfb71ddcdeb2", - "https://storage.googleapis.com/public-bazel-artifacts/go/go1.17.10.windows-arm64.zip": "9d06da8d3e9c3f4a5905c4ea9cb271294e2ff956926380322feb2561e84b4d68", "https://storage.googleapis.com/public-bazel-artifacts/gomod/github.com/bazelbuild/buildtools/v0.0.0-20200718160251-b1667ff58f71/buildtools-v0.0.0-20200718160251-b1667ff58f71.tar.gz": "a9ef5103739dfb5ed2a5b47ab1654842a89695812e4af09e57d7015a5caf97e0", "https://storage.googleapis.com/public-bazel-artifacts/java/railroad/rr-1.63-java8.zip": "d2791cd7a44ea5be862f33f5a9b3d40aaad9858455828ebade7007ad7113fb41", "https://storage.googleapis.com/public-bazel-artifacts/js/node/v16.13.0/node-v16.13.0-darwin-arm64.tar.gz": "46d83fc0bd971db5050ef1b15afc44a6665dee40bd6c1cbaec23e1b40fa49e6d",