fix: correctly detect missing source file during volume copy (#7784)

* fix: correctly detect missing source file during volume copy

The previous fix (commit 5c27522) incorrectly used progressedBytes == 0 to
detect if the source file didn't exist. This was wrong because it would also
delete files when the source file exists but is empty.

This fix:
1. Server side: Send ModifiedTsNs even for empty files, so the client knows
   the source file exists
2. Client side: Check modifiedTsNs == 0 instead of progressedBytes == 0 to
   determine if source file didn't exist

Now the logic correctly handles:
- Source file doesn't exist → No ModifiedTsNs sent → Remove empty file
- Source file exists but is empty → ModifiedTsNs sent → Keep empty file
- Source file exists with content → ModifiedTsNs sent → Keep file with content

Fixes #7777

* Update weed/server/volume_grpc_copy.go

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>

---------

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
This commit is contained in:
Chris Lu
2025-12-15 22:38:28 -08:00
committed by GitHub
parent 7920ffa98c
commit ef28f49ec3

View File

@@ -295,9 +295,11 @@ func writeToFile(client volume_server_pb.VolumeServer_CopyFileClient, fileName s
}
wt.MaybeSlowdown(int64(len(resp.FileContent)))
}
// If no data was written (source file was not found), remove the empty file
// to avoid leaving corrupted empty files that cause parse errors later
if progressedBytes == 0 && !isAppend {
// If we never received a modifiedTsNs, it means the source file did not exist.
// Remove the empty file we created to avoid leaving corrupted empty files.
// Note: We check modifiedTsNs (not progressedBytes) because an empty source file
// is valid and should result in an empty destination file.
if modifiedTsNs == 0 && !isAppend {
if removeErr := os.Remove(fileName); removeErr != nil {
glog.V(1).Infof("failed to remove empty file %s: %v", fileName, removeErr)
} else {
@@ -426,6 +428,19 @@ func (vs *VolumeServer) CopyFile(req *volume_server_pb.CopyFileRequest, stream v
}
// If no data has been sent in the loop (e.g. for an empty file, or when stopOffset is 0),
// we still need to send the ModifiedTsNs so the client knows the source file exists.
// fileModTsNs is set to 0 after the first send, so if it's still non-zero,
// we haven't sent anything yet.
if fileModTsNs != 0 {
err = stream.Send(&volume_server_pb.CopyFileResponse{
ModifiedTsNs: fileModTsNs,
})
if err != nil {
return err
}
}
return nil
}