Skip to content

Commit

Permalink
sql: improve tenant records
Browse files Browse the repository at this point in the history
This commit contains the following changes:
- rename "state" to "data_state", "active" to "ready"
- deprecate the column "active" since it mirrors "data_state'
- stored, non-virtual columns for "name", "data_state", "service_mode"

Details follow.

**rename TenantInfo.State to DataState, "ACTIVE" to "READY"**

We've discovered that we'd like to separate the readiness of the data
from the activation of the service. To emphasize this, this commit
renames the field "State" to "DataState".

Additionally, the state "ACTIVE" was confusing as it suggests that
something is running, whereas it merely marks the tenant data as ready
for use. So this commit also renames that state accordingly.

**new tenant info field ServiceMode**

Summary of changes:
- the new TenantInfo.ServiceMode field indicates how to run servers.
- new syntax: `ALTER TENANT ... START SERVICE EXTERNAL/SHARED`,
  `ALTER TENANT ... STOP SERVICE`.
- tenants created via `create_tenant(<id>)`
  (via CC serverless control plane) start in service mode EXTERNAL.
- other tenants start in service mode NONE.
- need ALTER TENANT STOP SERVICE before dropping a tenant.
  - except in the case of `crdb_internal.destroy_tenant`
    for compat with CC serverless control plane.

**make the output columns of SHOW TENANT lowercase**

All the SHOW statements report status-like data in lowercase.
SHOW TENANT(s) should not be different.

**use actual SQL columns for the TenantInfo fields**

Release note: None
  • Loading branch information
knz committed Jan 23, 2023
1 parent b21379b commit 41f5a04
Show file tree
Hide file tree
Showing 57 changed files with 1,038 additions and 428 deletions.
3 changes: 3 additions & 0 deletions docs/generated/sql/bnf/stmt_block.bnf
Original file line number Diff line number Diff line change
Expand Up @@ -1338,11 +1338,13 @@ unreserved_keyword ::=
| 'SEQUENCE'
| 'SEQUENCES'
| 'SERVER'
| 'SERVICE'
| 'SESSION'
| 'SESSIONS'
| 'SET'
| 'SETS'
| 'SHARE'
| 'SHARED'
| 'SHOW'
| 'SIMPLE'
| 'SKIP'
Expand All @@ -1361,6 +1363,7 @@ unreserved_keyword ::=
| 'STATEMENTS'
| 'STATISTICS'
| 'STDIN'
| 'STOP'
| 'STORAGE'
| 'STORE'
| 'STORED'
Expand Down
67 changes: 50 additions & 17 deletions pkg/ccl/backupccl/backup_planning_tenant.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,20 +22,22 @@ import (
const tenantMetadataQuery = `
SELECT
tenants.id, /* 0 */
tenants.active, /* 1 */
tenants.info, /* 2 */
tenant_usage.ru_burst_limit, /* 3 */
tenant_usage.ru_refill_rate, /* 4 */
tenant_usage.ru_current, /* 5 */
tenant_usage.total_consumption /* 6 */
tenants.info, /* 1 */
tenants.name, /* 2 */
tenants.data_state, /* 3 */
tenants.service_mode, /* 4 */
tenant_usage.ru_burst_limit, /* 5 */
tenant_usage.ru_refill_rate, /* 6 */
tenant_usage.ru_current, /* 7 */
tenant_usage.total_consumption /* 8 */
FROM
system.tenants
LEFT JOIN system.tenant_usage ON
tenants.id = tenant_usage.tenant_id AND tenant_usage.instance_id = 0
`

func tenantMetadataFromRow(row tree.Datums) (descpb.TenantInfoWithUsage, error) {
if len(row) != 7 {
if len(row) != 9 {
return descpb.TenantInfoWithUsage{}, errors.AssertionFailedf(
"unexpected row size %d from tenant metadata query", len(row),
)
Expand All @@ -44,30 +46,58 @@ func tenantMetadataFromRow(row tree.Datums) (descpb.TenantInfoWithUsage, error)
id := uint64(tree.MustBeDInt(row[0]))
res := descpb.TenantInfoWithUsage{
TenantInfo: descpb.TenantInfo{
// for compatibility
DeprecatedID: id,
},
TenantInfoWithUsage_ExtraColumns: descpb.TenantInfoWithUsage_ExtraColumns{
ID: id,
},
}
infoBytes := []byte(tree.MustBeDBytes(row[2]))
infoBytes := []byte(tree.MustBeDBytes(row[1]))
if err := protoutil.Unmarshal(infoBytes, &res.TenantInfo); err != nil {
return descpb.TenantInfoWithUsage{}, err
}
if row[2] != tree.DNull {
res.Name = roachpb.TenantName(tree.MustBeDString(row[2]))
}
if row[3] != tree.DNull {
res.DataState = descpb.TenantDataState(tree.MustBeDInt(row[3]))
} else {
// Pre-v23.1 info struct.
switch res.TenantInfo.DeprecatedDataState {
case descpb.TenantInfo_READY:
res.DataState = descpb.DataStateReady
case descpb.TenantInfo_ADD:
res.DataState = descpb.DataStateAdd
case descpb.TenantInfo_DROP:
res.DataState = descpb.DataStateDrop
return res, errors.AssertionFailedf("unhandled: %d", res.TenantInfo.DeprecatedDataState)
}
}
res.ServiceMode = descpb.ServiceModeNone
if row[4] != tree.DNull {
res.ServiceMode = descpb.TenantServiceMode(tree.MustBeDInt(row[4]))
} else if res.DataState == descpb.DataStateReady {
// Records created for CC Serverless pre-v23.1.
res.ServiceMode = descpb.ServiceModeExternal
}
// If this tenant had no reported consumption and its token bucket was not
// configured, the tenant_usage values are all NULL.
//
// It should be sufficient to check any one value, but we check all of them
// just to be defensive (in case the table contains invalid data).
for _, d := range row[3:5] {
for _, d := range row[5:] {
if d == tree.DNull {
return res, nil
}
}
res.Usage = &descpb.TenantInfoWithUsage_Usage{
RUBurstLimit: float64(tree.MustBeDFloat(row[3])),
RURefillRate: float64(tree.MustBeDFloat(row[4])),
RUCurrent: float64(tree.MustBeDFloat(row[5])),
RUBurstLimit: float64(tree.MustBeDFloat(row[5])),
RURefillRate: float64(tree.MustBeDFloat(row[6])),
RUCurrent: float64(tree.MustBeDFloat(row[7])),
}
if row[6] != tree.DNull {
consumptionBytes := []byte(tree.MustBeDBytes(row[6]))
if row[8] != tree.DNull {
consumptionBytes := []byte(tree.MustBeDBytes(row[8]))
if err := protoutil.Unmarshal(consumptionBytes, &res.Usage.Consumption); err != nil {
return descpb.TenantInfoWithUsage{}, err
}
Expand All @@ -88,11 +118,14 @@ func retrieveSingleTenantMetadata(
if row == nil {
return descpb.TenantInfoWithUsage{}, errors.Errorf("tenant %s does not exist", tenantID)
}
if !tree.MustBeDBool(row[1]) {
info, err := tenantMetadataFromRow(row)
if err != nil {
return descpb.TenantInfoWithUsage{}, err
}
if info.DataState != descpb.DataStateReady {
return descpb.TenantInfoWithUsage{}, errors.Errorf("tenant %s is not active", tenantID)
}

return tenantMetadataFromRow(row)
return info, nil
}

func retrieveAllTenantsMetadata(
Expand Down
164 changes: 83 additions & 81 deletions pkg/ccl/backupccl/backup_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6881,28 +6881,29 @@ func TestBackupRestoreTenant(t *testing.T) {
defer restoreTC.Stopper().Stop(ctx)
restoreDB := sqlutils.MakeSQLRunner(restoreTC.Conns[0])

restoreDB.CheckQueryResults(t, `select id, active, name, crdb_internal.pb_to_json('cockroach.sql.sqlbase.TenantInfo', info, true) from system.tenants`, [][]string{
{`1`,
`true`,
`system`,
`{"capabilities": {"canAdminSplit": false}, "droppedName": "", "id": "1", "name": "system", "state": "ACTIVE", "tenantReplicationJobId": "0"}`,
restoreDB.CheckQueryResults(t, `select id, active, name, data_state, service_mode, crdb_internal.pb_to_json('cockroach.sql.sqlbase.TenantInfo', info) from system.tenants`, [][]string{
{
`1`, `true`, `system`,
strconv.Itoa(int(descpb.DataStateReady)),
strconv.Itoa(int(descpb.ServiceModeShared)),
`{"capabilities": {}, "deprecatedId": "1"}`,
},
})
restoreDB.Exec(t, `RESTORE TENANT 10 FROM 'nodelocal://1/t10'`)
restoreDB.CheckQueryResults(t,
`SELECT id, active, name, crdb_internal.pb_to_json('cockroach.sql.sqlbase.TenantInfo', info, true) FROM system.tenants`,
`SELECT id, active, name, data_state, service_mode, crdb_internal.pb_to_json('cockroach.sql.sqlbase.TenantInfo', info) FROM system.tenants`,
[][]string{
{
`1`,
`true`,
`system`,
`{"capabilities": {"canAdminSplit": false}, "droppedName": "", "id": "1", "name": "system", "state": "ACTIVE", "tenantReplicationJobId": "0"}`,
`1`, `true`, `system`,
strconv.Itoa(int(descpb.DataStateReady)),
strconv.Itoa(int(descpb.ServiceModeShared)),
`{"capabilities": {}, "deprecatedId": "1"}`,
},
{
`10`,
`true`,
`tenant-10`,
`{"capabilities": {"canAdminSplit": false}, "droppedName": "", "id": "10", "name": "tenant-10", "state": "ACTIVE", "tenantReplicationJobId": "0"}`,
`10`, `true`, `tenant-10`,
strconv.Itoa(int(descpb.DataStateReady)),
strconv.Itoa(int(descpb.ServiceModeNone)),
`{"capabilities": {}, "deprecatedId": "10"}`,
},
},
)
Expand Down Expand Up @@ -6930,19 +6931,19 @@ func TestBackupRestoreTenant(t *testing.T) {
// Mark tenant as DROP.
restoreDB.Exec(t, `DROP TENANT [10]`)
restoreDB.CheckQueryResults(t,
`select id, active, name, crdb_internal.pb_to_json('cockroach.sql.sqlbase.TenantInfo', info, true) from system.tenants`,
`select id, active, name, data_state, service_mode, crdb_internal.pb_to_json('cockroach.sql.sqlbase.TenantInfo', info) from system.tenants`,
[][]string{
{
`1`,
`true`,
`system`,
`{"capabilities": {"canAdminSplit": false}, "droppedName": "", "id": "1", "name": "system", "state": "ACTIVE", "tenantReplicationJobId": "0"}`,
`1`, `true`, `system`,
strconv.Itoa(int(descpb.DataStateReady)),
strconv.Itoa(int(descpb.ServiceModeShared)),
`{"capabilities": {}, "deprecatedId": "1"}`,
},
{
`10`,
`false`,
`NULL`,
`{"capabilities": {"canAdminSplit": false}, "droppedName": "tenant-10", "id": "10", "name": "", "state": "DROP", "tenantReplicationJobId": "0"}`,
`10`, `false`, `NULL`,
strconv.Itoa(int(descpb.DataStateDrop)),
strconv.Itoa(int(descpb.ServiceModeNone)),
`{"capabilities": {}, "deprecatedDataState": "DROP", "deprecatedId": "10", "droppedName": "tenant-10"}`,
},
},
)
Expand All @@ -6965,19 +6966,19 @@ func TestBackupRestoreTenant(t *testing.T) {

restoreDB.Exec(t, `RESTORE TENANT 10 FROM 'nodelocal://1/t10'`)
restoreDB.CheckQueryResults(t,
`select id, active, name, crdb_internal.pb_to_json('cockroach.sql.sqlbase.TenantInfo', info, true) from system.tenants`,
`select id, active, name, data_state, service_mode, crdb_internal.pb_to_json('cockroach.sql.sqlbase.TenantInfo', info) from system.tenants`,
[][]string{
{
`1`,
`true`,
`system`,
`{"capabilities": {"canAdminSplit": false}, "droppedName": "", "id": "1", "name": "system", "state": "ACTIVE", "tenantReplicationJobId": "0"}`,
`1`, `true`, `system`,
strconv.Itoa(int(descpb.DataStateReady)),
strconv.Itoa(int(descpb.ServiceModeShared)),
`{"capabilities": {}, "deprecatedId": "1"}`,
},
{
`10`,
`true`,
`tenant-10`,
`{"capabilities": {"canAdminSplit": false}, "droppedName": "", "id": "10", "name": "tenant-10", "state": "ACTIVE", "tenantReplicationJobId": "0"}`,
`10`, `true`, `tenant-10`,
strconv.Itoa(int(descpb.DataStateReady)),
strconv.Itoa(int(descpb.ServiceModeNone)),
`{"capabilities": {}, "deprecatedId": "10"}`,
},
},
)
Expand All @@ -7000,30 +7001,30 @@ func TestBackupRestoreTenant(t *testing.T) {
)

restoreDB.CheckQueryResults(t,
`select id, active, name, crdb_internal.pb_to_json('cockroach.sql.sqlbase.TenantInfo', info, true) from system.tenants`,
`select id, active, name, data_state, service_mode, crdb_internal.pb_to_json('cockroach.sql.sqlbase.TenantInfo', info) from system.tenants`,
[][]string{
{
`1`,
`true`,
`system`,
`{"capabilities": {"canAdminSplit": false}, "droppedName": "", "id": "1", "name": "system", "state": "ACTIVE", "tenantReplicationJobId": "0"}`,
`1`, `true`, `system`,
strconv.Itoa(int(descpb.DataStateReady)),
strconv.Itoa(int(descpb.ServiceModeShared)),
`{"capabilities": {}, "deprecatedId": "1"}`,
},
})
restoreDB.Exec(t, `RESTORE TENANT 10 FROM 'nodelocal://1/t10'`)
restoreDB.CheckQueryResults(t,
`select id, active, name, crdb_internal.pb_to_json('cockroach.sql.sqlbase.TenantInfo', info, true) from system.tenants`,
`select id, active, name, data_state, service_mode, crdb_internal.pb_to_json('cockroach.sql.sqlbase.TenantInfo', info) from system.tenants`,
[][]string{
{
`1`,
`true`,
`system`,
`{"capabilities": {"canAdminSplit": false}, "droppedName": "", "id": "1", "name": "system", "state": "ACTIVE", "tenantReplicationJobId": "0"}`,
`1`, `true`, `system`,
strconv.Itoa(int(descpb.DataStateReady)),
strconv.Itoa(int(descpb.ServiceModeShared)),
`{"capabilities": {}, "deprecatedId": "1"}`,
},
{
`10`,
`true`,
`tenant-10`,
`{"capabilities": {"canAdminSplit": false}, "droppedName": "", "id": "10", "name": "tenant-10", "state": "ACTIVE", "tenantReplicationJobId": "0"}`,
`10`, `true`, `tenant-10`,
strconv.Itoa(int(descpb.DataStateReady)),
strconv.Itoa(int(descpb.ServiceModeNone)),
`{"capabilities": {}, "deprecatedId": "10"}`,
},
},
)
Expand All @@ -7044,30 +7045,30 @@ func TestBackupRestoreTenant(t *testing.T) {
restoreDB := sqlutils.MakeSQLRunner(restoreTC.Conns[0])

restoreDB.CheckQueryResults(t,
`select id, active, name, crdb_internal.pb_to_json('cockroach.sql.sqlbase.TenantInfo', info, true) from system.tenants`,
`select id, active, name, data_state, service_mode, crdb_internal.pb_to_json('cockroach.sql.sqlbase.TenantInfo', info) from system.tenants`,
[][]string{
{
`1`,
`true`,
`system`,
`{"capabilities": {"canAdminSplit": false}, "droppedName": "", "id": "1", "name": "system", "state": "ACTIVE", "tenantReplicationJobId": "0"}`,
`1`, `true`, `system`,
strconv.Itoa(int(descpb.DataStateReady)),
strconv.Itoa(int(descpb.ServiceModeShared)),
`{"capabilities": {}, "deprecatedId": "1"}`,
},
})
restoreDB.Exec(t, `RESTORE TENANT 10 FROM 'nodelocal://1/clusterwide'`)
restoreDB.CheckQueryResults(t,
`select id, active, name, crdb_internal.pb_to_json('cockroach.sql.sqlbase.TenantInfo', info, true) from system.tenants`,
`select id, active, name, data_state, service_mode, crdb_internal.pb_to_json('cockroach.sql.sqlbase.TenantInfo', info) from system.tenants`,
[][]string{
{
`1`,
`true`,
`system`,
`{"capabilities": {"canAdminSplit": false}, "droppedName": "", "id": "1", "name": "system", "state": "ACTIVE", "tenantReplicationJobId": "0"}`,
`1`, `true`, `system`,
strconv.Itoa(int(descpb.DataStateReady)),
strconv.Itoa(int(descpb.ServiceModeShared)),
`{"capabilities": {}, "deprecatedId": "1"}`,
},
{
`10`,
`true`,
`tenant-10`,
`{"capabilities": {"canAdminSplit": false}, "droppedName": "", "id": "10", "name": "tenant-10", "state": "ACTIVE", "tenantReplicationJobId": "0"}`,
`10`, `true`, `tenant-10`,
strconv.Itoa(int(descpb.DataStateReady)),
strconv.Itoa(int(descpb.ServiceModeNone)),
`{"capabilities": {}, "deprecatedId": "10"}`,
},
},
)
Expand Down Expand Up @@ -7099,41 +7100,42 @@ func TestBackupRestoreTenant(t *testing.T) {
restoreDB := sqlutils.MakeSQLRunner(restoreTC.Conns[0])

restoreDB.CheckQueryResults(t,
`select id, active, name, crdb_internal.pb_to_json('cockroach.sql.sqlbase.TenantInfo', info, true) from system.tenants`,
`select id, active, name, data_state, service_mode, crdb_internal.pb_to_json('cockroach.sql.sqlbase.TenantInfo', info) from system.tenants`,
[][]string{
{
`1`,
`true`,
`system`,
`{"capabilities": {"canAdminSplit": false}, "droppedName": "", "id": "1", "name": "system", "state": "ACTIVE", "tenantReplicationJobId": "0"}`,
`1`, `true`, `system`,
strconv.Itoa(int(descpb.DataStateReady)),
strconv.Itoa(int(descpb.ServiceModeShared)),
`{"capabilities": {}, "deprecatedId": "1"}`,
},
})
restoreDB.Exec(t, `RESTORE FROM 'nodelocal://1/clusterwide'`)
restoreDB.CheckQueryResults(t,
`select id, active, name, crdb_internal.pb_to_json('cockroach.sql.sqlbase.TenantInfo', info, true) from system.tenants`,
`select id, active, name, data_state, service_mode, crdb_internal.pb_to_json('cockroach.sql.sqlbase.TenantInfo', info) from system.tenants`,
[][]string{
{
`1`,
`true`, `system`,
`{"capabilities": {"canAdminSplit": false}, "droppedName": "", "id": "1", "name": "system", "state": "ACTIVE", "tenantReplicationJobId": "0"}`,
`1`, `true`, `system`,
strconv.Itoa(int(descpb.DataStateReady)),
strconv.Itoa(int(descpb.ServiceModeShared)),
`{"capabilities": {}, "deprecatedId": "1"}`,
},
{
`10`,
`true`,
`tenant-10`,
`{"capabilities": {"canAdminSplit": false}, "droppedName": "", "id": "10", "name": "tenant-10", "state": "ACTIVE", "tenantReplicationJobId": "0"}`,
`10`, `true`, `tenant-10`,
strconv.Itoa(int(descpb.DataStateReady)),
strconv.Itoa(int(descpb.ServiceModeNone)),
`{"capabilities": {}, "deprecatedId": "10"}`,
},
{
`11`,
`true`,
`tenant-11`,
`{"capabilities": {"canAdminSplit": false}, "droppedName": "", "id": "11", "name": "tenant-11", "state": "ACTIVE", "tenantReplicationJobId": "0"}`,
`11`, `true`, `tenant-11`,
strconv.Itoa(int(descpb.DataStateReady)),
strconv.Itoa(int(descpb.ServiceModeNone)),
`{"capabilities": {}, "deprecatedId": "11"}`,
},
{
`20`,
`true`,
`tenant-20`,
`{"capabilities": {"canAdminSplit": false}, "droppedName": "", "id": "20", "name": "tenant-20", "state": "ACTIVE", "tenantReplicationJobId": "0"}`,
`20`, `true`, `tenant-20`,
strconv.Itoa(int(descpb.DataStateReady)),
strconv.Itoa(int(descpb.ServiceModeNone)),
`{"capabilities": {}, "deprecatedId": "20"}`,
},
},
)
Expand Down
Loading

0 comments on commit 41f5a04

Please sign in to comment.