crushkv/crushmap/binary.go

209 lines
4.9 KiB
Go
Raw Normal View History

package crushmap
import (
"bytes"
"encoding/binary"
"fmt"
"io"
)
const (
Magic = uint32(0x00010000)
)
type CrushRuleOpType uint32
const (
CrushRuleNoop CrushRuleOpType = iota
CrushRuleTake
CrushRuleChooseFirstN
CrushRuleChooseIndep
CrushRuleEmit
CrushRuleChooseleafFirstN
CrushRuleChooseleafIndep
CrushRuleSetChooseTries
CrushRuleSetChooseleafTries
CrushRuleSetChooseLocalTries
CrushRuleSetChooseLocalFallbackTries
CrushRuleSetChooseleafVaryR
CrushRuleSetChooseleafStable
)
var (
crushRuleOpTypeStringMap = map[CrushRuleOpType]string{
CrushRuleNoop: "noop",
CrushRuleTake: "take",
CrushRuleChooseFirstN: "choose firstn",
CrushRuleChooseIndep: "choose indep",
CrushRuleEmit: "emit",
CrushRuleChooseleafFirstN: "choose_leaf firstn",
CrushRuleChooseleafIndep: "choose_leaf indep",
CrushRuleSetChooseTries: "set_choose_tries",
CrushRuleSetChooseleafTries: "set_chooseleaf_tries",
CrushRuleSetChooseLocalTries: "set_choose_local_tries",
CrushRuleSetChooseLocalFallbackTries: "set_choose_local_fallback_tries",
CrushRuleSetChooseleafVaryR: "set_choose_leaf_vary_r",
CrushRuleSetChooseleafStable: "set_choose_leaf_stable",
}
crushRuleOpStringTypeMap = map[string]CrushRuleOpType{
"noop": CrushRuleNoop,
"take": CrushRuleTake,
"choose firstn": CrushRuleChooseFirstN,
"choose indep": CrushRuleChooseIndep,
"emit": CrushRuleEmit,
"choose_leaf firstn": CrushRuleChooseleafFirstN,
"choose_leaf indep": CrushRuleChooseleafIndep,
"set choose_tries": CrushRuleSetChooseTries,
"set chooseleaf_tries": CrushRuleSetChooseleafTries,
"set choose_local_tries": CrushRuleSetChooseLocalTries,
"set choose_local_fallback_tries": CrushRuleSetChooseLocalFallbackTries,
"set choose_leaf_vary_r": CrushRuleSetChooseleafVaryR,
"set choose_leaf_stable": CrushRuleSetChooseleafStable,
}
)
func (t CrushRuleOpType) String() string {
op, ok := crushRuleOpTypeStringMap[t]
if !ok {
op = "invalid"
}
return op
}
type CrushRuleStep struct {
Op CrushRuleOpType
Arg1 int32
Arg2 int32
}
type binaryParser struct {
r io.Reader
w io.Writer
}
func (cmap *Map) DecodeBinary(data []byte) error {
var err error
var magic uint32
p := &binaryParser{r: bytes.NewBuffer(data)}
err = binary.Read(p.r, binary.LittleEndian, &magic)
if err != nil {
return err
} else if magic != Magic {
return fmt.Errorf("invalid magic: %0x != %0x", magic, Magic)
}
var (
maxBuckets int32
maxRules uint32
maxDevices int32
)
err = binary.Read(p.r, binary.LittleEndian, &maxBuckets)
if err != nil {
return err
}
err = binary.Read(p.r, binary.LittleEndian, &maxRules)
if err != nil {
return err
}
err = binary.Read(p.r, binary.LittleEndian, &maxDevices)
if err != nil {
return err
}
for i := int32(0); i < maxBuckets; i++ {
ibucket, err := p.handleBucket()
if err != nil {
return err
}
if ibucket == nil {
continue
}
cmap.Buckets = append(cmap.Buckets, ibucket)
}
for i := uint32(0); i < maxRules; i++ {
irule, err := p.handleRule()
if err != nil {
return err
}
cmap.Rules = append(cmap.Rules, irule)
}
itypes, err := p.handleType()
if err != nil {
return err
}
cmap.Types = itypes
btypes := make(map[int32]string, len(itypes))
for _, t := range itypes {
btypes[t.ID] = t.Name
}
bnames := make(map[int32]string)
itypes, err = p.handleType()
if err != nil {
return err
}
for _, t := range itypes {
bnames[t.ID] = t.Name
}
rnames := make(map[int32]string)
itypes, err = p.handleType()
if err != nil {
return err
}
for _, t := range itypes {
rnames[t.ID] = t.Name
}
var ok bool
for _, bucket := range cmap.Buckets {
if bucket != nil {
if bucket.TypeName, ok = btypes[int32(bucket.TypeID)]; !ok {
return fmt.Errorf("unknown type id: %d", bucket.TypeID)
}
for _, item := range bucket.Items {
if item.Name, ok = bnames[int32(bucket.ID)]; !ok {
return fmt.Errorf("unknown type id: %d", bucket.ID)
}
}
}
}
itypes, err = p.handleType()
if err != nil {
return err
}
for _, rule := range cmap.Rules {
if rule.Name, ok = rnames[int32(rule.Ruleset)]; !ok {
return fmt.Errorf("unknown type id: %d", rule.ID)
}
for _, step := range rule.Steps {
switch step.Op {
default:
case CrushRuleChooseFirstN.String(), CrushRuleChooseIndep.String(), CrushRuleChooseleafFirstN.String(), CrushRuleChooseleafIndep.String():
if step.ItemType, ok = btypes[step.ItemTypeID]; !ok {
return fmt.Errorf("unknown type id: %d", step.ItemTypeID)
}
}
}
}
itunables, err := p.handleTunable()
if err != nil {
return err
}
cmap.Tunables = itunables
cmap.rulesSort()
cmap.bucketsSort()
return nil
}