Skip to content

Commit

Permalink
sql: move ValidateNoRepeatKeysInZone to zonepb pkg
Browse files Browse the repository at this point in the history
This patch refactors the `ValidateNoRepeatKeysInZone` function
to a package accesible to the DSC.

Informs: cockroachdb#117574
Release note: None
  • Loading branch information
annrpom committed May 29, 2024
1 parent 163a896 commit 2a4f12e
Show file tree
Hide file tree
Showing 6 changed files with 66 additions and 62 deletions.
2 changes: 2 additions & 0 deletions pkg/config/zonepb/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ go_library(
"//pkg/clusterversion",
"//pkg/keys",
"//pkg/roachpb",
"//pkg/sql/pgwire/pgcode",
"//pkg/sql/pgwire/pgerror",
"//pkg/sql/sem/tree",
"//pkg/util/envutil",
"//pkg/util/log",
Expand Down
60 changes: 60 additions & 0 deletions pkg/config/zonepb/zone.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ import (
"github.com/cockroachdb/cockroach/pkg/clusterversion"
"github.com/cockroachdb/cockroach/pkg/keys"
"github.com/cockroachdb/cockroach/pkg/roachpb"
"github.com/cockroachdb/cockroach/pkg/sql/pgwire/pgcode"
"github.com/cockroachdb/cockroach/pkg/sql/pgwire/pgerror"
"github.com/cockroachdb/cockroach/pkg/sql/sem/tree"
"github.com/cockroachdb/cockroach/pkg/util/envutil"
"github.com/cockroachdb/cockroach/pkg/util/log"
Expand Down Expand Up @@ -1313,3 +1315,61 @@ func init() {
))
}
}

// ValidateNoRepeatKeysInZone checks that there are not duplicated values for a particular
// constraint. For example, constraints [+region=us-east1,+region=us-east2]
// will be rejected. Additionally, invalid constraints such as
// [+region=us-east1, -region=us-east1] will also be rejected.
func ValidateNoRepeatKeysInZone(zone *ZoneConfig) error {
for _, leasePreference := range zone.LeasePreferences {
if err := validateNoRepeatKeysInConstraints(leasePreference.Constraints); err != nil {
return err
}
}
if err := validateNoRepeatKeysInConjunction(zone.Constraints); err != nil {
return err
}
return validateNoRepeatKeysInConjunction(zone.VoterConstraints)
}

func validateNoRepeatKeysInConjunction(conjunctions []ConstraintsConjunction) error {
for _, constraints := range conjunctions {
if err := validateNoRepeatKeysInConstraints(constraints.Constraints); err != nil {
return err
}
}
return nil
}

func validateNoRepeatKeysInConstraints(constraints []Constraint) error {
// Because we expect to have a small number of constraints, a nested
// loop is probably better than allocating a map.
for i, curr := range constraints {
for _, other := range constraints[i+1:] {
// We don't want to enter the other validation logic if both of the constraints
// are attributes, due to the keys being the same for attributes.
if curr.Key == "" && other.Key == "" {
if curr.Value == other.Value {
return pgerror.Newf(pgcode.CheckViolation,
"incompatible zone constraints: %q and %q", curr, other)
}
} else {
if curr.Type == Constraint_REQUIRED {
if other.Type == Constraint_REQUIRED && other.Key == curr.Key ||
other.Type == Constraint_PROHIBITED && other.Key == curr.Key && other.Value == curr.Value {
return pgerror.Newf(pgcode.CheckViolation,
"incompatible zone constraints: %q and %q", curr, other)
}
} else if curr.Type == Constraint_PROHIBITED {
// If we have a -k=v pair, verify that there are not any
// +k=v pairs in the constraints.
if other.Type == Constraint_REQUIRED && other.Key == curr.Key && other.Value == curr.Value {
return pgerror.Newf(pgcode.CheckViolation,
"incompatible zone constraints: %q and %q", curr, other)
}
}
}
}
}
return nil
}
2 changes: 1 addition & 1 deletion pkg/sql/alter_database.go
Original file line number Diff line number Diff line change
Expand Up @@ -2413,7 +2413,7 @@ func (n *alterDatabaseSetZoneConfigExtensionNode) startExec(params runParams) er
}

// Validate that there are no conflicts in the zone setup.
if err := validateNoRepeatKeysInZone(newZone); err != nil {
if err := zonepb.ValidateNoRepeatKeysInZone(newZone); err != nil {
return err
}

Expand Down
2 changes: 1 addition & 1 deletion pkg/sql/region_util.go
Original file line number Diff line number Diff line change
Expand Up @@ -915,7 +915,7 @@ func generateAndValidateZoneConfigForMultiRegionDatabase(
return zonepb.ZoneConfig{}, pgerror.Wrap(err, pgcode.CheckViolation, "could not validate zone config")
}

if err := validateNoRepeatKeysInZone(&dbZoneConfig); err != nil {
if err := zonepb.ValidateNoRepeatKeysInZone(&dbZoneConfig); err != nil {
return zonepb.ZoneConfig{}, err
}

Expand Down
60 changes: 1 addition & 59 deletions pkg/sql/set_zone_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -614,7 +614,7 @@ func (n *setZoneConfigNode) startExec(params runParams) error {
}

// Validate that there are no conflicts in the zone setup.
if err := validateNoRepeatKeysInZone(&newZone); err != nil {
if err := zonepb.ValidateNoRepeatKeysInZone(&newZone); err != nil {
return err
}

Expand Down Expand Up @@ -782,64 +782,6 @@ func (n *setZoneConfigNode) FastPathResults() (int, bool) { return n.run.numAffe
type nodeGetter func(context.Context, *serverpb.NodesRequest) (*serverpb.NodesResponse, error)
type regionsGetter func(context.Context) (*serverpb.RegionsResponse, error)

// Check that there are not duplicated values for a particular
// constraint. For example, constraints [+region=us-east1,+region=us-east2]
// will be rejected. Additionally, invalid constraints such as
// [+region=us-east1, -region=us-east1] will also be rejected.
func validateNoRepeatKeysInZone(zone *zonepb.ZoneConfig) error {
for _, leasePreference := range zone.LeasePreferences {
if err := validateNoRepeatKeysInConstraints(leasePreference.Constraints); err != nil {
return err
}
}
if err := validateNoRepeatKeysInConjunction(zone.Constraints); err != nil {
return err
}
return validateNoRepeatKeysInConjunction(zone.VoterConstraints)
}

func validateNoRepeatKeysInConjunction(conjunctions []zonepb.ConstraintsConjunction) error {
for _, constraints := range conjunctions {
if err := validateNoRepeatKeysInConstraints(constraints.Constraints); err != nil {
return err
}
}
return nil
}

func validateNoRepeatKeysInConstraints(constraints []zonepb.Constraint) error {
// Because we expect to have a small number of constraints, a nested
// loop is probably better than allocating a map.
for i, curr := range constraints {
for _, other := range constraints[i+1:] {
// We don't want to enter the other validation logic if both of the constraints
// are attributes, due to the keys being the same for attributes.
if curr.Key == "" && other.Key == "" {
if curr.Value == other.Value {
return pgerror.Newf(pgcode.CheckViolation,
"incompatible zone constraints: %q and %q", curr, other)
}
} else {
if curr.Type == zonepb.Constraint_REQUIRED {
if other.Type == zonepb.Constraint_REQUIRED && other.Key == curr.Key ||
other.Type == zonepb.Constraint_PROHIBITED && other.Key == curr.Key && other.Value == curr.Value {
return pgerror.Newf(pgcode.CheckViolation,
"incompatible zone constraints: %q and %q", curr, other)
}
} else if curr.Type == zonepb.Constraint_PROHIBITED {
// If we have a -k=v pair, verify that there are not any
// +k=v pairs in the constraints.
if other.Type == zonepb.Constraint_REQUIRED && other.Key == curr.Key && other.Value == curr.Value {
return pgerror.Newf(pgcode.CheckViolation,
"incompatible zone constraints: %q and %q", curr, other)
}
}
}
}
}
return nil
}

// accumulateNewUniqueConstraints returns a list of unique constraints in the
// given newZone config proto that are not in the currentZone
func accumulateNewUniqueConstraints(currentZone, newZone *zonepb.ZoneConfig) []zonepb.Constraint {
Expand Down
2 changes: 1 addition & 1 deletion pkg/sql/set_zone_config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ func TestValidateNoRepeatKeysInZone(t *testing.T) {
if err != nil {
t.Fatal(err)
}
err = validateNoRepeatKeysInZone(&zone)
err = zonepb.ValidateNoRepeatKeysInZone(&zone)
if err != nil && expectSuccess {
t.Errorf("expected success for %q; got %v", constraint, err)
} else if err == nil && !expectSuccess {
Expand Down

0 comments on commit 2a4f12e

Please sign in to comment.