-
Notifications
You must be signed in to change notification settings - Fork 2.8k
[ZEPPELIN-5718] Notebook lost due to non-atomic file operations. #5511
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
JangAyeon
wants to merge
5
commits into
apache:master
Choose a base branch
from
JangAyeon:ZEPPELIN-5718
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
005d460
[ZEPPELIN-5718] Keep the original note file and recover interrupted s…
JangAyeon 30fa444
[ZEPPELIN-5718] Replace local note files atomically in VFSNotebookRepo
JangAyeon 896f9ae
ZEPPELIN-5718] Add tests for interrupted saves and recovery
JangAyeon 4223cf4
[ZEPPELIN-5718] Do not restore notes from a single leftover file
JangAyeon c33bdd5
[ZEPPELIN-5718] Update recoverInterruptedSaves Javadoc to match curre…
JangAyeon File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Keeping the original until the new file is in place looks like the right direction to me. I ran into one case, though, where this check treats a note that was already deleted or moved as an interrupted save and brings it back.
What happens
recoverInterruptedWritesrestores a.zplnwhenever it is missing and a complete.zpln.tmpexists. ButFileSystemNotebookRepo.remove()andmove()only delete/rename the.zplnitself, so a.tmp(or.bak) left next to it stays behind. On the next restart, that leftover is treated as an interrupted save:.zplnwith the same noteId appears at the old path;list()keys by noteId, so only one of the two is listedA complete
.tmpcan be left next to an existing.zplnin two ways with this PR:.tmpis fully written but beforefileis renamed to.bak.rename(tmpFile, file)fails:replaceFilerestores the original from.bakand throws, but does not delete.tmp. This one does not need a crash.I checked (2) end to end by making
rename(*.zpln.tmp → *.zpln)fail once: the save throws, the original.zplnand a complete.tmpremain, and afterremove()+ restart the note comes back, with the content of the save that had failed.Repro
These two tests fail on the PR branch when added to
FileSystemNotebookRepoTest:Possible fixes (just ideas, happy to go with whatever you prefer)
remove()/move(), also delete (or move along) the sibling.tmp/.bak.replaceFile, deletetmpFilewhen the final rename fails and the original has been restored..bakand.tmpexist without the.zpln, which is exactly the state this PR'swriteFileleaves when it is interrupted between the two renames. For the.tmp-only case (notes lost by earlier versions), a complete.tmpcan't be told apart from a leftover of a deleted note, so logging it or moving it aside for manual recovery might be safer than restoring it automatically.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the careful review and the repro tests, that was a real gap.
I went with options 2 and 3 in comment:
replaceFilenow deletes.tmpwhen the final rename fails and the original has been restored..bakand.tmpexist without the.zpln, which is the statewriteFileleaves when it stops between its two renames. A single leftover.tmpor.bakis logged instead of restored.I also added your two tests, and they pass now. As you pointed out, this means notes lost by earlier versions (only
.tmpleft) are no longer restored automatically, so I updated the PR description accordingly.I didn't change
remove()/move()for option 1, to keep this PR focused on the save path. Happy to add it here or in a follow-up if you think it's needed.