-
Notifications
You must be signed in to change notification settings - Fork 3.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
apiutil, roachpb: create utilities to map descriptors to ranges
Previously each range correlated to a single table, or even a single index in a database, so all that was required to identify which tables, indexes were in the range were to look at the start key of the range and map it accordingly. With range coalescing however, it's possible for one, or many, tables, indexes and the like to reside within the same range. To properly identify the contents of a range, this PR adds the following utilities: 1. A utility function which turns a range into a span, and clamps it to its tenant's table space. 2. A utility function which takes the above spans and uses the catalog and new descriptor by span utility to turn those spans into a set of table descriptors ordered by id. 3. A utility function which transforms those table descriptors into a set of (database, table, index) names which deduplicate and identify each index uniquely. 4. A utility function, which merges the ranges and indexes into a map keyed by RangeID whose values are the above index names. 5. A primary entrypoint for consumers from which a set of ranges can be passed in and a mapping from those ranges to indexes can be returned. A variety of caveats come with this approach. It attempts to scan the desciptors all at once, but it still will scan a sizable portion of the descriptors table if the request is large enough. This makes no attempt to describe system information which does not have a descriptor. It will describe system tables which appear in the descriptors table, but it will not try to explain "tables" which do not have descriptors (example tsdb), or any other information stored in the keyspace without a descriptor (PseudoTableIDs, GossipKeys for example). Throughout this work, many existing utilities were duplicated, and then un-duplicated (`keys.TableDataMin`, `roachpb.Span.Overlap`, etc). If you see anything that seems to already exist, feel free to point it out accordingly. Epic: CRDB-43151 Fixes: #130997 Release note: None
- Loading branch information
1 parent
10b9ee0
commit 0ee1828
Showing
10 changed files
with
714 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
// Copyright 2024 The Cockroach Authors. | ||
// | ||
// Use of this software is governed by the CockroachDB Software License | ||
// included in the /LICENSE file. | ||
|
||
package roachpb_test | ||
|
||
import ( | ||
"math" | ||
"testing" | ||
|
||
"github.com/cockroachdb/cockroach/pkg/keys" | ||
"github.com/cockroachdb/cockroach/pkg/roachpb" | ||
"github.com/cockroachdb/cockroach/pkg/util/encoding" | ||
) | ||
|
||
func TestKeyClampTenants(t *testing.T) { | ||
// tp = TablePrefix | ||
tp := keys.MakeSQLCodec(roachpb.MustMakeTenantID(3)).TablePrefix | ||
lowTp := keys.MakeSQLCodec(roachpb.MustMakeTenantID(1)).TablePrefix | ||
highTp := keys.MakeSQLCodec(roachpb.MustMakeTenantID(5)).TablePrefix | ||
sysTp := keys.SystemSQLCodec.TablePrefix | ||
tests := []struct { | ||
name string | ||
k, a, b roachpb.Key | ||
expected roachpb.Key | ||
}{ | ||
{"key within main tenant is unchanged", tp(5), tp(1), tp(10), tp(5)}, | ||
{"low tenant codec gets clamped to lower bound", lowTp(5), tp(1), tp(10), tp(1)}, | ||
{"high tenant codec gets clamped to upper bound", highTp(5), tp(1), tp(10), tp(10)}, | ||
{"system codec occurs below the tenant table boundaries", sysTp(5), tp(1), tp(10), tp(1)}, | ||
} | ||
|
||
for _, tt := range tests { | ||
t.Run(tt.name, func(t *testing.T) { | ||
result := tt.k.Clamp(tt.a, tt.b) | ||
if !result.Equal(tt.expected) { | ||
t.Errorf("Clamp(%v, %v, %v) = %v; want %v", tt.k, tt.a, tt.b, result, tt.expected) | ||
} | ||
}) | ||
} | ||
} | ||
|
||
func TestKeyClampTables(t *testing.T) { | ||
// tp = TablePrefix | ||
tp := keys.MakeSQLCodec(roachpb.MustMakeTenantID(3)).TablePrefix | ||
tests := []struct { | ||
name string | ||
k, a, b roachpb.Key | ||
expected roachpb.Key | ||
}{ | ||
{"table within prefix is unchanged", tp(5), tp(1), tp(10), tp(5)}, | ||
{"low table gets clamped to lower bound", tp(0), tp(1), tp(10), tp(1)}, | ||
{"high table gets clamped to upper bound", tp(11), tp(1), tp(10), tp(10)}, | ||
{"low table on lower bound is unchanged", tp(1), tp(1), tp(10), tp(1)}, | ||
{"high table on upper bound is unchanged", tp(10), tp(1), tp(10), tp(10)}, | ||
} | ||
|
||
for _, tt := range tests { | ||
t.Run(tt.name, func(t *testing.T) { | ||
result := tt.k.Clamp(tt.a, tt.b) | ||
if !result.Equal(tt.expected) { | ||
t.Errorf("Clamp(%v, %v, %v) = %v; want %v", tt.k, tt.a, tt.b, result, tt.expected) | ||
} | ||
}) | ||
} | ||
} | ||
|
||
func TestKeyClampTenantTablespace(t *testing.T) { | ||
timeseriesKeyPrefix := encoding.EncodeVarintAscending( | ||
encoding.EncodeBytesAscending( | ||
append(roachpb.Key(nil), keys.TimeseriesPrefix...), | ||
[]byte("my.fake.metric"), | ||
), | ||
int64(10), | ||
) | ||
tsKey := func(source string, timestamp int64) roachpb.Key { | ||
return append(encoding.EncodeVarintAscending(timeseriesKeyPrefix, timestamp), source...) | ||
} | ||
|
||
tp := keys.MakeSQLCodec(roachpb.MustMakeTenantID(3)).TablePrefix | ||
lower := tp(0) | ||
upper := tp(math.MaxUint32) | ||
tests := []struct { | ||
name string | ||
k, a, b roachpb.Key | ||
expected roachpb.Key | ||
}{ | ||
{"KeyMin gets clamped to lower", roachpb.KeyMin, lower, upper, lower}, | ||
{"KeyMax gets clamped to upper", roachpb.KeyMax, lower, upper, upper}, | ||
{"Meta1Prefix gets clamped to lower", keys.Meta1Prefix, lower, upper, lower}, | ||
{"Meta2Prefix gets clamped to lower", keys.Meta2Prefix, lower, upper, lower}, | ||
{"TableDataMin gets clamped to lower", keys.TableDataMin, lower, upper, lower}, | ||
// below is an unexpected test case for a tenant codec | ||
{"TableDataMax also gets clamped to lower", keys.TableDataMax, lower, upper, lower}, | ||
{"SystemPrefix gets clamped to lower", keys.SystemPrefix, lower, upper, lower}, | ||
{"TimeseriesKey gets clamped to lower", tsKey("5", 123), lower, upper, lower}, | ||
} | ||
|
||
for _, tt := range tests { | ||
t.Run(tt.name, func(t *testing.T) { | ||
result := tt.k.Clamp(tt.a, tt.b) | ||
if !result.Equal(tt.expected) { | ||
t.Errorf("Clamp(%v, %v, %v) = %v; want %v", tt.k, tt.a, tt.b, result, tt.expected) | ||
} | ||
}) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
// Copyright 2024 The Cockroach Authors. | ||
// | ||
// Use of this software is governed by the CockroachDB Software License | ||
// included in the /LICENSE file. | ||
|
||
package roachpb_test | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/cockroachdb/cockroach/pkg/keys" | ||
"github.com/cockroachdb/cockroach/pkg/roachpb" | ||
) | ||
|
||
func TestSpanZeroLength(t *testing.T) { | ||
// create two separate references here. | ||
shouldBeEmpty := roachpb.Span{ | ||
Key: keys.SystemSQLCodec.TablePrefix(1), | ||
EndKey: keys.SystemSQLCodec.TablePrefix(1), | ||
} | ||
if !shouldBeEmpty.ZeroLength() { | ||
t.Fatalf("expected span %s to be empty.", shouldBeEmpty) | ||
} | ||
|
||
shouldNotBeEmpty := roachpb.Span{ | ||
Key: keys.SystemSQLCodec.TablePrefix(1), | ||
EndKey: keys.SystemSQLCodec.TablePrefix(1).Next(), | ||
} | ||
if shouldNotBeEmpty.ZeroLength() { | ||
t.Fatalf("expected span %s to not be empty.", shouldNotBeEmpty) | ||
} | ||
} | ||
|
||
func TestSpanClamp(t *testing.T) { | ||
tp := keys.SystemSQLCodec.TablePrefix | ||
tests := []struct { | ||
name string | ||
span roachpb.Span | ||
bounds roachpb.Span | ||
want roachpb.Span | ||
}{ | ||
{ | ||
name: "within bounds", | ||
span: roachpb.Span{tp(5), tp(10)}, | ||
bounds: roachpb.Span{tp(0), tp(15)}, | ||
want: roachpb.Span{tp(5), tp(10)}, | ||
}, | ||
{ | ||
name: "clamp lower bound", | ||
span: roachpb.Span{tp(0), tp(10)}, | ||
bounds: roachpb.Span{tp(5), tp(15)}, | ||
want: roachpb.Span{tp(5), tp(10)}, | ||
}, | ||
{ | ||
name: "clamp upper bound", | ||
span: roachpb.Span{tp(5), tp(20)}, | ||
bounds: roachpb.Span{tp(0), tp(15)}, | ||
want: roachpb.Span{tp(5), tp(15)}, | ||
}, | ||
{ | ||
name: "clamp both bounds", | ||
span: roachpb.Span{tp(0), tp(20)}, | ||
bounds: roachpb.Span{tp(5), tp(15)}, | ||
want: roachpb.Span{tp(5), tp(15)}, | ||
}, | ||
} | ||
|
||
for _, tt := range tests { | ||
t.Run(tt.name, func(t *testing.T) { | ||
if got := tt.span.Clamp(tt.bounds); !got.Equal(tt.want) { | ||
t.Errorf("Clamp() = %v, want %v", got, tt.want) | ||
} | ||
}) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,36 @@ | ||
load("@io_bazel_rules_go//go:def.bzl", "go_library") | ||
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") | ||
|
||
go_library( | ||
name = "apiutil", | ||
srcs = ["apiutil.go"], | ||
srcs = [ | ||
"apiutil.go", | ||
"rangeutil.go", | ||
], | ||
importpath = "github.com/cockroachdb/cockroach/pkg/server/apiutil", | ||
visibility = ["//visibility:public"], | ||
deps = ["//pkg/server/srverrors"], | ||
deps = [ | ||
"//pkg/keys", | ||
"//pkg/roachpb", | ||
"//pkg/server/srverrors", | ||
"//pkg/sql/catalog", | ||
"//pkg/sql/catalog/descpb", | ||
"//pkg/sql/catalog/descs", | ||
"@com_github_cockroachdb_errors//:errors", | ||
], | ||
) | ||
|
||
go_test( | ||
name = "apiutil_test", | ||
srcs = ["rangeutil_test.go"], | ||
deps = [ | ||
":apiutil", | ||
"//pkg/keys", | ||
"//pkg/roachpb", | ||
"//pkg/sql/catalog", | ||
"//pkg/sql/catalog/dbdesc", | ||
"//pkg/sql/catalog/descpb", | ||
"//pkg/sql/catalog/tabledesc", | ||
"//pkg/sql/sem/catid", | ||
"@com_github_stretchr_testify//require", | ||
], | ||
) |
Oops, something went wrong.