mirror of
https://github.com/seaweedfs/seaweedfs.git
synced 2026-08-16 04:06:44 +00:00
perf(weed/storage/super_block): intern the byte-encoded replica placements (#10610)
NewReplicaPlacementFromByte formatted the byte with fmt.Sprintf and parsed the result back, allocating a string and a ReplicaPlacement every call. The master calls it once per volume in every heartbeat, and keeps the pointer for the lifetime of the volume, so a cluster with 1.6M volume replicas carries 1.6M of these where a handful of distinct values exist. The table is a flat pointer-free array, so it costs 6KB of static data and no heap objects however few placements a cluster actually uses. A byte only ever decodes to a valid placement, so the table is complete and the error return stays nil. BenchmarkSyncDataNodeRegistration/100000Volumes 500601 allocs/op -> 300589 allocs/op
This commit is contained in:
@@ -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 {
|
||||
|
||||
@@ -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())
|
||||
|
||||
Reference in New Issue
Block a user