Beispiel #1
0
func ringCmd(r ring.Ring, b *ring.Builder, filename string) error {
	if b == nil {
		return fmt.Errorf("only valid for builder files")
	}
	r = b.Ring()
	if err := persist(nil, b, filename); err != nil {
		return err
	}
	return persist(r, nil, strings.TrimSuffix(filename, ".builder")+".ring")
}
Beispiel #2
0
func removeCmd(r ring.Ring, b *ring.Builder, args []string) error {
	if r != nil {
		return fmt.Errorf("cannot remove a node from a ring; use with a builder instead")
	}
	if len(args) != 1 || !strings.HasPrefix(args[0], "id=") {
		return fmt.Errorf("must specify node to remove with id=<value>")
	}
	id, err := strconv.ParseUint(args[0][3:], 16, 64)
	if err != nil {
		return fmt.Errorf("invalid id %#v", args[0][3:])
	}
	b.RemoveNode(id)
	return nil
}
Beispiel #3
0
func tierCmd(r ring.Ring, b *ring.Builder, args []string) error {
	var tiers [][]string
	if r == nil {
		tiers = b.Tiers()
	} else {
		tiers = r.Tiers()
	}
	report := [][]string{
		[]string{"Tier", "Existing"},
		[]string{"Level", "Values"},
	}
	reportOpts := brimtext.NewDefaultAlignOptions()
	reportOpts.Alignments = []brimtext.Alignment{brimtext.Right, brimtext.Left}
	fmted := false
OUT:
	for _, values := range tiers {
		for _, value := range values {
			if strings.Contains(value, " ") {
				fmted = true
				break OUT
			}
		}
	}
	for level, values := range tiers {
		sort.Strings(values)
		var pvalue string
		if fmted {
			for _, value := range values {
				pvalue += fmt.Sprintf(" %#v", value)
			}
			pvalue = strings.Trim(pvalue, " ")
		} else {
			pvalue = strings.Join(values, " ")
		}
		report = append(report, []string{
			strconv.Itoa(level),
			strings.Trim(pvalue, " "),
		})
	}
	fmt.Print(brimtext.Align(report, reportOpts))
	return nil
}
Beispiel #4
0
func pretendElapsedCmd(r ring.Ring, b *ring.Builder, args []string) error {
	if b == nil {
		return fmt.Errorf("only valid for builder files")
	}
	if len(args) != 1 {
		return fmt.Errorf("syntax: <minutes>")
	}
	m, err := strconv.Atoi(args[0])
	if err != nil {
		return fmt.Errorf("could not parse %#v: %s", args[0], err.Error())
	}
	if m < 0 {
		return fmt.Errorf("cannot pretend to go backwards in time")
	}
	if m > math.MaxUint16 {
		return fmt.Errorf("cannot pretend to elapse more than %d minutes", math.MaxUint16)
	}
	b.PretendElapsed(uint16(m))
	return nil
}
Beispiel #5
0
func mainCmd(r ring.Ring, b *ring.Builder) error {
	if r != nil {
		// TODO:
		//  Version Info (the value as well as the time translation)
		//  Number of tier levels
		//  Replica count
		//  Indication of how risky the assignments are:
		//      Replicas not in distinct tiers, nodes
		s := r.Stats()
		report := [][]string{
			[]string{brimtext.ThousandsSep(int64(s.PartitionCount), ","), "Partitions"},
			[]string{brimtext.ThousandsSep(int64(s.PartitionBitCount), ","), "Partition Bits"},
			[]string{brimtext.ThousandsSep(int64(s.NodeCount), ","), "Nodes"},
			[]string{brimtext.ThousandsSep(int64(s.InactiveNodeCount), ","), "Inactive Nodes"},
			[]string{brimtext.ThousandsSepU(s.TotalCapacity, ","), "Total Node Capacity"},
			[]string{fmt.Sprintf("%.02f%%", s.MaxUnderNodePercentage), fmt.Sprintf("Worst Underweight Node (ID %016x)", s.MaxUnderNodeID)},
			[]string{fmt.Sprintf("%.02f%%", s.MaxOverNodePercentage), fmt.Sprintf("Worst Overweight Node (ID %016x)", s.MaxOverNodeID)},
		}
		reportOpts := brimtext.NewDefaultAlignOptions()
		reportOpts.Alignments = []brimtext.Alignment{brimtext.Right, brimtext.Left}
		fmt.Print(brimtext.Align(report, reportOpts))
	}
	if b != nil {
		// TODO:
		//  Inactive node count
		//  Total capacity
		report := [][]string{
			[]string{brimtext.ThousandsSep(int64(len(b.Nodes())), ","), "Nodes"},
			[]string{brimtext.ThousandsSep(int64(b.ReplicaCount()), ","), "Replicas"},
			[]string{brimtext.ThousandsSep(int64(b.PointsAllowed()), ","), "Points Allowed"},
			[]string{brimtext.ThousandsSep(int64(b.MaxPartitionBitCount()), ","), "Max Partition Bits"},
			[]string{brimtext.ThousandsSep(int64(b.MoveWait()), ","), "Move Wait"},
		}
		reportOpts := brimtext.NewDefaultAlignOptions()
		reportOpts.Alignments = []brimtext.Alignment{brimtext.Right, brimtext.Left}
		fmt.Print(brimtext.Align(report, reportOpts))
		return nil
	}
	return nil
}
Beispiel #6
0
func persist(r ring.Ring, b *ring.Builder, filename string) error {
	dir, name := path.Split(filename)
	if dir == "" {
		dir = "."
	}
	f, err := ioutil.TempFile(dir, name+".")
	if err != nil {
		return err
	}
	tmp := f.Name()
	if r != nil {
		err = r.Persist(f)
	} else {
		err = b.Persist(f)
	}
	if err != nil {
		f.Close()
		return err
	}
	if err = f.Close(); err != nil {
		return err
	}
	return os.Rename(path.Join(dir, tmp), filename)
}
Beispiel #7
0
func addOrSetCmd(r ring.Ring, b *ring.Builder, args []string, n ring.BuilderNode) error {
	if r != nil {
		return fmt.Errorf("cannot add a node to ring; use with a builder instead")
	}
	active := true
	capacity := uint32(1)
	var tiers []string
	var addresses []string
	meta := ""
	for _, arg := range args {
		sarg := strings.SplitN(arg, "=", 2)
		if len(sarg) != 2 {
			return fmt.Errorf(`invalid expression %#v; needs "="`, arg)
		}
		if sarg[0] == "" {
			return fmt.Errorf(`invalid expression %#v; nothing was left of "="`, arg)
		}
		if sarg[1] == "" {
			return fmt.Errorf(`invalid expression %#v; nothing was right of "="`, arg)
		}
		switch sarg[0] {
		case "active":
			switch sarg[1] {
			case "true":
				active = true
			case "false":
				active = false
			default:
				return fmt.Errorf(`invalid expression %#v; use "true" or "false" for the value of active`, arg)
			}
			if n != nil {
				n.SetActive(active)
			}
		case "capacity":
			c, err := strconv.Atoi(sarg[1])
			if err != nil {
				return fmt.Errorf("invalid expression %#v; %s", arg, err)
			}
			if c < 0 {
				return fmt.Errorf("invalid expression %#v; min is 0", arg)
			}
			if c > math.MaxUint32 {
				return fmt.Errorf("invalid expression %#v; max is %d", arg, math.MaxUint32)
			}
			capacity = uint32(c)
			if n != nil {
				n.SetCapacity(capacity)
			}
		case "meta":
			meta = sarg[1]
			if n != nil {
				n.SetMeta(meta)
			}
		default:
			if strings.HasPrefix(sarg[0], "tier") {
				level, err := strconv.Atoi(sarg[0][4:])
				if err != nil {
					return fmt.Errorf("invalid expression %#v; %#v doesn't specify a number", arg, sarg[0][4:])
				}
				if level < 0 {
					return fmt.Errorf("invalid expression %#v; minimum level is 0", arg)
				}
				if len(tiers) <= level {
					t := make([]string, level+1)
					copy(t, tiers)
					tiers = t
				}
				tiers[level] = sarg[1]
				if n != nil {
					n.SetTier(level, tiers[level])
				}
			} else if strings.HasPrefix(sarg[0], "address") {
				index, err := strconv.Atoi(sarg[0][7:])
				if err != nil {
					return fmt.Errorf("invalid expression %#v; %#v doesn't specify a number", arg, sarg[0][4:])
				}
				if index < 0 {
					return fmt.Errorf("invalid expression %#v; minimum index is 0", arg)
				}
				if len(addresses) <= index {
					a := make([]string, index+1)
					copy(a, addresses)
					addresses = a
				}
				addresses[index] = sarg[1]
				if n != nil {
					n.SetAddress(index, addresses[index])
				}
			}
		}
	}
	if n == nil {
		n = b.AddNode(active, capacity, tiers, addresses, meta)
		report := [][]string{
			[]string{"ID:", fmt.Sprintf("%016x", n.ID())},
			[]string{"Active:", fmt.Sprintf("%v", n.Active())},
			[]string{"Capacity:", fmt.Sprintf("%d", n.Capacity())},
			[]string{"Tiers:", strings.Join(n.Tiers(), "\n")},
			[]string{"Addresses:", strings.Join(n.Addresses(), "\n")},
			[]string{"Meta:", n.Meta()},
		}
		fmt.Print(brimtext.Align(report, nil))
	}
	return nil
}
Beispiel #8
0
func nodeCmd(r ring.Ring, b *ring.Builder, args []string, full bool) (changed bool, err error) {
	var nodes ring.NodeSlice
	if r != nil {
		nodes = r.Nodes()
	} else {
		bnodes := b.Nodes()
		nodes = make(ring.NodeSlice, len(bnodes))
		for i := len(nodes) - 1; i >= 0; i-- {
			nodes[i] = bnodes[i]
		}
	}
	filterArgs := make([]string, 0)
	setArgs := make([]string, 0)
	setFound := false
	for _, arg := range args {
		if arg == "set" {
			setFound = true
			continue
		}
		if setFound {
			setArgs = append(setArgs, arg)
		} else {
			filterArgs = append(filterArgs, arg)
		}
	}
	if len(setArgs) > 0 && b == nil {
		err = fmt.Errorf("set is only valid for builder files")
		return
	}
	if nodes, err = nodes.Filter(filterArgs); err != nil {
		return
	}
	if len(nodes) > 0 && len(setArgs) > 0 {
		for _, n := range nodes {
			if err = addOrSetCmd(r, b, setArgs, n.(ring.BuilderNode)); err != nil {
				return
			}
			changed = true
		}
	}
	if full || len(nodes) == 1 {
		first := true
		for _, n := range nodes {
			if first {
				first = false
			} else {
				fmt.Println()
			}
			report := [][]string{
				[]string{"ID:", fmt.Sprintf("%016x", n.ID())},
				[]string{"Active:", fmt.Sprintf("%v", n.Active())},
				[]string{"Capacity:", fmt.Sprintf("%d", n.Capacity())},
				[]string{"Tiers:", strings.Join(n.Tiers(), "\n")},
				[]string{"Addresses:", strings.Join(n.Addresses(), "\n")},
				[]string{"Meta:", n.Meta()},
			}
			fmt.Print(brimtext.Align(report, nil))
		}
		return
	}
	header := []string{
		"ID",
		"Active",
		"Capacity",
		"Address",
		"Meta",
	}
	report := [][]string{header}
	reportAlign := brimtext.NewDefaultAlignOptions()
	reportAlign.Alignments = []brimtext.Alignment{
		brimtext.Left,
		brimtext.Right,
		brimtext.Right,
		brimtext.Right,
		brimtext.Left,
	}
	reportLine := func(n ring.Node) []string {
		return []string{
			fmt.Sprintf("%016x", n.ID()),
			fmt.Sprintf("%v", n.Active()),
			fmt.Sprintf("%d", n.Capacity()),
			n.Address(0),
			n.Meta(),
		}
	}
	for _, n := range nodes {
		if n.Active() {
			report = append(report, reportLine(n))
		}
	}
	for _, n := range nodes {
		if !n.Active() {
			report = append(report, reportLine(n))
		}
	}
	fmt.Print(brimtext.Align(report, reportAlign))
	return
}