mirror of
https://github.com/seaweedfs/seaweedfs.git
synced 2026-09-08 15:41:15 +02:00
When a volume is tiered to remote storage or a remote-backed replica is restored locally, the cached DataInRemote on the same volume-server URL stayed at its old value because two pieces of state never updated: * master_grpc_server.go only split newVolumes and (already-tracked) volumes into NewVids vs RemoteVids. ChangedVolumes went straight to NewVids, so the broadcast announced the re-classified volume as a fresh arrival and the client had no way to tell whether its existing cache was stale. * vid_map.addLocationToMap early-returned when an entry already had the same URL. A tier transition reports the same URL with DataInRemote flipped, so the cached entry stayed at the old classification. Wire both sides together: ChangedVolumes now go through the same IsRemote split as newVolumes, and addLocationToMap replaces the existing entry in place when the URL matches but DataInRemote has changed. The server reference key only depends on URL/grpc port, so the refcount does not move across the flip. Adds vid_map_remote_transition_test.go covering the local->remote and remote->local paths so the in-place update and the cache-key stability are pinned by tests.
92 lines
2.9 KiB
Go
92 lines
2.9 KiB
Go
package wdclient
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/seaweedfs/seaweedfs/weed/pb"
|
|
)
|
|
|
|
// When the master reports a tier transition (local ↔ remote) for an existing
|
|
// replica on the same server URL, the cached DataInRemote must update. Otherwise
|
|
// reads keep preferring a remote-backed replica or skip a newly-restored local
|
|
// one. The server refcount must stay stable because the server key only depends
|
|
// on the URL/grpc port.
|
|
func TestAddLocationUpdatesDataInRemoteOnTransition(t *testing.T) {
|
|
vm := newVidMap("", DefaultVidMapCacheSize)
|
|
vid := uint32(11)
|
|
server := Location{Url: "10.0.0.1:8080", DataCenter: "dc1", GrpcPort: 18080}
|
|
|
|
// First seen as local.
|
|
vm.addLocation(vid, server)
|
|
locs, found := vm.GetLocations(vid)
|
|
if !found || len(locs) != 1 || locs[0].DataInRemote {
|
|
t.Fatalf("expected single local replica, got %+v", locs)
|
|
}
|
|
|
|
// Same URL flips to remote.
|
|
tiered := server
|
|
tiered.DataInRemote = true
|
|
vm.addLocation(vid, tiered)
|
|
|
|
locs, found = vm.GetLocations(vid)
|
|
if !found {
|
|
t.Fatalf("tier transition dropped the replica")
|
|
}
|
|
if len(locs) != 1 {
|
|
t.Fatalf("tier transition should replace in place, got %d entries: %+v", len(locs), locs)
|
|
}
|
|
if !locs[0].DataInRemote {
|
|
t.Errorf("DataInRemote did not flip to remote on tier-out: %+v", locs[0])
|
|
}
|
|
if locs[0].Url != server.Url || locs[0].DataCenter != server.DataCenter {
|
|
t.Errorf("replaced entry lost non-DataInRemote fields: %+v", locs[0])
|
|
}
|
|
if !vm.hasVolumeServer(pb.ServerAddress(server.Url)) {
|
|
t.Errorf("server ref should remain stable across DataInRemote flip")
|
|
}
|
|
|
|
// Restored locally: same URL, DataInRemote back to false.
|
|
restored := server
|
|
vm.addLocation(vid, restored)
|
|
|
|
locs, found = vm.GetLocations(vid)
|
|
if !found {
|
|
t.Fatalf("restore transition dropped the replica")
|
|
}
|
|
if len(locs) != 1 {
|
|
t.Fatalf("restore should replace in place, got %d entries: %+v", len(locs), locs)
|
|
}
|
|
if locs[0].DataInRemote {
|
|
t.Errorf("DataInRemote did not flip back to local on restore: %+v", locs[0])
|
|
}
|
|
}
|
|
|
|
// LookupVolumeServerUrl must reflect the latest DataInRemote so the local-first
|
|
// ordering picks up newly-restored local replicas on the next read.
|
|
func TestLookupVolumeServerUrlReflectsRemoteTransition(t *testing.T) {
|
|
vm := newVidMap("dc1", DefaultVidMapCacheSize)
|
|
vid := uint32(12)
|
|
|
|
remote := Location{Url: "10.0.0.1:8080", DataCenter: "dc1", DataInRemote: true}
|
|
vm.addLocation(vid, remote)
|
|
|
|
urls, err := vm.LookupVolumeServerUrl("12")
|
|
if err != nil {
|
|
t.Fatalf("lookup failed: %v", err)
|
|
}
|
|
if len(urls) != 1 || urls[0] != "10.0.0.1:8080" {
|
|
t.Fatalf("expected only the remote replica, got %v", urls)
|
|
}
|
|
|
|
// Tier restored: same URL, DataInRemote=false.
|
|
local := Location{Url: "10.0.0.1:8080", DataCenter: "dc1"}
|
|
vm.addLocation(vid, local)
|
|
|
|
urls, err = vm.LookupVolumeServerUrl("12")
|
|
if err != nil {
|
|
t.Fatalf("lookup after restore failed: %v", err)
|
|
}
|
|
if len(urls) != 1 || urls[0] != "10.0.0.1:8080" {
|
|
t.Fatalf("expected only the restored replica, got %v", urls)
|
|
}
|
|
} |