mirror of
https://github.com/seaweedfs/seaweedfs.git
synced 2026-10-07 14:57:48 +02:00
volume: return error instead of panicking when .dat open fails (#11619)
* volume: return error instead of panicking when .dat open fails When backend.OpenVolumeFile returns an error (e.g. disk below -minFreeSpace), dataFile is nil. Calling backend.NewDiskFile(nil) immediately after caused a nil-pointer panic in f.Stat()/f.Name(). Move the existing error check to run right after OpenVolumeFile, before NewDiskFile is called, so the error is returned cleanly. Fixes seaweedfs/seaweedfs#11615 * volume: share .dat load error handling Extract datFileLoadError helper so open and create paths share one check. * volume: trim dat-open-fail test comments * volume(rust): cover unopenable .dat load path --------- Co-authored-by: Chris Lu <chris.lu@gmail.com>
This commit is contained in:
1 parent
32e77ff980
commit
23893eb378
3 files changed
+71
-5
No files matched your search
@@ -9687,6 +9687,31 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
// A directory occupying the .dat path fails open even as root; load must
|
||||
// return the error. Mirrors Go's TestLoad_DatOpenFail_NoNilPanic.
|
||||
#[test]
|
||||
fn test_load_dat_open_fail_returns_error() {
|
||||
let tmp = TempDir::new().unwrap();
|
||||
let dir = tmp.path().to_str().unwrap();
|
||||
|
||||
{
|
||||
let _v = make_test_volume(dir);
|
||||
}
|
||||
|
||||
let dat_path = format!("{dir}/1.dat");
|
||||
std::fs::remove_file(&dat_path).unwrap();
|
||||
std::fs::create_dir(&dat_path).unwrap();
|
||||
|
||||
let result = Volume::new(
|
||||
dir,
|
||||
dir,
|
||||
VolumeId(1),
|
||||
NeedleMapKind::InMemory,
|
||||
&VolumeSpec::default(),
|
||||
);
|
||||
assert!(result.is_err(), "unopenable .dat must fail load");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_remote_only_volume_load_reads_from_tier_backend() {
|
||||
let tmp = TempDir::new().unwrap();
|
||||
|
||||
@@ -198,6 +198,9 @@ func (v *Volume) load(alsoLoadIndex bool, createDatIfMissing bool, needleMapKind
|
||||
dataFile, err = backend.OpenVolumeFile(v.FileName(".dat"), os.O_RDONLY)
|
||||
v.noWriteOrDelete = true
|
||||
}
|
||||
if err != nil {
|
||||
return datFileLoadError(v.FileName(".dat"), err)
|
||||
}
|
||||
v.lastModifiedTsSeconds = uint64(modifiedTime.Unix())
|
||||
if fileSize >= super_block.SuperBlockSize {
|
||||
alreadyHasSuperBlock = true
|
||||
@@ -212,11 +215,7 @@ func (v *Volume) load(alsoLoadIndex bool, createDatIfMissing bool, needleMapKind
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
if !os.IsPermission(err) {
|
||||
return fmt.Errorf("cannot load volume data %s: %v", v.FileName(".dat"), err)
|
||||
} else {
|
||||
return fmt.Errorf("load data file %s: %v", v.FileName(".dat"), err)
|
||||
}
|
||||
return datFileLoadError(v.FileName(".dat"), err)
|
||||
}
|
||||
|
||||
if alreadyHasSuperBlock {
|
||||
@@ -417,3 +416,10 @@ func (v *Volume) load(alsoLoadIndex bool, createDatIfMissing bool, needleMapKind
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func datFileLoadError(fileName string, err error) error {
|
||||
if os.IsPermission(err) {
|
||||
return fmt.Errorf("load data file %s: %v", fileName, err)
|
||||
}
|
||||
return fmt.Errorf("cannot load volume data %s: %v", fileName, err)
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package storage
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/seaweedfs/seaweedfs/weed/storage/needle"
|
||||
"github.com/seaweedfs/seaweedfs/weed/storage/super_block"
|
||||
)
|
||||
|
||||
// A directory occupying the .dat path fails open even as root; load must
|
||||
// return the error rather than crash inside backend.NewDiskFile.
|
||||
func TestLoad_DatOpenFail_NoNilPanic(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
|
||||
v, err := NewVolume(dir, dir, "", 1, NeedleMapInMemory, &super_block.ReplicaPlacement{}, &needle.TTL{}, 0, needle.GetCurrentVersion(), 0, 0)
|
||||
if err != nil {
|
||||
t.Fatalf("create volume: %v", err)
|
||||
}
|
||||
v.Close()
|
||||
|
||||
datPath := VolumeFileName(dir, "", 1) + ".dat"
|
||||
if err := os.Remove(datPath); err != nil {
|
||||
t.Fatalf("remove .dat: %v", err)
|
||||
}
|
||||
if err := os.Mkdir(datPath, 0755); err != nil {
|
||||
t.Fatalf("mkdir .dat: %v", err)
|
||||
}
|
||||
|
||||
v2, err := NewVolume(dir, dir, "", 1, NeedleMapInMemory, &super_block.ReplicaPlacement{}, &needle.TTL{}, 0, needle.GetCurrentVersion(), 0, 0)
|
||||
if err == nil {
|
||||
v2.Close()
|
||||
t.Fatal("expected error when .dat cannot be opened, got nil")
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user