Skip to content

Commit

Permalink
spanconfig/{watcher,translator}: add testing knobs
Browse files Browse the repository at this point in the history
We introduce two testing knobs that we'll use in future commits:

- SQLWatcherCheckpointNoopsEveryDurationOverride, if set, will override
  how often the SQLWatcher checkpoints no-ops (follow up to cockroachdb#73171)

- ExcludeDroppedDescriptorsFromLookup will control whether the
  SQLTranslator ignores dropped descriptors. We'll also use this knob
  for the Reconciler (cockroachdb#71994), for the same purpose. Ignoring dropped
  descriptors in tests is a convenient (and faster!) alternative to
  waiting for the descriptor to actually get GC-ed by the GC job. It
  also makes it easier to order events transactionally -- it's
  sufficient for a checkpoint to cross the timestamp when the table is
  dropped, instead of waiting for the GC job to pick it up post TTL.
  This latter form is used in our current sqltranslator tests where we
  sleep arbitrarily:

    # Sleep for 5 seconds, which is more than the TTL on db.t1, so that
    # the gc job can delete the descriptor.
    sleep duration=5

  This is unfortunate and makes for slower tests than necessary. We can
  get rid of it in a subsequent commit.

Release note: None
  • Loading branch information
irfansharif committed Dec 6, 2021
1 parent eea11ee commit 2a67e8f
Show file tree
Hide file tree
Showing 8 changed files with 62 additions and 36 deletions.
1 change: 1 addition & 0 deletions pkg/ccl/spanconfigccl/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ go_test(
"//pkg/security/securitytest",
"//pkg/server",
"//pkg/spanconfig",
"//pkg/spanconfig/spanconfigsqltranslator",
"//pkg/sql",
"//pkg/sql/catalog/catalogkv",
"//pkg/sql/catalog/descpb",
Expand Down
3 changes: 2 additions & 1 deletion pkg/ccl/spanconfigccl/datadriven_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"github.com/cockroachdb/cockroach/pkg/kv"
"github.com/cockroachdb/cockroach/pkg/roachpb"
"github.com/cockroachdb/cockroach/pkg/spanconfig"
"github.com/cockroachdb/cockroach/pkg/spanconfig/spanconfigsqltranslator"
"github.com/cockroachdb/cockroach/pkg/sql"
"github.com/cockroachdb/cockroach/pkg/sql/catalog/catalogkv"
"github.com/cockroachdb/cockroach/pkg/sql/catalog/descpb"
Expand Down Expand Up @@ -142,7 +143,7 @@ func TestSQLTranslatorDataDriven(t *testing.T) {
require.NoError(t, err)
return datadrivenTranslationResult(entries)
case "full-translate":
entries, _, err := spanconfig.FullTranslate(ctx, sqlTranslator)
entries, _, err := spanconfigsqltranslator.FullTranslate(ctx, sqlTranslator)
require.NoError(t, err)
return datadrivenTranslationResult(entries)
case "sleep":
Expand Down
2 changes: 1 addition & 1 deletion pkg/server/server_sql.go
Original file line number Diff line number Diff line change
Expand Up @@ -856,7 +856,7 @@ func newSQLServer(ctx context.Context, cfg sqlServerArgs) (*SQLServer, error) {
// Instantiate a span config manager. If we're the host tenant we'll
// only do it if COCKROACH_EXPERIMENTAL_SPAN_CONFIGS is set.
spanConfigKnobs, _ := cfg.TestingKnobs.SpanConfig.(*spanconfig.TestingKnobs)
sqlTranslator := spanconfigsqltranslator.New(execCfg, codec)
sqlTranslator := spanconfigsqltranslator.New(execCfg, codec, spanConfigKnobs)
sqlWatcher := spanconfigsqlwatcher.New(
codec,
cfg.Settings,
Expand Down
1 change: 0 additions & 1 deletion pkg/spanconfig/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ go_library(
visibility = ["//visibility:public"],
deps = [
"//pkg/base",
"//pkg/keys",
"//pkg/roachpb:with-mocks",
"//pkg/sql/catalog",
"//pkg/sql/catalog/descpb",
Expand Down
35 changes: 11 additions & 24 deletions pkg/spanconfig/spanconfig.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ package spanconfig
import (
"context"

"github.com/cockroachdb/cockroach/pkg/keys"
"github.com/cockroachdb/cockroach/pkg/roachpb"
"github.com/cockroachdb/cockroach/pkg/sql/catalog"
"github.com/cockroachdb/cockroach/pkg/sql/catalog/descpb"
Expand Down Expand Up @@ -106,18 +105,6 @@ type SQLTranslator interface {
Translate(ctx context.Context, ids descpb.IDs) ([]roachpb.SpanConfigEntry, hlc.Timestamp, error)
}

// FullTranslate translates the entire SQL zone configuration state to the
// span configuration state. The timestamp at which such a translation is valid
// is also returned.
func FullTranslate(
ctx context.Context, s SQLTranslator,
) ([]roachpb.SpanConfigEntry, hlc.Timestamp, error) {
// As RANGE DEFAULT is the root of all zone configurations (including
// other named zones for the system tenant), we can construct the entire
// span configuration state by starting from RANGE DEFAULT.
return s.Translate(ctx, descpb.IDs{keys.RootNamespaceID})
}

// SQLWatcher watches for events on system.zones and system.descriptors.
type SQLWatcher interface {
// WatchForSQLUpdates watches for updates to zones and descriptors starting
Expand All @@ -143,17 +130,6 @@ type SQLWatcher interface {
) error
}

// DescriptorUpdate captures the ID and type of a descriptor or zone that the
// SQLWatcher has observed updated.
type DescriptorUpdate struct {
// ID of the descriptor/zone that has been updated.
ID descpb.ID

// DescriptorType of the descriptor/zone that has been updated. Could be either
// the specific type or catalog.Any if no information is available.
DescriptorType catalog.DescriptorType
}

// ReconciliationDependencies captures what's needed by the span config
// reconciliation job to perform its task. The job is responsible for
// reconciling a tenant's zone configurations with the clusters span
Expand Down Expand Up @@ -259,6 +235,17 @@ type StoreReader interface {
GetSpanConfigForKey(ctx context.Context, key roachpb.RKey) (roachpb.SpanConfig, error)
}

// DescriptorUpdate captures the ID and type of a descriptor or zone that the
// SQLWatcher has observed updated.
type DescriptorUpdate struct {
// ID of the descriptor/zone that has been updated.
ID descpb.ID

// DescriptorType of the descriptor/zone that has been updated. Could be either
// the specific type or catalog.Any if no information is available.
DescriptorType catalog.DescriptorType
}

// Update captures a span and the corresponding config change. It's the unit of
// what can be applied to a StoreWriter.
type Update struct {
Expand Down
38 changes: 30 additions & 8 deletions pkg/spanconfig/spanconfigsqltranslator/sqltranslator.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,20 @@ var _ spanconfig.SQLTranslator = &SQLTranslator{}
type SQLTranslator struct {
execCfg *sql.ExecutorConfig
codec keys.SQLCodec
knobs *spanconfig.TestingKnobs
}

// New constructs and returns a SQLTranslator.
func New(execCfg *sql.ExecutorConfig, codec keys.SQLCodec) *SQLTranslator {
func New(
execCfg *sql.ExecutorConfig, codec keys.SQLCodec, knobs *spanconfig.TestingKnobs,
) *SQLTranslator {
if knobs == nil {
knobs = &spanconfig.TestingKnobs{}
}
return &SQLTranslator{
execCfg: execCfg,
codec: codec,
knobs: knobs,
}
}

Expand All @@ -64,7 +71,7 @@ func (s *SQLTranslator) Translate(

// For every ID we want to translate, first expand it to descendant leaf
// IDs that have span configurations associated for them. We also
// de-duplicate leaf IDs so as to not generate redundant entries.
// de-duplicate leaf IDs to not generate redundant entries.
seen := make(map[descpb.ID]struct{})
var leafIDs descpb.IDs
for _, id := range ids {
Expand All @@ -80,8 +87,7 @@ func (s *SQLTranslator) Translate(
}
}

// For every leaf ID, which has been de-duplicated, generate span
// configurations.
// For every unique leaf ID, generate span configurations.
for _, leafID := range leafIDs {
translatedEntries, err := s.generateSpanConfigurations(ctx, leafID, txn, descsCol)
if err != nil {
Expand Down Expand Up @@ -116,11 +122,13 @@ func (s *SQLTranslator) generateSpanConfigurations(
})
if err != nil {
if errors.Is(err, catalog.ErrDescriptorNotFound) {
// The descriptor has been deleted. Nothing to do here.
return nil, nil
return nil, nil // the descriptor has been deleted; nothing to do here
}
return nil, err
}
if s.knobs.ExcludeDroppedDescriptorsFromLookup && desc.Dropped() {
return nil, nil // we're excluding this descriptor; nothing to do here
}

if desc.DescriptorType() != catalog.Table {
return nil, errors.AssertionFailedf(
Expand Down Expand Up @@ -297,11 +305,13 @@ func (s *SQLTranslator) findDescendantLeafIDsForDescriptor(
})
if err != nil {
if errors.Is(err, catalog.ErrDescriptorNotFound) {
// The descriptor has been deleted. Nothing to do here.
return nil, nil
return nil, nil // the descriptor has been deleted; nothing to do here
}
return nil, err
}
if s.knobs.ExcludeDroppedDescriptorsFromLookup && desc.Dropped() {
return nil, nil // we're excluding this descriptor; nothing to do here
}

switch desc.DescriptorType() {
case catalog.Type, catalog.Schema:
Expand Down Expand Up @@ -386,3 +396,15 @@ func (s *SQLTranslator) findDescendantLeafIDsForNamedZone(
}
return descendantIDs, nil
}

// FullTranslate translates the entire SQL zone configuration state to the
// span configuration state. The timestamp at which such a translation is valid
// is also returned.
func FullTranslate(
ctx context.Context, s spanconfig.SQLTranslator,
) ([]roachpb.SpanConfigEntry, hlc.Timestamp, error) {
// As RANGE DEFAULT is the root of all zone configurations (including
// other named zones for the system tenant), we can construct the entire
// span configuration state by starting from RANGE DEFAULT.
return s.Translate(ctx, descpb.IDs{keys.RootNamespaceID})
}
6 changes: 5 additions & 1 deletion pkg/spanconfig/spanconfigsqlwatcher/sqlwatcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,11 @@ func New(
if knobs == nil {
knobs = &spanconfig.TestingKnobs{}
}

if override := knobs.SQLWatcherCheckpointNoopsEveryDurationOverride; override.Nanoseconds() != 0 {
checkpointNoopsEvery = override
}

return &SQLWatcher{
codec: codec,
settings: settings,
Expand Down Expand Up @@ -90,7 +95,6 @@ func (s *SQLWatcher) watch(
startTS hlc.Timestamp,
handler func(context.Context, []spanconfig.DescriptorUpdate, hlc.Timestamp) error,
) error {

// The callbacks below are invoked by both the rangefeeds we establish, both
// of which run on separate goroutines. We serialize calls to the handler
// function by invoking in this single watch thread (instead of pushing it
Expand Down
12 changes: 12 additions & 0 deletions pkg/spanconfig/testing_knobs.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
package spanconfig

import (
"time"

"github.com/cockroachdb/cockroach/pkg/base"
"github.com/cockroachdb/cockroach/pkg/util/hlc"
)
Expand Down Expand Up @@ -57,6 +59,16 @@ type TestingKnobs struct {
// SQLWatcherOnEventInterceptor, if set, is invoked when the SQLWatcher
// receives an event on one of its rangefeeds.
SQLWatcherOnEventInterceptor func() error

// SQLWatcherCheckpointNoopsEveryDurationOverride, if set, overrides how
// often the SQLWatcher checkpoints noops.
SQLWatcherCheckpointNoopsEveryDurationOverride time.Duration

// ExcludeDroppedDescriptorsFromLookup is used to control if the
// SQLTranslator ignores dropped descriptors. If enabled, dropped
// descriptors appear as missing -- a convenient+faster alternative to
// waiting for the descriptor to actually get GC-ed in tests.
ExcludeDroppedDescriptorsFromLookup bool
}

// ModuleTestingKnobs is part of the base.ModuleTestingKnobs interface.
Expand Down

0 comments on commit 2a67e8f

Please sign in to comment.