mirror of
https://github.com/overcuriousity/autopsy-flatpak.git
synced 2025-07-12 16:06:15 +00:00
Add ingest cancellation reasons; fix job startup bug
This commit is contained in:
parent
2bc998155f
commit
4d19cf1e83
@ -73,6 +73,7 @@ import org.sleuthkit.autopsy.casemodule.events.ContentTagAddedEvent;
|
||||
import org.sleuthkit.autopsy.casemodule.events.ContentTagDeletedEvent;
|
||||
import org.sleuthkit.autopsy.core.RuntimeProperties;
|
||||
import org.sleuthkit.autopsy.core.UserPreferencesException;
|
||||
import org.sleuthkit.autopsy.ingest.IngestJob;
|
||||
import org.sleuthkit.autopsy.ingest.IngestManager;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifactTag;
|
||||
import org.sleuthkit.datamodel.Content;
|
||||
@ -327,7 +328,7 @@ public class Case implements SleuthkitCase.ErrorObserver {
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
WindowManager.getDefault().getMainWindow().setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
|
||||
});
|
||||
IngestManager.getInstance().cancelAllIngestJobs();
|
||||
IngestManager.getInstance().cancelAllIngestJobs(IngestJob.CancellationReason.CASE_CLOSED);
|
||||
doCaseChange(null); //closes windows, etc
|
||||
if (null != oldCase.tskErrorReporter) {
|
||||
oldCase.tskErrorReporter.shutdown(); // stop listening for TSK errors for the old case
|
||||
|
@ -118,6 +118,8 @@ final class DataSourceIngestJob {
|
||||
*/
|
||||
private volatile boolean currentDataSourceIngestModuleCancelled;
|
||||
private volatile boolean cancelled;
|
||||
private volatile IngestJob.CancellationReason cancellationReason = IngestJob.CancellationReason.NOT_CANCELLED;
|
||||
private final Object cancellationStateMonitor = new Object();
|
||||
private final List<String> cancelledDataSourceIngestModules = new CopyOnWriteArrayList<>();
|
||||
|
||||
/**
|
||||
@ -160,12 +162,12 @@ final class DataSourceIngestJob {
|
||||
* Constructs an object that encapsulates a data source and the ingest
|
||||
* module pipelines used to process it.
|
||||
*
|
||||
* @param parentJob The ingest job of which this data source ingest job is a
|
||||
* part.
|
||||
* @param dataSource The data source to be ingested.
|
||||
* @param settings The settings for the ingest job.
|
||||
* @param parentJob The ingest job of which this data source ingest
|
||||
* job is a part.
|
||||
* @param dataSource The data source to be ingested.
|
||||
* @param settings The settings for the ingest job.
|
||||
* @param runInteractively Whether or not this job should use NetBeans
|
||||
* progress handles.
|
||||
* progress handles.
|
||||
*/
|
||||
DataSourceIngestJob(IngestJob parentJob, Content dataSource, IngestJobSettings settings, boolean runInteractively) {
|
||||
this.parentJob = parentJob;
|
||||
@ -252,12 +254,12 @@ final class DataSourceIngestJob {
|
||||
* collection as they are added to the output collection.
|
||||
*
|
||||
* @param ingestModuleTemplates A mapping of ingest module factory class
|
||||
* names to ingest module templates.
|
||||
* @param pipelineConfig An ordered list of ingest module factory class
|
||||
* names representing an ingest pipeline.
|
||||
* names to ingest module templates.
|
||||
* @param pipelineConfig An ordered list of ingest module factory
|
||||
* class names representing an ingest pipeline.
|
||||
*
|
||||
* @return An ordered list of ingest module templates, i.e., an
|
||||
* uninstantiated pipeline.
|
||||
* uninstantiated pipeline.
|
||||
*/
|
||||
private static List<IngestModuleTemplate> getConfiguredIngestModuleTemplates(Map<String, IngestModuleTemplate> ingestModuleTemplates, List<String> pipelineConfig) {
|
||||
List<IngestModuleTemplate> templates = new ArrayList<>();
|
||||
@ -498,7 +500,7 @@ final class DataSourceIngestJob {
|
||||
String dialogTitle = NbBundle.getMessage(DataSourceIngestJob.this.getClass(), "IngestJob.cancellationDialog.title");
|
||||
JOptionPane.showConfirmDialog(null, panel, dialogTitle, JOptionPane.OK_OPTION, JOptionPane.PLAIN_MESSAGE);
|
||||
if (panel.cancelAllDataSourceIngestModules()) {
|
||||
DataSourceIngestJob.this.cancel();
|
||||
DataSourceIngestJob.this.cancel(IngestJob.CancellationReason.USER_CANCELLED);
|
||||
} else {
|
||||
DataSourceIngestJob.this.cancelCurrentDataSourceIngestModule();
|
||||
}
|
||||
@ -527,7 +529,7 @@ final class DataSourceIngestJob {
|
||||
// the cancel button on the progress bar and the OK button
|
||||
// of a cancelation confirmation dialog supplied by
|
||||
// NetBeans.
|
||||
DataSourceIngestJob.this.cancel();
|
||||
DataSourceIngestJob.this.cancel(IngestJob.CancellationReason.USER_CANCELLED);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
@ -672,8 +674,9 @@ final class DataSourceIngestJob {
|
||||
* @param task A file ingest task.
|
||||
*
|
||||
* @throws InterruptedException if the thread executing this code is
|
||||
* interrupted while blocked on taking from or putting to the file ingest
|
||||
* pipelines collection.
|
||||
* interrupted while blocked on taking from or
|
||||
* putting to the file ingest pipelines
|
||||
* collection.
|
||||
*/
|
||||
void process(FileIngestTask task) throws InterruptedException {
|
||||
try {
|
||||
@ -774,7 +777,7 @@ final class DataSourceIngestJob {
|
||||
* process the data source is known.
|
||||
*
|
||||
* @param workUnits Total number of work units for the processing of the
|
||||
* data source.
|
||||
* data source.
|
||||
*/
|
||||
void switchDataSourceIngestProgressBarToDeterminate(int workUnits) {
|
||||
if (this.doUI && !this.cancelled) {
|
||||
@ -839,7 +842,7 @@ final class DataSourceIngestJob {
|
||||
* mode. The task name is the "subtitle" under the display name.
|
||||
*
|
||||
* @param currentTask The task name.
|
||||
* @param workUnits Number of work units performed.
|
||||
* @param workUnits Number of work units performed.
|
||||
*/
|
||||
void advanceDataSourceIngestProgressBar(String currentTask, int workUnits) {
|
||||
if (this.doUI && !this.cancelled) {
|
||||
@ -910,8 +913,10 @@ final class DataSourceIngestJob {
|
||||
/**
|
||||
* Requests cancellation of ingest, i.e., a shutdown of the data source
|
||||
* level and file level ingest pipelines.
|
||||
*
|
||||
* @param reason The cancellation reason.
|
||||
*/
|
||||
void cancel() {
|
||||
void cancel(IngestJob.CancellationReason reason) {
|
||||
if (this.doUI) {
|
||||
/**
|
||||
* Put a cancellation message on data source level ingest progress
|
||||
@ -951,7 +956,14 @@ final class DataSourceIngestJob {
|
||||
}
|
||||
}
|
||||
|
||||
this.cancelled = true;
|
||||
synchronized (cancellationStateMonitor) {
|
||||
/*
|
||||
* These fields are volatile for reading, synchronized on the
|
||||
* monitor here for writing.
|
||||
*/
|
||||
this.cancelled = true;
|
||||
this.cancellationReason = reason;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tell the task scheduler to cancel all pending tasks, i.e., tasks not
|
||||
@ -964,9 +976,9 @@ final class DataSourceIngestJob {
|
||||
/**
|
||||
* Set the current module name being run and the file name it is running on.
|
||||
* To be used for more detailed cancelling.
|
||||
*
|
||||
*
|
||||
* @param moduleName Name of module currently running.
|
||||
* @param taskName Name of file the module is running on.
|
||||
* @param taskName Name of file the module is running on.
|
||||
*/
|
||||
void setCurrentFileIngestModule(String moduleName, String taskName) {
|
||||
this.currentFileIngestModule = moduleName;
|
||||
@ -983,6 +995,15 @@ final class DataSourceIngestJob {
|
||||
return this.cancelled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the reason this job was cancelled.
|
||||
*
|
||||
* @return The cancellation reason, may be not cancelled.
|
||||
*/
|
||||
IngestJob.CancellationReason getCancellationReason() {
|
||||
return this.cancellationReason;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write ingest module errors to the log.
|
||||
*
|
||||
@ -1019,6 +1040,7 @@ final class DataSourceIngestJob {
|
||||
private final long estimatedFilesToProcess;
|
||||
private final IngestTasksScheduler.IngestJobTasksSnapshot tasksSnapshot;
|
||||
private final boolean jobCancelled;
|
||||
private final IngestJob.CancellationReason jobCancellationReason;
|
||||
private final List<String> cancelledDataSourceModules;
|
||||
|
||||
/**
|
||||
@ -1047,6 +1069,7 @@ final class DataSourceIngestJob {
|
||||
}
|
||||
|
||||
this.jobCancelled = cancelled;
|
||||
this.jobCancellationReason = cancellationReason;
|
||||
this.cancelledDataSourceModules = new ArrayList<>(DataSourceIngestJob.this.cancelledDataSourceIngestModules);
|
||||
|
||||
if (getIngestTasksSnapshot) {
|
||||
@ -1069,7 +1092,7 @@ final class DataSourceIngestJob {
|
||||
* Gets time these statistics were collected.
|
||||
*
|
||||
* @return The statistics collection time as number of milliseconds
|
||||
* since January 1, 1970, 00:00:00 GMT.
|
||||
* since January 1, 1970, 00:00:00 GMT.
|
||||
*/
|
||||
long getSnapshotTime() {
|
||||
return snapShotTime;
|
||||
@ -1099,7 +1122,7 @@ final class DataSourceIngestJob {
|
||||
* Gets the time the ingest job was started.
|
||||
*
|
||||
* @return The start time as number of milliseconds since January 1,
|
||||
* 1970, 00:00:00 GMT.
|
||||
* 1970, 00:00:00 GMT.
|
||||
*/
|
||||
long getJobStartTime() {
|
||||
return jobStartTime;
|
||||
@ -1185,12 +1208,21 @@ final class DataSourceIngestJob {
|
||||
return this.jobCancelled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the reason this job was cancelled.
|
||||
*
|
||||
* @return The cancellation reason, may be not cancelled.
|
||||
*/
|
||||
IngestJob.CancellationReason getCancellationReason() {
|
||||
return this.jobCancellationReason;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a list of the display names of any canceled data source level
|
||||
* ingest modules
|
||||
*
|
||||
* @return A list of canceled data source level ingest module display
|
||||
* names, possibly empty.
|
||||
* names, possibly empty.
|
||||
*/
|
||||
List<String> getCancelledDataSourceIngestModules() {
|
||||
return Collections.unmodifiableList(this.cancelledDataSourceModules);
|
||||
|
@ -37,12 +37,26 @@ import org.sleuthkit.datamodel.Content;
|
||||
*/
|
||||
public final class IngestJob {
|
||||
|
||||
/*
|
||||
* An ingest job can be cancelled for various reasons.
|
||||
*/
|
||||
public enum CancellationReason {
|
||||
|
||||
NOT_CANCELLED,
|
||||
USER_CANCELLED,
|
||||
INGEST_MODULES_STARTUP_FAILED,
|
||||
OUT_OF_DISK_SPACE,
|
||||
SERVICES_DOWN,
|
||||
CASE_CLOSED
|
||||
}
|
||||
|
||||
private static final AtomicLong nextId = new AtomicLong(0L);
|
||||
private final long id;
|
||||
private final Map<Long, DataSourceIngestJob> dataSourceJobs;
|
||||
private final AtomicInteger incompleteJobsCount;
|
||||
private boolean started; // Guarded by this
|
||||
private volatile boolean cancelled;
|
||||
private boolean started;
|
||||
private boolean cancelled;
|
||||
private CancellationReason cancellationReason;
|
||||
|
||||
/**
|
||||
* Constructs an ingest job that runs a collection of data sources through a
|
||||
@ -61,6 +75,7 @@ public final class IngestJob {
|
||||
this.dataSourceJobs.put(dataSourceIngestJob.getId(), dataSourceIngestJob);
|
||||
}
|
||||
incompleteJobsCount = new AtomicInteger(dataSourceJobs.size());
|
||||
cancellationReason = CancellationReason.NOT_CANCELLED;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -108,19 +123,32 @@ public final class IngestJob {
|
||||
}
|
||||
started = true;
|
||||
|
||||
List<DataSourceIngestJob> startedDataSourceJobs = new ArrayList<>();
|
||||
/*
|
||||
* Try to start each data source ingest job. Note that there is a not
|
||||
* unwarranted assumption here that if there is going to be a module
|
||||
* startup failure, it will be for the first data source ingest job.
|
||||
*
|
||||
* TODO (RC): Consider separating module start up from pipeline startup
|
||||
* so that no processing is done if this assumption is false.
|
||||
*/
|
||||
for (DataSourceIngestJob dataSourceJob : this.dataSourceJobs.values()) {
|
||||
errors.addAll(dataSourceJob.start());
|
||||
if (errors.isEmpty()) {
|
||||
IngestManager.getInstance().fireDataSourceAnalysisStarted(id, dataSourceJob.getId(), dataSourceJob.getDataSource());
|
||||
startedDataSourceJobs.add(dataSourceJob);
|
||||
} else {
|
||||
startedDataSourceJobs.stream().forEach((startedDataSourceJob) -> {
|
||||
startedDataSourceJob.cancel();
|
||||
});
|
||||
if (errors.isEmpty() == false) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle start up success or failure.
|
||||
*/
|
||||
if (errors.isEmpty()) {
|
||||
for (DataSourceIngestJob dataSourceJob : this.dataSourceJobs.values()) {
|
||||
IngestManager.getInstance().fireDataSourceAnalysisStarted(id, dataSourceJob.getId(), dataSourceJob.getDataSource());
|
||||
}
|
||||
} else {
|
||||
cancel(CancellationReason.INGEST_MODULES_STARTUP_FAILED);
|
||||
}
|
||||
|
||||
return errors;
|
||||
}
|
||||
|
||||
@ -161,13 +189,37 @@ public final class IngestJob {
|
||||
* unfinished tasks and stopping the ingest pipelines. Returns immediately,
|
||||
* but there may be a delay before all of the ingest modules in the
|
||||
* pipelines respond by stopping processing.
|
||||
*
|
||||
* @deprecated Use cancel(CancellationReason reason) instead
|
||||
*/
|
||||
@Deprecated
|
||||
synchronized public void cancel() {
|
||||
IngestManager ingestManager = IngestManager.getInstance();
|
||||
cancel(CancellationReason.USER_CANCELLED);
|
||||
}
|
||||
|
||||
/**
|
||||
* Requests cancellation of this ingest job, which means discarding
|
||||
* unfinished tasks and stopping the ingest pipelines. Returns immediately,
|
||||
* but there may be a delay before all of the ingest modules in the
|
||||
* pipelines respond by stopping processing.
|
||||
*
|
||||
* @param reason The reason for cancellation.
|
||||
*/
|
||||
synchronized public void cancel(CancellationReason reason) {
|
||||
this.dataSourceJobs.values().stream().forEach((job) -> {
|
||||
job.cancel();
|
||||
job.cancel(reason);
|
||||
});
|
||||
this.cancelled = true;
|
||||
this.cancellationReason = reason;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the reason this job was cancelled.
|
||||
*
|
||||
* @return The cancellation reason, may be not cancelled.
|
||||
*/
|
||||
synchronized public CancellationReason getCancellationReason() {
|
||||
return this.cancellationReason;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -176,7 +228,7 @@ public final class IngestJob {
|
||||
*
|
||||
* @return True or false.
|
||||
*/
|
||||
public boolean isCancelled() {
|
||||
synchronized public boolean isCancelled() {
|
||||
return this.cancelled;
|
||||
}
|
||||
|
||||
@ -208,6 +260,7 @@ public final class IngestJob {
|
||||
private boolean fileIngestRunning;
|
||||
private Date fileIngestStartTime;
|
||||
private final boolean jobCancelled;
|
||||
private final IngestJob.CancellationReason jobCancellationReason;
|
||||
|
||||
/**
|
||||
* A snapshot of the progress of an ingest job on the processing of a
|
||||
@ -241,6 +294,15 @@ public final class IngestJob {
|
||||
return snapshot.isCancelled();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the reason this job was cancelled.
|
||||
*
|
||||
* @return The cancellation reason, may be not cancelled.
|
||||
*/
|
||||
synchronized public CancellationReason getCancellationReason() {
|
||||
return snapshot.getCancellationReason();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a list of the display names of any canceled data source
|
||||
* level ingest modules.
|
||||
@ -280,6 +342,7 @@ public final class IngestJob {
|
||||
}
|
||||
}
|
||||
this.jobCancelled = cancelled;
|
||||
this.jobCancellationReason = cancellationReason;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -312,8 +375,8 @@ public final class IngestJob {
|
||||
}
|
||||
|
||||
/**
|
||||
* Queries whether or not a cancellation request had been issued at the
|
||||
* time the snapshot was taken.
|
||||
* Queries whether or not an ingest job level cancellation request had
|
||||
* been issued at the time the snapshot was taken.
|
||||
*
|
||||
* @return True or false.
|
||||
*/
|
||||
@ -321,6 +384,15 @@ public final class IngestJob {
|
||||
return this.jobCancelled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the reason this job was cancelled.
|
||||
*
|
||||
* @return The cancellation reason, may be not cancelled.
|
||||
*/
|
||||
synchronized public CancellationReason getCancellationReason() {
|
||||
return this.jobCancellationReason;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets snapshots of the progress processing individual data sources.
|
||||
*
|
||||
|
@ -357,7 +357,7 @@ public class IngestManager {
|
||||
}
|
||||
|
||||
// cancel ingest if running
|
||||
cancelAllIngestJobs();
|
||||
cancelAllIngestJobs(IngestJob.CancellationReason.SERVICES_DOWN);
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -627,8 +627,21 @@ public class IngestManager {
|
||||
|
||||
/**
|
||||
* Cancels all ingest jobs in progress.
|
||||
*
|
||||
* @deprecated Use cancelAllIngestJobs(IngestJob.CancellationReason reason)
|
||||
* instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public synchronized void cancelAllIngestJobs() {
|
||||
cancelAllIngestJobs(IngestJob.CancellationReason.USER_CANCELLED);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancels all ingest jobs in progress.
|
||||
*
|
||||
* @param reason The cancellation reason.
|
||||
*/
|
||||
public synchronized void cancelAllIngestJobs(IngestJob.CancellationReason reason) {
|
||||
// Stop creating new ingest jobs.
|
||||
for (Future<Void> handle : ingestJobStarters.values()) {
|
||||
handle.cancel(true);
|
||||
@ -636,7 +649,7 @@ public class IngestManager {
|
||||
|
||||
// Cancel all the jobs already created.
|
||||
for (IngestJob job : this.jobsById.values()) {
|
||||
job.cancel();
|
||||
job.cancel(reason);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -196,7 +196,7 @@ public final class IngestMonitor {
|
||||
/*
|
||||
* Shut down ingest by cancelling all ingest jobs.
|
||||
*/
|
||||
manager.cancelAllIngestJobs();
|
||||
manager.cancelAllIngestJobs(IngestJob.CancellationReason.OUT_OF_DISK_SPACE);
|
||||
String diskPath = root.getAbsolutePath();
|
||||
IngestServices.getInstance().postMessage(IngestMessage.createManagerErrorMessage(
|
||||
NbBundle.getMessage(this.getClass(), "IngestMonitor.mgrErrMsg.lowDiskSpace.title", diskPath),
|
||||
|
Loading…
x
Reference in New Issue
Block a user