diff --git a/weed/storage/super_block/replica_placement.go b/weed/storage/super_block/replica_placement.go index ec4ecf254..9a821db2a 100644 --- a/weed/storage/super_block/replica_placement.go +++ b/weed/storage/super_block/replica_placement.go @@ -43,8 +43,26 @@ func NewReplicaPlacementFromString(t string) (*ReplicaPlacement, error) { return rp, nil } +// replicaPlacementsByByte is one 6KB pointer-free array covering every encoding +// a byte can hold. The master decodes one per volume in every volume server +// heartbeat and keeps it for the volume's lifetime, so handing out a shared +// element keeps that path off fmt and off the heap entirely. +// +// Elements are immutable. Callers must not write through the returned pointer. +var replicaPlacementsByByte [256]ReplicaPlacement + +func init() { + for b := range replicaPlacementsByByte { + replicaPlacementsByByte[b] = ReplicaPlacement{ + DiffDataCenterCount: b / 100, + DiffRackCount: b / 10 % 10, + SameRackCount: b % 10, + } + } +} + func NewReplicaPlacementFromByte(b byte) (*ReplicaPlacement, error) { - return NewReplicaPlacementFromString(fmt.Sprintf("%03d", b)) + return &replicaPlacementsByByte[b], nil } func (rp *ReplicaPlacement) HasReplication() bool { diff --git a/weed/storage/super_block/replica_placement_test.go b/weed/storage/super_block/replica_placement_test.go index 203e3e860..6e19f5794 100644 --- a/weed/storage/super_block/replica_placement_test.go +++ b/weed/storage/super_block/replica_placement_test.go @@ -1,9 +1,29 @@ package super_block import ( + "fmt" "testing" ) +func TestReplicaPlacementFromByteMatchesString(t *testing.T) { + for b := 0; b < 256; b++ { + want, err := NewReplicaPlacementFromString(fmt.Sprintf("%03d", b)) + if err != nil { + t.Fatalf("byte %d: %v", b, err) + } + got, err := NewReplicaPlacementFromByte(byte(b)) + if err != nil { + t.Fatalf("byte %d: %v", b, err) + } + if !got.Equals(want) { + t.Errorf("byte %d: got %+v, want %+v", b, got, want) + } + if got.Byte() != byte(b) { + t.Errorf("byte %d: round trip gave %d", b, got.Byte()) + } + } +} + func TestReplicaPlacementSerialDeserial(t *testing.T) { rp, _ := NewReplicaPlacementFromString("001") newRp, _ := NewReplicaPlacementFromByte(rp.Byte())