mirror of
https://github.com/seaweedfs/seaweedfs.git
synced 2026-09-02 06:07:24 +00:00
* test: pin that a .vif replication outranks the superblock Store.ConfigureVolume rewrites the .vif and never the replica-placement byte in the .dat, so that byte keeps whatever the volume was created with for good. readSuperBlock reads it and then overrides it from the .vif, which is what makes a replication change take effect and survive a remount. Invert that and every replication change silently reverts on the next mount, while the .vif on disk still records what the operator asked for -- a durability setting quietly going back to its old value, with nothing to indicate it. Worth pinning rather than reading off the code, because the field beside it resolves the other way: version takes the superblock over the .vif. Two fields, one function, opposite precedence, each a line to invert wrongly. Covers the empty case too, since a .vif that declares no replication has to leave the superblock standing or a volume whose replication was never configured would be forced to whatever the zero value parses as. * test: drop the unreachable nil check on MaybeLoadVolumeInfo It initialises the returned pointer before the existence check and every return is naked, so it never yields nil. Guarding against it implied a contract the callee does not have.
102 lines
3.6 KiB
Go
102 lines
3.6 KiB
Go
package storage
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
|
|
"github.com/seaweedfs/seaweedfs/weed/pb/volume_server_pb"
|
|
"github.com/seaweedfs/seaweedfs/weed/storage/needle"
|
|
"github.com/seaweedfs/seaweedfs/weed/storage/super_block"
|
|
"github.com/seaweedfs/seaweedfs/weed/storage/volume_info"
|
|
)
|
|
|
|
// A volume's replication lives in two places that can disagree, and the .vif is
|
|
// the one that counts.
|
|
//
|
|
// Store.ConfigureVolume rewrites the .vif and never the replica-placement byte
|
|
// in the .dat superblock, so that byte keeps whatever the volume was created
|
|
// with for good. readSuperBlock reads the byte and then overrides it from the
|
|
// .vif, which is what makes the change take effect and survive a remount.
|
|
//
|
|
// Preferring the superblock instead would silently revert every replication
|
|
// change on the next mount, while the .vif on disk still recorded what the
|
|
// operator asked for. That is worth a test rather than a reading of the code,
|
|
// because it is one line to invert and the field beside it -- version -- really
|
|
// does resolve the other way, with the superblock outranking the .vif.
|
|
func TestVifReplicationOutranksSuperBlock(t *testing.T) {
|
|
dir := t.TempDir()
|
|
|
|
// Created carrying 000: the byte written into the .dat, and left there.
|
|
created, err := super_block.NewReplicaPlacementFromString("000")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
v, err := NewVolume(dir, dir, "", 1, NeedleMapInMemory, created, &needle.TTL{}, 0, needle.GetCurrentVersion(), 0, 0)
|
|
if err != nil {
|
|
t.Fatalf("create volume: %v", err)
|
|
}
|
|
if got := v.SuperBlock.ReplicaPlacement.String(); got != "000" {
|
|
t.Fatalf("volume created with replication %q, want 000", got)
|
|
}
|
|
v.Close()
|
|
|
|
// What ConfigureVolume does: rewrite the .vif alone.
|
|
vifFile := filepath.Join(dir, "1.vif")
|
|
info, _, _, err := volume_info.MaybeLoadVolumeInfo(vifFile)
|
|
if err != nil {
|
|
t.Fatalf("load vif: %v", err)
|
|
}
|
|
info.Replication = "010"
|
|
if err := volume_info.SaveVolumeInfo(vifFile, info); err != nil {
|
|
t.Fatalf("save vif: %v", err)
|
|
}
|
|
|
|
// The .dat still says 000 — nothing rewrote it.
|
|
reopened, err := NewVolume(dir, dir, "", 1, NeedleMapInMemory, nil, nil, 0, needle.GetCurrentVersion(), 0, 0)
|
|
if err != nil {
|
|
t.Fatalf("reload volume: %v", err)
|
|
}
|
|
defer reopened.Close()
|
|
|
|
if got := reopened.SuperBlock.ReplicaPlacement.String(); got != "010" {
|
|
t.Errorf("replication after reload = %q, want 010 from the .vif; "+
|
|
"a reconfigured volume must not revert to the byte in its .dat", got)
|
|
}
|
|
}
|
|
|
|
// An empty replication in the .vif declares nothing, so the superblock stands.
|
|
// Without this a volume that never had its replication configured would be
|
|
// forced to whatever the zero value parses as.
|
|
func TestEmptyVifReplicationLeavesSuperBlockAlone(t *testing.T) {
|
|
dir := t.TempDir()
|
|
|
|
created, err := super_block.NewReplicaPlacementFromString("010")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
v, err := NewVolume(dir, dir, "", 2, NeedleMapInMemory, created, &needle.TTL{}, 0, needle.GetCurrentVersion(), 0, 0)
|
|
if err != nil {
|
|
t.Fatalf("create volume: %v", err)
|
|
}
|
|
v.Close()
|
|
|
|
vifFile := filepath.Join(dir, "2.vif")
|
|
if err := volume_info.SaveVolumeInfo(vifFile, &volume_server_pb.VolumeInfo{Version: uint32(needle.GetCurrentVersion())}); err != nil {
|
|
t.Fatalf("save vif: %v", err)
|
|
}
|
|
if _, err := os.Stat(vifFile); err != nil {
|
|
t.Fatalf("vif not written: %v", err)
|
|
}
|
|
|
|
reopened, err := NewVolume(dir, dir, "", 2, NeedleMapInMemory, nil, nil, 0, needle.GetCurrentVersion(), 0, 0)
|
|
if err != nil {
|
|
t.Fatalf("reload volume: %v", err)
|
|
}
|
|
defer reopened.Close()
|
|
|
|
if got := reopened.SuperBlock.ReplicaPlacement.String(); got != "010" {
|
|
t.Errorf("replication after reload = %q, want the superblock's 010 to stand", got)
|
|
}
|
|
}
|