diff --git a/weed/server/master_grpc_server_volume.go b/weed/server/master_grpc_server_volume.go index 079bac676..48d03e9f1 100644 --- a/weed/server/master_grpc_server_volume.go +++ b/weed/server/master_grpc_server_volume.go @@ -236,32 +236,40 @@ func (ms *MasterServer) LookupEcVolume(ctx context.Context, req *master_pb.Looku } resp := &master_pb.LookupEcVolumeResponse{} + volumeId := needle.VolumeId(req.VolumeId) - // Determine which generation to lookup - targetGeneration := req.Generation - if targetGeneration == 0 { - // If no specific generation requested, use the active generation - if activeGen, found := ms.Topo.GetEcActiveGeneration(needle.VolumeId(req.VolumeId)); found { - targetGeneration = activeGen - } - // If no active generation found, fall back to 0 for backward compatibility - } - - ecLocations, found := ms.Topo.LookupEcShards(needle.VolumeId(req.VolumeId), targetGeneration) + // Use the new helper function for intelligent lookup with fallback + ecLocations, actualGeneration, found := ms.Topo.LookupEcShardsWithFallback(volumeId, req.Generation) if !found { - return resp, fmt.Errorf("ec volume %d not found", req.VolumeId) + if req.Generation != 0 { + return resp, fmt.Errorf("ec volume %d generation %d not found", req.VolumeId, req.Generation) + } else { + return resp, fmt.Errorf("ec volume %d not found", req.VolumeId) + } } + glog.V(4).Infof("LookupEcVolume: Found volume %d generation %d (requested: %d)", req.VolumeId, actualGeneration, req.Generation) + + // Set response fields resp.VolumeId = req.VolumeId - // Set the active generation from the master's tracking - if activeGen, found := ms.Topo.GetEcActiveGeneration(needle.VolumeId(req.VolumeId)); found { + + // Always report the actual active generation, regardless of what was looked up + if activeGen, found := ms.Topo.GetEcActiveGeneration(volumeId); found { resp.ActiveGeneration = activeGen } else { - resp.ActiveGeneration = ecLocations.Generation // fallback to the generation we found + // If no active generation tracked, use the generation we found + resp.ActiveGeneration = ecLocations.Generation + glog.V(2).Infof("LookupEcVolume: No active generation tracked for volume %d, using found generation %d", req.VolumeId, ecLocations.Generation) } + // Build shard location response for shardId, shardLocations := range ecLocations.Locations { + // Skip empty shard locations + if len(shardLocations) == 0 { + continue + } + var locations []*master_pb.Location for _, dn := range shardLocations { locations = append(locations, &master_pb.Location{ @@ -273,10 +281,13 @@ func (ms *MasterServer) LookupEcVolume(ctx context.Context, req *master_pb.Looku resp.ShardIdLocations = append(resp.ShardIdLocations, &master_pb.LookupEcVolumeResponse_EcShardIdLocation{ ShardId: uint32(shardId), Locations: locations, - Generation: ecLocations.Generation, // set generation for each shard location + Generation: ecLocations.Generation, // generation of the actual shards returned }) } + glog.V(4).Infof("LookupEcVolume: Found %d shard locations for volume %d generation %d (active: %d)", + len(resp.ShardIdLocations), req.VolumeId, ecLocations.Generation, resp.ActiveGeneration) + return resp, nil } diff --git a/weed/topology/topology_ec.go b/weed/topology/topology_ec.go index faca9a5b4..0cab86395 100644 --- a/weed/topology/topology_ec.go +++ b/weed/topology/topology_ec.go @@ -305,3 +305,36 @@ func (t *Topology) ListEcVolumesWithActiveGeneration() map[needle.VolumeId]uint3 } return result } + +// LookupEcShardsWithFallback looks up EC shards for a volume with intelligent fallback +// If no specific generation is requested (generation == 0), it uses the active generation +// If the requested/active generation is not found, it falls back to generation 0 +func (t *Topology) LookupEcShardsWithFallback(vid needle.VolumeId, requestedGeneration uint32) (locations *EcShardLocations, actualGeneration uint32, found bool) { + // Determine target generation + targetGeneration := requestedGeneration + if requestedGeneration == 0 { + // Use active generation if available + if activeGen, exists := t.GetEcActiveGeneration(vid); exists { + targetGeneration = activeGen + } + } + + // Try the target generation first + if locations, found = t.LookupEcShards(vid, targetGeneration); found { + return locations, targetGeneration, true + } + + // If requested specific generation and not found, don't fallback + if requestedGeneration != 0 { + return nil, 0, false + } + + // Fallback to generation 0 if target generation wasn't found + if targetGeneration != 0 { + if locations, found = t.LookupEcShards(vid, 0); found { + return locations, 0, true + } + } + + return nil, 0, false +}