Skip to content

Commit

Permalink
sql: Implement ALTER TABLE ... LOCALITY REGIONAL BY TABLE from GLOBAL
Browse files Browse the repository at this point in the history
Implements ALTER TABLE ... LOCALITY REGIONAL BY TABLE (all permutations)
from LOCALITY GLOBAL.

Release note (sql change): Implements ALTER TABLE ... LOCALITY REGIONAL
BY TABLE from LOCALITY GLOBAL.
  • Loading branch information
ajstorm committed Jan 27, 2021
1 parent 6cbbc45 commit 470152f
Show file tree
Hide file tree
Showing 3 changed files with 168 additions and 109 deletions.
79 changes: 74 additions & 5 deletions pkg/ccl/logictestccl/testdata/logic_test/alter_table_locality
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ statement error unimplemented: implementation pending
ALTER TABLE regional_by_row SET LOCALITY REGIONAL BY TABLE

statement error unimplemented: implementation pending
ALTER TABLE regional_by_row SET LOCALITY REGIONAL BY TABLE in "ap-southeast"
ALTER TABLE regional_by_row SET LOCALITY REGIONAL BY TABLE in "ap-southeast-2"

statement error unimplemented: implementation pending
ALTER TABLE regional_by_row SET LOCALITY REGIONAL BY TABLE in PRIMARY REGION
Expand Down Expand Up @@ -192,15 +192,84 @@ DATABASE alter_locality_test ALTER DATABASE alter_locality_test CONFIGURE ZONE
constraints = '{+region=ap-southeast-2: 1, +region=ca-central-1: 1, +region=us-east-1: 1}',
lease_preferences = '[[+region=ca-central-1]]'

statement error unimplemented: implementation pending
statement ok
ALTER TABLE global SET LOCALITY REGIONAL BY TABLE

statement error unimplemented: implementation pending
ALTER TABLE global SET LOCALITY REGIONAL BY TABLE in "ap-southeast"
query TT
SHOW CREATE TABLE global
----
global CREATE TABLE public.global (
i INT8 NULL,
FAMILY "primary" (i, rowid)
) LOCALITY REGIONAL BY TABLE IN PRIMARY REGION

statement error unimplemented: implementation pending
query TT
SHOW ZONE CONFIGURATION FOR TABLE global
----
DATABASE alter_locality_test ALTER DATABASE alter_locality_test CONFIGURE ZONE USING
range_min_bytes = 134217728,
range_max_bytes = 536870912,
gc.ttlseconds = 90000,
num_replicas = 3,
constraints = '{+region=ap-southeast-2: 1, +region=ca-central-1: 1, +region=us-east-1: 1}',
lease_preferences = '[[+region=ca-central-1]]'

# Alter back, to get back to original state
statement ok
ALTER TABLE global SET LOCALITY GLOBAL

statement ok
ALTER TABLE global SET LOCALITY REGIONAL BY TABLE in "ap-southeast-2"

query TT
SHOW CREATE TABLE global
----
global CREATE TABLE public.global (
i INT8 NULL,
FAMILY "primary" (i, rowid)
) LOCALITY REGIONAL BY TABLE IN "ap-southeast-2"

query TT
SHOW ZONE CONFIGURATION FOR TABLE global
----
TABLE global ALTER TABLE global CONFIGURE ZONE USING
range_min_bytes = 134217728,
range_max_bytes = 536870912,
gc.ttlseconds = 90000,
num_replicas = 3,
constraints = '{+region=ap-southeast-2: 3}',
lease_preferences = '[[+region=ap-southeast-2]]'

# Alter back, to get back to original state
statement ok
ALTER TABLE global SET LOCALITY GLOBAL

statement ok
ALTER TABLE global SET LOCALITY REGIONAL BY TABLE in PRIMARY REGION

query TT
SHOW CREATE TABLE global
----
global CREATE TABLE public.global (
i INT8 NULL,
FAMILY "primary" (i, rowid)
) LOCALITY REGIONAL BY TABLE IN PRIMARY REGION

query TT
SHOW ZONE CONFIGURATION FOR TABLE global
----
DATABASE alter_locality_test ALTER DATABASE alter_locality_test CONFIGURE ZONE USING
range_min_bytes = 134217728,
range_max_bytes = 536870912,
gc.ttlseconds = 90000,
num_replicas = 3,
constraints = '{+region=ap-southeast-2: 1, +region=ca-central-1: 1, +region=us-east-1: 1}',
lease_preferences = '[[+region=ca-central-1]]'

# Alter back, to get back to original state
statement ok
ALTER TABLE global SET LOCALITY GLOBAL

statement ok
ALTER TABLE global SET LOCALITY GLOBAL

Expand Down
184 changes: 94 additions & 90 deletions pkg/sql/alter_table_locality.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,17 +70,36 @@ func (n *alterTableSetLocalityNode) Next(runParams) (bool, error) { return false
func (n *alterTableSetLocalityNode) Values() tree.Datums { return tree.Datums{} }
func (n *alterTableSetLocalityNode) Close(context.Context) {}

func (n *alterTableSetLocalityNode) alterTableLocalityGlobalToRegionalByTable() error {
return unimplemented.New("alter table locality from GLOBAL to REGIONAL BY TABLE", "implementation pending")
func (n *alterTableSetLocalityNode) alterTableLocalityGlobalToRegionalByTable(
params runParams, dbDesc *dbdesc.Immutable, tableName tree.TableName,
) error {
const operation string = "alter table locality GLOBAL to REGIONAL BY TABLE"
if !n.tableDesc.IsLocalityGlobal() {
return errors.AssertionFailedf(
"invalid call %q on incorrect table locality. %v",
operation,
n.tableDesc.LocalityConfig,
)
}

n.tableDesc.SetTableLocalityRegionalByTable(n.n.Locality.TableRegion)

// Finalize the alter by writing a new table descriptor and updating the zone configuration.
if err := n.validateAndWriteNewTableLocalityAndZoneConfig(
params,
dbDesc,
tableName,
); err != nil {
return err
}

return nil
}

func (n *alterTableSetLocalityNode) alterTableLocalityRegionalByTableToGlobal(
params runParams, desc *dbdesc.Immutable,
params runParams, dbDesc *dbdesc.Immutable, tableName tree.TableName,
) error {
const operation string = "alter table locality REGIONAL BY TABLE to GLOBAL"
if err := assertIsMultiRegionDatabase(desc, operation); err != nil {
return err
}
if !n.tableDesc.IsLocalityRegionalByTable() {
return errors.AssertionFailedf(
"invalid call %q on incorrect table locality. %v",
Expand All @@ -90,42 +109,12 @@ func (n *alterTableSetLocalityNode) alterTableLocalityRegionalByTableToGlobal(
}

n.tableDesc.SetTableLocalityGlobal()
// Validate the locality config.
dg := catalogkv.NewOneLevelUncachedDescGetter(params.p.txn, params.EvalContext().Codec)
if err := n.tableDesc.ValidateTableLocalityConfig(params.ctx, dg); err != nil {
return err
}
resolvedSchema, err := params.p.Descriptors().GetImmutableSchemaByID(
params.ctx,
params.p.txn,
n.tableDesc.GetParentSchemaID(),
tree.SchemaLookupFlags{})
if err != nil {
return err
}

tableName := tree.MakeTableNameWithSchema(
tree.Name(desc.Name),
tree.Name(resolvedSchema.Name),
tree.Name(n.tableDesc.GetName()),
)

// Write out the table descriptor update.
if err := params.p.writeSchemaChange(
params.ctx,
n.tableDesc,
descpb.InvalidMutationID,
tree.AsStringWithFQNames(&n.n, params.Ann()),
); err != nil {
return err
}

// Update the zone configuration.
if err := params.p.applyZoneConfigFromTableLocalityConfig(
params.ctx,
// Finalize the alter by writing a new table descriptor and updating the zone configuration.
if err := n.validateAndWriteNewTableLocalityAndZoneConfig(
params,
dbDesc,
tableName,
n.tableDesc.TableDesc(),
*desc.RegionConfig,
); err != nil {
return err
}
Expand All @@ -134,12 +123,9 @@ func (n *alterTableSetLocalityNode) alterTableLocalityRegionalByTableToGlobal(
}

func (n *alterTableSetLocalityNode) alterTableLocalityRegionalByTableToRegionalByTable(
params runParams, desc *dbdesc.Immutable,
params runParams, dbDesc *dbdesc.Immutable, tableName tree.TableName,
) error {
const operation string = "alter table locality REGIONAL BY TABLE to REGIONAL BY TABLE"
if err := assertIsMultiRegionDatabase(desc, operation); err != nil {
return err
}
if !n.tableDesc.IsLocalityRegionalByTable() {
return errors.AssertionFailedf(
"invalid call %q on incorrect table locality. %v",
Expand All @@ -148,49 +134,13 @@ func (n *alterTableSetLocalityNode) alterTableLocalityRegionalByTableToRegionalB
)
}

if n.n.Locality.InPrimaryRegion() {
n.tableDesc.SetTableLocalityRegionalByTable(tree.PrimaryRegionLocalityName)
} else {
n.tableDesc.SetTableLocalityRegionalByTable(n.n.Locality.TableRegion)
}

// Validate the new locality before updating the table descriptor.
dg := catalogkv.NewOneLevelUncachedDescGetter(params.p.txn, params.EvalContext().Codec)
if err := n.tableDesc.ValidateTableLocalityConfig(params.ctx, dg); err != nil {
return err
}
// Write out the table descriptor update.
if err := params.p.writeSchemaChange(
params.ctx,
n.tableDesc,
descpb.InvalidMutationID,
tree.AsStringWithFQNames(&n.n, params.Ann()),
); err != nil {
return err
}

// Validate the new locality before updating the table descriptor.
resolvedSchema, err := params.p.Descriptors().GetImmutableSchemaByID(
params.ctx,
params.p.txn,
n.tableDesc.GetParentSchemaID(),
tree.SchemaLookupFlags{})
if err != nil {
return err
}

tableName := tree.MakeTableNameWithSchema(
tree.Name(desc.Name),
tree.Name(resolvedSchema.Name),
tree.Name(n.tableDesc.GetName()),
)
n.tableDesc.SetTableLocalityRegionalByTable(n.n.Locality.TableRegion)

// Update the table's zone configuration.
if err := params.p.applyZoneConfigFromTableLocalityConfig(
params.ctx,
// Finalize the alter by writing a new table descriptor and updating the zone configuration.
if err := n.validateAndWriteNewTableLocalityAndZoneConfig(
params,
dbDesc,
tableName,
n.tableDesc.TableDesc(),
*desc.RegionConfig,
); err != nil {
return err
}
Expand All @@ -200,7 +150,7 @@ func (n *alterTableSetLocalityNode) alterTableLocalityRegionalByTableToRegionalB

func (n *alterTableSetLocalityNode) startExec(params runParams) error {
// Ensure that the database is multi-region enabled.
desc, err := params.p.Descriptors().GetImmutableDatabaseByID(
dbDesc, err := params.p.Descriptors().GetImmutableDatabaseByID(
params.ctx,
params.p.txn,
n.tableDesc.GetParentID(),
Expand All @@ -209,13 +159,29 @@ func (n *alterTableSetLocalityNode) startExec(params runParams) error {
if err != nil {
return err
}
if !desc.IsMultiRegion() {
if !dbDesc.IsMultiRegion() {
return pgerror.Newf(
pgcode.InvalidTableDefinition,
"cannot alter a table's LOCALITY if its database is not multi-region enabled",
)
}

// Get the fully resolved table name for use in the calls below.
resolvedSchema, err := params.p.Descriptors().GetImmutableSchemaByID(
params.ctx,
params.p.txn,
n.tableDesc.GetParentSchemaID(),
tree.SchemaLookupFlags{})
if err != nil {
return err
}

tableName := tree.MakeTableNameWithSchema(
tree.Name(dbDesc.Name),
tree.Name(resolvedSchema.Name),
tree.Name(n.tableDesc.GetName()),
)

newLocality := n.n.Locality
existingLocality := n.tableDesc.LocalityConfig

Expand All @@ -231,7 +197,7 @@ func (n *alterTableSetLocalityNode) startExec(params runParams) error {
// GLOBAL to REGIONAL BY ROW
return unimplemented.New("alter table locality to REGIONAL BY ROW", "implementation pending")
case tree.LocalityLevelTable:
if err = n.alterTableLocalityGlobalToRegionalByTable(); err != nil {
if err = n.alterTableLocalityGlobalToRegionalByTable(params, dbDesc, tableName); err != nil {
return err
}
default:
Expand All @@ -240,14 +206,14 @@ func (n *alterTableSetLocalityNode) startExec(params runParams) error {
case *descpb.TableDescriptor_LocalityConfig_RegionalByTable_:
switch newLocality.LocalityLevel {
case tree.LocalityLevelGlobal:
err = n.alterTableLocalityRegionalByTableToGlobal(params, desc)
err = n.alterTableLocalityRegionalByTableToGlobal(params, dbDesc, tableName)
if err != nil {
return err
}
case tree.LocalityLevelRow:
return unimplemented.New("alter table locality to REGIONAL BY ROW", "implementation pending")
case tree.LocalityLevelTable:
err = n.alterTableLocalityRegionalByTableToRegionalByTable(params, desc)
err = n.alterTableLocalityRegionalByTableToRegionalByTable(params, dbDesc, tableName)
if err != nil {
return err
}
Expand Down Expand Up @@ -279,3 +245,41 @@ func (n *alterTableSetLocalityNode) startExec(params runParams) error {
TableName: n.n.Name.String(),
})
}

// validateAndWriteNewTableLocalityAndZoneConfig validates the newly updated LocalityConfig
// in a table descriptor, writes that table descriptor, and writes a new zone configuration
// for the given table.
func (n *alterTableSetLocalityNode) validateAndWriteNewTableLocalityAndZoneConfig(
params runParams, dbDesc *dbdesc.Immutable, tableName tree.TableName,
) error {
// Validate the new locality before updating the table descriptor.
dg := catalogkv.NewOneLevelUncachedDescGetter(params.p.txn, params.EvalContext().Codec)
if err := n.tableDesc.ValidateTableLocalityConfig(
params.ctx,
dg,
); err != nil {
return err
}

// Write out the table descriptor update.
if err := params.p.writeSchemaChange(
params.ctx,
n.tableDesc,
descpb.InvalidMutationID,
tree.AsStringWithFQNames(&n.n, params.Ann()),
); err != nil {
return err
}

// Update the zone configuration.
if err := params.p.applyZoneConfigFromTableLocalityConfig(
params.ctx,
tableName,
n.tableDesc.TableDesc(),
*dbDesc.RegionConfig,
); err != nil {
return err
}

return nil
}
14 changes: 0 additions & 14 deletions pkg/sql/region_util.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,20 +49,6 @@ func (s *liveClusterRegions) toStrings() []string {
return ret
}

// assertIsMultiRegionDatabase ensures that we're in a multi-region database, and
// if not, returns an assertion error. Takes an "operation" string which describes
// the operation in progress which requires database to be multi-region.
func assertIsMultiRegionDatabase(desc *dbdesc.Immutable, operation string) error {
if !desc.IsMultiRegion() {
return errors.AssertionFailedf(
"invalid call to %q on a non-multi-region database. %v",
operation,
desc,
)
}
return nil
}

// getLiveClusterRegions returns a set of live region names in the cluster.
// A region name is deemed active if there is at least one alive node
// in the cluster in with locality set to a given region.
Expand Down

0 comments on commit 470152f

Please sign in to comment.