mirror of
https://github.com/seaweedfs/seaweedfs.git
synced 2026-11-12 23:09:33 +01:00
* volume: refuse a tier upload whose .dat grew during the copy AttachRemoteDatFile only checked that the data backend was still the one copied, so a needle write acknowledged after the copy read the .dat was missing from the remote object, and the upload then switched reads to it and removed the local .dat. Compare the .dat size with the copy under the same data-file locks; on a mismatch the handler deletes the copy and keeps the local file. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * seaweed-volume: refuse a tier upload whose .dat grew during the copy Mirror the Go AttachRemoteDatFile check. The tier-up attach took the write lease only inside each step, so a needle write acknowledged after the upload read the .dat was missing from the object the volume then switched to, and the local .dat holding it was removed. Hold one write lease across the instance, revision and size checks, the remote-file update, the .vif save and the backend swap, as tier-down does; a size mismatch aborts, deleting the object and keeping the local .dat. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * volume: compare the physical .dat size before a tier attach DiskFile pads its size past an unaligned tail, which a read-only load keeps, while the upload copies the physical bytes. Stat the file itself so such a volume is not refused as written during the copy. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
59 lines
1.9 KiB
Go
59 lines
1.9 KiB
Go
package storage
|
|
|
|
import (
|
|
"os"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"github.com/seaweedfs/seaweedfs/weed/pb/volume_server_pb"
|
|
"github.com/seaweedfs/seaweedfs/weed/storage/backend"
|
|
"github.com/seaweedfs/seaweedfs/weed/storage/needle"
|
|
"github.com/seaweedfs/seaweedfs/weed/storage/super_block"
|
|
"github.com/seaweedfs/seaweedfs/weed/storage/types"
|
|
)
|
|
|
|
// A read-only load keeps an unaligned .dat tail, and the data backend pads its
|
|
// size past it. The copy holds the physical bytes, so AttachRemoteDatFile must
|
|
// not read the padding as a write that landed during the copy.
|
|
func TestAttachRemoteDatFileAcceptsAnUnalignedDatTail(t *testing.T) {
|
|
b := newLocalDirBackend(t)
|
|
registerTestBackend(t, b)
|
|
|
|
dir := t.TempDir()
|
|
open := func() *Volume {
|
|
v, err := NewVolume(dir, dir, "", 88, NeedleMapInMemory, &super_block.ReplicaPlacement{}, &needle.TTL{}, 0, needle.GetCurrentVersion(), 0, 0)
|
|
require.NoError(t, err)
|
|
return v
|
|
}
|
|
v := open()
|
|
for i := 1; i <= 3; i++ {
|
|
_, _, _, err := v.writeNeedle2(newRandomNeedle(uint64(i)), true, false, false)
|
|
require.NoError(t, err)
|
|
}
|
|
require.NoError(t, v.PersistReadOnly(true, false))
|
|
datName := v.FileName(".dat")
|
|
v.Close()
|
|
f, err := os.OpenFile(datName, os.O_WRONLY|os.O_APPEND, 0)
|
|
require.NoError(t, err)
|
|
_, err = f.Write([]byte{1, 2, 3})
|
|
require.NoError(t, err)
|
|
require.NoError(t, f.Close())
|
|
|
|
v = open()
|
|
defer v.Close()
|
|
diskFile, ok := v.DataBackend.(*backend.DiskFile)
|
|
require.True(t, ok)
|
|
key, size, err := b.CopyFile(diskFile.File, nil, 0)
|
|
require.NoError(t, err)
|
|
require.NotZero(t, size%types.NeedlePaddingSize, "the .dat must end unaligned") // positive control
|
|
|
|
bType, bId := backend.BackendNameToTypeId(testBackendName)
|
|
require.NoError(t, v.AttachRemoteDatFile(diskFile, &volume_server_pb.RemoteFile{
|
|
BackendType: bType, BackendId: bId, Key: key, FileSize: uint64(size),
|
|
ModifiedTime: uint64(time.Now().Unix()), Extension: ".dat",
|
|
}))
|
|
require.True(t, v.HasRemoteFile())
|
|
}
|