X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=src%2Fjalview%2Fio%2FBackupFiles.java;h=14c1260bbac561167382e2af1f2f2329ad79a589;hb=5aa8888ce7093703fc7e5ed4cc24d4d7059a8299;hp=defc47b50f5abfd852545c5b1593b37cdc248bb6;hpb=cb8e52fbbc5f725e3f7f48c672cdddb0690bd978;p=jalview.git diff --git a/src/jalview/io/BackupFiles.java b/src/jalview/io/BackupFiles.java index defc47b..14c1260 100644 --- a/src/jalview/io/BackupFiles.java +++ b/src/jalview/io/BackupFiles.java @@ -29,8 +29,14 @@ import java.nio.file.StandardCopyOption; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.TreeMap; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; import jalview.bin.Cache; import jalview.bin.Console; @@ -105,6 +111,117 @@ public class BackupFiles private static final String oldTempFileSuffix = "_oldfile_tobedeleted"; + // thread pool used for completablefutures + private static final ExecutorService executorService = Executors + .newFixedThreadPool(3); + + private static List savesInProgress = new ArrayList<>(); + + private CompletableFuture myFuture = null; + + private boolean addSaveInProgress() + { + if (savesInProgress.contains(this)) + { + return false; + } + else + { + this.setMyFuture(); + savesInProgress.add(this); + return true; + } + } + + private boolean removeSaveInProgress(boolean ret) + { + if (savesInProgress.contains(this)) + { + this.getMyFuture().complete(ret); + // remove all occurrences + while (savesInProgress.remove(this)) + { + } + return true; + } + return false; + } + + private static CompletableFuture getNewFuture() + { + return new CompletableFuture() + { + }; + } + + private CompletableFuture getMyFuture() + { + return this.myFuture; + } + + private void setMyFuture() + { + this.myFuture = getNewFuture(); + } + + public static boolean hasSavesInProgress() + { + boolean has = false; + for (CompletableFuture cf : savesInProgressCompletableFutures(true)) + { + has |= !cf.isDone(); + } + return has; + } + + public static List savesInProgressFiles(boolean all) + { + List files = new ArrayList<>(); + for (BackupFiles bfile : savesInProgress) + { + if (all || !bfile.getMyFuture().isDone()) + files.add(bfile.getFile()); + } + return files; + } + + public static List> savesInProgressCompletableFutures( + boolean all) + { + List> cfs = new ArrayList<>(); + for (BackupFiles bfile : savesInProgress) + { + if (all || !bfile.getMyFuture().isDone()) + cfs.add(bfile.getMyFuture()); + } + return cfs; + } + + public static Future allSaved() + { + CompletableFuture f = new CompletableFuture<>(); + + executorService.submit(() -> { + for (BackupFiles buf : savesInProgress) + { + boolean allSaved = true; + try + { + allSaved &= buf.getMyFuture().get(); + } catch (InterruptedException e) + { + Console.debug("InterruptedException waiting for files to save", + e); + } catch (ExecutionException e) + { + Console.debug("ExecutionException waiting for files to save", e); + } + f.complete(allSaved); + } + }); + return f; + } + public BackupFiles(String filename) { this(new File(filename)); @@ -116,6 +233,10 @@ public class BackupFiles { classInit(); this.file = file; + + // add this file from the save in progress stack + addSaveInProgress(); + BackupFilesPresetEntry bfpe = BackupFilesPresetEntry .getSavedBackupEntry(); this.suffix = bfpe.suffix; @@ -132,6 +253,7 @@ public class BackupFiles { String tempfilename = file.getName(); File tempdir = file.getParentFile(); + tempdir.mkdirs(); Console.trace( "BACKUPFILES [file!=null] attempting to create temp file for " + tempfilename + " in dir " + tempdir); @@ -381,8 +503,8 @@ public class BackupFiles boolean delete = confirmNewerDeleteFile(fileToBeDeleted, replacementFile, true); - Console.trace("BACKUPFILES " + (delete ? "confirmed" : "not") - + " deleting file " + Console.trace("BACKUPFILES " + + (delete ? "confirmed" : "not") + " deleting file " + fileToBeDeleted.getAbsolutePath() + " which is newer than " + replacementFile.getAbsolutePath()); @@ -484,7 +606,8 @@ public class BackupFiles File fileToBeDeleted = backupFiles[i]; boolean delete = true; - Console.trace("BACKUPFILES fileToBeDeleted: " + fileToBeDeleted); + Console.trace( + "BACKUPFILES fileToBeDeleted: " + fileToBeDeleted); boolean newer = false; if (replacementFile != null) @@ -551,8 +674,9 @@ public class BackupFiles // using boolean '&' instead of '&&' as don't want moveFileToFile attempt to // be conditional (short-circuit) ret = ret & moveFileToFile(file, new File(latestBackupFilename)); - Console.debug("BACKUPFILES moving " + file + " to " + latestBackupFilename - + " was " + (ret ? "" : "NOT ") + "successful"); + Console.debug( + "BACKUPFILES moving " + file + " to " + latestBackupFilename + + " was " + (ret ? "" : "NOT ") + "successful"); if (tidyUp) { Console.debug("BACKUPFILES tidying up files"); @@ -817,6 +941,9 @@ public class BackupFiles tidyUpFiles(); } + // remove this file from the save in progress stack + removeSaveInProgress(rename); + return rename; } @@ -888,6 +1015,11 @@ public class BackupFiles return ret; } + public File getFile() + { + return file; + } + public static boolean moveFileToFile(File oldFile, File newFile) { Console.initLogger(); @@ -899,8 +1031,8 @@ public class BackupFiles // delete destination file - not usually necessary but Just In Case... Console.trace("BACKUPFILES deleting " + newFile.getAbsolutePath()); newFile.delete(); - Console.trace("BACKUPFILES moving " + oldFile.getAbsolutePath() + " to " - + newFile.getAbsolutePath()); + Console.trace("BACKUPFILES moving " + oldFile.getAbsolutePath() + + " to " + newFile.getAbsolutePath()); Files.move(oldPath, newPath, StandardCopyOption.REPLACE_EXISTING); ret = true; Console.trace("BACKUPFILES move seems to have succeeded");