Skip to content

Commit

Permalink
Add throttle to AutosaveUIManager (#5680)
Browse files Browse the repository at this point in the history
* Add throttle to AutosaveUIManager (fixes #5679)

* Fix checkstyle errors
  • Loading branch information
Ka0o0 authored and tobiasdiez committed Dec 7, 2019
1 parent 359a1cc commit d0f6c2b
Show file tree
Hide file tree
Showing 2 changed files with 17 additions and 16 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -21,38 +19,40 @@

/**
* 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<AutosaveManager> runningInstances = new HashSet<>();

private final BibDatabaseContext bibDatabaseContext;
private final BlockingQueue<Runnable> 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);
}

@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() {
Expand Down

0 comments on commit d0f6c2b

Please sign in to comment.