Skip to content
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

More conservative write #8750

Closed
wants to merge 33 commits into from
Closed

More conservative write #8750

wants to merge 33 commits into from

Conversation

koppor
Copy link
Member

@koppor koppor commented May 2, 2022

Refs #8746

This introduces a feature of our AtomicFileWriter to not "commit" changes if an error happened during write.

I currently don't know how to test. Maybe simulating a small virtual hard disk not having enough space for writing?


should fix:


open things:


does not fix:


  • Change in CHANGELOG.md described in a way that is understandable for the average user (if applicable)
  • Tests created for changes (if applicable)
  • Manually tested changed features in running JabRef (always required)
  • Screenshots added in PR description (for UI changes)
  • Checked developer's documentation: Is the information available and up to date? If not, I outlined it in this pull request.
  • Checked documentation: Is the information available and up to date? If not, I created an issue at https://github.com/JabRef/user-documentation/issues or, even better, I submitted a pull request to the documentation repository.

@Siedlerchr
Copy link
Member

Still does not fix one of the root issues that there is no Filelock and that this method can be executed in parallel

@koppor
Copy link
Member Author

koppor commented May 2, 2022

(outdated)

Sure, this DOES NOT fix following issues: #6694, #8484, #6102, #4877, #8746. All of them are (currently) part of our next milestone v5.7: https://github.com/JabRef/jabref/milestone/26

This thing was one quick thought to implement following contract:

* underlying output stream. In this way, we make sure that the errors during the write process do not destroy the

Copy link
Member

@tobiasdiez tobiasdiez left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would suggest to take some inspiration by established libraries like https://github.com/npm/write-file-atomic or https://github.com/typicode/steno that implement similar secure writes, if you haven't done so. In particular, adding the pid and threadid, and invocation counter to the temporary file name looks like a good idea. Also having a thread lock-by-file is a good design choice in my opinion.

cleanup();
}
}

private void replaceOriginalFileByWrittenFile() throws IOException {
// Move temporary file (replace original if it exists)
// We implement the move as write into the original and delete the temporary one to keep file permissions etc.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then hard-exiting JabRef during a write operation may leave the file corrupt and kind of defeats the purpose of the atomic writer.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note to self: I'll create an ADR. - The intended implementation fixes #8887.

@koppor
Copy link
Member Author

koppor commented May 16, 2022

Refs #6688, because users don't want that directory to be cluttered.

@Siedlerchr
Copy link
Member

Another more general thing I just came across as I looked into this saving issues again:

  1. We call the AtomicOutputStream with a NIO-File-Channel based Stream (ChannelOutputstream) which wil fail the instanceof check and never create a File Lock => We would need to call the constructor with
    super(new FileOutputStream(getPathOfTemporaryFile(path).toAbsolutePath().toString()));
  2. Second problem: Each saving creates a new SaveDatabaseAction object which itself creates a new Writer and Outputstream.
  3. The fileLock variable is an object var. To have any effect it would ne need to be static
  4. Saving and writing happens on the javafx thread...

# Conflicts:
#	build.gradle
#	src/main/java/org/jabref/logic/exporter/AtomicFileOutputStream.java
koppor and others added 5 commits August 13, 2022 21:04
# Conflicts:
#	src/main/java/org/jabref/gui/exporter/SaveDatabaseAction.java
Additionally

- FileUtil vs. FileHelper comments

Co-authored-by: Christoph <siedlerkiller@gmail.com>
Co-authored-by: Carl Christian Snethlage <50491877+calixtus@users.noreply.github.com>
Co-authored-by: Christoph <siedlerkiller@gmail.com>
Co-authored-by: Carl Christian Snethlage <50491877+calixtus@users.noreply.github.com>
Co-authored-by: Christoph <siedlerkiller@gmail.com>
Co-authored-by: Carl Christian Snethlage <50491877+calixtus@users.noreply.github.com>
Co-authored-by: Carl Christian Snethlage <50491877+calixtus@users.noreply.github.com>
@ThiloteE ThiloteE added this to the v5.8 milestone Aug 13, 2022
@calixtus calixtus mentioned this pull request Aug 14, 2022
6 tasks
@tobiasdiez
Copy link
Member

I did a bit of research how other (code) editors are handling this and was a bit surprised that vscode for example uses a simple write (not an atomic write). However, there are quite a few issues in the vscode repo about lost or corrupt files, see microsoft/vscode#98063 and linked issues. Other data points: visual studio uses atomic writer, sublime text has an option to toggle between them.

While going through vscode's code, I found a few really nice implementations of things that JabRef is struggling with. They might be handy to be used as reference. In general, the vscode is very readable and well-structured; so worth looking at.

# Conflicts:
#	src/main/java/org/jabref/logic/autosaveandbackup/BackupManager.java
#	src/main/java/org/jabref/logic/exporter/AtomicFileOutputStream.java
#	src/main/java/org/jabref/logic/util/BackupFileType.java
#	src/main/java/org/jabref/logic/util/io/FileUtil.java
#	src/test/java/org/jabref/logic/autosaveandbackup/BackupManagerTest.java

import org.jabref.logic.util.BackupFileType;
import org.jabref.logic.util.io.BackupFileUtil;
import org.jabref.logic.util.io.FileUtil;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [reviewdog] <com.puppycrawl.tools.checkstyle.checks.imports.UnusedImportsCheck> reported by reviewdog 🐶
Unused import - org.jabref.logic.util.io.FileUtil.

@koppor koppor modified the milestones: v5.8, v6.0 Aug 16, 2022
@koppor
Copy link
Member Author

koppor commented Dec 16, 2022

We fixed the AtomicFileOutputStream in summer. The discussions at #8750 (comment) show that we should re-iterate on the idea again. - Especially #7718 should be regarded.

We close this PR and need to go back. The ADR https://github.com/JabRef/jabref/pull/8750/files#diff-123ad108d1738a32004ec352c9156e0088de245e0cb840687b658725c40bbf96 can still from a good basis for capturing the implementation decisions.

@koppor koppor closed this Dec 16, 2022
@koppor koppor deleted the more-conservative-save branch December 18, 2022 19:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants