mirror of
https://github.com/seaweedfs/seaweedfs.git
synced 2026-09-20 13:30:46 +02:00
* fix(storage): keep EC .vif when deleting a coexisting regular volume A regular volume and an EC volume for the same id share <base>.vif. When EC shards are distributed onto a server that still holds the regular volume — the encode source, or any replica the planner targets — the post-encode VolumeDelete ran removeVolumeFiles and stripped the shared .vif, leaving the freshly built EC volume without its info file. Skip the .vif in removeVolumeFiles when an EC volume for the same id exists on the disk (mounted, or a sealed .ecx on disk). The regular volume's .dat/.idx still go; the EC sidecars survive. A two-server end-to-end test encodes a volume whose source and a stub replica both also receive shards, and asserts the final on-disk layout: both .dat/.idx gone, each server holding only its assigned shards plus .ecx/.vif. Storage unit tests cover the with-EC and no-EC cases, and the Rust seaweed-volume port carries the same guard and tests. * test(storage): assert .idx is removed in the no-EC destroy case Strengthen TestDestroyRemovesVifWhenNoEc to confirm the full regular volume cleanup (.dat, .idx, .vif) when no EC volume coexists.
76 lines
2.8 KiB
Go
76 lines
2.8 KiB
Go
package storage
|
|
|
|
import (
|
|
"os"
|
|
"testing"
|
|
|
|
"github.com/seaweedfs/seaweedfs/weed/storage/erasure_coding"
|
|
"github.com/seaweedfs/seaweedfs/weed/storage/needle"
|
|
"github.com/seaweedfs/seaweedfs/weed/storage/super_block"
|
|
"github.com/seaweedfs/seaweedfs/weed/storage/types"
|
|
"github.com/seaweedfs/seaweedfs/weed/util"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
// A regular volume and an EC volume for the same id share <base>.vif. Deleting
|
|
// the regular volume must drop its .dat/.idx but keep the .vif so the
|
|
// coexisting EC volume's info file survives. This is the same-disk case that
|
|
// arises when EC shards are distributed onto a source/replica server before
|
|
// the original volume is deleted.
|
|
func TestDestroyKeepsVifWhenEcCoexists(t *testing.T) {
|
|
dir := t.TempDir()
|
|
v, err := NewVolume(dir, dir, "", 1, NeedleMapInMemory, &super_block.ReplicaPlacement{}, &needle.TTL{}, 0, needle.GetCurrentVersion(), 0, 0)
|
|
require.NoError(t, err)
|
|
v.location = newTestDiskLocation(dir)
|
|
_, _, _, err = v.writeNeedle2(newRandomNeedle(1), true, false)
|
|
require.NoError(t, err)
|
|
|
|
base := VolumeFileName(dir, "", 1)
|
|
vifPath := base + ".vif"
|
|
require.NoError(t, os.WriteFile(vifPath, []byte("ec-volume-info"), 0o644))
|
|
// An on-disk .ecx marks a coexisting EC volume for the same id.
|
|
ecxPath := erasure_coding.EcShardFileName("", dir, 1) + ".ecx"
|
|
require.NoError(t, os.WriteFile(ecxPath, []byte("ec-index"), 0o644))
|
|
|
|
require.NoError(t, v.Destroy(false, false))
|
|
|
|
assertFileExist(t, false, base+".dat")
|
|
assertFileExist(t, false, base+".idx")
|
|
assertFileExist(t, true, vifPath) // shared with the EC volume, must survive
|
|
assertFileExist(t, true, ecxPath) // EC sidecars are never touched here
|
|
}
|
|
|
|
// With no coexisting EC volume the .vif is a plain regular-volume file and is
|
|
// removed with the rest.
|
|
func TestDestroyRemovesVifWhenNoEc(t *testing.T) {
|
|
dir := t.TempDir()
|
|
v, err := NewVolume(dir, dir, "", 1, NeedleMapInMemory, &super_block.ReplicaPlacement{}, &needle.TTL{}, 0, needle.GetCurrentVersion(), 0, 0)
|
|
require.NoError(t, err)
|
|
v.location = newTestDiskLocation(dir)
|
|
_, _, _, err = v.writeNeedle2(newRandomNeedle(1), true, false)
|
|
require.NoError(t, err)
|
|
|
|
base := VolumeFileName(dir, "", 1)
|
|
vifPath := base + ".vif"
|
|
require.NoError(t, os.WriteFile(vifPath, []byte("regular-volume-info"), 0o644))
|
|
|
|
require.NoError(t, v.Destroy(false, false))
|
|
|
|
assertFileExist(t, false, base+".dat")
|
|
assertFileExist(t, false, base+".idx")
|
|
assertFileExist(t, false, vifPath) // removed along with the regular volume
|
|
}
|
|
|
|
func newTestDiskLocation(dir string) *DiskLocation {
|
|
loc := &DiskLocation{
|
|
Directory: dir,
|
|
IdxDirectory: dir,
|
|
DiskType: types.HddType,
|
|
MaxVolumeCount: 100,
|
|
MinFreeSpace: util.MinFreeSpace{Type: util.AsPercent, Percent: 1, Raw: "1"},
|
|
}
|
|
loc.volumes = make(map[needle.VolumeId]*Volume)
|
|
loc.ecVolumes = make(map[needle.VolumeId]*erasure_coding.EcVolume)
|
|
return loc
|
|
}
|