diff --git a/weed/shell/command_volume_tier_download.go b/weed/shell/command_volume_tier_download.go index e614e64665..ea5103ea2c 100644 --- a/weed/shell/command_volume_tier_download.go +++ b/weed/shell/command_volume_tier_download.go @@ -15,6 +15,7 @@ import ( "github.com/seaweedfs/seaweedfs/weed/pb/master_pb" "github.com/seaweedfs/seaweedfs/weed/pb/volume_server_pb" "github.com/seaweedfs/seaweedfs/weed/storage/needle" + "github.com/seaweedfs/seaweedfs/weed/storage/types" ) func init() { @@ -220,7 +221,7 @@ func downloadAndReplicateFromRemoteTier(grpcDialOption grpc.DialOption, writer i func replicateTierDownloadedVolume(grpcDialOption grpc.DialOption, writer io.Writer, vid needle.VolumeId, source pb.ServerAddress, target tierDownloadReplica) error { fmt.Fprintf(writer, "replicate downloaded volume %d from %s to %s\n", vid, source, target.server) - if _, err := copyVolume(context.Background(), grpcDialOption, writer, vid, source, target.server, target.diskType, 0, true); err != nil { + if _, err := copyVolume(context.Background(), grpcDialOption, writer, vid, source, target.server, types.ToDiskType(target.diskType).ReadableString(), 0, true); err != nil { return fmt.Errorf("replicate volume %d from %s to %s: %v", vid, source, target.server, err) } return nil diff --git a/weed/shell/command_volume_tier_download_test.go b/weed/shell/command_volume_tier_download_test.go index 88c42531bf..c08b54fc5b 100644 --- a/weed/shell/command_volume_tier_download_test.go +++ b/weed/shell/command_volume_tier_download_test.go @@ -16,6 +16,7 @@ import ( "github.com/seaweedfs/seaweedfs/weed/pb/master_pb" "github.com/seaweedfs/seaweedfs/weed/pb/volume_server_pb" "github.com/seaweedfs/seaweedfs/weed/storage/needle" + "github.com/seaweedfs/seaweedfs/weed/storage/types" ) const ( @@ -88,8 +89,13 @@ func (s *tierDownloadTestServer) VolumeCopy(req *volume_server_pb.VolumeCopyRequ c := s.cluster c.mu.Lock() defer c.mu.Unlock() - if req.DiskType != c.diskTypes[s.addr] { - return fmt.Errorf("copy volume %d onto disk type %q, replica is on %q", req.VolumeId, req.DiskType, c.diskTypes[s.addr]) + // an empty disk type means the source's, as on the real servers + want, got := types.ToDiskType(c.diskTypes[s.addr]), types.ToDiskType(c.diskTypes[pb.ServerAddress(req.SourceDataNode)]) + if req.DiskType != "" { + got = types.ToDiskType(req.DiskType) + } + if got != want { + return fmt.Errorf("copy volume %d onto disk type %q, replica is on %q", req.VolumeId, got, want) } switch c.replicas[pb.ServerAddress(req.SourceDataNode)] { case tierReplicaLocal: @@ -262,3 +268,12 @@ func TestTierDownloadRerunReusesLocalReplica(t *testing.T) { t.Errorf("want no download when a replica is already local, got %d", c.downloads) } } + +func TestTierDownloadCopiesFromSsdSourceOntoHddReplica(t *testing.T) { + c := newTierDownloadCluster(t, tierReplicaRemote, tierReplicaRemote, tierReplicaRemote) + c.hide(0, c.servers[0]) + if err := c.run(t); err != nil { + t.Fatalf("tier download: %v", err) + } + c.assertAllLocal(t) +}