mirror of
https://github.com/overcuriousity/autopsy-flatpak.git
synced 2025-07-12 16:06:15 +00:00
convert dbWorkerThread to an executor, call shutdown and awaitTerminaton on case close.
This commit is contained in:
parent
026e3de17b
commit
f0bb38cfbf
@ -18,14 +18,16 @@
|
|||||||
*/
|
*/
|
||||||
package org.sleuthkit.autopsy.imagegallery;
|
package org.sleuthkit.autopsy.imagegallery;
|
||||||
|
|
||||||
|
import com.google.common.util.concurrent.ListeningExecutorService;
|
||||||
|
import com.google.common.util.concurrent.MoreExecutors;
|
||||||
|
import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
||||||
import java.beans.PropertyChangeEvent;
|
import java.beans.PropertyChangeEvent;
|
||||||
import java.beans.PropertyChangeListener;
|
import java.beans.PropertyChangeListener;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.concurrent.BlockingQueue;
|
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
import java.util.concurrent.LinkedBlockingQueue;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import javafx.application.Platform;
|
import javafx.application.Platform;
|
||||||
import javafx.beans.Observable;
|
import javafx.beans.Observable;
|
||||||
@ -55,6 +57,7 @@ import javax.annotation.Nullable;
|
|||||||
import javax.swing.SwingUtilities;
|
import javax.swing.SwingUtilities;
|
||||||
import org.netbeans.api.progress.ProgressHandle;
|
import org.netbeans.api.progress.ProgressHandle;
|
||||||
import org.openide.util.Cancellable;
|
import org.openide.util.Cancellable;
|
||||||
|
import org.openide.util.Exceptions;
|
||||||
import org.openide.util.NbBundle;
|
import org.openide.util.NbBundle;
|
||||||
import org.sleuthkit.autopsy.casemodule.Case;
|
import org.sleuthkit.autopsy.casemodule.Case;
|
||||||
import org.sleuthkit.autopsy.casemodule.events.ContentTagAddedEvent;
|
import org.sleuthkit.autopsy.casemodule.events.ContentTagAddedEvent;
|
||||||
@ -92,11 +95,6 @@ public final class ImageGalleryController implements Executor {
|
|||||||
private Runnable showTree;
|
private Runnable showTree;
|
||||||
private Toolbar toolbar;
|
private Toolbar toolbar;
|
||||||
|
|
||||||
@Override
|
|
||||||
public void execute(Runnable command) {
|
|
||||||
execDelegate.execute(command);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final Logger LOGGER = Logger.getLogger(ImageGalleryController.class.getName());
|
private static final Logger LOGGER = Logger.getLogger(ImageGalleryController.class.getName());
|
||||||
|
|
||||||
private final Region infoOverLayBackground = new Region() {
|
private final Region infoOverLayBackground = new Region() {
|
||||||
@ -108,13 +106,6 @@ public final class ImageGalleryController implements Executor {
|
|||||||
|
|
||||||
private static ImageGalleryController instance;
|
private static ImageGalleryController instance;
|
||||||
|
|
||||||
public static synchronized ImageGalleryController getDefault() {
|
|
||||||
if (instance == null) {
|
|
||||||
instance = new ImageGalleryController();
|
|
||||||
}
|
|
||||||
return instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
private final History<GroupViewState> historyManager = new History<>();
|
private final History<GroupViewState> historyManager = new History<>();
|
||||||
private final UndoRedoManager undoManager = new UndoRedoManager();
|
private final UndoRedoManager undoManager = new UndoRedoManager();
|
||||||
|
|
||||||
@ -134,8 +125,6 @@ public final class ImageGalleryController implements Executor {
|
|||||||
|
|
||||||
private final FileIDSelectionModel selectionModel = new FileIDSelectionModel(this);
|
private final FileIDSelectionModel selectionModel = new FileIDSelectionModel(this);
|
||||||
|
|
||||||
private DBWorkerThread dbWorkerThread;
|
|
||||||
|
|
||||||
private DrawableDB db;
|
private DrawableDB db;
|
||||||
|
|
||||||
private final GroupManager groupManager = new GroupManager(this);
|
private final GroupManager groupManager = new GroupManager(this);
|
||||||
@ -150,6 +139,22 @@ public final class ImageGalleryController implements Executor {
|
|||||||
private Node infoOverlay;
|
private Node infoOverlay;
|
||||||
private SleuthkitCase sleuthKitCase;
|
private SleuthkitCase sleuthKitCase;
|
||||||
|
|
||||||
|
private final ReadOnlyIntegerWrapper queueSizeProperty = new ReadOnlyIntegerWrapper(0);
|
||||||
|
|
||||||
|
private ListeningExecutorService dbExecutor;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute(Runnable command) {
|
||||||
|
execDelegate.execute(command);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static synchronized ImageGalleryController getDefault() {
|
||||||
|
if (instance == null) {
|
||||||
|
instance = new ImageGalleryController();
|
||||||
|
}
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
public ReadOnlyBooleanProperty getMetaDataCollapsed() {
|
public ReadOnlyBooleanProperty getMetaDataCollapsed() {
|
||||||
return metaDataCollapsed.getReadOnlyProperty();
|
return metaDataCollapsed.getReadOnlyProperty();
|
||||||
}
|
}
|
||||||
@ -363,23 +368,15 @@ public final class ImageGalleryController implements Executor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
synchronized private DBWorkerThread restartWorker() {
|
|
||||||
if (dbWorkerThread == null) {
|
|
||||||
dbWorkerThread = new DBWorkerThread(this);
|
|
||||||
dbWorkerThread.start();
|
|
||||||
} else {
|
|
||||||
// Keep using the same worker thread if one exists
|
|
||||||
}
|
|
||||||
return dbWorkerThread;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* configure the controller for a specific case.
|
* configure the controller for a specific case.
|
||||||
*
|
*
|
||||||
* @param theNewCase the case to configure the controller for
|
* @param theNewCase the case to configure the controller for
|
||||||
*/
|
*/
|
||||||
public synchronized void setCase(Case theNewCase) {
|
public synchronized void setCase(Case theNewCase) {
|
||||||
if (Objects.nonNull(theNewCase)) {
|
if (null == theNewCase) {
|
||||||
|
reset();
|
||||||
|
} else {
|
||||||
this.sleuthKitCase = theNewCase.getSleuthkitCase();
|
this.sleuthKitCase = theNewCase.getSleuthkitCase();
|
||||||
this.db = DrawableDB.getDrawableDB(ImageGalleryModule.getModuleOutputDir(theNewCase), this);
|
this.db = DrawableDB.getDrawableDB(ImageGalleryModule.getModuleOutputDir(theNewCase), this);
|
||||||
|
|
||||||
@ -388,7 +385,6 @@ public final class ImageGalleryController implements Executor {
|
|||||||
|
|
||||||
// if we add this line icons are made as files are analyzed rather than on demand.
|
// if we add this line icons are made as files are analyzed rather than on demand.
|
||||||
// db.addUpdatedFileListener(IconCache.getDefault());
|
// db.addUpdatedFileListener(IconCache.getDefault());
|
||||||
restartWorker();
|
|
||||||
historyManager.clear();
|
historyManager.clear();
|
||||||
groupManager.setDB(db);
|
groupManager.setDB(db);
|
||||||
hashSetManager.setDb(db);
|
hashSetManager.setDb(db);
|
||||||
@ -396,9 +392,8 @@ public final class ImageGalleryController implements Executor {
|
|||||||
tagsManager.setAutopsyTagsManager(theNewCase.getServices().getTagsManager());
|
tagsManager.setAutopsyTagsManager(theNewCase.getServices().getTagsManager());
|
||||||
tagsManager.registerListener(groupManager);
|
tagsManager.registerListener(groupManager);
|
||||||
tagsManager.registerListener(categoryManager);
|
tagsManager.registerListener(categoryManager);
|
||||||
|
shutDownDBExecutor();
|
||||||
} else {
|
dbExecutor = getNewDBExecutor();
|
||||||
reset();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -415,9 +410,7 @@ public final class ImageGalleryController implements Executor {
|
|||||||
tagsManager.clearFollowUpTagName();
|
tagsManager.clearFollowUpTagName();
|
||||||
tagsManager.unregisterListener(groupManager);
|
tagsManager.unregisterListener(groupManager);
|
||||||
tagsManager.unregisterListener(categoryManager);
|
tagsManager.unregisterListener(categoryManager);
|
||||||
dbWorkerThread.cancel();
|
shutDownDBExecutor();
|
||||||
dbWorkerThread = null;
|
|
||||||
dbWorkerThread = restartWorker();
|
|
||||||
|
|
||||||
if (toolbar != null) {
|
if (toolbar != null) {
|
||||||
toolbar.reset();
|
toolbar.reset();
|
||||||
@ -429,16 +422,42 @@ public final class ImageGalleryController implements Executor {
|
|||||||
db = null;
|
db = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void shutDownDBExecutor() {
|
||||||
|
if (dbExecutor != null) {
|
||||||
|
dbExecutor.shutdownNow();
|
||||||
|
try {
|
||||||
|
dbExecutor.awaitTermination(30, TimeUnit.SECONDS);
|
||||||
|
} catch (InterruptedException ex) {
|
||||||
|
Exceptions.printStackTrace(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ListeningExecutorService getNewDBExecutor() {
|
||||||
|
return MoreExecutors.listeningDecorator(Executors.newSingleThreadExecutor(
|
||||||
|
new ThreadFactoryBuilder().setNameFormat("DB-Worker-Thread-%d").build()));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* add InnerTask to the queue that the worker thread gets its work from
|
* add InnerTask to the queue that the worker thread gets its work from
|
||||||
*
|
*
|
||||||
* @param innerTask
|
* @param bgTask
|
||||||
*/
|
*/
|
||||||
public synchronized void queueDBWorkerTask(BackgroundTask innerTask) {
|
public synchronized void queueDBWorkerTask(BackgroundTask bgTask) {
|
||||||
if (dbWorkerThread == null) {
|
if (dbExecutor == null || dbExecutor.isShutdown()) {
|
||||||
dbWorkerThread = restartWorker();
|
dbExecutor = getNewDBExecutor();
|
||||||
}
|
}
|
||||||
dbWorkerThread.addTask(innerTask);
|
incrementQueueSize();
|
||||||
|
dbExecutor.submit(bgTask).addListener(this::decrementQueueSize, MoreExecutors.directExecutor());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void incrementQueueSize() {
|
||||||
|
Platform.runLater(() -> queueSizeProperty.set(queueSizeProperty.get() + 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void decrementQueueSize() {
|
||||||
|
Platform.runLater(() -> queueSizeProperty.set(queueSizeProperty.get() - 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@ -504,76 +523,6 @@ public final class ImageGalleryController implements Executor {
|
|||||||
public ReadOnlyIntegerProperty getDBTasksQueueSizeProperty() {
|
public ReadOnlyIntegerProperty getDBTasksQueueSizeProperty() {
|
||||||
return queueSizeProperty.getReadOnlyProperty();
|
return queueSizeProperty.getReadOnlyProperty();
|
||||||
}
|
}
|
||||||
private final ReadOnlyIntegerWrapper queueSizeProperty = new ReadOnlyIntegerWrapper(0);
|
|
||||||
|
|
||||||
// @@@ review this class for synchronization issues (i.e. reset and cancel being called, add, etc.)
|
|
||||||
static private class DBWorkerThread extends Thread implements Cancellable {
|
|
||||||
|
|
||||||
private final ImageGalleryController controller;
|
|
||||||
|
|
||||||
DBWorkerThread(ImageGalleryController controller) {
|
|
||||||
super("DB-Worker-Thread");
|
|
||||||
setDaemon(false);
|
|
||||||
this.controller = controller;
|
|
||||||
}
|
|
||||||
|
|
||||||
// true if the process was requested to stop. Currently no way to reset it
|
|
||||||
private volatile boolean cancelled = false;
|
|
||||||
|
|
||||||
// list of tasks to run
|
|
||||||
private final BlockingQueue<BackgroundTask> workQueue = new LinkedBlockingQueue<>();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Cancel all of the queued up tasks and the currently scheduled task.
|
|
||||||
* Note that after you cancel, you cannot submit new jobs to this
|
|
||||||
* thread.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public boolean cancel() {
|
|
||||||
cancelled = true;
|
|
||||||
for (BackgroundTask it : workQueue) {
|
|
||||||
it.cancel();
|
|
||||||
}
|
|
||||||
workQueue.clear();
|
|
||||||
int size = workQueue.size();
|
|
||||||
Platform.runLater(() -> controller.queueSizeProperty.set(size));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add a task for the worker thread to perform
|
|
||||||
*
|
|
||||||
* @param it
|
|
||||||
*/
|
|
||||||
public void addTask(BackgroundTask it) {
|
|
||||||
workQueue.add(it);
|
|
||||||
int size = workQueue.size();
|
|
||||||
Platform.runLater(() -> controller.queueSizeProperty.set(size));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
|
|
||||||
// nearly infinite loop waiting for tasks
|
|
||||||
while (true) {
|
|
||||||
if (cancelled || isInterrupted()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
BackgroundTask it = workQueue.take();
|
|
||||||
|
|
||||||
if (it.isCancelled() == false) {
|
|
||||||
it.run();
|
|
||||||
}
|
|
||||||
int size = workQueue.size();
|
|
||||||
Platform.runLater(() -> controller.queueSizeProperty.set(size));
|
|
||||||
|
|
||||||
} catch (InterruptedException ex) {
|
|
||||||
LOGGER.log(Level.SEVERE, "Failed to run DB worker thread", ex); //NON-NLS
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public synchronized SleuthkitCase getSleuthKitCase() {
|
public synchronized SleuthkitCase getSleuthKitCase() {
|
||||||
return sleuthKitCase;
|
return sleuthKitCase;
|
||||||
@ -643,7 +592,7 @@ public final class ImageGalleryController implements Executor {
|
|||||||
/**
|
/**
|
||||||
* Abstract base class for tasks associated with a file in the database
|
* Abstract base class for tasks associated with a file in the database
|
||||||
*/
|
*/
|
||||||
static public abstract class FileTask extends BackgroundTask {
|
static abstract class FileTask extends BackgroundTask {
|
||||||
|
|
||||||
private final AbstractFile file;
|
private final AbstractFile file;
|
||||||
private final DrawableDB taskDB;
|
private final DrawableDB taskDB;
|
||||||
@ -713,7 +662,6 @@ public final class ImageGalleryController implements Executor {
|
|||||||
Logger.getLogger(RemoveFileTask.class.getName()).log(Level.SEVERE, "Case was closed out from underneath RemoveFile task"); //NON-NLS
|
Logger.getLogger(RemoveFileTask.class.getName()).log(Level.SEVERE, "Case was closed out from underneath RemoveFile task"); //NON-NLS
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -775,7 +723,7 @@ public final class ImageGalleryController implements Executor {
|
|||||||
DrawableDB.DrawableTransaction tr = taskDB.beginTransaction();
|
DrawableDB.DrawableTransaction tr = taskDB.beginTransaction();
|
||||||
int workDone = 0;
|
int workDone = 0;
|
||||||
for (final AbstractFile f : files) {
|
for (final AbstractFile f : files) {
|
||||||
if (isCancelled()) {
|
if (isCancelled() || Thread.interrupted()) {
|
||||||
LOGGER.log(Level.WARNING, "Task cancelled: not all contents may be transfered to drawable database."); //NON-NLS
|
LOGGER.log(Level.WARNING, "Task cancelled: not all contents may be transfered to drawable database."); //NON-NLS
|
||||||
progressHandle.finish();
|
progressHandle.finish();
|
||||||
break;
|
break;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user