Skip to content

Commit

Permalink
spanconfigsqltranslator: populate protected_timestamps in SpanConfig
Browse files Browse the repository at this point in the history
This change teaches the SQLTranslator to hydrate the SpanConfigs
for a table with protected timestamps that apply to that table.

Concretely, this change initializes a spanconfig.ProtectedTimestampStateReader
in the txn in which the translation is taking place, thereby
providing a transactional view of the system.protected_ts_records
table. After generating the span configurations based on the zone
configurations that apply to the table, we hydrate the newly
introduced protected_timestamps field on each span configuration
with all the protected timestamps that apply to this table. This
includes protected timestamp records that directly target this
table, as well as records targetting the table's parent database.
This information is obtained from the ProtectedTimestampStateReader
mentioned above.

Additionally, this change modifies StartTenant to allow secondary
tenants to interact with the protected timestamp subsystem using a
"real" protectedts.Provider provided the migration
EnableProtectedTimestampsForTenant has run.

For testing purposes, this change teaches the data driven framework
of two additional commands protect and release.

Informs: #73727

Release note: None
  • Loading branch information
adityamaru committed Jan 22, 2022
1 parent 22f45e5 commit 57f3502
Show file tree
Hide file tree
Showing 22 changed files with 436 additions and 54 deletions.
2 changes: 1 addition & 1 deletion docs/generated/settings/settings-for-tenants.txt
Original file line number Diff line number Diff line change
Expand Up @@ -174,4 +174,4 @@ trace.debug.enable boolean false if set, traces for recent requests can be seen
trace.jaeger.agent string the address of a Jaeger agent to receive traces using the Jaeger UDP Thrift protocol, as <host>:<port>. If no port is specified, 6381 will be used.
trace.opentelemetry.collector string address of an OpenTelemetry trace collector to receive traces using the otel gRPC protocol, as <host>:<port>. If no port is specified, 4317 will be used.
trace.zipkin.collector string the address of a Zipkin instance to receive traces, as <host>:<port>. If no port is specified, 9411 will be used.
version version 21.2-48 set the active cluster version in the format '<major>.<minor>'
version version 21.2-50 set the active cluster version in the format '<major>.<minor>'
2 changes: 1 addition & 1 deletion docs/generated/settings/settings.html
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,6 @@
<tr><td><code>trace.jaeger.agent</code></td><td>string</td><td><code></code></td><td>the address of a Jaeger agent to receive traces using the Jaeger UDP Thrift protocol, as <host>:<port>. If no port is specified, 6381 will be used.</td></tr>
<tr><td><code>trace.opentelemetry.collector</code></td><td>string</td><td><code></code></td><td>address of an OpenTelemetry trace collector to receive traces using the otel gRPC protocol, as <host>:<port>. If no port is specified, 4317 will be used.</td></tr>
<tr><td><code>trace.zipkin.collector</code></td><td>string</td><td><code></code></td><td>the address of a Zipkin instance to receive traces, as <host>:<port>. If no port is specified, 9411 will be used.</td></tr>
<tr><td><code>version</code></td><td>version</td><td><code>21.2-48</code></td><td>set the active cluster version in the format '<major>.<minor>'</td></tr>
<tr><td><code>version</code></td><td>version</td><td><code>21.2-50</code></td><td>set the active cluster version in the format '<major>.<minor>'</td></tr>
</tbody>
</table>
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ func TestDataDriven(t *testing.T) {
tdb.Exec(t, `SET CLUSTER SETTING kv.closed_timestamp.target_duration = '100ms'`)
}

spanConfigTestCluster := spanconfigtestcluster.NewHandle(t, tc, scKnobs)
spanConfigTestCluster := spanconfigtestcluster.NewHandle(t, tc, scKnobs, nil /* ptsKnobs */)
defer spanConfigTestCluster.Cleanup()

kvSubscriber := tc.Server(0).SpanConfigKVSubscriber().(spanconfig.KVSubscriber)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ func TestDataDriven(t *testing.T) {
tdb.Exec(t, `SET CLUSTER SETTING kv.closed_timestamp.target_duration = '100ms'`)
}

spanConfigTestCluster := spanconfigtestcluster.NewHandle(t, tc, scKnobs)
spanConfigTestCluster := spanconfigtestcluster.NewHandle(t, tc, scKnobs, nil /* ptsKnobs */)
defer spanConfigTestCluster.Cleanup()

systemTenant := spanConfigTestCluster.InitializeTenant(ctx, roachpb.SystemTenantID)
Expand Down
6 changes: 6 additions & 0 deletions pkg/ccl/spanconfigccl/spanconfigsqltranslatorccl/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ go_test(
"//pkg/ccl/partitionccl",
"//pkg/ccl/utilccl",
"//pkg/config/zonepb",
"//pkg/jobs/jobsprotectedts",
"//pkg/kv",
"//pkg/kv/kvserver/protectedts",
"//pkg/kv/kvserver/protectedts/ptpb",
"//pkg/roachpb:with-mocks",
"//pkg/security",
"//pkg/security/securitytest",
Expand All @@ -26,9 +30,11 @@ go_test(
"//pkg/testutils/serverutils",
"//pkg/testutils/sqlutils",
"//pkg/testutils/testcluster",
"//pkg/util/hlc",
"//pkg/util/leaktest",
"//pkg/util/log",
"//pkg/util/randutil",
"//pkg/util/uuid",
"@com_github_cockroachdb_datadriven//:datadriven",
"@com_github_stretchr_testify//require",
],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ import (
_ "github.com/cockroachdb/cockroach/pkg/ccl/kvccl/kvtenantccl"
_ "github.com/cockroachdb/cockroach/pkg/ccl/partitionccl"
"github.com/cockroachdb/cockroach/pkg/config/zonepb"
"github.com/cockroachdb/cockroach/pkg/jobs/jobsprotectedts"
"github.com/cockroachdb/cockroach/pkg/kv"
"github.com/cockroachdb/cockroach/pkg/kv/kvserver/protectedts"
"github.com/cockroachdb/cockroach/pkg/kv/kvserver/protectedts/ptpb"
"github.com/cockroachdb/cockroach/pkg/roachpb"
"github.com/cockroachdb/cockroach/pkg/spanconfig"
"github.com/cockroachdb/cockroach/pkg/spanconfig/spanconfigtestutils"
Expand All @@ -28,8 +32,10 @@ import (
"github.com/cockroachdb/cockroach/pkg/testutils"
"github.com/cockroachdb/cockroach/pkg/testutils/sqlutils"
"github.com/cockroachdb/cockroach/pkg/testutils/testcluster"
"github.com/cockroachdb/cockroach/pkg/util/hlc"
"github.com/cockroachdb/cockroach/pkg/util/leaktest"
"github.com/cockroachdb/cockroach/pkg/util/log"
"github.com/cockroachdb/cockroach/pkg/util/uuid"
"github.com/cockroachdb/datadriven"
"github.com/stretchr/testify/require"
)
Expand Down Expand Up @@ -61,6 +67,15 @@ import (
// - "mark-table-public" [database=<str>] [table=<str>]
// Marks the given table as public.
//
// - "protect" [record-id=<int>] [ts=<int>]
// cluster OR
// tenants id1,id2... OR
// descs id1,id2...
// Creates and writes a protected timestamp record with id and ts with an
// appropriate ptpb.Target.
//
// - "release" [record-id=<int>]
// Releases the protected timestamp record with id.
func TestDataDriven(t *testing.T) {
defer leaktest.AfterTest(t)()
defer log.Scope(t).Close(t)
Expand All @@ -77,17 +92,21 @@ func TestDataDriven(t *testing.T) {
// test cluster).
ManagerDisableJobCreation: true,
}
ptsKnobs := &protectedts.TestingKnobs{
EnableProtectedTimestampForMultiTenant: true,
}
datadriven.Walk(t, testutils.TestDataPath(t), func(t *testing.T, path string) {
tc := testcluster.StartTestCluster(t, 1, base.TestClusterArgs{
ServerArgs: base.TestServerArgs{
Knobs: base.TestingKnobs{
SpanConfig: scKnobs,
SpanConfig: scKnobs,
ProtectedTS: ptsKnobs,
},
},
})
defer tc.Stopper().Stop(ctx)

spanConfigTestCluster := spanconfigtestcluster.NewHandle(t, tc, scKnobs)
spanConfigTestCluster := spanconfigtestcluster.NewHandle(t, tc, scKnobs, ptsKnobs)
defer spanConfigTestCluster.Cleanup()

var tenant *spanconfigtestcluster.Tenant
Expand All @@ -98,6 +117,10 @@ func TestDataDriven(t *testing.T) {
tenant = spanConfigTestCluster.InitializeTenant(ctx, roachpb.SystemTenantID)
}

execCfg := tenant.ExecCfg()
ptp := tenant.ProtectedTimestampProvider()
jr := tenant.JobsRegistry()

datadriven.RunTest(t, path, func(t *testing.T, d *datadriven.TestData) string {
switch d.Cmd {
case "exec-sql":
Expand Down Expand Up @@ -183,6 +206,40 @@ func TestDataDriven(t *testing.T) {
mutable.SetPublic()
})

case "protect":
mkRecordAndProtect := func(recordID string, ts hlc.Timestamp, target *ptpb.Target) {
jobID := jr.MakeJobID()
require.NoError(t, execCfg.DB.Txn(ctx, func(ctx context.Context, txn *kv.Txn) (err error) {
require.Len(t, recordID, 1, "datadriven test only supports single digit record IDs")
recID, err := uuid.FromBytes([]byte(strings.Repeat(recordID, 16)))
require.NoError(t, err)
rec := jobsprotectedts.MakeRecord(recID, int64(jobID), ts,
nil /* deprecatedSpans */, jobsprotectedts.Jobs, target)
return ptp.Protect(ctx, txn, rec)
}))
}

var recordID string
var protectTS int
d.ScanArgs(t, "record-id", &recordID)
d.ScanArgs(t, "ts", &protectTS)
target := spanconfigtestutils.ParseProtectionTarget(t, d.Input)

mkRecordAndProtect(recordID, hlc.Timestamp{WallTime: int64(protectTS)}, target)

case "release":
releaseRecord := func(recordID string) {
require.NoError(t, execCfg.DB.Txn(ctx, func(ctx context.Context, txn *kv.Txn) error {
require.Len(t, recordID, 1, "datadriven test only supports single digit record IDs")
recID, err := uuid.FromBytes([]byte(strings.Repeat(recordID, 16)))
require.NoError(t, err)
return ptp.Release(ctx, txn, recID)
}))
}

var recordID string
d.ScanArgs(t, "record-id", &recordID)
releaseRecord(recordID)
default:
t.Fatalf("unknown command: %s", d.Cmd)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
# Create a database with some tables and write protected timestamps on the
# tables and database. Check that span configurations are as we expect.

exec-sql
CREATE DATABASE db;
CREATE TABLE db.t1(id INT);
CREATE TABLE db.t2();
----

# Schema object IDs
# db: 54
# t1: 56
# t2: 57

# Alter zone config fields on the database and one of the tables to ensure
# things are cascading.
exec-sql
ALTER DATABASE db CONFIGURE ZONE USING num_replicas=7;
ALTER TABLE db.t1 CONFIGURE ZONE USING num_voters=5;
----

# Write a protected timestamp on t1.
protect record-id=1 ts=1
descs 56
----

translate database=db
----
/Table/5{6-7} num_replicas=7 num_voters=5 pts=[1]
/Table/5{7-8} num_replicas=7

# Write a protected timestamp on db, so we should see it on both t1 and t2.
protect record-id=2 ts=2
descs 54
----

translate database=db
----
/Table/5{6-7} num_replicas=7 num_voters=5 pts=[1 2]
/Table/5{7-8} num_replicas=7 pts=[2]

# Release the protected timestamp on table t1
release record-id=1
----

translate database=db
----
/Table/5{6-7} num_replicas=7 num_voters=5 pts=[2]
/Table/5{7-8} num_replicas=7 pts=[2]

# Release the protected timestamp on database db
release record-id=2
----

translate database=db
----
/Table/5{6-7} num_replicas=7 num_voters=5
/Table/5{7-8} num_replicas=7

# Create an index on t1 to ensure that subzones also see protected timestamps.
exec-sql
CREATE INDEX idx ON db.t1(id);
ALTER INDEX db.t1@idx CONFIGURE ZONE USING gc.ttlseconds = 1;
----

protect record-id=3 ts=3
descs 56
----

translate database=db
----
/Table/56{-/2} num_replicas=7 num_voters=5 pts=[3]
/Table/56/{2-3} ttl_seconds=1 num_replicas=7 num_voters=5 pts=[3]
/Table/5{6/3-7} num_replicas=7 num_voters=5 pts=[3]
/Table/5{7-8} num_replicas=7

Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# Create a database with some tables and write protected timestamps on the
# tables and database. Check that span configurations are as we expect.

exec-sql
CREATE DATABASE db;
CREATE TABLE db.t1(id INT);
CREATE TABLE db.t2();
----

# Schema object IDs
# db: 54
# t1: 56
# t2: 57

# Alter zone config fields on the database and one of the tables to ensure
# things are cascading.
exec-sql
ALTER DATABASE db CONFIGURE ZONE USING num_replicas=7;
ALTER TABLE db.t1 CONFIGURE ZONE USING num_voters=5;
----

# Write a protected timestamp on t1.
protect record-id=1 ts=1
descs 56
----

translate database=db
----
/Tenant/10/Table/5{6-7} num_replicas=7 num_voters=5 pts=[1]
/Tenant/10/Table/5{7-8} num_replicas=7

# Write a protected timestamp on db, so we should see it on both t1 and t2.
protect record-id=2 ts=2
descs 54
----

translate database=db
----
/Tenant/10/Table/5{6-7} num_replicas=7 num_voters=5 pts=[1 2]
/Tenant/10/Table/5{7-8} num_replicas=7 pts=[2]

# Release the protected timestamp on table t1
release record-id=1
----

translate database=db
----
/Tenant/10/Table/5{6-7} num_replicas=7 num_voters=5 pts=[2]
/Tenant/10/Table/5{7-8} num_replicas=7 pts=[2]

# Release the protected timestamp on database db
release record-id=2
----

translate database=db
----
/Tenant/10/Table/5{6-7} num_replicas=7 num_voters=5
/Tenant/10/Table/5{7-8} num_replicas=7

# Create an index on t1 to ensure that subzones also see protected timestamps.
exec-sql
CREATE INDEX idx ON db.t1(id);
ALTER INDEX db.t1@idx CONFIGURE ZONE USING gc.ttlseconds = 1;
----

protect record-id=3 ts=3
descs 56
----

translate database=db
----
/Tenant/10/Table/56{-/2} num_replicas=7 num_voters=5 pts=[3]
/Tenant/10/Table/56/{2-3} ttl_seconds=1 num_replicas=7 num_voters=5 pts=[3]
/Tenant/10/Table/5{6/3-7} num_replicas=7 num_voters=5 pts=[3]
/Tenant/10/Table/5{7-8} num_replicas=7
29 changes: 18 additions & 11 deletions pkg/clusterversion/cockroach_versions.go
Original file line number Diff line number Diff line change
Expand Up @@ -225,10 +225,6 @@ const (
SeedTenantSpanConfigs
// PublicSchemasWithDescriptors backs public schemas with descriptors.
PublicSchemasWithDescriptors
// AlterSystemProtectedTimestampAddColumn adds a target column to the
// system.protected_ts_records table that describes what is protected by the
// record.
AlterSystemProtectedTimestampAddColumn
// EnsureSpanConfigReconciliation ensures that the host tenant has run its
// reconciliation process at least once.
EnsureSpanConfigReconciliation
Expand All @@ -248,6 +244,13 @@ const (
// that correspond to range descriptor changes resulting from recovery
// procedures.
UnsafeLossOfQuorumRecoveryRangeLog
// AlterSystemProtectedTimestampAddColumn adds a target column to the
// system.protected_ts_records table that describes what is protected by the
// record.
AlterSystemProtectedTimestampAddColumn
// EnableProtectedTimestampsForTenant enables the use of protected timestamps
// in secondary tenants.
EnableProtectedTimestampsForTenant

// *************************************************
// Step (1): Add new versions here.
Expand Down Expand Up @@ -353,33 +356,37 @@ var versionsSingleton = keyedVersions{
Version: roachpb.Version{Major: 21, Minor: 2, Internal: 34},
},
{
Key: AlterSystemProtectedTimestampAddColumn,
Key: EnsureSpanConfigReconciliation,
Version: roachpb.Version{Major: 21, Minor: 2, Internal: 36},
},
{
Key: EnsureSpanConfigReconciliation,
Key: EnsureSpanConfigSubscription,
Version: roachpb.Version{Major: 21, Minor: 2, Internal: 38},
},
{
Key: EnsureSpanConfigSubscription,
Key: EnableSpanConfigStore,
Version: roachpb.Version{Major: 21, Minor: 2, Internal: 40},
},
{
Key: EnableSpanConfigStore,
Key: ScanWholeRows,
Version: roachpb.Version{Major: 21, Minor: 2, Internal: 42},
},
{
Key: ScanWholeRows,
Key: SCRAMAuthentication,
Version: roachpb.Version{Major: 21, Minor: 2, Internal: 44},
},
{
Key: SCRAMAuthentication,
Key: UnsafeLossOfQuorumRecoveryRangeLog,
Version: roachpb.Version{Major: 21, Minor: 2, Internal: 46},
},
{
Key: UnsafeLossOfQuorumRecoveryRangeLog,
Key: AlterSystemProtectedTimestampAddColumn,
Version: roachpb.Version{Major: 21, Minor: 2, Internal: 48},
},
{
Key: EnableProtectedTimestampsForTenant,
Version: roachpb.Version{Major: 21, Minor: 2, Internal: 50},
},

// *************************************************
// Step (2): Add new versions here.
Expand Down
Loading

0 comments on commit 57f3502

Please sign in to comment.