diff --git a/weed/storage/needle/needle_read_tail.go b/weed/storage/needle/needle_read_tail.go index dfaab1706..156dbbf65 100644 --- a/weed/storage/needle/needle_read_tail.go +++ b/weed/storage/needle/needle_read_tail.go @@ -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) } diff --git a/weed/storage/needle/needle_read_tail_test.go b/weed/storage/needle/needle_read_tail_test.go new file mode 100644 index 000000000..b5817a511 --- /dev/null +++ b/weed/storage/needle/needle_read_tail_test.go @@ -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") + } +}