diff --git a/docs/generated/settings/settings-for-tenants.txt b/docs/generated/settings/settings-for-tenants.txt
index aa505b41e955..4248fcea0444 100644
--- a/docs/generated/settings/settings-for-tenants.txt
+++ b/docs/generated/settings/settings-for-tenants.txt
@@ -134,9 +134,6 @@ This session variable default should now be configured using ALTER ROLE... SET:
sql.defaults.experimental_implicit_column_partitioning.enabled boolean false "default value for experimental_enable_temp_tables; allows for the use of implicit column partitioning
This cluster setting is being kept to preserve backwards-compatibility.
This session variable default should now be configured using ALTER ROLE... SET: https://www.cockroachlabs.com/docs/stable/alter-role.html"
-sql.defaults.experimental_stream_replication.enabled boolean false "default value for experimental_stream_replication session setting;enables the ability to setup a replication stream
-This cluster setting is being kept to preserve backwards-compatibility.
-This session variable default should now be configured using ALTER ROLE... SET: https://www.cockroachlabs.com/docs/stable/alter-role.html"
sql.defaults.experimental_temporary_tables.enabled boolean false "default value for experimental_enable_temp_tables; allows for use of temporary tables by default
This cluster setting is being kept to preserve backwards-compatibility.
This session variable default should now be configured using ALTER ROLE... SET: https://www.cockroachlabs.com/docs/stable/alter-role.html"
diff --git a/docs/generated/settings/settings.html b/docs/generated/settings/settings.html
index 62825f595d8a..11081ead30f9 100644
--- a/docs/generated/settings/settings.html
+++ b/docs/generated/settings/settings.html
@@ -135,7 +135,6 @@
sql.defaults.experimental_distsql_planning
| enumeration | off | default experimental_distsql_planning mode; enables experimental opt-driven DistSQL planning [off = 0, on = 1] This cluster setting is being kept to preserve backwards-compatibility. This session variable default should now be configured using ALTER ROLE... SET |
sql.defaults.experimental_enable_unique_without_index_constraints.enabled
| boolean | false | default value for experimental_enable_unique_without_index_constraints session setting;disables unique without index constraints by default This cluster setting is being kept to preserve backwards-compatibility. This session variable default should now be configured using ALTER ROLE... SET |
sql.defaults.experimental_implicit_column_partitioning.enabled
| boolean | false | default value for experimental_enable_temp_tables; allows for the use of implicit column partitioning This cluster setting is being kept to preserve backwards-compatibility. This session variable default should now be configured using ALTER ROLE... SET |
-sql.defaults.experimental_stream_replication.enabled
| boolean | false | default value for experimental_stream_replication session setting;enables the ability to setup a replication stream This cluster setting is being kept to preserve backwards-compatibility. This session variable default should now be configured using ALTER ROLE... SET |
sql.defaults.experimental_temporary_tables.enabled
| boolean | false | default value for experimental_enable_temp_tables; allows for use of temporary tables by default This cluster setting is being kept to preserve backwards-compatibility. This session variable default should now be configured using ALTER ROLE... SET |
sql.defaults.foreign_key_cascades_limit
| integer | 10000 | default value for foreign_key_cascades_limit session setting; limits the number of cascading operations that run as part of a single query This cluster setting is being kept to preserve backwards-compatibility. This session variable default should now be configured using ALTER ROLE... SET |
sql.defaults.idle_in_session_timeout
| duration | 0s | default value for the idle_in_session_timeout; default value for the idle_in_session_timeout session setting; controls the duration a session is permitted to idle before the session is terminated; if set to 0, there is no timeout This cluster setting is being kept to preserve backwards-compatibility. This session variable default should now be configured using ALTER ROLE... SET |
diff --git a/pkg/ccl/spanconfigccl/spanconfigreconcilerccl/testdata/multitenant/tenant_end_key_split b/pkg/ccl/spanconfigccl/spanconfigreconcilerccl/testdata/multitenant/tenant_end_key_split
new file mode 100644
index 000000000000..ac6a68ec6b5c
--- /dev/null
+++ b/pkg/ccl/spanconfigccl/spanconfigreconcilerccl/testdata/multitenant/tenant_end_key_split
@@ -0,0 +1,115 @@
+# Test that tenant creation does not overwrite span config state for another
+# tenant.
+
+reconcile
+----
+
+mutations discard
+----
+
+# Initialize a new tenant, tenant=11, that DOES NOT have a pre-existing tenant,
+# tenant=12, next to it.
+initialize tenant=11
+----
+
+# A record IS written for a key that logically belongs to the next tenant,
+# tenant=12, because tenant=12 DOES NOT exist.
+state offset=57 limit=3
+----
+...
+/Tenant/11{-\x00} database system (tenant)
+/Tenant/12{-\x00} database system (tenant)
+
+# Start the reconciliation loop for the tenant=11. It'll first clear out its own
+# first-key record and install span configs for its SQL state. It won't touch
+# the record we created at in the tenant=12 keyspace because it's not taught to
+# look there, and neither should it. The keyspace it's responsible for is its
+# own.
+reconcile tenant=11
+----
+
+# Peek near the start of the span_configurations table where tenant=11's records
+# are stored. The first one is from the start of its keyspace to start of
+# table with ID=4: /Tenant/11{-/Table/4}.
+state offset=56 limit=3
+----
+...
+/Table/5{7-8} ttl_seconds=3600 ignore_strict_gc=true num_replicas=5 rangefeed_enabled=true
+/Tenant/11{-/Table/4} database system (tenant)
+/Tenant/11/Table/{4-5} database system (tenant)
+...
+
+# Peek near the end of the span_configurations table where tenant=11's records
+# are stored. The last one is for its last system table:
+# /Tenant/11/Table/5{7-8}. Right now the split is at /Tenant/12. Which is fine.
+state offset=99 limit=3
+----
+...
+/Tenant/11/Table/5{7-8} database system (tenant)
+/Tenant/12{-\x00} database system (tenant)
+
+# Just another view of what the tenant's reconciler actually did. It got rid of
+# the original, single-key /Tenant/11{-\x00} record, and replaced it with
+# /Tenant/11{-/Table/4}, just like the comment above said. The remaining upserts
+# are for its SQL state.
+mutations tenant=11 limit=2
+----
+delete /Tenant/11{-\x00}
+upsert /Tenant/11{-/Table/4} database system (tenant)
+upsert /Tenant/11/Table/{4-5} database system (tenant)
+upsert /Tenant/11/Table/{5-6} database system (tenant)
+upsert /Tenant/11/Table/{6-7} database system (tenant)
+upsert /Tenant/11/Table/{7-8} database system (tenant)
+upsert /Tenant/11/Table/1{1-2} database system (tenant)
+upsert /Tenant/11/Table/1{2-3} database system (tenant)
+upsert /Tenant/11/Table/1{3-4} database system (tenant)
+upsert /Tenant/11/Table/1{4-5} database system (tenant)
+upsert /Tenant/11/Table/1{5-6} database system (tenant)
+upsert /Tenant/11/Table/{19-20} database system (tenant)
+upsert /Tenant/11/Table/2{0-1} database system (tenant)
+upsert /Tenant/11/Table/2{1-2} database system (tenant)
+upsert /Tenant/11/Table/2{3-4} database system (tenant)
+upsert /Tenant/11/Table/2{4-5} database system (tenant)
+upsert /Tenant/11/Table/2{5-6} database system (tenant)
+upsert /Tenant/11/Table/2{6-7} database system (tenant)
+upsert /Tenant/11/Table/2{7-8} database system (tenant)
+upsert /Tenant/11/Table/2{8-9} database system (tenant)
+upsert /Tenant/11/NamespaceTable/{30-Max} database system (tenant)
+upsert /Tenant/11/{NamespaceTable/Max-Table/32} database system (tenant)
+upsert /Tenant/11/Table/3{2-3} database system (tenant)
+upsert /Tenant/11/Table/3{3-4} database system (tenant)
+upsert /Tenant/11/Table/3{4-5} database system (tenant)
+upsert /Tenant/11/Table/3{5-6} database system (tenant)
+upsert /Tenant/11/Table/3{6-7} database system (tenant)
+upsert /Tenant/11/Table/3{7-8} database system (tenant)
+upsert /Tenant/11/Table/{39-40} database system (tenant)
+upsert /Tenant/11/Table/4{0-1} database system (tenant)
+upsert /Tenant/11/Table/4{1-2} database system (tenant)
+upsert /Tenant/11/Table/4{2-3} database system (tenant)
+upsert /Tenant/11/Table/4{3-4} database system (tenant)
+upsert /Tenant/11/Table/4{4-5} database system (tenant)
+upsert /Tenant/11/Table/4{6-7} database system (tenant)
+upsert /Tenant/11/Table/4{8-9} database system (tenant)
+upsert /Tenant/11/Table/5{0-1} database system (tenant)
+upsert /Tenant/11/Table/5{1-2} database system (tenant)
+upsert /Tenant/11/Table/5{2-3} database system (tenant)
+upsert /Tenant/11/Table/5{3-4} database system (tenant)
+upsert /Tenant/11/Table/5{4-5} database system (tenant)
+upsert /Tenant/11/Table/5{5-6} database system (tenant)
+upsert /Tenant/11/Table/5{6-7} database system (tenant)
+upsert /Tenant/11/Table/5{7-8} database system (tenant)
+
+# Initialize a new tenant, tenant=10, that DOES have a pre-existing tenant,
+# tenant=11, next to it.
+initialize tenant=10
+----
+
+# A record IS NOT written for a key that logically belongs to the next tenant,
+# tenant=11, because tenant=11 DOES exist.
+state offset=57 limit=3
+----
+...
+/Tenant/10{-\x00} database system (tenant)
+/Tenant/11{-/Table/4} database system (tenant)
+/Tenant/11/Table/{4-5} database system (tenant)
+...
diff --git a/pkg/ccl/streamingccl/replicationtestutils/replication_helpers.go b/pkg/ccl/streamingccl/replicationtestutils/replication_helpers.go
index 0b33bd078476..80c6fe418837 100644
--- a/pkg/ccl/streamingccl/replicationtestutils/replication_helpers.go
+++ b/pkg/ccl/streamingccl/replicationtestutils/replication_helpers.go
@@ -223,7 +223,7 @@ func NewReplicationHelper(
SET CLUSTER SETTING kv.rangefeed.enabled = true;
SET CLUSTER SETTING kv.closed_timestamp.target_duration = '1s';
SET CLUSTER SETTING changefeed.experimental_poll_interval = '10ms';
-SET CLUSTER SETTING sql.defaults.experimental_stream_replication.enabled = 'on';
+SET CLUSTER SETTING cross_cluster_replication.enabled = true;
`, `;`)...)
// Sink to read data from.
diff --git a/pkg/ccl/streamingccl/replicationtestutils/testutils.go b/pkg/ccl/streamingccl/replicationtestutils/testutils.go
index 9d370d63d04a..847bb513cbe5 100644
--- a/pkg/ccl/streamingccl/replicationtestutils/testutils.go
+++ b/pkg/ccl/streamingccl/replicationtestutils/testutils.go
@@ -273,7 +273,7 @@ func CreateTenantStreamingClusters(
args.DestInitFunc(t, tsc.DestSysSQL)
}
// Enable stream replication on dest by default.
- tsc.DestSysSQL.Exec(t, `SET enable_experimental_stream_replication = true;`)
+ tsc.DestSysSQL.Exec(t, `SET CLUSTER SETTING cross_cluster_replication.enabled = true;`)
return tsc, func() {
require.NoError(t, srcTenantConn.Close())
destCleanup()
diff --git a/pkg/ccl/streamingccl/settings.go b/pkg/ccl/streamingccl/settings.go
index ebaff1db04f4..cdcc62ee44b6 100644
--- a/pkg/ccl/streamingccl/settings.go
+++ b/pkg/ccl/streamingccl/settings.go
@@ -14,6 +14,15 @@ import (
"github.com/cockroachdb/cockroach/pkg/settings"
)
+// CrossClusterReplicationEnabled enables the ability to setup and control a
+// cross cluster replication stream.
+var CrossClusterReplicationEnabled = settings.RegisterBoolSetting(
+ settings.TenantWritable,
+ "cross_cluster_replication.enabled",
+ "enables the ability to setup and control a cross cluster replication stream",
+ false,
+)
+
// StreamReplicationStreamLivenessTrackFrequency controls frequency to check
// the liveness of a streaming replication producer job.
var StreamReplicationStreamLivenessTrackFrequency = settings.RegisterDurationSetting(
diff --git a/pkg/ccl/streamingccl/streamingest/alter_replication_job.go b/pkg/ccl/streamingccl/streamingest/alter_replication_job.go
index faa9562ef314..4644ef86afbe 100644
--- a/pkg/ccl/streamingccl/streamingest/alter_replication_job.go
+++ b/pkg/ccl/streamingccl/streamingest/alter_replication_job.go
@@ -12,6 +12,7 @@ import (
"context"
"math"
+ "github.com/cockroachdb/cockroach/pkg/ccl/streamingccl"
"github.com/cockroachdb/cockroach/pkg/ccl/streamingccl/replicationutils"
"github.com/cockroachdb/cockroach/pkg/ccl/utilccl"
"github.com/cockroachdb/cockroach/pkg/jobs"
@@ -111,6 +112,19 @@ func alterReplicationJobHook(
return nil, nil, nil, false, nil
}
+ if !streamingccl.CrossClusterReplicationEnabled.Get(&p.ExecCfg().Settings.SV) {
+ return nil, nil, nil, false, errors.WithTelemetry(
+ pgerror.WithCandidateCode(
+ errors.WithHint(
+ errors.Newf("cross cluster replication is disabled"),
+ "You can enable cross cluster replication by running `SET CLUSTER SETTING cross_cluster_replication.enabled = true`.",
+ ),
+ pgcode.ExperimentalFeature,
+ ),
+ "cross_cluster_replication.enabled",
+ )
+ }
+
if err := p.RequireAdminRole(ctx, "ALTER TENANT REPLICATION"); err != nil {
return nil, nil, nil, false, err
}
diff --git a/pkg/ccl/streamingccl/streamingest/alter_replication_job_test.go b/pkg/ccl/streamingccl/streamingest/alter_replication_job_test.go
index ec17cfb30764..cc1424251297 100644
--- a/pkg/ccl/streamingccl/streamingest/alter_replication_job_test.go
+++ b/pkg/ccl/streamingccl/streamingest/alter_replication_job_test.go
@@ -85,6 +85,7 @@ func TestAlterTenantPauseResume(t *testing.T) {
})
t.Run("pause-resume-as-non-system-tenant", func(t *testing.T) {
+ c.DestTenantSQL.Exec(t, `SET CLUSTER SETTING cross_cluster_replication.enabled = true`)
c.DestTenantSQL.ExpectErr(t, "only the system tenant can alter tenant", `ALTER TENANT $1 PAUSE REPLICATION`, "foo")
c.DestTenantSQL.ExpectErr(t, "only the system tenant can alter tenant", `ALTER TENANT $1 RESUME REPLICATION`, "foo")
})
diff --git a/pkg/ccl/streamingccl/streamingest/metrics.go b/pkg/ccl/streamingccl/streamingest/metrics.go
index 18cba44f8fb1..909cdefb1479 100644
--- a/pkg/ccl/streamingccl/streamingest/metrics.go
+++ b/pkg/ccl/streamingccl/streamingest/metrics.go
@@ -24,31 +24,31 @@ const (
var (
metaReplicationEventsIngested = metric.Metadata{
Name: "replication.events_ingested",
- Help: "Events ingested by all ingestion jobs",
+ Help: "Events ingested by all replication jobs",
Measurement: "Events",
Unit: metric.Unit_COUNT,
}
metaReplicationResolvedEventsIngested = metric.Metadata{
Name: "replication.resolved_events_ingested",
- Help: "Resolved events ingested by all ingestion jobs",
+ Help: "Resolved events ingested by all replication jobs",
Measurement: "Events",
Unit: metric.Unit_COUNT,
}
metaReplicationIngestedBytes = metric.Metadata{
- Name: "replication.ingested_bytes",
- Help: "Bytes ingested by all ingestion jobs",
+ Name: "replication.logical_bytes",
+ Help: "Logical bytes (sum of keys + values) ingested by all replication jobs",
Measurement: "Bytes",
Unit: metric.Unit_BYTES,
}
metaReplicationSSTBytes = metric.Metadata{
Name: "replication.sst_bytes",
- Help: "SST bytes (compressed) sent to KV by all ingestion jobs",
+ Help: "SST bytes (compressed) sent to KV by all replication jobs",
Measurement: "Bytes",
Unit: metric.Unit_BYTES,
}
metaReplicationFlushes = metric.Metadata{
Name: "replication.flushes",
- Help: "Total flushes across all ingestion jobs",
+ Help: "Total flushes across all replication jobs",
Measurement: "Flushes",
Unit: metric.Unit_COUNT,
}
@@ -105,8 +105,9 @@ var (
Unit: metric.Unit_COUNT,
}
metaFrontierLagSeconds = metric.Metadata{
- Name: "replication.frontier_lag_seconds",
- Help: "Time the replication frontier lags",
+ Name: "replication.frontier_lag_seconds",
+ Help: "Time between the wall clock and replicated time of the replication stream. " +
+ "This metric tracks how far behind the replication stream is relative to now",
Measurement: "Seconds",
Unit: metric.Unit_SECONDS,
}
diff --git a/pkg/ccl/streamingccl/streamingest/replication_random_client_test.go b/pkg/ccl/streamingccl/streamingest/replication_random_client_test.go
index def502dec46f..9fd3f7041cba 100644
--- a/pkg/ccl/streamingccl/streamingest/replication_random_client_test.go
+++ b/pkg/ccl/streamingccl/streamingest/replication_random_client_test.go
@@ -238,9 +238,9 @@ func TestStreamIngestionJobWithRandomClient(t *testing.T) {
// Attempt to run the ingestion job without enabling the experimental setting.
_, err = conn.Exec(query)
- require.True(t, testutils.IsError(err, "stream replication is only supported experimentally"))
+ require.True(t, testutils.IsError(err, "cross cluster replication is disabled"))
- _, err = conn.Exec(`SET enable_experimental_stream_replication = true`)
+ _, err = conn.Exec(`SET CLUSTER SETTING cross_cluster_replication.enabled = true;`)
require.NoError(t, err)
_, err = conn.Exec(query)
diff --git a/pkg/ccl/streamingccl/streamingest/stream_ingestion_job_test.go b/pkg/ccl/streamingccl/streamingest/stream_ingestion_job_test.go
index 4ff05a3f5a70..5dfc1872461b 100644
--- a/pkg/ccl/streamingccl/streamingest/stream_ingestion_job_test.go
+++ b/pkg/ccl/streamingccl/streamingest/stream_ingestion_job_test.go
@@ -113,7 +113,7 @@ SET CLUSTER SETTING stream_replication.consumer_heartbeat_frequency = '100ms';
SET CLUSTER SETTING bulkio.stream_ingestion.minimum_flush_interval = '500ms';
SET CLUSTER SETTING bulkio.stream_ingestion.cutover_signal_poll_interval = '100ms';
SET CLUSTER SETTING stream_replication.job_checkpoint_frequency = '100ms';
-SET enable_experimental_stream_replication = true;
+SET CLUSTER SETTING cross_cluster_replication.enabled = true;
`,
";")...)
@@ -191,7 +191,7 @@ func TestTenantStreamingCreationErrors(t *testing.T) {
SrcSysSQL.Exec(t, `SET CLUSTER SETTING kv.rangefeed.enabled = true`)
DestSysSQL := sqlutils.MakeSQLRunner(destDB)
- DestSysSQL.Exec(t, `SET enable_experimental_stream_replication = true`)
+ DestSysSQL.Exec(t, `SET CLUSTER SETTING cross_cluster_replication.enabled = true;`)
// Sink to read data from.
srcPgURL, cleanupSink := sqlutils.PGUrl(t, srcServer.ServingSQLAddr(), t.Name(), url.User(username.RootUser))
diff --git a/pkg/ccl/streamingccl/streamingest/stream_ingestion_planning.go b/pkg/ccl/streamingccl/streamingest/stream_ingestion_planning.go
index 249533858a62..9f77c1dd61cc 100644
--- a/pkg/ccl/streamingccl/streamingest/stream_ingestion_planning.go
+++ b/pkg/ccl/streamingccl/streamingest/stream_ingestion_planning.go
@@ -68,17 +68,16 @@ func ingestionPlanHook(
return nil, nil, nil, false, nil
}
- // Check if the experimental feature is enabled.
- if !p.SessionData().EnableStreamReplication {
+ if !streamingccl.CrossClusterReplicationEnabled.Get(&p.ExecCfg().Settings.SV) {
return nil, nil, nil, false, errors.WithTelemetry(
pgerror.WithCandidateCode(
errors.WithHint(
- errors.Newf("stream replication is only supported experimentally"),
- "You can enable stream replication by running `SET enable_experimental_stream_replication = true`.",
+ errors.Newf("cross cluster replication is disabled"),
+ "You can enable cross cluster replication by running `SET CLUSTER SETTING cross_cluster_replication.enabled = true`.",
),
pgcode.ExperimentalFeature,
),
- "replication.ingest.disabled",
+ "cross_cluster_replication.enabled",
)
}
diff --git a/pkg/ccl/streamingccl/streamproducer/replication_stream_test.go b/pkg/ccl/streamingccl/streamproducer/replication_stream_test.go
index 8314de7806f8..c416b85911b9 100644
--- a/pkg/ccl/streamingccl/streamproducer/replication_stream_test.go
+++ b/pkg/ccl/streamingccl/streamproducer/replication_stream_test.go
@@ -176,7 +176,7 @@ func startReplication(
conn, err := pgx.ConnectConfig(queryCtx, pgxConfig)
require.NoError(t, err)
- rows, err := conn.Query(queryCtx, `SET enable_experimental_stream_replication = true`)
+ rows, err := conn.Query(queryCtx, `SET CLUSTER SETTING cross_cluster_replication.enabled = true;`)
require.NoError(t, err)
rows.Close()
diff --git a/pkg/cmd/roachtest/cluster.go b/pkg/cmd/roachtest/cluster.go
index b6629203a625..2912588e41e6 100644
--- a/pkg/cmd/roachtest/cluster.go
+++ b/pkg/cmd/roachtest/cluster.go
@@ -1047,14 +1047,14 @@ func (c *clusterImpl) StopCockroachGracefullyOnNode(
gracefulOpts.RoachprodOpts.Sig = 15 // SIGTERM
gracefulOpts.RoachprodOpts.Wait = true
gracefulOpts.RoachprodOpts.MaxWait = 60
- c.Stop(ctx, l, gracefulOpts, c.Node(node))
- // NB: we still call Stop to make sure the process is dead when we try
- // to restart it (or we'll catch an error from the RocksDB dir being
- // locked). This won't happen unless run with --local due to timing.
- c.Stop(ctx, l, option.DefaultStopOpts(), c.Node(node))
- // TODO(tschottdorf): should return an error. I doubt that we want to
- // call these *testing.T-style methods on goroutines.
- return nil
+ if err := c.StopE(ctx, l, gracefulOpts, c.Node(node)); err != nil {
+ return err
+ }
+
+ // NB: we still call Stop to make sure the process is dead when we
+ // try to restart it (in case it takes longer than `MaxWait` for it
+ // to finish).
+ return c.StopE(ctx, l, option.DefaultStopOpts(), c.Node(node))
}
// Save marks the cluster as "saved" so that it doesn't get destroyed.
diff --git a/pkg/cmd/roachtest/tests/cluster_to_cluster.go b/pkg/cmd/roachtest/tests/cluster_to_cluster.go
index f42aff2ac8cd..dcf348b5dac6 100644
--- a/pkg/cmd/roachtest/tests/cluster_to_cluster.go
+++ b/pkg/cmd/roachtest/tests/cluster_to_cluster.go
@@ -611,7 +611,7 @@ func srcClusterSettings(t test.Test, db *sqlutils.SQLRunner) {
}
func destClusterSettings(t test.Test, db *sqlutils.SQLRunner) {
- db.ExecMultiple(t, `SET enable_experimental_stream_replication = true;`)
+ db.ExecMultiple(t, `SET CLUSTER SETTING cross_cluster_replication.enabled = true;`)
}
func copyPGCertsAndMakeURL(
diff --git a/pkg/settings/registry.go b/pkg/settings/registry.go
index efbbb3e4e4fd..05844f866d32 100644
--- a/pkg/settings/registry.go
+++ b/pkg/settings/registry.go
@@ -160,7 +160,8 @@ var retiredSettings = map[string]struct{}{
"changefeed.active_protected_timestamps.enabled": {},
"jobs.scheduler.single_node_scheduler.enabled": {},
// renamed.
- "spanconfig.host_coalesce_adjacent.enabled": {},
+ "spanconfig.host_coalesce_adjacent.enabled": {},
+ "sql.defaults.experimental_stream_replication.enabled": {},
}
// sqlDefaultSettings is the list of "grandfathered" existing sql.defaults
@@ -182,7 +183,6 @@ var sqlDefaultSettings = map[string]struct{}{
"sql.defaults.experimental_distsql_planning": {},
"sql.defaults.experimental_enable_unique_without_index_constraints.enabled": {},
"sql.defaults.experimental_implicit_column_partitioning.enabled": {},
- "sql.defaults.experimental_stream_replication.enabled": {},
"sql.defaults.experimental_temporary_tables.enabled": {},
"sql.defaults.foreign_key_cascades_limit": {},
"sql.defaults.idle_in_session_timeout": {},
diff --git a/pkg/spanconfig/spanconfigreconciler/BUILD.bazel b/pkg/spanconfig/spanconfigreconciler/BUILD.bazel
index 986d4ee63a2a..cfccd98cf5d4 100644
--- a/pkg/spanconfig/spanconfigreconciler/BUILD.bazel
+++ b/pkg/spanconfig/spanconfigreconciler/BUILD.bazel
@@ -21,6 +21,7 @@ go_library(
"//pkg/sql/isql",
"//pkg/sql/sqlliveness",
"//pkg/util/hlc",
+ "//pkg/util/iterutil",
"//pkg/util/log",
"//pkg/util/retry",
"//pkg/util/syncutil",
diff --git a/pkg/spanconfig/spanconfigreconciler/reconciler.go b/pkg/spanconfig/spanconfigreconciler/reconciler.go
index af08674f43e9..b04c3022da8b 100644
--- a/pkg/spanconfig/spanconfigreconciler/reconciler.go
+++ b/pkg/spanconfig/spanconfigreconciler/reconciler.go
@@ -28,6 +28,7 @@ import (
"github.com/cockroachdb/cockroach/pkg/sql/isql"
"github.com/cockroachdb/cockroach/pkg/sql/sqlliveness"
"github.com/cockroachdb/cockroach/pkg/util/hlc"
+ "github.com/cockroachdb/cockroach/pkg/util/iterutil"
"github.com/cockroachdb/cockroach/pkg/util/log"
"github.com/cockroachdb/cockroach/pkg/util/retry"
"github.com/cockroachdb/cockroach/pkg/util/syncutil"
@@ -298,6 +299,29 @@ func (f *fullReconciler) reconcile(
storeWithLatestSpanConfigs.Apply(ctx, false /* dryrun */, del)
}
+ if !f.codec.ForSystemTenant() {
+ tenantPrefixKey := f.codec.TenantPrefix()
+ // We want to ensure tenant ranges do not straddle tenant boundaries. As
+ // such, a full reconciliation should always include a SpanConfig where the
+ // start key is keys.MakeTenantPrefix(tenantID). This ensures there is a
+ // split point right at the start of the tenant's keyspace, so that the
+ // last range of the previous tenant doesn't straddle across into this
+ // tenant. Also, sql.CreateTenantRecord relies on such a SpanConfigs
+ // existence to ensure the same thing for newly created tenants.
+ if err := storeWithLatestSpanConfigs.Iterate(func(record spanconfig.Record) error {
+ spanConfigStartKey := record.GetTarget().GetSpan().Key
+ if tenantPrefixKey.Compare(spanConfigStartKey) != 0 {
+ return errors.AssertionFailedf(
+ "tenant prefix key %q does not match first span config start key %q",
+ tenantPrefixKey, spanConfigStartKey,
+ )
+ }
+ return iterutil.StopIteration()
+ }); err != nil {
+ return nil, hlc.Timestamp{}, err
+ }
+ }
+
return storeWithLatestSpanConfigs, readTimestamp, nil
}
diff --git a/pkg/sql/BUILD.bazel b/pkg/sql/BUILD.bazel
index f56f0f75dc15..521f196eedbf 100644
--- a/pkg/sql/BUILD.bazel
+++ b/pkg/sql/BUILD.bazel
@@ -666,6 +666,7 @@ go_test(
"txn_restart_test.go",
"txn_state_test.go",
"type_change_test.go",
+ "unique_without_index_test.go",
"unsplit_range_test.go",
"unsplit_test.go",
"upsert_test.go",
diff --git a/pkg/sql/catalog/tabledesc/structured.go b/pkg/sql/catalog/tabledesc/structured.go
index 40e42fa27e1a..875c20790404 100644
--- a/pkg/sql/catalog/tabledesc/structured.go
+++ b/pkg/sql/catalog/tabledesc/structured.go
@@ -276,6 +276,12 @@ func ForEachExprStringInTableDesc(descI catalog.TableDescriptor, f func(expr *st
doCheck := func(c *descpb.TableDescriptor_CheckConstraint) error {
return f(&c.Expr)
}
+ doUwi := func(uwi *descpb.UniqueWithoutIndexConstraint) error {
+ if uwi.Predicate != "" {
+ return f(&uwi.Predicate)
+ }
+ return nil
+ }
// Process columns.
for i := range desc.Columns {
@@ -300,6 +306,13 @@ func ForEachExprStringInTableDesc(descI catalog.TableDescriptor, f func(expr *st
}
}
+ // Process uwis.
+ for i := range desc.UniqueWithoutIndexConstraints {
+ if err := doUwi(&desc.UniqueWithoutIndexConstraints[i]); err != nil {
+ return err
+ }
+ }
+
// Process all non-index mutations.
for _, mut := range desc.Mutations {
if c := mut.GetColumn(); c != nil {
@@ -313,6 +326,12 @@ func ForEachExprStringInTableDesc(descI catalog.TableDescriptor, f func(expr *st
return err
}
}
+ if c := mut.GetConstraint(); c != nil &&
+ c.ConstraintType == descpb.ConstraintToUpdate_UNIQUE_WITHOUT_INDEX {
+ if err := doUwi(&c.UniqueWithoutIndexConstraint); err != nil {
+ return err
+ }
+ }
}
return nil
}
diff --git a/pkg/sql/exec_util.go b/pkg/sql/exec_util.go
index 15f6f9776713..d1f991066f0c 100644
--- a/pkg/sql/exec_util.go
+++ b/pkg/sql/exec_util.go
@@ -512,14 +512,6 @@ var experimentalUseNewSchemaChanger = settings.RegisterEnumSetting(
},
).WithPublic()
-var experimentalStreamReplicationEnabled = settings.RegisterBoolSetting(
- settings.TenantWritable,
- "sql.defaults.experimental_stream_replication.enabled",
- "default value for experimental_stream_replication session setting;"+
- "enables the ability to setup a replication stream",
- false,
-).WithPublic()
-
var stubCatalogTablesEnabledClusterValue = settings.RegisterBoolSetting(
settings.TenantWritable,
`sql.defaults.stub_catalog_tables.enabled`,
diff --git a/pkg/sql/logictest/testdata/logic_test/information_schema b/pkg/sql/logictest/testdata/logic_test/information_schema
index 79783fd52ad1..050851e452c1 100644
--- a/pkg/sql/logictest/testdata/logic_test/information_schema
+++ b/pkg/sql/logictest/testdata/logic_test/information_schema
@@ -4931,7 +4931,6 @@ disallow_full_table_scans off
enable_auto_rehoming off
enable_drop_enum_value on
enable_experimental_alter_column_type_general off
-enable_experimental_stream_replication off
enable_implicit_select_for_update on
enable_implicit_transaction_for_batch_statements on
enable_insert_fast_path on
diff --git a/pkg/sql/logictest/testdata/logic_test/pg_catalog b/pkg/sql/logictest/testdata/logic_test/pg_catalog
index ee94dd9d7550..fe282b88117e 100644
--- a/pkg/sql/logictest/testdata/logic_test/pg_catalog
+++ b/pkg/sql/logictest/testdata/logic_test/pg_catalog
@@ -2570,7 +2570,6 @@ disallow_full_table_scans off NULL
distsql off NULL NULL NULL string
enable_auto_rehoming off NULL NULL NULL string
enable_experimental_alter_column_type_general off NULL NULL NULL string
-enable_experimental_stream_replication off NULL NULL NULL string
enable_implicit_select_for_update on NULL NULL NULL string
enable_implicit_transaction_for_batch_statements on NULL NULL NULL string
enable_insert_fast_path on NULL NULL NULL string
@@ -2714,7 +2713,6 @@ disallow_full_table_scans off NULL
distsql off NULL user NULL off off
enable_auto_rehoming off NULL user NULL off off
enable_experimental_alter_column_type_general off NULL user NULL off off
-enable_experimental_stream_replication off NULL user NULL off off
enable_implicit_select_for_update on NULL user NULL on on
enable_implicit_transaction_for_batch_statements on NULL user NULL on on
enable_insert_fast_path on NULL user NULL on on
@@ -2856,7 +2854,6 @@ distsql NULL NULL NULL
distsql_workmem NULL NULL NULL NULL NULL
enable_auto_rehoming NULL NULL NULL NULL NULL
enable_experimental_alter_column_type_general NULL NULL NULL NULL NULL
-enable_experimental_stream_replication NULL NULL NULL NULL NULL
enable_implicit_select_for_update NULL NULL NULL NULL NULL
enable_implicit_transaction_for_batch_statements NULL NULL NULL NULL NULL
enable_insert_fast_path NULL NULL NULL NULL NULL
diff --git a/pkg/sql/logictest/testdata/logic_test/schema_change_in_txn b/pkg/sql/logictest/testdata/logic_test/schema_change_in_txn
index 6bada7ca76eb..c2037b0e683a 100644
--- a/pkg/sql/logictest/testdata/logic_test/schema_change_in_txn
+++ b/pkg/sql/logictest/testdata/logic_test/schema_change_in_txn
@@ -1950,3 +1950,50 @@ DROP SCHEMA sc;
# Prior to fixing this bug, this commit would hang indefinitely.
statement ok
COMMIT;
+
+# This is a regression test to handle the case where a newly created table or
+# a previously unleased table are referenced in a transaction involving
+# transactional constraint validation.
+subtest validate_constraint_referencing_modified_table
+
+statement ok
+CREATE TABLE t1 (id STRING PRIMARY KEY, other_id STRING NOT NULL);
+CREATE TABLE t2 (id STRING PRIMARY KEY);
+ALTER TABLE t1 ADD CONSTRAINT fk FOREIGN KEY (other_id) REFERENCES t2(id) NOT VALID;
+
+statement ok
+BEGIN;
+SET TRANSACTION PRIORITY HIGH;
+ALTER TABLE t2 RENAME TO t3;
+ALTER TABLE t1 VALIDATE CONSTRAINT fk;
+COMMIT;
+
+statement ok
+DROP TABLE t1, t3 CASCADE
+
+statement ok
+CREATE TABLE t1 (id STRING PRIMARY KEY, other_id STRING NOT NULL);
+CREATE TABLE t2 (id STRING PRIMARY KEY);
+ALTER TABLE t1 ADD CONSTRAINT fk FOREIGN KEY (other_id) REFERENCES t2(id) NOT VALID;
+
+statement ok
+BEGIN;
+SET TRANSACTION PRIORITY HIGH;
+ALTER TABLE t1 RENAME TO t3;
+ALTER TABLE t3 VALIDATE CONSTRAINT fk;
+COMMIT;
+
+statement ok
+DROP TABLE t2, t3 CASCADE
+
+statement ok
+BEGIN;
+SET TRANSACTION PRIORITY HIGH;
+CREATE TABLE t1 (id STRING PRIMARY KEY, other_id STRING NOT NULL);
+CREATE TABLE t2 (id STRING PRIMARY KEY);
+ALTER TABLE t1 ADD CONSTRAINT fk FOREIGN KEY (other_id) REFERENCES t2(id);
+ALTER TABLE t1 VALIDATE CONSTRAINT fk;
+COMMIT;
+
+statement ok
+DROP TABLE t1, t2 CASCADE
diff --git a/pkg/sql/logictest/testdata/logic_test/sequences b/pkg/sql/logictest/testdata/logic_test/sequences
index f9754e6b2b23..3f03b7878908 100644
--- a/pkg/sql/logictest/testdata/logic_test/sequences
+++ b/pkg/sql/logictest/testdata/logic_test/sequences
@@ -2085,6 +2085,10 @@ CREATE SEQUENCE seqas_error
subtest sequence_in_transaction
+# We're using explicit transactions, so we might hit retries.
+
+skip_on_retry
+
# create a sequence and nextval in the same transaction
statement ok
BEGIN
diff --git a/pkg/sql/logictest/testdata/logic_test/show_source b/pkg/sql/logictest/testdata/logic_test/show_source
index d766199fe25a..0241725c4dba 100644
--- a/pkg/sql/logictest/testdata/logic_test/show_source
+++ b/pkg/sql/logictest/testdata/logic_test/show_source
@@ -57,7 +57,6 @@ disallow_full_table_scans off
distsql off
enable_auto_rehoming off
enable_experimental_alter_column_type_general off
-enable_experimental_stream_replication off
enable_implicit_select_for_update on
enable_implicit_transaction_for_batch_statements on
enable_insert_fast_path on
diff --git a/pkg/sql/logictest/testdata/logic_test/temp_table b/pkg/sql/logictest/testdata/logic_test/temp_table
index 11b103d55dae..762d099916d8 100644
--- a/pkg/sql/logictest/testdata/logic_test/temp_table
+++ b/pkg/sql/logictest/testdata/logic_test/temp_table
@@ -356,4 +356,44 @@ to_drop.pg_temp.testuser_tmp
to_drop.pg_temp.tempuser_view
to_drop.pg_temp.root_temp
+subtest create_after_discard_and_drop_database
+
+statement ok
+ALTER ROLE testuser WITH CREATEDB;
+
user testuser
+
+statement ok
+CREATE DATABASE to_drop
+
+statement ok
+USE to_drop
+
+statement ok
+CREATE TEMPORARY TABLE t (i INT PRIMARY KEY);
+
+statement ok
+SELECT * FROM pg_temp.t
+
+statement ok
+DISCARD TEMP
+
+statement error pgcode 42P01 relation "pg_temp.t" does not exist
+SELECT * FROM pg_temp.t
+
+statement ok
+USE defaultdb;
+DROP DATABASE to_drop CASCADE;
+
+statement ok
+CREATE DATABASE to_drop
+
+statement ok
+CREATE TEMPORARY TABLE t (i INT PRIMARY KEY);
+
+statement ok
+SELECT * FROM pg_temp.t
+
+statement ok
+USE defaultdb;
+DROP DATABASE to_drop CASCADE;
diff --git a/pkg/sql/pgwire/conn_test.go b/pkg/sql/pgwire/conn_test.go
index 979076c6df82..e61c10ae7fb0 100644
--- a/pkg/sql/pgwire/conn_test.go
+++ b/pkg/sql/pgwire/conn_test.go
@@ -1593,6 +1593,14 @@ func TestParseClientProvidedSessionParameters(t *testing.T) {
_ = c.Ping(ctx)
// closing connection immediately, since getSessionArgs is blocking
_ = c.Close(ctx)
+
+ select {
+ case <-c.PgConn().CleanupDone():
+ case <-time.After(20 * time.Second):
+ // 20 seconds was picked because pgconn has an internal deadline of
+ // 15 seconds when performing the async close request.
+ t.Error("pgconn asyncClose did not clean up on time")
+ }
}(tc.query)
// Wait for the client to connect and perform the handshake.
_, args, err := getSessionArgs(ln, true /* trustRemoteAddr */)
diff --git a/pkg/sql/schemachanger/scplan/internal/opgen/opgen_unique_without_index_constraint.go b/pkg/sql/schemachanger/scplan/internal/opgen/opgen_unique_without_index_constraint.go
index 1155d15c1ae4..76c868d55f6a 100644
--- a/pkg/sql/schemachanger/scplan/internal/opgen/opgen_unique_without_index_constraint.go
+++ b/pkg/sql/schemachanger/scplan/internal/opgen/opgen_unique_without_index_constraint.go
@@ -44,15 +44,6 @@ func init() {
BackReferencedTableID: this.TableID,
}
}),
- emit(func(this *scpb.UniqueWithoutIndexConstraint) *scop.UpdateTableBackReferencesInSequences {
- if this.Predicate == nil || this.Predicate.UsesSequenceIDs == nil || len(this.Predicate.UsesSequenceIDs) == 0 {
- return nil
- }
- return &scop.UpdateTableBackReferencesInSequences{
- SequenceIDs: this.Predicate.UsesSequenceIDs,
- BackReferencedTableID: this.TableID,
- }
- }),
),
to(scpb.Status_VALIDATED,
emit(func(this *scpb.UniqueWithoutIndexConstraint) *scop.ValidateConstraint {
@@ -92,6 +83,15 @@ func init() {
ConstraintID: this.ConstraintID,
}
}),
+ emit(func(this *scpb.UniqueWithoutIndexConstraint) *scop.UpdateTableBackReferencesInTypes {
+ if this.Predicate == nil || this.Predicate.UsesTypeIDs == nil || len(this.Predicate.UsesTypeIDs) == 0 {
+ return nil
+ }
+ return &scop.UpdateTableBackReferencesInTypes{
+ TypeIDs: this.Predicate.UsesTypeIDs,
+ BackReferencedTableID: this.TableID,
+ }
+ }),
),
),
)
diff --git a/pkg/sql/tenant_creation.go b/pkg/sql/tenant_creation.go
index 7e6e25d57dcd..442b08f90197 100644
--- a/pkg/sql/tenant_creation.go
+++ b/pkg/sql/tenant_creation.go
@@ -396,27 +396,65 @@ func CreateTenantRecord(
// This adds a split at the start of the tenant keyspace.
tenantPrefix := keys.MakeTenantPrefix(tenantID)
- startRecord, err := spanconfig.MakeRecord(spanconfig.MakeTargetFromSpan(roachpb.Span{
+ startRecordTarget := spanconfig.MakeTargetFromSpan(roachpb.Span{
Key: tenantPrefix,
EndKey: tenantPrefix.Next(),
- }), tenantSpanConfig)
+ })
+ startRecord, err := spanconfig.MakeRecord(startRecordTarget, tenantSpanConfig)
if err != nil {
return roachpb.TenantID{}, err
}
-
- // This adds a split at the end of the tenant keyspace. This split would
- // eventually be created when the next tenant is created, but until then
- // this tenant's EndKey will be /Max which is outside of it's keyspace.
+ toUpsert := []spanconfig.Record{startRecord}
+
+ // We want to ensure we have a split at the non-inclusive end of the tenant's
+ // keyspace, which also happens to be the inclusive start of the next
+ // tenant's (with ID=ours+1). If we didn't do anything here, and we were the
+ // tenant with the highest ID thus far, our last range would extend to /Max.
+ // If a tenant with a higher ID was created, when installing its initial span
+ // config record, it would carve itself off (and our last range would only
+ // extend to that next tenant's boundary), but this is a bit awkward for code
+ // that wants to rely on the invariant that ranges for a tenant only extend
+ // to the tenant's well-defined end key.
+ //
+ // So how do we ensure this split at this tenant's non-inclusive end key?
+ // Hard splits are controlled by the start keys on span config records[^1],
+ // so we'll try insert one accordingly. But we cannot do this blindly. We
+ // cannot assume that tenants are created in ID order, so it's possible that
+ // the tenant with the next ID is already present + running. If so, it may
+ // already have span config records that start at the key at which we want
+ // to write a span config record for. Over-writing it blindly would be a
+ // mistake -- there's no telling what config that next tenant has associated
+ // for that span. So we'll do something simple -- we'll check transactionally
+ // whether there's anything written already, and if so, do nothing. We
+ // already have the split we need.
+ //
+ // [^1]: See ComputeSplitKey in spanconfig.StoreReader.
tenantPrefixEnd := tenantPrefix.PrefixEnd()
- endRecord, err := spanconfig.MakeRecord(spanconfig.MakeTargetFromSpan(roachpb.Span{
+ endRecordTarget := spanconfig.MakeTargetFromSpan(roachpb.Span{
Key: tenantPrefixEnd,
EndKey: tenantPrefixEnd.Next(),
- }), tenantSpanConfig)
+ })
+
+ // Check if a record exists for the next tenant's startKey from when the next
+ // tenant was created. The current tenant's endRecordTarget is the same as
+ // the next tenant's startRecordTarget.
+ records, err := spanConfigs.GetSpanConfigRecords(ctx, []spanconfig.Target{endRecordTarget})
if err != nil {
return roachpb.TenantID{}, err
}
- toUpsert := []spanconfig.Record{startRecord, endRecord}
+ // If the next tenant's startKey record exists then do not split at the
+ // current tenant's endKey. Doing will incorrectly overwrite the next
+ // tenant's first span config.
+ // See: https://github.com/cockroachdb/cockroach/issues/95882
+ if len(records) == 0 {
+ endRecord, err := spanconfig.MakeRecord(endRecordTarget, tenantSpanConfig)
+ if err != nil {
+ return roachpb.TenantID{}, err
+ }
+ toUpsert = append(toUpsert, endRecord)
+ }
+
return tenantID, spanConfigs.UpdateSpanConfigRecords(
ctx, nil, toUpsert, hlc.MinTimestamp, hlc.MaxTimestamp,
)
diff --git a/pkg/sql/unique_without_index_test.go b/pkg/sql/unique_without_index_test.go
new file mode 100644
index 000000000000..9e973773122a
--- /dev/null
+++ b/pkg/sql/unique_without_index_test.go
@@ -0,0 +1,73 @@
+// Copyright 2023 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 sql
+
+import (
+ "context"
+ "testing"
+
+ "github.com/cockroachdb/cockroach/pkg/base"
+ "github.com/cockroachdb/cockroach/pkg/keys"
+ "github.com/cockroachdb/cockroach/pkg/sql/catalog/descpb"
+ "github.com/cockroachdb/cockroach/pkg/sql/catalog/desctestutils"
+ "github.com/cockroachdb/cockroach/pkg/testutils"
+ "github.com/cockroachdb/cockroach/pkg/testutils/serverutils"
+ "github.com/cockroachdb/cockroach/pkg/testutils/sqlutils"
+ "github.com/cockroachdb/cockroach/pkg/util/leaktest"
+ "github.com/cockroachdb/cockroach/pkg/util/log"
+ "github.com/stretchr/testify/require"
+)
+
+// TestUWIConstraintReferencingTypes tests that adding/dropping
+// unique without index constraints that reference other type descriptors
+// properly adds/drops back-references in the type descriptor.
+func TestUWIConstraintReferencingTypes(t *testing.T) {
+ defer leaktest.AfterTest(t)()
+ defer log.Scope(t).Close(t)
+ ctx := context.Background()
+
+ testutils.RunTrueAndFalse(t, "test-in-both-legacy-and-declarative-schema-changer", func(
+ t *testing.T, useDeclarativeSchemaChanger bool,
+ ) {
+ s, sqlDB, kvDB := serverutils.StartServer(t, base.TestServerArgs{})
+ defer s.Stopper().Stop(ctx)
+ tdb := sqlutils.MakeSQLRunner(sqlDB)
+
+ if useDeclarativeSchemaChanger {
+ tdb.Exec(t, "SET use_declarative_schema_changer = on;")
+ } else {
+ tdb.Exec(t, "SET use_declarative_schema_changer = off;")
+ }
+ tdb.Exec(t, "SET experimental_enable_unique_without_index_constraints = true;")
+ tdb.Exec(t, "CREATE TYPE typ AS ENUM ('a', 'b');")
+ tdb.Exec(t, "CREATE TABLE t (i INT PRIMARY KEY, j STRING);")
+ tdb.Exec(t, "ALTER TABLE t ADD UNIQUE WITHOUT INDEX (j) WHERE (j::typ != 'a');")
+
+ // Ensure that `typ` has a back-reference to table `t`.
+ tableDesc := desctestutils.TestingGetPublicTableDescriptor(kvDB, keys.SystemSQLCodec,
+ "defaultdb", "t")
+ typDesc := desctestutils.TestingGetPublicTypeDescriptor(kvDB, keys.SystemSQLCodec,
+ "defaultdb", "typ")
+ require.Equal(t, []descpb.ID{tableDesc.GetID()}, typDesc.GetReferencingDescriptorIDs())
+
+ // Ensure that dropping `typ` fails because `typ` is referenced by the constraint.
+ tdb.ExpectErr(t, `pq: cannot drop type "typ" because other objects \(\[defaultdb.public.t\]\) still depend on it`, "DROP TYPE typ")
+
+ // Ensure that dropping the constraint removes the back-reference from `typ`.
+ tdb.Exec(t, "ALTER TABLE t DROP CONSTRAINT unique_j")
+ typDesc = desctestutils.TestingGetPublicTypeDescriptor(kvDB, keys.SystemSQLCodec,
+ "defaultdb", "typ")
+ require.Nil(t, typDesc.GetReferencingDescriptorIDs())
+
+ // Ensure that now we can succeed dropping `typ`.
+ tdb.Exec(t, "DROP TYPE typ")
+ })
+}
diff --git a/pkg/sql/vars.go b/pkg/sql/vars.go
index f0648b65938b..b98e10818fb0 100644
--- a/pkg/sql/vars.go
+++ b/pkg/sql/vars.go
@@ -1745,24 +1745,6 @@ var varGen = map[string]sessionVar{
},
},
- `enable_experimental_stream_replication`: {
- GetStringVal: makePostgresBoolGetStringValFn(`enable_experimental_stream_replication`),
- Set: func(_ context.Context, m sessionDataMutator, s string) error {
- b, err := paramparse.ParseBoolVar(`enable_experimental_stream_replication`, s)
- if err != nil {
- return err
- }
- m.SetStreamReplicationEnabled(b)
- return nil
- },
- Get: func(evalCtx *extendedEvalContext, _ *kv.Txn) (string, error) {
- return formatBoolAsPostgresSetting(evalCtx.SessionData().EnableStreamReplication), nil
- },
- GlobalDefault: func(sv *settings.Values) string {
- return formatBoolAsPostgresSetting(experimentalStreamReplicationEnabled.Get(sv))
- },
- },
-
// CockroachDB extension. See experimentalComputedColumnRewrites or
// ParseComputedColumnRewrites for a description of the format.
`experimental_computed_column_rewrites`: {
diff --git a/pkg/ts/catalog/chart_catalog.go b/pkg/ts/catalog/chart_catalog.go
index 265ca532f0f9..0a099065b693 100644
--- a/pkg/ts/catalog/chart_catalog.go
+++ b/pkg/ts/catalog/chart_catalog.go
@@ -1614,9 +1614,9 @@ var charts = []sectionDescription{
},
},
{
- Title: "Ingested Bytes",
+ Title: "Logical Bytes",
Metrics: []string{
- "replication.ingested_bytes",
+ "replication.logical_bytes",
},
},
{
diff --git a/pkg/ui/workspaces/db-console/src/redux/clusterSettings/clusterSettings.selectors.ts b/pkg/ui/workspaces/db-console/src/redux/clusterSettings/clusterSettings.selectors.ts
index 62d0e3601e27..efb446a5bed4 100644
--- a/pkg/ui/workspaces/db-console/src/redux/clusterSettings/clusterSettings.selectors.ts
+++ b/pkg/ui/workspaces/db-console/src/redux/clusterSettings/clusterSettings.selectors.ts
@@ -52,3 +52,14 @@ export const selectAutomaticStatsCollectionEnabled = createSelector(
return value === "true";
},
);
+
+export const selectCrossClusterReplicationEnabled = createSelector(
+ selectClusterSettings,
+ (settings): boolean | undefined => {
+ if (!settings) {
+ return undefined;
+ }
+ const value = settings["cross_cluster_replication.enabled"]?.value;
+ return value === "true";
+ },
+);
diff --git a/pkg/ui/workspaces/db-console/src/views/cluster/containers/nodeGraphs/dashboards/crossClusterReplication.tsx b/pkg/ui/workspaces/db-console/src/views/cluster/containers/nodeGraphs/dashboards/crossClusterReplication.tsx
new file mode 100644
index 000000000000..3c02089335a5
--- /dev/null
+++ b/pkg/ui/workspaces/db-console/src/views/cluster/containers/nodeGraphs/dashboards/crossClusterReplication.tsx
@@ -0,0 +1,63 @@
+// Copyright 2023 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.
+
+import React from "react";
+
+import { LineGraph } from "src/views/cluster/components/linegraph";
+import { Metric, Axis } from "src/views/shared/components/metricQuery";
+import { AxisUnits } from "@cockroachlabs/cluster-ui";
+
+import { GraphDashboardProps } from "./dashboardUtils";
+
+export default function (props: GraphDashboardProps) {
+ const { storeSources } = props;
+
+ return [
+
+
+
+
+ ,
+
+
+
+
+ ,
+
+
+
+
+ ,
+ ];
+}
diff --git a/pkg/ui/workspaces/db-console/src/views/cluster/containers/nodeGraphs/index.tsx b/pkg/ui/workspaces/db-console/src/views/cluster/containers/nodeGraphs/index.tsx
index 57b1f60d4b3a..81bd8711b389 100644
--- a/pkg/ui/workspaces/db-console/src/views/cluster/containers/nodeGraphs/index.tsx
+++ b/pkg/ui/workspaces/db-console/src/views/cluster/containers/nodeGraphs/index.tsx
@@ -64,6 +64,7 @@ import hardwareDashboard from "./dashboards/hardware";
import changefeedsDashboard from "./dashboards/changefeeds";
import overloadDashboard from "./dashboards/overload";
import ttlDashboard from "./dashboards/ttl";
+import crossClusterReplicationDashboard from "./dashboards/crossClusterReplication";
import { getMatchParamByName } from "src/util/query";
import { PayloadAction } from "src/interfaces/action";
import {
@@ -84,7 +85,9 @@ import moment from "moment";
import {
selectResolution10sStorageTTL,
selectResolution30mStorageTTL,
+ selectCrossClusterReplicationEnabled,
} from "src/redux/clusterSettings";
+
interface GraphDashboard {
label: string;
component: (props: GraphDashboardProps) => React.ReactElement[];
@@ -103,6 +106,10 @@ const dashboards: { [key: string]: GraphDashboard } = {
changefeeds: { label: "Changefeeds", component: changefeedsDashboard },
overload: { label: "Overload", component: overloadDashboard },
ttl: { label: "TTL", component: ttlDashboard },
+ crossClusterReplication: {
+ label: "Cross-Cluster Replication",
+ component: crossClusterReplicationDashboard,
+ },
};
const defaultDashboard = "overview";
@@ -127,6 +134,7 @@ type MapStateToProps = {
nodeDisplayNameByID: ReturnType<
typeof nodeDisplayNameByIDSelector.resultFunc
>;
+ crossClusterReplicationEnabled: boolean;
};
type MapDispatchToProps = {
@@ -166,6 +174,7 @@ export class NodeGraphs extends React.Component<
refresh = () => {
this.props.refreshNodes();
this.props.refreshLiveness();
+ this.props.refreshNodeSettings();
};
setClusterPath(nodeID: string, dashboardName: string) {
@@ -317,6 +326,12 @@ export class NodeGraphs extends React.Component<
const paddingBottom =
nodeIDs.length > 8 ? 90 + Math.ceil(nodeIDs.length / 3) * 10 : 50;
+ const filteredDropdownOptions = this.props.crossClusterReplicationEnabled
+ ? dashboardDropdownOptions // Already in the list, no need to filter
+ : dashboardDropdownOptions.filter(
+ option => option.label !== "Cross-Cluster Replication",
+ );
+
return (
@@ -333,7 +348,7 @@ export class NodeGraphs extends React.Component<
({
storeIDsByNodeID: selectStoreIDsByNodeID(state),
nodeDropdownOptions: nodeDropdownOptionsSelector(state),
nodeDisplayNameByID: nodeDisplayNameByIDSelector(state),
+ crossClusterReplicationEnabled: selectCrossClusterReplicationEnabled(state),
});
const mapDispatchToProps: MapDispatchToProps = {