shell: name the hdd disk type when copying a downloaded volume

VolumeCopy treats an empty disk type as the source's, so an HDD replica
copied from an SSD source was placed on SSD or failed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Chris LuandClaude Opus 5.5 committed 2026-11-12 18:46:42 -08:00
1 parent 8b021ac0d6
commit d9786c240c
2 files changed
+19 -3

No files matched your search

+2 -1
View File
@@ -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
@@ -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)
}