303 lines
7.2 KiB
Go
303 lines
7.2 KiB
Go
package crushmap
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"fmt"
|
|
"math"
|
|
)
|
|
|
|
type binaryBucket interface {
|
|
BucketID() int32
|
|
BucketType() CrushBucketType
|
|
BucketAlg() CrushAlgType
|
|
BucketHash() CrushBucketHashType
|
|
BucketWeight() float32
|
|
BucketSize() uint32
|
|
}
|
|
|
|
func (b *BucketUniform) BucketID() int32 {
|
|
return b.ID
|
|
}
|
|
func (b *BucketUniform) BucketType() CrushBucketType {
|
|
return b.Type
|
|
}
|
|
func (b *BucketUniform) BucketAlg() CrushAlgType {
|
|
return b.Alg
|
|
}
|
|
func (b *BucketUniform) BucketHash() CrushBucketHashType {
|
|
return b.Hash
|
|
}
|
|
func (b *BucketUniform) BucketWeight() float32 {
|
|
return b.Weight
|
|
}
|
|
func (b *BucketUniform) BucketSize() uint32 {
|
|
return b.Size
|
|
}
|
|
func (b *BucketList) BucketID() int32 {
|
|
return b.ID
|
|
}
|
|
func (b *BucketList) BucketType() CrushBucketType {
|
|
return b.Type
|
|
}
|
|
func (b *BucketList) BucketAlg() CrushAlgType {
|
|
return b.Alg
|
|
}
|
|
func (b *BucketList) BucketHash() CrushBucketHashType {
|
|
return b.Hash
|
|
}
|
|
func (b *BucketList) BucketWeight() float32 {
|
|
return b.Weight
|
|
}
|
|
func (b *BucketList) BucketSize() uint32 {
|
|
return b.Size
|
|
}
|
|
func (b *BucketTree) BucketID() int32 {
|
|
return b.ID
|
|
}
|
|
func (b *BucketTree) BucketType() CrushBucketType {
|
|
return b.Type
|
|
}
|
|
func (b *BucketTree) BucketAlg() CrushAlgType {
|
|
return b.Alg
|
|
}
|
|
func (b *BucketTree) BucketHash() CrushBucketHashType {
|
|
return b.Hash
|
|
}
|
|
func (b *BucketTree) BucketWeight() float32 {
|
|
return b.Weight
|
|
}
|
|
func (b *BucketTree) BucketSize() uint32 {
|
|
return b.Size
|
|
}
|
|
func (b *BucketStraw) BucketID() int32 {
|
|
return b.ID
|
|
}
|
|
func (b *BucketStraw) BucketType() CrushBucketType {
|
|
return b.Type
|
|
}
|
|
func (b *BucketStraw) BucketAlg() CrushAlgType {
|
|
return b.Alg
|
|
}
|
|
func (b *BucketStraw) BucketHash() CrushBucketHashType {
|
|
return b.Hash
|
|
}
|
|
func (b *BucketStraw) BucketWeight() float32 {
|
|
return b.Weight
|
|
}
|
|
func (b *BucketStraw) BucketSize() uint32 {
|
|
return b.Size
|
|
}
|
|
|
|
func (b *BucketStraw2) BucketID() int32 {
|
|
return b.ID
|
|
}
|
|
func (b *BucketStraw2) BucketType() CrushBucketType {
|
|
return b.Type
|
|
}
|
|
func (b *BucketStraw2) BucketAlg() CrushAlgType {
|
|
return b.Alg
|
|
}
|
|
func (b *BucketStraw2) BucketHash() CrushBucketHashType {
|
|
return b.Hash
|
|
}
|
|
func (b *BucketStraw2) BucketWeight() float32 {
|
|
return b.Weight
|
|
}
|
|
func (b *BucketStraw2) BucketSize() uint32 {
|
|
return b.Size
|
|
}
|
|
|
|
type binaryBucketHeader struct {
|
|
ID int32
|
|
Type CrushBucketType
|
|
Alg CrushAlgType
|
|
Hash CrushBucketHashType
|
|
Weight float32
|
|
Size uint32
|
|
}
|
|
|
|
type binaryBucketCommon struct {
|
|
binaryBucketHeader
|
|
Items []int32
|
|
}
|
|
|
|
type BucketUniform struct {
|
|
binaryBucketCommon
|
|
ItemWeight float32
|
|
}
|
|
|
|
type BucketList struct {
|
|
binaryBucketCommon
|
|
ItemWeights []float32
|
|
SumWeights []float32
|
|
}
|
|
|
|
type BucketTree struct {
|
|
binaryBucketCommon
|
|
NumNodes uint8
|
|
NodeWeights []float32
|
|
}
|
|
|
|
type BucketStraw struct {
|
|
binaryBucketCommon
|
|
ItemWeights []float32
|
|
Straws []uint32
|
|
}
|
|
|
|
type BucketStraw2 struct {
|
|
binaryBucketCommon
|
|
ItemWeights []float32
|
|
}
|
|
|
|
func (b *binaryBucketHeader) String() string {
|
|
return fmt.Sprintf("id: %d, type: %s, alg: %s, hash: %s, weight: %f, size: %d",
|
|
b.ID, b.Type, b.Alg, b.Hash, b.Weight, b.Size)
|
|
}
|
|
|
|
func (p *binaryParser) handleBucket() (*Bucket, error) {
|
|
var err error
|
|
ibucket := &Bucket{}
|
|
var bucket binaryBucket
|
|
|
|
var alg uint32
|
|
err = binary.Read(p.r, binary.LittleEndian, &alg)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if CrushAlgType(alg) == CrushAlgInvalid {
|
|
return nil, nil
|
|
}
|
|
|
|
bucketHeader := binaryBucketHeader{}
|
|
err = binary.Read(p.r, binary.LittleEndian, &bucketHeader.ID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
err = binary.Read(p.r, binary.LittleEndian, &bucketHeader.Type)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
err = binary.Read(p.r, binary.LittleEndian, &bucketHeader.Alg)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
err = binary.Read(p.r, binary.LittleEndian, &bucketHeader.Hash)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var weight uint32
|
|
err = binary.Read(p.r, binary.LittleEndian, &weight)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
bucketHeader.Weight = math.Float32frombits(weight)
|
|
err = binary.Read(p.r, binary.LittleEndian, &bucketHeader.Size)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
bucketCommon := binaryBucketCommon{binaryBucketHeader: bucketHeader}
|
|
bucketCommon.Items = make([]int32, bucketHeader.Size)
|
|
for i := uint32(0); i < bucketHeader.Size; i++ {
|
|
err = binary.Read(p.r, binary.LittleEndian, &bucketCommon.Items[i])
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
switch bucketHeader.Alg {
|
|
case CrushAlgUniform:
|
|
bucketUniform := &BucketUniform{
|
|
binaryBucketCommon: bucketCommon,
|
|
}
|
|
var itemWeight uint32
|
|
err = binary.Read(p.r, binary.LittleEndian, &itemWeight)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
bucketUniform.ItemWeight = math.Float32frombits(itemWeight)
|
|
bucket = bucketUniform
|
|
case CrushAlgList:
|
|
itemWeights := make([]uint32, bucketHeader.Size)
|
|
sumWeights := make([]uint32, bucketHeader.Size)
|
|
bucketList := &BucketList{
|
|
binaryBucketCommon: bucketCommon,
|
|
ItemWeights: make([]float32, bucketHeader.Size),
|
|
SumWeights: make([]float32, bucketHeader.Size),
|
|
}
|
|
for i := uint32(0); i <= bucketHeader.Size; i++ {
|
|
err = binary.Read(p.r, binary.LittleEndian, &itemWeights[i])
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
bucketList.ItemWeights[i] = math.Float32frombits(itemWeights[i])
|
|
err = binary.Read(p.r, binary.LittleEndian, &sumWeights[i])
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
bucketList.SumWeights[i] = math.Float32frombits(sumWeights[i])
|
|
}
|
|
bucket = bucketList
|
|
case CrushAlgTree:
|
|
bucketTree := &BucketTree{
|
|
binaryBucketCommon: bucketCommon,
|
|
}
|
|
err = binary.Read(p.r, binary.LittleEndian, &bucketTree.NumNodes)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
nodeWeights := make([]uint32, bucketTree.NumNodes*4)
|
|
bucketTree.NodeWeights = make([]float32, bucketTree.NumNodes*4)
|
|
err = binary.Read(p.r, binary.LittleEndian, &nodeWeights)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
for i := 0; i < int(bucketTree.NumNodes*4); i++ {
|
|
bucketTree.NodeWeights[i] = math.Float32frombits(nodeWeights[i])
|
|
}
|
|
bucket = bucketTree
|
|
case CrushAlgStraw:
|
|
itemWeights := make([]uint32, (bucketHeader.Size)*4)
|
|
bucketStraw := &BucketStraw{
|
|
binaryBucketCommon: bucketCommon,
|
|
Straws: make([]uint32, (bucketHeader.Size)*4),
|
|
ItemWeights: make([]float32, (bucketHeader.Size)*4),
|
|
}
|
|
for i := uint32(0); i < bucketHeader.Size; i++ {
|
|
err = binary.Read(p.r, binary.LittleEndian, &itemWeights[i])
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
bucketStraw.ItemWeights[i] = math.Float32frombits(itemWeights[i])
|
|
err = binary.Read(p.r, binary.LittleEndian, &bucketStraw.Straws[i])
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
bucket = bucketStraw
|
|
case CrushAlgStraw2:
|
|
itemWeights := make([]uint32, (bucketHeader.Size+1)*4)
|
|
bucketStraw2 := &BucketStraw2{
|
|
binaryBucketCommon: bucketCommon,
|
|
ItemWeights: make([]float32, (bucketHeader.Size+1)*4),
|
|
}
|
|
err = binary.Read(p.r, binary.LittleEndian, &itemWeights)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
for i := uint32(0); i < (bucketHeader.Size+1)*4; i++ {
|
|
bucketStraw2.ItemWeights[i] = math.Float32frombits(itemWeights[i])
|
|
}
|
|
bucket = bucketStraw2
|
|
}
|
|
ibucket.ID = bucketHeader.ID
|
|
ibucket.Alg = bucketHeader.Alg.String()
|
|
ibucket.Hash = bucketHeader.Hash.String()
|
|
ibucket.TypeID = bucketHeader.Type
|
|
ibucket.Weight = bucketHeader.Weight
|
|
ibucket.Size = bucketHeader.Size
|
|
_ = bucket
|
|
return ibucket, nil
|
|
}
|