Merge pull request #3955 from esaunders/4013_aid_refresh

4013 Fix for job list threading issue
This commit is contained in:
Richard Cordovano 2018-07-13 16:56:28 -04:00 committed by GitHub
commit fe96e5bcdf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 79 additions and 101 deletions

View File

@ -338,7 +338,7 @@ final class AutoIngestAdminActions {
dashboard.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
AutoIngestManager.CaseDeletionResult result = dashboard.getMonitor().deleteCase(job);
dashboard.getCompletedJobsPanel().refresh(new AutoIngestNodeRefreshEvents.RefreshChildrenEvent(dashboard.getMonitor().getJobsSnapshot()));
dashboard.getCompletedJobsPanel().refresh(new AutoIngestNodeRefreshEvents.RefreshChildrenEvent(dashboard.getMonitor()));
dashboard.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
if (AutoIngestManager.CaseDeletionResult.FAILED == result) {
JOptionPane.showMessageDialog(dashboard,

View File

@ -38,7 +38,6 @@ import org.openide.util.NbBundle;
import org.openide.util.NbBundle.Messages;
import org.sleuthkit.autopsy.core.ServicesMonitor;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.experimental.autoingest.AutoIngestMonitor.JobsSnapshot;
import org.sleuthkit.autopsy.experimental.autoingest.AutoIngestNodeRefreshEvents.RefreshChildrenEvent;
/**
@ -257,7 +256,7 @@ final class AutoIngestDashboard extends JPanel implements Observer {
@Override
public void update(Observable observable, Object arg) {
if (arg instanceof JobsSnapshot) {
if (arg == null ) {
EventQueue.invokeLater(() -> {
refreshTables();
});
@ -271,9 +270,9 @@ final class AutoIngestDashboard extends JPanel implements Observer {
* @param nodeStateSnapshot The jobs snapshot.
*/
void refreshTables() {
pendingJobsPanel.refresh(new RefreshChildrenEvent(autoIngestMonitor.getJobsSnapshot()));
runningJobsPanel.refresh(new RefreshChildrenEvent(autoIngestMonitor.getJobsSnapshot()));
completedJobsPanel.refresh(new RefreshChildrenEvent(autoIngestMonitor.getJobsSnapshot()));
pendingJobsPanel.refresh(new RefreshChildrenEvent(autoIngestMonitor));
runningJobsPanel.refresh(new RefreshChildrenEvent(autoIngestMonitor));
completedJobsPanel.refresh(new RefreshChildrenEvent(autoIngestMonitor));
}
/**

View File

@ -33,7 +33,6 @@ import org.openide.nodes.Node;
import org.openide.nodes.Sheet;
import org.openide.util.NbBundle.Messages;
import org.sleuthkit.autopsy.datamodel.NodeProperty;
import org.sleuthkit.autopsy.experimental.autoingest.AutoIngestMonitor.JobsSnapshot;
import org.sleuthkit.autopsy.guiutils.DurationCellRenderer;
import org.sleuthkit.autopsy.guiutils.StatusIconCellRenderer;
@ -61,13 +60,13 @@ final class AutoIngestJobsNode extends AbstractNode {
/**
* Construct a new AutoIngestJobsNode.
*
* @param snapshot the snapshot which contains the AutoIngestJobs
* @param monitor the monitor which gives access to the AutoIngestJobs
* @param status the status of the jobs being displayed
* @param eventBus the event bus which will be used to send and receive
* refresh events
*/
AutoIngestJobsNode(JobsSnapshot jobsSnapshot, AutoIngestJobStatus status, EventBus eventBus) {
super(Children.create(new AutoIngestNodeChildren(jobsSnapshot, status, eventBus), false));
AutoIngestJobsNode(AutoIngestMonitor monitor, AutoIngestJobStatus status, EventBus eventBus) {
super(Children.create(new AutoIngestNodeChildren(monitor, status, eventBus), false));
refreshChildrenEventBus = eventBus;
}
@ -84,7 +83,7 @@ final class AutoIngestJobsNode extends AbstractNode {
static final class AutoIngestNodeChildren extends ChildFactory<AutoIngestJob> {
private final AutoIngestJobStatus autoIngestJobStatus;
private JobsSnapshot jobsSnapshot;
private AutoIngestMonitor monitor;
private final RefreshChildrenSubscriber refreshChildrenSubscriber = new RefreshChildrenSubscriber();
private final EventBus refreshEventBus;
@ -92,13 +91,13 @@ final class AutoIngestJobsNode extends AbstractNode {
* Create children nodes for the AutoIngestJobsNode which will each
* represent a single AutoIngestJob
*
* @param snapshot the snapshot which contains the AutoIngestJobs
* @param monitor the monitor which gives access to the AutoIngestJobs
* @param status the status of the jobs being displayed
* @param eventBus the event bus which the class registers to for
* refresh events
*/
AutoIngestNodeChildren(JobsSnapshot snapshot, AutoIngestJobStatus status, EventBus eventBus) {
jobsSnapshot = snapshot;
AutoIngestNodeChildren(AutoIngestMonitor monitor, AutoIngestJobStatus status, EventBus eventBus) {
this.monitor = monitor;
autoIngestJobStatus = status;
refreshEventBus = eventBus;
refreshChildrenSubscriber.register(refreshEventBus);
@ -109,14 +108,14 @@ final class AutoIngestJobsNode extends AbstractNode {
List<AutoIngestJob> jobs;
switch (autoIngestJobStatus) {
case PENDING_JOB:
jobs = jobsSnapshot.getPendingJobs();
jobs = monitor.getPendingJobs();
Collections.sort(jobs);
break;
case RUNNING_JOB:
jobs = jobsSnapshot.getRunningJobs();
jobs = monitor.getRunningJobs();
break;
case COMPLETED_JOB:
jobs = jobsSnapshot.getCompletedJobs();
jobs = monitor.getCompletedJobs();
break;
default:
jobs = new ArrayList<>();
@ -167,7 +166,7 @@ final class AutoIngestJobsNode extends AbstractNode {
//Ignore netbeans suggesting this isn't being used, it is used behind the scenes by the EventBus
//RefreshChildrenEvents can change which children are present however
//RefreshJobEvents and RefreshCaseEvents can still change the order we want to display them in
jobsSnapshot = refreshEvent.getJobsSnapshot();
monitor = refreshEvent.getMonitor();
refresh(true);
}

View File

@ -171,7 +171,7 @@ final class AutoIngestJobsPanel extends javax.swing.JPanel implements ExplorerMa
((AutoIngestJobsNode) explorerManager.getRootContext()).refresh(refreshEvent);
} else {
//Make a new AutoIngestJobsNode with it's own EventBus and set it as the root context
explorerManager.setRootContext(new AutoIngestJobsNode(refreshEvent.getJobsSnapshot(), status, new EventBus("AutoIngestJobsNodeEventBus")));
explorerManager.setRootContext(new AutoIngestJobsNode(refreshEvent.getMonitor(), status, new EventBus("AutoIngestJobsNodeEventBus")));
}
outline.setRowSelectionAllowed(true);
outline.setFocusable(true);

View File

@ -172,7 +172,7 @@ final class AutoIngestMonitor extends Observable implements PropertyChangeListen
jobsSnapshot.removePendingJob(event.getJob());
jobsSnapshot.addOrReplaceRunningJob(event.getJob());
setChanged();
notifyObservers(jobsSnapshot);
notifyObservers();
}
}
@ -190,7 +190,7 @@ final class AutoIngestMonitor extends Observable implements PropertyChangeListen
jobsSnapshot.removePendingJob(job);
// Update the state of the existing job in the running jobs table
for (AutoIngestJob runningJob : jobsSnapshot.getRunningJobs()) {
for (AutoIngestJob runningJob : getRunningJobs()) {
if (runningJob.equals(job)) {
runningJob.setIngestJobsSnapshot(job.getIngestJobSnapshots());
runningJob.setIngestThreadSnapshot(job.getIngestThreadActivitySnapshots());
@ -200,7 +200,7 @@ final class AutoIngestMonitor extends Observable implements PropertyChangeListen
}
}
setChanged();
notifyObservers(jobsSnapshot);
notifyObservers();
}
}
@ -216,7 +216,7 @@ final class AutoIngestMonitor extends Observable implements PropertyChangeListen
jobsSnapshot.removeRunningJob(job);
jobsSnapshot.addOrReplaceCompletedJob(job);
setChanged();
notifyObservers(jobsSnapshot);
notifyObservers();
}
}
@ -259,15 +259,35 @@ final class AutoIngestMonitor extends Observable implements PropertyChangeListen
}
/**
* Gets the auto ingest monitor's current snapshot of the pending jobs
* queue, running jobs list, and completed jobs list for an auto ingest
* cluster.
* Gets the snapshot of the pending jobs queue for an auto ingest cluster.
*
* @return The snapshot.
* @return The pending jobs queue.
*/
JobsSnapshot getJobsSnapshot() {
List<AutoIngestJob> getPendingJobs() {
synchronized (jobsLock) {
return jobsSnapshot;
return new ArrayList<>(jobsSnapshot.pendingJobs);
}
}
/**
* Gets the snapshot of the running jobs list for an auto ingest cluster.
*
* @return The running jobs list.
*/
List<AutoIngestJob> getRunningJobs() {
synchronized (jobsLock) {
return new ArrayList<>(jobsSnapshot.runningJobs);
}
}
/**
* Gets the snapshot of the completed jobs list for an auto ingest cluster.
*
* @return The completed jobs list.
*/
List<AutoIngestJob> getCompletedJobs() {
synchronized (jobsLock) {
return new ArrayList<>(jobsSnapshot.completedJobs);
}
}
@ -287,10 +307,9 @@ final class AutoIngestMonitor extends Observable implements PropertyChangeListen
*
* @return The refreshed snapshot.
*/
JobsSnapshot refreshJobsSnapshot() {
void refreshJobsSnapshot() {
synchronized (jobsLock) {
jobsSnapshot = queryCoordinationService();
return jobsSnapshot;
}
}
@ -358,13 +377,12 @@ final class AutoIngestMonitor extends Observable implements PropertyChangeListen
* @throws AutoIngestMonitorException If there is an error removing the
* priority of the jobs for the case.
*
* @return The latest jobs snapshot.
*/
JobsSnapshot deprioritizeCase(final String caseName) throws AutoIngestMonitorException {
void deprioritizeCase(final String caseName) throws AutoIngestMonitorException {
List<AutoIngestJob> jobsToDeprioritize = new ArrayList<>();
synchronized (jobsLock) {
for (AutoIngestJob pendingJob : jobsSnapshot.getPendingJobs()) {
for (AutoIngestJob pendingJob : getPendingJobs()) {
if (pendingJob.getManifest().getCaseName().equals(caseName)) {
jobsToDeprioritize.add(pendingJob);
}
@ -395,7 +413,6 @@ final class AutoIngestMonitor extends Observable implements PropertyChangeListen
AutoIngestManager.getSystemUserNameProperty(), AutoIngestCasePrioritizedEvent.EventType.CASE_DEPRIORITIZED, ""));
}).start();
}
return jobsSnapshot;
}
}
@ -407,13 +424,12 @@ final class AutoIngestMonitor extends Observable implements PropertyChangeListen
* @throws AutoIngestMonitorException If there is an error bumping the
* priority of the jobs for the case.
*
* @return The latest jobs snapshot.
*/
JobsSnapshot prioritizeCase(final String caseName) throws AutoIngestMonitorException {
void prioritizeCase(final String caseName) throws AutoIngestMonitorException {
List<AutoIngestJob> jobsToPrioritize = new ArrayList<>();
int highestPriority = 0;
synchronized (jobsLock) {
for (AutoIngestJob pendingJob : jobsSnapshot.getPendingJobs()) {
for (AutoIngestJob pendingJob : getPendingJobs()) {
if (pendingJob.getPriority() > highestPriority) {
highestPriority = pendingJob.getPriority();
}
@ -448,7 +464,6 @@ final class AutoIngestMonitor extends Observable implements PropertyChangeListen
AutoIngestManager.getSystemUserNameProperty(), AutoIngestCasePrioritizedEvent.EventType.CASE_PRIORITIZED, ""));
}).start();
}
return jobsSnapshot;
}
}
@ -460,15 +475,14 @@ final class AutoIngestMonitor extends Observable implements PropertyChangeListen
* @throws AutoIngestMonitorException If there is an error removing the
* priority of the job.
*
* @return The latest jobs snapshot.
*/
JobsSnapshot deprioritizeJob(AutoIngestJob job) throws AutoIngestMonitorException {
void deprioritizeJob(AutoIngestJob job) throws AutoIngestMonitorException {
synchronized (jobsLock) {
AutoIngestJob jobToDeprioritize = null;
/*
* Make sure the job is still in the pending jobs queue.
*/
for (AutoIngestJob pendingJob : jobsSnapshot.getPendingJobs()) {
for (AutoIngestJob pendingJob : getPendingJobs()) {
if (pendingJob.equals(job)) {
jobToDeprioritize = job;
break;
@ -506,7 +520,6 @@ final class AutoIngestMonitor extends Observable implements PropertyChangeListen
}).start();
}
return jobsSnapshot;
}
}
@ -518,9 +531,8 @@ final class AutoIngestMonitor extends Observable implements PropertyChangeListen
* @throws AutoIngestMonitorException If there is an error bumping the
* priority of the job.
*
* @return The latest jobs snapshot.
*/
JobsSnapshot prioritizeJob(AutoIngestJob job) throws AutoIngestMonitorException {
void prioritizeJob(AutoIngestJob job) throws AutoIngestMonitorException {
synchronized (jobsLock) {
int highestPriority = 0;
AutoIngestJob jobToPrioritize = null;
@ -528,7 +540,7 @@ final class AutoIngestMonitor extends Observable implements PropertyChangeListen
* Get the highest known priority and make sure the job is still in
* the pending jobs queue.
*/
for (AutoIngestJob pendingJob : jobsSnapshot.getPendingJobs()) {
for (AutoIngestJob pendingJob : getPendingJobs()) {
if (pendingJob.getPriority() > highestPriority) {
highestPriority = pendingJob.getPriority();
}
@ -569,7 +581,6 @@ final class AutoIngestMonitor extends Observable implements PropertyChangeListen
}).start();
}
return jobsSnapshot;
}
}
@ -591,7 +602,7 @@ final class AutoIngestMonitor extends Observable implements PropertyChangeListen
*/
void reprocessJob(AutoIngestJob job) throws AutoIngestMonitorException {
synchronized (jobsLock) {
if (!jobsSnapshot.getCompletedJobs().contains(job)) {
if (!getCompletedJobs().contains(job)) {
return;
}
@ -660,7 +671,7 @@ final class AutoIngestMonitor extends Observable implements PropertyChangeListen
// Update the state of completed jobs associated with this case to indicate
// that the case has been deleted
for (AutoIngestJob completedJob : jobsSnapshot.getCompletedJobs()) {
for (AutoIngestJob completedJob : getCompletedJobs()) {
if (caseName.equals(completedJob.getManifest().getCaseName())) {
try {
completedJob.setProcessingStatus(DELETED);
@ -741,7 +752,7 @@ final class AutoIngestMonitor extends Observable implements PropertyChangeListen
synchronized (jobsLock) {
jobsSnapshot = queryCoordinationService();
setChanged();
notifyObservers(jobsSnapshot);
notifyObservers();
}
}
}
@ -752,42 +763,12 @@ final class AutoIngestMonitor extends Observable implements PropertyChangeListen
* A snapshot of the pending jobs queue, running jobs list and completed
* jobs list for an auto ingest cluster.
*/
static final class JobsSnapshot {
private static final class JobsSnapshot {
private final Set<AutoIngestJob> pendingJobs = new HashSet<>();
private final Set<AutoIngestJob> runningJobs = new HashSet<>();
private final Set<AutoIngestJob> completedJobs = new HashSet<>();
/**
* Gets the snapshot of the pending jobs queue for an auto ingest
* cluster.
*
* @return The pending jobs queue.
*/
List<AutoIngestJob> getPendingJobs() {
return new ArrayList<>(this.pendingJobs);
}
/**
* Gets the snapshot of the running jobs list for an auto ingest
* cluster.
*
* @return The running jobs list.
*/
List<AutoIngestJob> getRunningJobs() {
return new ArrayList<>(this.runningJobs);
}
/**
* Gets the snapshot of the completed jobs list for an auto ingest
* cluster.
*
* @return The completed jobs list.
*/
List<AutoIngestJob> getCompletedJobs() {
return new ArrayList<>(this.completedJobs);
}
/**
* Adds an auto job to the snapshot of the pending jobs queue for an
* auto ingest cluster. If an equivalent job already exists, it is

View File

@ -18,8 +18,6 @@
*/
package org.sleuthkit.autopsy.experimental.autoingest;
import org.sleuthkit.autopsy.experimental.autoingest.AutoIngestMonitor.JobsSnapshot;
/**
* Class which contains events to identify what should be refreshed in the
* AutoIngestJobsNode
@ -31,19 +29,20 @@ class AutoIngestNodeRefreshEvents {
*/
static class AutoIngestRefreshEvent {
private final JobsSnapshot jobsSnapshot;
private final AutoIngestMonitor monitor;
AutoIngestRefreshEvent(JobsSnapshot jobs) {
this.jobsSnapshot = jobs;
AutoIngestRefreshEvent(AutoIngestMonitor monitor) {
this.monitor = monitor;
}
/**
* Get the state of the jobs lists when the event was fired.
* Get the monitor which will provide access to the state of
* the jobs.
*
* @return
*/
JobsSnapshot getJobsSnapshot() {
return this.jobsSnapshot;
AutoIngestMonitor getMonitor() {
return this.monitor;
}
}
@ -56,8 +55,8 @@ class AutoIngestNodeRefreshEvents {
/**
* Constructs a RefreshChildrenEvent.
*/
RefreshChildrenEvent(JobsSnapshot jobs) {
super(jobs);
RefreshChildrenEvent(AutoIngestMonitor monitor) {
super(monitor);
}
}
@ -72,11 +71,11 @@ class AutoIngestNodeRefreshEvents {
/**
* Contructs a RefreshCaseEvent
*
* @param jobs The current state of the jobs lists.
* @param monitor The monitor that will provide access to the current state of the jobs lists.
* @param name The name of the case whose nodes should be refreshed.
*/
RefreshCaseEvent(JobsSnapshot jobs, String name) {
super(jobs);
RefreshCaseEvent(AutoIngestMonitor monitor, String name) {
super(monitor);
caseName = name;
}
@ -103,11 +102,11 @@ class AutoIngestNodeRefreshEvents {
/**
* Constructs a RefreshJobEvent.
*
* @param jobs The curent state of the jobs lists.
* @param monitor The monitor which will provide access to the current state of the jobs lists.
* @param job The job which should be refreshed.
*/
RefreshJobEvent(JobsSnapshot jobs, AutoIngestJob job) {
super(jobs);
RefreshJobEvent(AutoIngestMonitor monitor, AutoIngestJob job) {
super(monitor);
autoIngestJob = job;
}

View File

@ -145,7 +145,7 @@ abstract class PrioritizationAction extends AbstractAction {
@Override
AutoIngestNodeRefreshEvents.AutoIngestRefreshEvent getRefreshEvent(AutoIngestMonitor monitor) {
return new AutoIngestNodeRefreshEvents.RefreshJobEvent(monitor.getJobsSnapshot(), getJob());
return new AutoIngestNodeRefreshEvents.RefreshJobEvent(monitor, getJob());
}
}
@ -184,7 +184,7 @@ abstract class PrioritizationAction extends AbstractAction {
@Override
AutoIngestNodeRefreshEvents.AutoIngestRefreshEvent getRefreshEvent(AutoIngestMonitor monitor) {
return new AutoIngestNodeRefreshEvents.RefreshJobEvent(monitor.getJobsSnapshot(), getJob());
return new AutoIngestNodeRefreshEvents.RefreshJobEvent(monitor, getJob());
}
}
@ -225,7 +225,7 @@ abstract class PrioritizationAction extends AbstractAction {
@Override
AutoIngestNodeRefreshEvents.AutoIngestRefreshEvent getRefreshEvent(AutoIngestMonitor monitor) {
return new AutoIngestNodeRefreshEvents.RefreshCaseEvent(monitor.getJobsSnapshot(), getJob().getManifest().getCaseName());
return new AutoIngestNodeRefreshEvents.RefreshCaseEvent(monitor, getJob().getManifest().getCaseName());
}
}
@ -266,7 +266,7 @@ abstract class PrioritizationAction extends AbstractAction {
@Override
AutoIngestNodeRefreshEvents.AutoIngestRefreshEvent getRefreshEvent(AutoIngestMonitor monitor) {
return new AutoIngestNodeRefreshEvents.RefreshCaseEvent(monitor.getJobsSnapshot(), getJob().getManifest().getCaseName());
return new AutoIngestNodeRefreshEvents.RefreshCaseEvent(monitor, getJob().getManifest().getCaseName());
}
}
}