From 29eae7232826bbd609cb48b7d59aed2541ac7721 Mon Sep 17 00:00:00 2001 From: Chris Lu Date: Thu, 12 Nov 2026 21:54:45 -0800 Subject: [PATCH] topology: treat a nil ttl as the empty ttl when looking for duplicate volume ids Volume layouts are keyed by ttl.String(), so a nil ttl and the empty ttl share one layout. ttlEqual told them apart, so a replica reported with a nil ttl into a layout created with the empty ttl matched its own layout as a duplicate, and every copy was quarantined. Co-Authored-By: Claude Opus 5.5 --- weed/topology/duplicate_volume_id_test.go | 24 +++++++++++++++++++++++ weed/topology/topology.go | 5 +---- 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/weed/topology/duplicate_volume_id_test.go b/weed/topology/duplicate_volume_id_test.go index 5fb315ea88..201583410b 100644 --- a/weed/topology/duplicate_volume_id_test.go +++ b/weed/topology/duplicate_volume_id_test.go @@ -73,6 +73,30 @@ func TestSameLayoutReplicaIsNotDuplicate(t *testing.T) { } } +func TestSameLayoutReplicaWithoutTtlIsNotDuplicate(t *testing.T) { + topo := NewTopology("topo", nil, 128, 3, false) + rp, _ := super_block.NewReplicaPlacementFromString("001") + + dn1 := NewDataNode("server1") + dn1.Ip = "10.0.0.1" + dn1.Port = 8080 + dn2 := NewDataNode("server2") + dn2.Ip = "10.0.0.2" + dn2.Port = 8080 + + v1 := storage.VolumeInfo{Id: 7, Collection: "a", ReplicaPlacement: rp, Ttl: needle.EMPTY_TTL} + v2 := storage.VolumeInfo{Id: 7, Collection: "a", ReplicaPlacement: rp} + dn1.UpdateVolumes([]storage.VolumeInfo{v1}) + dn2.UpdateVolumes([]storage.VolumeInfo{v2}) + topo.RegisterVolumeLayout(v1, dn1) + topo.RegisterVolumeLayout(v2, dn2) + topo.duplicateFlagChecks.Wait() + + if topo.isQuarantined(dn1, v1.Id) || topo.isQuarantined(dn2, v2.Id) { + t.Fatal("a nil ttl and the empty ttl share one layout, so the replica is not a duplicate") + } +} + func TestSameNodeVolumeMoveIsNotDuplicate(t *testing.T) { topo := NewTopology("topo", nil, 128, 3, false) rp, _ := super_block.NewReplicaPlacementFromString("000") diff --git a/weed/topology/topology.go b/weed/topology/topology.go index 81db2ff59a..47efeac322 100644 --- a/weed/topology/topology.go +++ b/weed/topology/topology.go @@ -1084,10 +1084,7 @@ func volumeLayoutKey(collection string, rp *super_block.ReplicaPlacement, ttl *n } func ttlEqual(a, b *needle.TTL) bool { - if a == nil || b == nil { - return a == b - } - return a.ToUint32() == b.ToUint32() + return a.String() == b.String() } // findDuplicateVolumeLayouts reports every layout that already holds v.Id on