diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java index 63cffcaa0c..9fea3b7cd9 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java @@ -778,8 +778,8 @@ public class Case { * * @param caseName The case name. * - * @return The case name transformed into a corresponding PostgreSQL - * case database name. + * @return The case name transformed into a corresponding PostgreSQL case + * database name. */ private static String caseNameToCaseDbName(String caseName) throws IllegalCaseNameException { /* @@ -961,31 +961,6 @@ public class Case { } } - /** - * Acquires an exclusive case name lock. - * - * @param caseName The case name (not the case display name, which can be - * changed by a user). - * - * @return The lock. - * - * @throws CaseActionException with a user-friendly message if the lock - * cannot be acquired. - */ - @Messages({"Case.creationException.couldNotAcquireNameLock=Failed to get lock on case name"}) - private static CoordinationService.Lock acquireExclusiveCaseNameLock(String caseName) throws CaseActionException { - try { - Lock lock = CoordinationService.getInstance().tryGetExclusiveLock(CategoryNode.CASES, caseName, NAME_LOCK_TIMOUT_HOURS, TimeUnit.HOURS); - if (null == lock) { - throw new CaseActionException(Bundle.Case_creationException_couldNotAcquireNameLock()); - } - return lock; - - } catch (InterruptedException | CoordinationServiceException ex) { - throw new CaseActionException(Bundle.Case_creationException_couldNotAcquireNameLock(), ex); - } - } - /** * Acquires an exclusive case resources lock. * @@ -1679,37 +1654,30 @@ public class Case { open(caseDir, caseName, caseDisplayName, caseNumber, examiner, caseType, progressIndicator); } else { /* - * First, acquire an exclusive case name lock to prevent two - * nodes from creating the same case at the same time. + * Acquire a shared case directory lock that will be held as + * long as this node has this case open. This will prevent + * deletion of the case by another node. */ progressIndicator.start(Bundle.Case_progressMessage_openingCaseResources()); - try (CoordinationService.Lock nameLock = Case.acquireExclusiveCaseNameLock(caseName)) { - assert (null != nameLock); - /* - * Next, acquire a shared case directory lock that will be - * held as long as this node has this case open. This will - * prevent deletion of the case by another node. - */ - acquireSharedCaseDirLock(caseDir); - /* - * Finally, acquire an exclusive case resources lock to - * ensure only one node at a time can - * create/open/upgrade/close the case resources. - */ - try (CoordinationService.Lock resourcesLock = acquireExclusiveCaseResourcesLock(caseName)) { - assert (null != resourcesLock); - try { - open(caseDir, caseName, caseDisplayName, caseNumber, examiner, caseType, progressIndicator); - } catch (CaseActionException ex) { - /* - * Release the case directory lock immediately if - * there was a problem opening the case. - */ - if (CaseType.MULTI_USER_CASE == caseType) { - releaseSharedCaseDirLock(caseName); - } - throw ex; + acquireSharedCaseDirLock(caseDir); + /* + * Acquire an exclusive case resources lock to ensure only one + * node at a time can create/open/upgrade/close the case + * resources. + */ + try (CoordinationService.Lock resourcesLock = acquireExclusiveCaseResourcesLock(caseName)) { + assert (null != resourcesLock); + try { + open(caseDir, caseName, caseDisplayName, caseNumber, examiner, caseType, progressIndicator); + } catch (CaseActionException ex) { + /* + * Release the case directory lock immediately if there + * was a problem opening the case. + */ + if (CaseType.MULTI_USER_CASE == caseType) { + releaseSharedCaseDirLock(caseName); } + throw ex; } } } diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java index dd370b0534..c347ec39d2 100644 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java @@ -1932,38 +1932,50 @@ public final class AutoIngestManager extends Observable implements PropertyChang } SYS_LOGGER.log(Level.INFO, "Opening case {0} ({1}) for {2}", new Object[]{caseDisplayName, caseName, manifest.getFilePath()}); currentJob.setStage(AutoIngestJob.Stage.OPENING_CASE); - try { - Path caseDirectoryPath = PathUtils.findCaseDirectory(rootOutputDirectory, caseName); - if (null != caseDirectoryPath) { - Path metadataFilePath = caseDirectoryPath.resolve(caseName + CaseMetadata.getFileExtension()); - Case.openAsCurrentCase(metadataFilePath.toString()); - } else { - caseDirectoryPath = PathUtils.createCaseFolderPath(rootOutputDirectory, caseName); - Case.createAsCurrentCase(caseDirectoryPath.toString(), caseName, "", "", CaseType.MULTI_USER_CASE); - /* - * Sleep a bit before releasing the lock to ensure that the - * new case folder is visible on the network. - */ - Thread.sleep(AutoIngestUserPreferences.getSecondsToSleepBetweenCases() * 1000); - } - currentJob.setCaseDirectoryPath(caseDirectoryPath); - Case caseForJob = Case.getCurrentCase(); - SYS_LOGGER.log(Level.INFO, "Opened case {0} for {1}", new Object[]{caseForJob.getName(), manifest.getFilePath()}); - return caseForJob; + /* + * Acquire and hold a case name lock so that only one node at as + * time can scan the output directory at a time. This prevents + * making duplicate cases for the saem auto ingest case. + */ + try (Lock caseLock = coordinationService.tryGetExclusiveLock(CoordinationService.CategoryNode.CASES, caseName, 30, TimeUnit.MINUTES)) { + if (null != caseLock) { + try { + Path caseDirectoryPath = PathUtils.findCaseDirectory(rootOutputDirectory, caseName); + if (null != caseDirectoryPath) { + Path metadataFilePath = caseDirectoryPath.resolve(caseName + CaseMetadata.getFileExtension()); + Case.openAsCurrentCase(metadataFilePath.toString()); + } else { + caseDirectoryPath = PathUtils.createCaseFolderPath(rootOutputDirectory, caseName); + Case.createAsCurrentCase(caseDirectoryPath.toString(), caseName, "", "", CaseType.MULTI_USER_CASE); + /* + * Sleep a bit before releasing the lock to ensure + * that the new case folder is visible on the + * network. + */ + Thread.sleep(AutoIngestUserPreferences.getSecondsToSleepBetweenCases() * 1000); + } + currentJob.setCaseDirectoryPath(caseDirectoryPath); + Case caseForJob = Case.getCurrentCase(); + SYS_LOGGER.log(Level.INFO, "Opened case {0} for {1}", new Object[]{caseForJob.getName(), manifest.getFilePath()}); + return caseForJob; - } catch (CaseActionException ex) { - throw new CaseManagementException(String.format("Error creating or opening case %s (%s) for %s", manifest.getCaseName(), caseName, manifest.getFilePath()), ex); - } catch (IllegalStateException ex) { - /* - * Deal with the unfortunate fact that Case.getCurrentCase - * throws IllegalStateException. - */ - throw new CaseManagementException(String.format("Error getting current case %s (%s) for %s", caseName, manifest.getCaseName(), manifest.getFilePath()), ex); + } catch (CaseActionException ex) { + throw new CaseManagementException(String.format("Error creating or opening case %s (%s) for %s", manifest.getCaseName(), caseName, manifest.getFilePath()), ex); + } catch (IllegalStateException ex) { + /* + * Deal with the unfortunate fact that + * Case.getCurrentCase throws IllegalStateException. + */ + throw new CaseManagementException(String.format("Error getting current case %s (%s) for %s", caseName, manifest.getCaseName(), manifest.getFilePath()), ex); + } + } else { + throw new CaseManagementException(String.format("Timed out acquiring case name lock for %s for %s", manifest.getCaseName(), manifest.getFilePath())); + } } } /** - * Runs the ingest porocess for the current job. + * Runs the ingest process for the current job. * * @param caseForJob The case for the job. *