Skip to content

Commit

Permalink
Ensure that the project files are only overwritten, when the saving p…
Browse files Browse the repository at this point in the history
…rocess was successful and not interrupted

* Strategy to achieve this:
 * When saving the mastodon project files, they are first saved to projectfile_pending
 * When saving was successful, projectfile gets overwritten with projectfile_pending
 * In the past, it has been observed that *.mastodon files were corrupted and could not be read anymore
 * Typical saving times for a project range from ~0.2s to ~2s (depending on project size, attributes, etc.). Not very long, but long enough to kill mastodon during the saving process.
  • Loading branch information
stefanhahmann committed Jun 10, 2024
1 parent 19ea45d commit 2f2a061
Showing 1 changed file with 45 additions and 8 deletions.
53 changes: 45 additions & 8 deletions src/main/java/org/mastodon/mamut/io/project/MamutProject.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
*/
package org.mastodon.mamut.io.project;

import org.apache.commons.lang3.tuple.Pair;

import java.io.Closeable;
import java.io.File;
import java.io.FileInputStream;
Expand All @@ -36,6 +38,9 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
Expand Down Expand Up @@ -334,22 +339,31 @@ public void close() throws IOException
private class WriteToDirectory implements ProjectWriter
{

private final List< Pair< File, File > > files;

private WriteToDirectory()
{
files = new ArrayList<>();
}

@Override
public OutputStream getProjectXmlOutputStream() throws FileNotFoundException
{
return new FileOutputStream( new File( projectRoot, PROJECT_FILE_NAME ) );
return new FileOutputStream( getPendingFile( PROJECT_FILE_NAME ) );
}

@Override
public OutputStream getRawModelOutputStream() throws FileNotFoundException
{
return new FileOutputStream( new File( projectRoot, RAW_MODEL_FILE_NAME ) );

return new FileOutputStream( getPendingFile( RAW_MODEL_FILE_NAME ) );
}

@Override
public OutputStream getRawTagsOutputStream() throws FileNotFoundException
{
return new FileOutputStream( new File( projectRoot, RAW_TAGS_FILE_NAME ) );

return new FileOutputStream( getPendingFile( RAW_TAGS_FILE_NAME ) );
}

@Override
Expand All @@ -358,33 +372,55 @@ public OutputStream getFeatureOutputStream( final String featureKey ) throws IOE
final File featureFolder = new File( projectRoot, FEATURE_FOLDER_NAME );
if ( !featureFolder.exists() )
featureFolder.mkdir();
return new FileOutputStream( new File( featureFolder, featureKey + ".raw" ) );
return new FileOutputStream( getPendingFile( featureFolder, featureKey + ".raw" ) );
}

@Override
public OutputStream getGuiOutputStream() throws IOException
{
return new FileOutputStream( new File( projectRoot, GUI_FILE_NAME ) );
return new FileOutputStream( getPendingFile( GUI_FILE_NAME ) );
}

@Override
public OutputStream getBackupDatasetXmlOutputStream() throws IOException
{
return new FileOutputStream( new File( projectRoot, BACKUP_DATASET_XML_FILE_NAME ) );
return new FileOutputStream( getPendingFile( BACKUP_DATASET_XML_FILE_NAME ) );
}

@Override
public void close() throws IOException
{}
{
for ( final Pair< File, File > pair : files )
Files.move( pair.getLeft().toPath(), pair.getRight().toPath(), StandardCopyOption.REPLACE_EXISTING );
}

private File getPendingFile( final File parent, final String fileName )
{
String suffix = "_pending";
File pendingFile = new File( parent, fileName + suffix );
File targetFile = new File( parent, fileName );
files.add( Pair.of( pendingFile, targetFile ) );
return pendingFile;
}

private File getPendingFile( final String fileName )
{
return getPendingFile( projectRoot, fileName );
}

}

private class WriteToZip implements ProjectWriter
{
private final WriteZip zip;

private final File pendingFile;

WriteToZip() throws IOException
{
zip = new WriteZip( projectRoot );
String suffix = "_pending";
pendingFile = new File( projectRoot.getParent(), projectRoot.getName() + suffix );
zip = new WriteZip( pendingFile );
}

@Override
Expand Down Expand Up @@ -427,6 +463,7 @@ public OutputStream getBackupDatasetXmlOutputStream() throws IOException
public void close() throws IOException
{
zip.close();
Files.move( pendingFile.toPath(), projectRoot.toPath(), StandardCopyOption.REPLACE_EXISTING );
}
}
}

0 comments on commit 2f2a061

Please sign in to comment.