diff --git a/CHANGELOG.md b/CHANGELOG.md index cb60b9aa838..1a75af1b603 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,7 @@ We refer to [GitHub issues](https://github.com/JabRef/jabref/issues) by using `# - We added support to switch between biblatex and bibtex library types. [#5550](https://github.com/JabRef/jabref/issues/5550) - We changed the save action buttons to be easier to understand. [#5565](https://github.com/JabRef/jabref/issues/5565) - We made the columns for groups, files and uri in the main table reorderable and merged the clickable icon columns for uri, url, doi and eprint. [#5544](https://github.com/JabRef/jabref/pull/5544) +- We reduced the number of write actions performed when autosave is enabled [#5679](https://github.com/JabRef/jabref/issues/5679) ### Fixed diff --git a/src/main/java/org/jabref/logic/autosaveandbackup/AutosaveManager.java b/src/main/java/org/jabref/logic/autosaveandbackup/AutosaveManager.java index 95a651c7aa6..10e941fac15 100644 --- a/src/main/java/org/jabref/logic/autosaveandbackup/AutosaveManager.java +++ b/src/main/java/org/jabref/logic/autosaveandbackup/AutosaveManager.java @@ -2,11 +2,9 @@ import java.util.HashSet; import java.util.Set; -import java.util.concurrent.ArrayBlockingQueue; -import java.util.concurrent.BlockingQueue; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.RejectedExecutionException; -import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.Future; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.TimeUnit; import org.jabref.model.database.BibDatabaseContext; @@ -21,24 +19,27 @@ /** * Saves the given {@link BibDatabaseContext} on every {@link BibDatabaseContextChangedEvent} by posting a new {@link AutosaveEvent}. - * An intelligent {@link ExecutorService} with a {@link BlockingQueue} prevents a high load while saving and rejects all redundant save tasks. + * An intelligent {@link ScheduledThreadPoolExecutor} prevents a high load while saving and rejects all redundant save tasks. + * The scheduled action is stored and canceled if a newer save action is proposed. */ public class AutosaveManager { private static final Logger LOGGER = LoggerFactory.getLogger(AutosaveManager.class); + private static final int AUTO_SAVE_DELAY = 200; private static Set runningInstances = new HashSet<>(); private final BibDatabaseContext bibDatabaseContext; - private final BlockingQueue workerQueue; - private final ExecutorService executor; + private final ScheduledExecutorService executor; private final EventBus eventBus; private final CoarseChangeFilter changeFilter; + private Future scheduledSaveAction; private AutosaveManager(BibDatabaseContext bibDatabaseContext) { this.bibDatabaseContext = bibDatabaseContext; - this.workerQueue = new ArrayBlockingQueue<>(1); - this.executor = new ThreadPoolExecutor(1, 1, 0, TimeUnit.SECONDS, workerQueue); + ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(1); + executor.setRemoveOnCancelPolicy(true); // This prevents memory leaks + this.executor = executor; this.eventBus = new EventBus(); this.changeFilter = new CoarseChangeFilter(bibDatabaseContext); changeFilter.registerListener(this); @@ -46,13 +47,12 @@ private AutosaveManager(BibDatabaseContext bibDatabaseContext) { @Subscribe public synchronized void listen(@SuppressWarnings("unused") BibDatabaseContextChangedEvent event) { - try { - executor.submit(() -> { - eventBus.post(new AutosaveEvent()); - }); - } catch (RejectedExecutionException e) { - LOGGER.debug("Rejecting autosave while another save process is already running."); + if (scheduledSaveAction != null) { + scheduledSaveAction.cancel(false); } + scheduledSaveAction = executor.schedule(() -> { + eventBus.post(new AutosaveEvent()); + }, AUTO_SAVE_DELAY, TimeUnit.MILLISECONDS); } private void shutdown() {