Skip to content

Commit

Permalink
config: convert ZoneConfig to the new format
Browse files Browse the repository at this point in the history
Converts ZoneConfig to the new format specified in the expressive ZoneConfig
RFC.  This is intermediate work on cockroachdb#4868.
https://github.com/cockroachdb/cockroach/blob/develop/docs/RFCS/expressive_zone_config.md

- Allocator and StorePool use []config.Constraint instead of roachpb.Attributes
  since the new type allows for different types of constraint.
- Adds a `ZoneConfigLegacy` struct for upgrades to the new format.
- Adds a `ZoneConfigHuman` struct for easier specification on the command line.
  • Loading branch information
d4l3k committed Aug 18, 2016
1 parent abcd50d commit 27ecfd1
Show file tree
Hide file tree
Showing 25 changed files with 1,717 additions and 362 deletions.
24 changes: 12 additions & 12 deletions cli/cli_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -503,41 +503,41 @@ func Example_zone() {
// .default
// zone set system --file=./testdata/zone_attrs.yaml
// INSERT 1
// replicas:
// - attrs: [us-east-1a, ssd]
// range_min_bytes: 1048576
// range_max_bytes: 67108864
// gc:
// ttlseconds: 86400
// num_replicas: 1
// constraints: [us-east-1a, ssd]
// zone ls
// .default
// system
// zone get system.nonexistent
// system.nonexistent not found
// zone get system.lease
// system
// replicas:
// - attrs: [us-east-1a, ssd]
// range_min_bytes: 1048576
// range_max_bytes: 67108864
// gc:
// ttlseconds: 86400
// num_replicas: 1
// constraints: [us-east-1a, ssd]
// zone set system --file=./testdata/zone_range_max_bytes.yaml
// UPDATE 1
// replicas:
// - attrs: [us-east-1a, ssd]
// range_min_bytes: 1048576
// range_max_bytes: 134217728
// gc:
// ttlseconds: 86400
// num_replicas: 1
// constraints: [us-east-1a, ssd]
// zone get system
// system
// replicas:
// - attrs: [us-east-1a, ssd]
// range_min_bytes: 1048576
// range_max_bytes: 134217728
// gc:
// ttlseconds: 86400
// num_replicas: 1
// constraints: [us-east-1a, ssd]
// zone rm system
// DELETE 1
// zone ls
Expand All @@ -546,20 +546,20 @@ func Example_zone() {
// unable to remove .default
// zone set .default --file=./testdata/zone_range_max_bytes.yaml
// UPDATE 1
// replicas:
// - attrs: []
// range_min_bytes: 1048576
// range_max_bytes: 134217728
// gc:
// ttlseconds: 86400
// num_replicas: 1
// constraints: []
// zone get system
// .default
// replicas:
// - attrs: []
// range_min_bytes: 1048576
// range_max_bytes: 134217728
// gc:
// ttlseconds: 86400
// num_replicas: 1
// constraints: []
}

func Example_sql() {
Expand Down
4 changes: 2 additions & 2 deletions cli/testdata/zone_attrs.yaml
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
replicas:
- attrs: [us-east-1a,ssd]
num_replicas: 1
constraints: [us-east-1a,ssd]
17 changes: 9 additions & 8 deletions cli/zone.go
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ func runGetZone(cmd *cobra.Command, args []string) error {
}
}

res, err := yaml.Marshal(zone)
res, err := yaml.Marshal(zone.ToHuman())
if err != nil {
return err
}
Expand Down Expand Up @@ -461,9 +461,9 @@ func runSetZone(cmd *cobra.Command, args []string) error {
// Convert it to proto and marshal it again to put into the table. This is a
// bit more tedious than taking protos directly, but yaml is a more widely
// understood format.
origReplicaAttrs := zone.ReplicaAttrs
zone.ReplicaAttrs = nil
// Read zoneConfig file to conf.

humanZone := zone.ToHuman()
var conf []byte
if zoneConfig == "-" {
conf, err = ioutil.ReadAll(os.Stdin)
Expand All @@ -473,13 +473,14 @@ func runSetZone(cmd *cobra.Command, args []string) error {
if err != nil {
return fmt.Errorf("error reading zone config: %s", err)
}
if err := yaml.Unmarshal(conf, &zone); err != nil {
if err := yaml.Unmarshal(conf, &humanZone); err != nil {
return fmt.Errorf("unable to parse zoneConfig file: %s", err)
}
if zone.ReplicaAttrs == nil {
zone.ReplicaAttrs = origReplicaAttrs
}

zone, err = humanZone.ToMachine()
if err != nil {
return err
}
if err := zone.Validate(); err != nil {
return err
}
Expand All @@ -504,7 +505,7 @@ func runSetZone(cmd *cobra.Command, args []string) error {
return err
}

res, err := yaml.Marshal(zone)
res, err := yaml.Marshal(zone.ToHuman())
if err != nil {
return err
}
Expand Down
94 changes: 88 additions & 6 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"crypto/sha1"
"fmt"
"sort"
"strings"

"golang.org/x/net/context"

Expand All @@ -44,11 +45,7 @@ var (
// defaultZoneConfig is the default zone configuration used when no custom
// config has been specified.
defaultZoneConfig = ZoneConfig{
ReplicaAttrs: []roachpb.Attributes{
{},
{},
{},
},
NumReplicas: 3,
RangeMinBytes: 1 << 20,
RangeMaxBytes: 64 << 20,
GC: GCPolicy{
Expand All @@ -66,6 +63,91 @@ var (
testingLargestIDHook func(uint32) uint32
)

func (c Constraint) String() string {
var str string
switch c.Type {
case Constraint_REQUIRED:
str += "+"
case Constraint_PROHIBITED:
str += "-"
}
if len(c.Key) > 0 {
str += c.Key + "="
}
str += c.Value
return str
}

// FromString populates the constraint from the constraint shorthand notation.
func (c *Constraint) FromString(short string) error {
switch short[0] {
case '+':
c.Type = Constraint_REQUIRED
short = short[1:]
case '-':
c.Type = Constraint_PROHIBITED
short = short[1:]
default:
c.Type = Constraint_POSITIVE
}
parts := strings.Split(short, "=")
if len(parts) == 1 {
c.Value = parts[0]
} else if len(parts) == 2 {
c.Key = parts[0]
c.Value = parts[1]
} else {
return errors.Errorf("constraint needs to be in the form \"(key=)value\", not %q", short)
}
return nil
}

// ParseConstraints parses the shorthand constraint notation.
func ParseConstraints(shortConstraints []string) ([]Constraint, error) {
constraints := make([]Constraint, len(shortConstraints))
for i, short := range shortConstraints {
if err := constraints[i].FromString(short); err != nil {
return nil, err
}
}
return constraints, nil
}

// DumpConstraints converts the list of constraints to the shorthand notation.
func DumpConstraints(constraints []Constraint) []string {
short := make([]string, len(constraints))
for i, c := range constraints {
short[i] = c.String()
}
return short
}

// ToHuman converts a ZoneConfig to the human readable shorthand form.
func (z ZoneConfig) ToHuman() ZoneConfigHuman {
return ZoneConfigHuman{
RangeMinBytes: z.RangeMinBytes,
RangeMaxBytes: z.RangeMaxBytes,
GC: z.GC,
NumReplicas: z.NumReplicas,
Constraints: DumpConstraints(z.Constraints),
}
}

// ToMachine converts a ZoneConfig to the machine usable form.
func (z ZoneConfigHuman) ToMachine() (ZoneConfig, error) {
constraints, err := ParseConstraints(z.Constraints)
if err != nil {
return ZoneConfig{}, err
}
return ZoneConfig{
RangeMinBytes: z.RangeMinBytes,
RangeMaxBytes: z.RangeMaxBytes,
GC: z.GC,
NumReplicas: z.NumReplicas,
Constraints: constraints,
}, nil
}

// DefaultZoneConfig is the default zone configuration used when no custom
// config has been specified.
func DefaultZoneConfig() ZoneConfig {
Expand All @@ -92,7 +174,7 @@ func TestingSetDefaultZoneConfig(cfg ZoneConfig) func() {
// Validate verifies some ZoneConfig fields.
// This should be used to validate user input when setting a new zone config.
func (z ZoneConfig) Validate() error {
switch len(z.ReplicaAttrs) {
switch z.NumReplicas {
case 0:
return fmt.Errorf("attributes for at least one replica must be specified in zone config")
case 2:
Expand Down
Loading

0 comments on commit 27ecfd1

Please sign in to comment.