mirror of
https://github.com/seaweedfs/seaweedfs.git
synced 2026-06-13 23:36:45 +03:00
volume: accept legacy needle CRC encoding on read (#9564)
Volumes written by versions before 3.09 (commit 056c480eb) store the
needle checksum using the deprecated CRC.Value() transform. When the
read path moved into readNeedleTail, the fallback that accepts both
encodings was dropped, so .dat files copied from old installs now fail
verification with "invalid CRC ... data on disk corrupted" even though
the data is intact. Restore the dual check, matching the surviving
fallback in volume_read.go.
This commit is contained in:
@@ -13,10 +13,10 @@ func (n *Needle) readNeedleTail(needleBody []byte, version Version) error {
|
||||
if len(n.Data) > 0 {
|
||||
expectedChecksum := CRC(util.BytesToUint32(needleBody[0:NeedleChecksumSize]))
|
||||
dataChecksum := NewCRC(n.Data)
|
||||
if expectedChecksum != dataChecksum {
|
||||
// the crc.Value() function is to be deprecated. this double checking is for backward compatibility
|
||||
// with seaweed version using crc.Value() instead of uint32(crc), which appears in commit 056c480eb
|
||||
// and switch appeared in version 3.09.
|
||||
if expectedChecksum != dataChecksum && uint32(expectedChecksum) != dataChecksum.Value() {
|
||||
// crc.Value() is the deprecated legacy transform used before commit 056c480eb
|
||||
// (volume server <3.09). Accept either encoding so .dat files written by older
|
||||
// versions still verify after an upgrade.
|
||||
stats.VolumeServerHandlerCounter.WithLabelValues(stats.ErrorCRC).Inc()
|
||||
return fmt.Errorf("invalid CRC for needle %v (got %08x, want %08x), data on disk corrupted: %w", n.Id, dataChecksum, expectedChecksum, ErrorCorrupted)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
package needle
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
. "github.com/seaweedfs/seaweedfs/weed/storage/types"
|
||||
"github.com/seaweedfs/seaweedfs/weed/util"
|
||||
)
|
||||
|
||||
// .dat files written by volume server versions prior to 3.09 (before commit
|
||||
// 056c480eb) store the needle checksum using the legacy CRC.Value() transform.
|
||||
// Reads of such needles must still verify after an upgrade.
|
||||
func TestReadNeedleTailLegacyChecksum(t *testing.T) {
|
||||
data := []byte("hello seaweed")
|
||||
rawChecksum := NewCRC(data)
|
||||
legacyChecksum := rawChecksum.Value()
|
||||
|
||||
tail := make([]byte, NeedleChecksumSize+TimestampSize)
|
||||
util.Uint32toBytes(tail[0:NeedleChecksumSize], legacyChecksum)
|
||||
|
||||
n := &Needle{Data: data}
|
||||
if err := n.readNeedleTail(tail, Version3); err != nil {
|
||||
t.Fatalf("legacy checksum should verify, got %v", err)
|
||||
}
|
||||
if n.Checksum != rawChecksum {
|
||||
t.Fatalf("expected raw checksum stored, got %x want %x", uint32(n.Checksum), uint32(rawChecksum))
|
||||
}
|
||||
}
|
||||
|
||||
func TestReadNeedleTailRawChecksum(t *testing.T) {
|
||||
data := []byte("hello seaweed")
|
||||
rawChecksum := NewCRC(data)
|
||||
|
||||
tail := make([]byte, NeedleChecksumSize+TimestampSize)
|
||||
util.Uint32toBytes(tail[0:NeedleChecksumSize], uint32(rawChecksum))
|
||||
|
||||
n := &Needle{Data: data}
|
||||
if err := n.readNeedleTail(tail, Version3); err != nil {
|
||||
t.Fatalf("raw checksum should verify, got %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestReadNeedleTailCorrupted(t *testing.T) {
|
||||
data := []byte("hello seaweed")
|
||||
|
||||
tail := make([]byte, NeedleChecksumSize+TimestampSize)
|
||||
util.Uint32toBytes(tail[0:NeedleChecksumSize], 0xdeadbeef)
|
||||
|
||||
n := &Needle{Data: data}
|
||||
if err := n.readNeedleTail(tail, Version3); err == nil {
|
||||
t.Fatal("expected CRC mismatch error, got nil")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user