Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

spanconfigsqltranslator: introduce a pts table reader #74737

Merged
merged 1 commit into from
Jan 20, 2022

Conversation

adityamaru
Copy link
Contributor

This change introduces a ProtectedTimestampTableReader
that provides a txn scoped, in-memory view of the system
table that stores protected timestamp records.

The SQLTranslator will use this table reader to generate
SpanConfigs and SystemSpanConfigs in a follow up PR.

Informs: #73727

Release note: None

@adityamaru adityamaru requested review from arulajmani, irfansharif and a team January 12, 2022 16:59
@adityamaru adityamaru requested review from a team as code owners January 12, 2022 16:59
@adityamaru adityamaru requested review from stevendanna and removed request for a team January 12, 2022 16:59
@cockroach-teamcity
Copy link
Member

This change is Reviewable

@adityamaru adityamaru requested review from a team and removed request for a team January 12, 2022 16:59
@adityamaru
Copy link
Contributor Author

First commit is from #74297.

Copy link
Collaborator

@arulajmani arulajmani left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mostly looks good 💯

Reviewed 19 of 19 files at r1, 2 of 5 files at r2, all commit messages.
Reviewable status: :shipit: complete! 0 of 0 LGTMs obtained (waiting on @adityamaru, @irfansharif, and @stevendanna)


pkg/spanconfig/spanconfig.go, line 247 at r2 (raw file):

// protected timestamps that apply to the different targets that can be
// protected from GC.
type ProtectedTimestampTableReader interface {

Now that we're only using this thing in the Translator, and not in the Reconciler, does this thing need to be a top level interface? Or can we contain it to the spanconfigsqltranslator package


pkg/spanconfig/spanconfigprotectedts/protectedts_table_reader.go, line 76 at r2 (raw file):

// read from the in-memory store.
type ProtectedTimestampTableReader struct {
	protections map[key][]hlc.Timestamp

Instead of this single map, you could instead have 3 separate fields for cluster, schema objects, and tenants instead. For schema objects/tenants you could use a map keyed by descriptor ID/tenantID. This would allow you to get rid of the key encoding scheme (and string allocations) above.


pkg/spanconfig/spanconfigprotectedts/protectedts_table_reader.go, line 124 at r2 (raw file):

}

func (p *ProtectedTimestampTableReader) unmarshalProtectedTimestampRecord(

Should we make this into a decoder struct similar to what we do for system.zones and system.descriptors? It might be worth doing that because we'll use this thing in the sqlwatcher as well.


pkg/spanconfig/spanconfigprotectedts/protectedts_table_reader.go, line 163 at r2 (raw file):

	ctx context.Context, ptsRecordsSystemTable string, ie sqlutil.InternalExecutor, txn *kv.Txn,
) (retErr error) {
	getProtectedTimestampRecordStmt := fmt.Sprintf(`SELECT ts, target FROM %s`, ptsRecordsSystemTable)

Can we use the GetState method on protectedts.Storage instead by threading in that interface into here?


pkg/spanconfig/spanconfigprotectedts/protectedts_table_reader_test.go, line 36 at r2 (raw file):

)

func TestProtectedTimestampTableReader(t *testing.T) {

You could convert this thing into a datadriven test -- it'll allow you to test things like different records that target the same schema object/tenant/cluster easily.


pkg/spanconfig/spanconfigprotectedts/protectedts_table_reader_test.go, line 66 at r2 (raw file):

	// Protect the cluster.
	clusterProtect := s0.Clock().Now()

nit: Instead of using Now(), you can instead create synthetic timestamps. Check out the TestBuffer in the spanconfigsqlwatcher package


pkg/spanconfig/spanconfigprotectedts/protectedts_table_reader_test.go, line 72 at r2 (raw file):

	tenantProtect := s0.Clock().Now()
	mkRecordAndProtect(tenantProtect, ptpb.MakeTenantsTarget([]roachpb.TenantID{roachpb.MakeTenantID(1),
		roachpb.MakeTenantID(2)}))

Might be worth protecting a tenant in a separate record and ensuring that all tenant protections are returned.

Copy link
Contributor Author

@adityamaru adityamaru left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewable status: :shipit: complete! 0 of 0 LGTMs obtained (waiting on @arulajmani, @irfansharif, and @stevendanna)


pkg/spanconfig/spanconfig.go, line 247 at r2 (raw file):

Previously, arulajmani (Arul Ajmani) wrote…

Now that we're only using this thing in the Translator, and not in the Reconciler, does this thing need to be a top level interface? Or can we contain it to the spanconfigsqltranslator package

i don't think it needs to be a top-level interface, removed and moved into the spanconfigsqltranslator package.


pkg/spanconfig/spanconfigprotectedts/protectedts_table_reader.go, line 76 at r2 (raw file):

Previously, arulajmani (Arul Ajmani) wrote…

Instead of this single map, you could instead have 3 separate fields for cluster, schema objects, and tenants instead. For schema objects/tenants you could use a map keyed by descriptor ID/tenantID. This would allow you to get rid of the key encoding scheme (and string allocations) above.

good idea yeah, simplifies everything.


pkg/spanconfig/spanconfigprotectedts/protectedts_table_reader.go, line 124 at r2 (raw file):

Previously, arulajmani (Arul Ajmani) wrote…

Should we make this into a decoder struct similar to what we do for system.zones and system.descriptors? It might be worth doing that because we'll use this thing in the sqlwatcher as well.

As discussed offline, i'll bring this in the PR that sets up the rangefeed in the SQLWatcher, and come back and clean this up then.


pkg/spanconfig/spanconfigprotectedts/protectedts_table_reader.go, line 163 at r2 (raw file):

Can we use the GetState method on protectedts.Storage instead by threading in that interface into here?

Very nice catch. I think we can, the SQLTranslator which will use this reader already has an ExecCfg which in turn has a ptpb.Provider. Changed to do that instead!


pkg/spanconfig/spanconfigprotectedts/protectedts_table_reader_test.go, line 36 at r2 (raw file):

Previously, arulajmani (Arul Ajmani) wrote…

You could convert this thing into a datadriven test -- it'll allow you to test things like different records that target the same schema object/tenant/cluster easily.

Done.


pkg/spanconfig/spanconfigprotectedts/protectedts_table_reader_test.go, line 72 at r2 (raw file):

Previously, arulajmani (Arul Ajmani) wrote…

Might be worth protecting a tenant in a separate record and ensuring that all tenant protections are returned.

Done.

@adityamaru adityamaru changed the title spanconfigprotectedts: introduce a pts table reader spanconfigsqltranslator: introduce a pts table reader Jan 14, 2022
@adityamaru
Copy link
Contributor Author

Rebased, and RFAL!

@adityamaru adityamaru removed the request for review from a team January 17, 2022 19:24
Copy link
Collaborator

@arulajmani arulajmani left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Couple of testing suggestions but otherwise :lgtm:

Thanks for putting in the effort to make the tests here datadriven!

Reviewed 35 of 35 files at r4, all commit messages.
Reviewable status: :shipit: complete! 1 of 0 LGTMs obtained (waiting on @adityamaru, @arulajmani, @irfansharif, and @stevendanna)


pkg/spanconfig/spanconfigsqltranslator/protectedts_table_reader.go, line 39 at r4 (raw file):

	ctx context.Context, txn *kv.Txn, ptsProvider protectedts.Provider,
) (*ProtectedTimestampTableReader, error) {
	reader := &ProtectedTimestampTableReader{

nit: Let's add an assertion failure if the passed in txn is nil?


pkg/spanconfig/spanconfigsqltranslator/testdata/ptstablereader, line 8 at r4 (raw file):


query-sql
SELECT id FROM system.namespace WHERE name='db'

nit: Instead of the queries to system.namespace below, just comment the IDs of these objects here instead.


pkg/spanconfig/spanconfigsqltranslator/testdata/ptstablereader, line 49 at r4 (raw file):

# Write a protected timestamp on tenant 2.
protect id=6 ts=6
tenant 2

Maybe add another on this tenant for completeness?


pkg/spanconfig/spanconfigsqltranslator/testdata/ptstablereader, line 75 at r4 (raw file):

tablereader tenants
----
id=1 [ts=5]

nit: s/id/tenant_id/g (in the datadriven test where such output is printed) considering "id" is overloaded here.


pkg/spanconfig/spanconfigsqltranslator/testdata/ptstablereader, line 89 at r4 (raw file):


# Records on t1.
tablereader schemaObject=56

Let's add a test that releases either id=1 or id=2 as well, to test that records being protected/released don't affect other records that apply to a particular ID.

Copy link
Contributor Author

@adityamaru adityamaru left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewable status: :shipit: complete! 1 of 0 LGTMs obtained (waiting on @arulajmani, @irfansharif, and @stevendanna)


pkg/spanconfig/spanconfigsqltranslator/protectedts_table_reader.go, line 39 at r4 (raw file):

Previously, arulajmani (Arul Ajmani) wrote…

nit: Let's add an assertion failure if the passed in txn is nil?

Since we're passing in a state now this check happens in GetState() itself.


pkg/spanconfig/spanconfigsqltranslator/testdata/ptstablereader, line 8 at r4 (raw file):

Previously, arulajmani (Arul Ajmani) wrote…

nit: Instead of the queries to system.namespace below, just comment the IDs of these objects here instead.

done.


pkg/spanconfig/spanconfigsqltranslator/testdata/ptstablereader, line 49 at r4 (raw file):

Previously, arulajmani (Arul Ajmani) wrote…

Maybe add another on this tenant for completeness?

Done.


pkg/spanconfig/spanconfigsqltranslator/testdata/ptstablereader, line 75 at r4 (raw file):

Previously, arulajmani (Arul Ajmani) wrote…

nit: s/id/tenant_id/g (in the datadriven test where such output is printed) considering "id" is overloaded here.

done.


pkg/spanconfig/spanconfigsqltranslator/testdata/ptstablereader, line 89 at r4 (raw file):

Previously, arulajmani (Arul Ajmani) wrote…

Let's add a test that releases either id=1 or id=2 as well, to test that records being protected/released don't affect other records that apply to a particular ID.

Done.

@adityamaru
Copy link
Contributor Author

@irfansharif changed the state reader to take in a ptpb.State instead as we discussed, let me know what you think.

defer spanConfigTestCluster.Cleanup()

var tenant *spanconfigtestcluster.Tenant
// TODO(adityamaru): When secondary tenants have a "real"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Take the opportunity to move this test code to pkg/ccl/spanconfigccl/...; when using tenant code you need a CCL binary, and need to sit under pkg/ccl.


// ProtectedTimestampStateReader provides a target specific view of the
// protected timestamp records stored in the system table.
type ProtectedTimestampStateReader struct {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't need to be exported from this package, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

doesn't yup, changed.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ahh can't do this because the linter doesn't like it:

exported func TestingNewProtectedTimestampStateReader returns unexported type *spanconfigsqltranslator.protectedTimestampStateReader, which can be annoying to use

Copy link
Contributor

@irfansharif irfansharif Jan 20, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, you don't need that method either?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yup removed it in the most recent push once i changed the pkg to non _test


// TenantProtectedTimestamps represents all the Protections that apply to a
// tenant's keyspace.
type TenantProtectedTimestamps struct {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto, we don't expect to be used outside the translator package, do we?

Copy link
Contributor Author

@adityamaru adityamaru Jan 19, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need it in the testing package when comparing output so had to leave it exported.

Copy link
Contributor

@irfansharif irfansharif Jan 19, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's an internal type, right? Would using a package internal test make more sense? s/package spanconfigsqltranslator_test/package spanconfigsqltranslator. It would let you unexport as well.

"github.com/stretchr/testify/require"
)

// TestProtectedTimestampStateReader is a data driven test for the
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Discussed a bit offline, but for now while we're just testing this state reader type, and given that it operates off a static ptpb.State snapshot, a simple unit test would suffice. We can graft pieces of this test we've written when hooking it up to the translator as a way to conveniently write to the protected_ts table and ensure the right span configs are generated.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed to a unit test, kept some of the stringer methods around for readabilty, and ease of comparison since I already had them written out.

Copy link
Collaborator

@arulajmani arulajmani left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewable status: :shipit: complete! 0 of 0 LGTMs obtained (and 1 stale) (waiting on @adityamaru, @arulajmani, @irfansharif, and @stevendanna)


pkg/spanconfig/spanconfigsqltranslator/protectedts_state_reader_test.go, line 47 at r5 (raw file):

Previously, adityamaru (Aditya Maru) wrote…

Changed to a unit test, kept some of the stringer methods around for readabilty, and ease of comparison since I already had them written out.

Not to rehash what we talked about offline, but I'm not a fan of going from the datadriven test we had here before to this unit test. We're reducing coverage at worst, and reducing readability at best. Sure, you can test these things using the Translator in a future PR, but that feels very indirect to me.

In particular, having a data driven test allows us to write multiple records to the same schema object/tenant, records that apply to various schema objects/tenants, and release records. Considering this struct responsible for transforming this state and providing accessors over it, what we had earlier provided value.

Copy link
Contributor

@irfansharif irfansharif left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This does not feel much less readable to me. This is a pretty small component, and I think it's fine for our testing of it not have to use the full datadriven machinery. We're really only testing loadProtectedTimestampRecords, right? (which is <20 lines of Go code.)


// TenantProtectedTimestamps represents all the Protections that apply to a
// tenant's keyspace.
type TenantProtectedTimestamps struct {
Copy link
Contributor

@irfansharif irfansharif Jan 19, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's an internal type, right? Would using a package internal test make more sense? s/package spanconfigsqltranslator_test/package spanconfigsqltranslator. It would let you unexport as well.

This change introduces a `ProtectedTimestampStateReader`
that provides an in-memory view of the system
table that stores protected timestamp records.

The `SQLTranslator` will use this table reader to generate
SpanConfigs and SystemSpanConfigs in a follow up PR.

Informs: cockroachdb#73727

Release note: None
@adityamaru
Copy link
Contributor Author

bazel ORM failures are unrelated

TFTRs!

bors r+

@craig craig bot merged commit 506412f into cockroachdb:master Jan 20, 2022
@craig
Copy link
Contributor

craig bot commented Jan 20, 2022

Build succeeded:

@adityamaru adityamaru deleted the full-translate branch January 20, 2022 14:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants