filer.remote.sync: do not pin the sync offset on completed work (#11569)

* filer.remote.sync: do not pin the sync offset on completed work

* filer.remote.sync: a superseded rename uploads the current entry; typed NotFound for a stamp on a deleted entry

* filer.remote.sync: a superseded rename keeps the old key when it is the only copy and uploads once

* filer.remote.sync: a rename whose content is now remote-only fails the event instead of completing it

* filer.remote.sync: a remote-only rename copies the old object to the destination before deleting it

* filer.remote.sync: the remote-only rename path follows the filer's current entry and verifies the destination object

* filer.remote.sync: an event that described an entry without data is superseded once the filer wrote to it

* filer.remote.sync: a superseded rename does only the work left to do

uploadCurrentEntry met a remote-only current entry with a fixed error, but a
sync plus remote.uncache in the meantime leaves the destination holding the
stamped object; that state is complete, not lost. The remote-only case now
finishes through completeRemoteOnlyRename, which verifies the destination
against the entry stamp and fails only when neither key holds the content.

A current entry whose stamp covers its content was already uploaded by the
superseding event; skip it instead of writing the same bytes again.

* filer.remote.sync: an inherited stamp does not prove the content synced

The stamp-coverage skip in uploadCurrentEntry read LastLocalSyncTsNs as
proof the current content was uploaded, but a rename carries the source
entry's stamp to the destination: a rewrite hidden by that stamp (the case
the fallback upload exists for) carries a LastLocalSyncTsNs at or after its
mtime and would have been skipped. Drop the check; the remote-only path
verifies content at the destination itself through describes.

---------

Co-authored-by: James Sas <james@medable.com>
Co-authored-by: Chris Lu <chris.lu@gmail.com>
This commit is contained in:
authored and GitHub committed 2026-10-03 12:34:52 +08:00
1 parent 793ce06b10
commit 68df7511f6
5 files changed
+653 -41

No files matched your search

+3
View File
@@ -39,6 +39,9 @@ var transientErrorMessages = []string{
"requesttimeout",
"slowdown",
"throttling",
"ratelimitexceeded",
"rate limit",
"too many requests",
"internalerror",
"resourceexhausted",
"unavailable",
+4
View File
@@ -83,6 +83,10 @@ func TestIsTransientErrorMessage(t *testing.T) {
"Connection reset by peer",
"dial tcp 10.0.0.1:8888: connect: no route to host",
"rpc error: code = Unavailable desc = the connection is unavailable",
// GCS per-object mutation limit on a hot file; the next attempt after a
// one-second backoff is under it
"googleapi: Error 429: The object bucket/samples.json exceeded the rate limit for object mutation operations (create, update, and delete). Please reduce your request rate. See https://cloud.google.com/storage/docs/gcs429., rateLimitExceeded",
"429 Too Many Requests",
}
for _, msg := range transient {
if !IsTransientErrorMessage(msg) {