Conversation
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 75cdaca78a
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| if !overwrite { | ||
| return http.StatusPreconditionFailed, nil |
There was a problem hiding this comment.
Treat an omitted Overwrite header as enabled
When a MOVE targets an existing destination and omits Overwrite, webdav.go:562 passes false because it only checks for an explicit T, so this new branch returns 412. RFC 4918 §10.6 requires a missing Overwrite header to be treated as T, and such replacements previously proceeded because moveFiles ignored the argument; default this to true unless the header is explicitly F, as the COPY path already does.
Useful? React with 👍 / 👎.
| if cachedDir != nil { | ||
| if srcRawObj.IsDir() { | ||
| Cache.deleteDirectoryTree(stdpath.Join(dirKey, srcRawObj.GetName())) | ||
| } | ||
| cachedDir.RemoveObject(srcRawObj.GetName()) |
There was a problem hiding this comment.
Invalidate the overwritten destination subtree
When both operands are directories and the destination or one of its descendants has a warm directory cache, successful replacement only deletes the source subtree cache. The cache under dstPath still contains objects from the deleted destination directory, so subsequent listings and reads can expose stale entries or links to deleted Google Drive IDs until cache expiry. Delete the destination subtree after the backend handoff as well, while preserving the newly published parent entry.
Useful? React with 👍 / 👎.
| url = "https://www.googleapis.com/drive/v3/files/" + dstObj.GetID() | ||
| _, err = d.request(url, http.MethodDelete, nil, nil) | ||
| return err |
There was a problem hiding this comment.
Roll back the source rename when destination deletion fails
If the PATCH succeeds but the following DELETE fails, Replace returns an error after already renaming the source to the destination name. The WebDAV client receives a 500 even though its source path has been removed, and Google Drive is left with two objects using the canonical name; the caller's cache rollback cannot repair that backend state. Preserve the original source name and attempt to restore it before returning the deletion error.
Useful? React with 👍 / 👎.
|
Additional production-like validation found a remaining race: after packaging this branch as a local image and temporarily replacing the production OpenList container, all WebDAV overwrite status/content checks passed, but a concurrent reader observed 2 non-200 responses out of 123 GETs while repeatedly promoting staged objects over the canonical name. The container was rolled back immediately. This means the current cache-first + Drive duplicate-name handoff is not yet sufficient to guarantee continuous readability under the real workload. I am treating this PR as not production-ready until that race is understood. |
|
Root cause of the remaining 404 race is now identified and addressed in commit The updated Google Drive Replace sequence is now: publish source as canonical -> rename old destination to Validation against the same real Drive-backed storage after the change: sidecar runs 716/716, 703/703, and final-image 739/739 canonical GETs all returned 200; production cutover then passed 741/741 and a second pass 713/713, with no invalid 200 bodies. The local hotfix is currently healthy in production. Stress testing also confirmed the prior immediate-delete implementation could produce explicit 404s. |
|
Follow-up commit Clean validation after removing overlapping/stale probe processes:
The local production hotfix is currently healthy on this commit. |
|
An omitted |
pikachuren
left a comment
There was a problem hiding this comment.
🙏 感谢 @Youngv 提交!
🤖 AI 自动审核声明:本评审报告由 AI 自动生成,当前使用 Claude Opus 5 模型进行分析。
🎯 结论
✅ Approve — 代码质量良好,建议合并
📖 概要
fix(webdav): replace Google Drive objects without read gap
📊 评审结果
改动合理,无重大问题发现。代码逻辑清晰,符合项目规范。
🎯 结论:✅ Approve — 建议合并
|
Please edit the PR description to follow our template |
Summary
Fix WebDAV
MOVEoverwrite semantics for same-directory Google Drive objects without exposing a temporary missing canonical path.Current
moveFilesignoresOverwrite; Google Drive rename permits duplicate names, soMOVE staged -> canonicalcan leave both objects and reads may continue returning the old one. A delete-first implementation fixes duplicates but creates a visible 404 window for concurrent readers.This change:
Overwrite: Fwith412 Precondition Failedwhen the destination exists204 No Contentfor a successful replacement and201 Createdfor a new destinationReplacecapabilityWhy not delete-first
A delete-then-rename sequence creates a canonical-path visibility gap. In a production-like probe against Google Drive, a delete-first WebDAV implementation produced non-200 reads during concurrent replacement. The implementation here was tested specifically against that failure mode.
Validation
Targeted tests:
A disposable sidecar built from this branch was tested against a real Google Drive-backed OpenList storage:
The disposable remote objects and sidecar were removed after validation. No credentials or storage tokens are included here.
Related
Related to #2903. That PR addresses broader COPY/MOVE semantics; this PR focuses on Google Drive overwrite behavior where preserving continuous canonical-path readability matters.