From a175329e4f0b71845650d0ea8443996c763e80ee Mon Sep 17 00:00:00 2001
From: Ann Priestman <apriestman@basistech.com>
Date: Wed, 23 May 2018 09:10:40 -0400
Subject: [PATCH] Testing with hashset and sparsebitset

---
 .../sleuthkit/datamodel/AbstractContent.java  |   5 +-
 .../sleuthkit/datamodel/SleuthkitCase.java    | 212 +++++++++---------
 .../org/sleuthkit/datamodel/SleuthkitJNI.java |   1 +
 3 files changed, 104 insertions(+), 114 deletions(-)
 mode change 100755 => 100644 bindings/java/src/org/sleuthkit/datamodel/SleuthkitCase.java

diff --git a/bindings/java/src/org/sleuthkit/datamodel/AbstractContent.java b/bindings/java/src/org/sleuthkit/datamodel/AbstractContent.java
index 32384265c..71fd39e59 100644
--- a/bindings/java/src/org/sleuthkit/datamodel/AbstractContent.java
+++ b/bindings/java/src/org/sleuthkit/datamodel/AbstractContent.java
@@ -90,9 +90,10 @@ public boolean hasChildren() throws TskCoreException {
 			return hasChildren;
 		}
 
-		childrenCount = this.getSleuthkitCase().getContentChildrenCount(this);
+		//childrenCount = this.getSleuthkitCase().getContentChildrenCount(this);
+		hasChildren = this.getSleuthkitCase().getHasChildren(this.objId);
 
-		hasChildren = childrenCount > 0;
+		//hasChildren = childrenCount > 0;
 		checkedHasChildren = true;
 
 		return hasChildren;
diff --git a/bindings/java/src/org/sleuthkit/datamodel/SleuthkitCase.java b/bindings/java/src/org/sleuthkit/datamodel/SleuthkitCase.java
old mode 100755
new mode 100644
index d7e015230..cafc81b15
--- a/bindings/java/src/org/sleuthkit/datamodel/SleuthkitCase.java
+++ b/bindings/java/src/org/sleuthkit/datamodel/SleuthkitCase.java
@@ -88,6 +88,7 @@
 public class SleuthkitCase {
 
 	private static final int MAX_DB_NAME_LEN_BEFORE_TIMESTAMP = 47;
+	private static int getContentChildrenCountCount = 0;
 
 	/**
 	 * This must be the same as TSK_SCHEMA_VER and TSK_SCHEMA_MINOR_VER in
@@ -121,6 +122,8 @@ public class SleuthkitCase {
 	private Map<Integer, BlackboardAttribute.Type> typeIdToAttributeTypeMap;
 	private Map<String, BlackboardArtifact.Type> typeNameToArtifactTypeMap;
 	private Map<String, BlackboardAttribute.Type> typeNameToAttributeTypeMap;
+	//private Set<Long> hasChildren;
+	private SparseBitSet hasChildrenBitSet;
 
 	private long nextArtifactId; // Used to ensure artifact ids come from the desired range.
 	// This read/write lock is used to implement a layer of locking on top of
@@ -274,8 +277,46 @@ private void init() throws Exception {
 		initIngestStatusTypes(connection);
 		initReviewStatuses(connection);
 		initEncodingTypes(connection);
+
+		
+		long timestamp = System.currentTimeMillis();
+		//hasChildren = new HashSet<Long>();
+		hasChildrenBitSet = new SparseBitSet(); // Could query for current highest obj id
+		Statement statement = null;
+		ResultSet resultSet = null;
+		acquireSingleUserCaseWriteLock();
+		try {
+			statement = connection.createStatement();
+			try {
+				//resultSet = statement.executeQuery("select distinct obj_id as par_obj_id from blackboard_artifacts where artifact_type_id = 13 or artifact_type_id = 24 union select distinct par_obj_id from tsk_objects where type=4"); //NON-NLS
+				resultSet = statement.executeQuery("select distinct par_obj_id from tsk_objects"); //NON-NLS
+				while(resultSet.next()) {
+					//hasChildren.add(resultSet.getLong("par_obj_id"));
+					hasChildrenBitSet.set((int)(resultSet.getLong("par_obj_id")));
+				}
+			} catch (SQLException ex) {//NON-NLS
+				
+				resultSet.close();
+				resultSet = null;
+			}
+		} finally {
+			closeResultSet(resultSet);
+			closeStatement(statement);
+			releaseSingleUserCaseWriteLock();
+		}
+		//System.out.println("\n###### Number nodes with children: " + hasChildren.size());
+		System.out.println("\n###### Bit set stats: " + hasChildrenBitSet.statistics());
+		long delay = System.currentTimeMillis() - timestamp;
+		System.out.println("   Elapsed milliseconds: " + delay);
+		
+
 		connection.close();
 	}
+	
+	public boolean getHasChildren(Long objId) {
+		//return hasChildren.contains(objId);
+		return hasChildrenBitSet.get(objId.intValue());
+	}
 
 	/**
 	 * Returns an instance of CommunicationsManager
@@ -3482,17 +3523,10 @@ private BlackboardArtifact newBlackboardArtifact(int artifact_type_id, long obj_
 		acquireSingleUserCaseWriteLock();
 		ResultSet resultSet = null;
 		try {
-
-			PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_OBJECT, Statement.RETURN_GENERATED_KEYS);
-			statement.clearParameters();
-			statement.setLong(1, obj_id);
-			statement.setInt(2, TskData.ObjectType.ARTIFACT.getObjectType());
-			connection.executeUpdate(statement);
-			resultSet = statement.getGeneratedKeys();
-			resultSet.next();
-			long artifact_obj_id = resultSet.getLong(1); //last_insert_rowid()
+			long artifact_obj_id = addObject(obj_id, TskData.ObjectType.ARTIFACT.getObjectType(), connection);
 			long data_source_obj_id = getDataSourceObjectId(connection, obj_id);
 
+			PreparedStatement statement = null;
 			if (dbType == DbType.POSTGRESQL) {
 				statement = connection.getPreparedStatement(PREPARED_STATEMENT.POSTGRESQL_INSERT_ARTIFACT, Statement.RETURN_GENERATED_KEYS);
 				statement.clearParameters();
@@ -3575,6 +3609,13 @@ boolean getContentHasChildren(Content content) throws TskCoreException {
 	 *                          within tsk core
 	 */
 	int getContentChildrenCount(Content content) throws TskCoreException {
+		
+		if( ! this.getHasChildren(content.getId())) {
+			return 0;
+		}
+		
+		getContentChildrenCountCount++;
+		//System.out.println("getContentChildrenCountCount: " + getContentChildrenCountCount + " Current file: " + content.getName());
 		CaseDbConnection connection = connections.getConnection();
 		acquireSingleUserCaseReadLock();
 		ResultSet rs = null;
@@ -4422,6 +4463,37 @@ public VirtualDirectory addVirtualDirectory(long parentId, String directoryName)
 			releaseSingleUserCaseWriteLock();
 		}
 	}
+	
+	private long addObject(long parentId, int objectType, CaseDbConnection connection) throws SQLException {
+		ResultSet resultSet = null;
+		acquireSingleUserCaseWriteLock();
+		try {
+			// INSERT INTO tsk_objects (par_obj_id, type) VALUES (?, ?)
+			PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_OBJECT, Statement.RETURN_GENERATED_KEYS);
+			statement.clearParameters();
+			if (parentId != 0) {
+				statement.setLong(1, parentId);
+			} else {
+				statement.setNull(1, java.sql.Types.BIGINT);
+			}
+			statement.setInt(2, objectType);
+			connection.executeUpdate(statement);
+			resultSet = statement.getGeneratedKeys();
+		
+			if(resultSet.next()) {
+				if(parentId != 0) {
+					//this.hasChildren.add(parentId);
+					this.hasChildrenBitSet.set((int)parentId);
+				}
+				return resultSet.getLong(1); //last_insert_rowid()
+			} else {
+				throw new SQLException("Error inserting object with parent " + parentId + " into tsk_objects");
+			}
+		} finally {
+			closeResultSet(resultSet);
+			releaseSingleUserCaseWriteLock();
+		}
+	}
 
 	/**
 	 * Adds a virtual directory to the database and returns a VirtualDirectory
@@ -4460,25 +4532,13 @@ public VirtualDirectory addVirtualDirectory(long parentId, String directoryName,
 			}
 
 			// Insert a row for the virtual directory into the tsk_objects table.
-			// INSERT INTO tsk_objects (par_obj_id, type) VALUES (?, ?)
-			PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_OBJECT, Statement.RETURN_GENERATED_KEYS);
-			statement.clearParameters();
-			if (parentId != 0) {
-				statement.setLong(1, parentId);
-			} else {
-				statement.setNull(1, java.sql.Types.BIGINT);
-			}
-			statement.setInt(2, TskData.ObjectType.ABSTRACTFILE.getObjectType());
-			connection.executeUpdate(statement);
-			resultSet = statement.getGeneratedKeys();
-			resultSet.next();
-			long newObjId = resultSet.getLong(1); //last_insert_rowid()
+			long newObjId = addObject(parentId, TskData.ObjectType.ABSTRACTFILE.getObjectType(), connection);		
 
 			// Insert a row for the virtual directory into the tsk_files table.
 			// INSERT INTO tsk_files (obj_id, fs_obj_id, name, type, has_path, dir_type, meta_type,
 			// dir_flags, meta_flags, size, ctime, crtime, atime, mtime, parent_path, data_source_obj_id,extension)
 			// VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,?)
-			statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE);
+			PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE);
 			statement.clearParameters();
 			statement.setLong(1, newObjId);
 
@@ -4618,25 +4678,13 @@ public LocalDirectory addLocalDirectory(long parentId, String directoryName, Cas
 			}
 
 			// Insert a row for the local directory into the tsk_objects table.
-			// INSERT INTO tsk_objects (par_obj_id, type) VALUES (?, ?)
-			PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_OBJECT, Statement.RETURN_GENERATED_KEYS);
-			statement.clearParameters();
-			if (parentId != 0) {
-				statement.setLong(1, parentId);
-			} else {
-				statement.setNull(1, java.sql.Types.BIGINT);
-			}
-			statement.setInt(2, TskData.ObjectType.ABSTRACTFILE.getObjectType());
-			connection.executeUpdate(statement);
-			resultSet = statement.getGeneratedKeys();
-			resultSet.next();
-			long newObjId = resultSet.getLong(1); //last_insert_rowid()
+			long newObjId = addObject(parentId, TskData.ObjectType.ABSTRACTFILE.getObjectType(), connection);
 
 			// Insert a row for the local directory into the tsk_files table.
 			// INSERT INTO tsk_files (obj_id, fs_obj_id, name, type, has_path, dir_type, meta_type,
 			// dir_flags, meta_flags, size, ctime, crtime, atime, mtime, parent_path, data_source_obj_id)
 			// VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
-			statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE);
+			PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE);
 			statement.clearParameters();
 			statement.setLong(1, newObjId);
 
@@ -4717,22 +4765,11 @@ public LocalDirectory addLocalDirectory(long parentId, String directoryName, Cas
 	public LocalFilesDataSource addLocalFilesDataSource(String deviceId, String rootDirectoryName, String timeZone, CaseDbTransaction transaction) throws TskCoreException {
 		acquireSingleUserCaseWriteLock();
 		Statement statement = null;
-		ResultSet resultSet = null;
 		try {
 			// Insert a row for the root virtual directory of the data source
 			// into the tsk_objects table.
-			// INSERT INTO tsk_objects (par_obj_id, type) VALUES (?, ?)
 			CaseDbConnection connection = transaction.getConnection();
-			PreparedStatement preparedStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_OBJECT, Statement.RETURN_GENERATED_KEYS);
-			preparedStatement.clearParameters();
-			preparedStatement.setNull(1, java.sql.Types.BIGINT);
-			preparedStatement.setInt(2, TskData.ObjectType.ABSTRACTFILE.getObjectType());
-			connection.executeUpdate(preparedStatement);
-			resultSet = preparedStatement.getGeneratedKeys();
-			resultSet.next();
-			long newObjId = resultSet.getLong(1); //last_insert_rowid()
-			resultSet.close();
-			resultSet = null;
+			long newObjId = addObject(0, TskData.ObjectType.ABSTRACTFILE.getObjectType(), connection);
 
 			// Insert a row for the virtual directory of the data source into
 			// the data_source_info table.
@@ -4747,7 +4784,7 @@ public LocalFilesDataSource addLocalFilesDataSource(String deviceId, String root
 			// dir_type, meta_type, dir_flags, meta_flags, size, ctime, crtime,
 			// atime, mtime, parent_path, data_source_obj_id, extension)
 			// VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,?)
-			preparedStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE);
+			PreparedStatement preparedStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE);
 			preparedStatement.clearParameters();
 			preparedStatement.setLong(1, newObjId);
 			preparedStatement.setNull(2, java.sql.Types.BIGINT);
@@ -4779,7 +4816,6 @@ public LocalFilesDataSource addLocalFilesDataSource(String deviceId, String root
 		} catch (SQLException ex) {
 			throw new TskCoreException(String.format("Error creating local files data source with device id %s and directory name %s", deviceId, rootDirectoryName), ex);
 		} finally {
-			closeResultSet(resultSet);
 			closeStatement(statement);
 			releaseSingleUserCaseWriteLock();
 		}
@@ -4858,14 +4894,7 @@ public final List<LayoutFile> addLayoutFiles(Content parent, List<TskFileRange>
 				 * table: INSERT INTO tsk_objects (par_obj_id, type) VALUES (?,
 				 * ?)
 				 */
-				PreparedStatement prepStmt = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_OBJECT, Statement.RETURN_GENERATED_KEYS);
-				prepStmt.clearParameters();
-				prepStmt.setLong(1, parent.getId()); // par_obj_id
-				prepStmt.setLong(2, TskData.ObjectType.ABSTRACTFILE.getObjectType()); // type
-				connection.executeUpdate(prepStmt);
-				resultSet = prepStmt.getGeneratedKeys();
-				resultSet.next();
-				long fileRangeId = resultSet.getLong(1); //last_insert_rowid()
+				long fileRangeId = addObject(parent.getId(), TskData.ObjectType.ABSTRACTFILE.getObjectType(), connection);
 				long end_byte_in_parent = fileRange.getByteStart() + fileRange.getByteLen() - 1;
 				/*
 				 * Insert a row for the Tsk file range into the tsk_files table:
@@ -4875,7 +4904,7 @@ public final List<LayoutFile> addLayoutFiles(Content parent, List<TskFileRange>
 				 * data_source_obj_id,extension) VALUES (?, ?, ?, ?, ?, ?, ?, ?,
 				 * ?, ?, ?, ?, ?, ?, ?, ?,?)
 				 */
-				prepStmt = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE);
+				PreparedStatement prepStmt = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE);
 				prepStmt.clearParameters();
 				prepStmt.setLong(1, fileRangeId); // obj_id	from tsk_objects			
 				prepStmt.setNull(2, java.sql.Types.BIGINT); // fs_obj_id				
@@ -5052,14 +5081,7 @@ public final List<LayoutFile> addCarvedFiles(CarvingResult carvingResult) throws
 				 * Insert a row for the carved file into the tsk_objects table:
 				 * INSERT INTO tsk_objects (par_obj_id, type) VALUES (?, ?)
 				 */
-				PreparedStatement prepStmt = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_OBJECT, Statement.RETURN_GENERATED_KEYS);
-				prepStmt.clearParameters();
-				prepStmt.setLong(1, carvedFilesDir.getId()); // par_obj_id
-				prepStmt.setLong(2, TskData.ObjectType.ABSTRACTFILE.getObjectType()); // type
-				connection.executeUpdate(prepStmt);
-				resultSet = prepStmt.getGeneratedKeys();
-				resultSet.next();
-				long carvedFileId = resultSet.getLong(1); //last_insert_rowid()
+				long carvedFileId = addObject(carvedFilesDir.getId(), TskData.ObjectType.ABSTRACTFILE.getObjectType(), connection);
 
 				/*
 				 * Insert a row for the carved file into the tsk_files table:
@@ -5069,7 +5091,7 @@ public final List<LayoutFile> addCarvedFiles(CarvingResult carvingResult) throws
 				 * data_source_obj_id,extenion) VALUES (?, ?, ?, ?, ?, ?, ?, ?,
 				 * ?, ?, ?, ?, ?, ?, ?, ?,?)
 				 */
-				prepStmt = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE);
+				PreparedStatement prepStmt = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE);
 				prepStmt.clearParameters();
 				prepStmt.setLong(1, carvedFileId); // obj_id
 				if (root instanceof FileSystem) {
@@ -5202,7 +5224,6 @@ public DerivedFile addDerivedFile(String fileName, String localPath,
 			String otherDetails, TskData.EncodingType encodingType) throws TskCoreException {
 		CaseDbConnection connection = connections.getConnection();
 		acquireSingleUserCaseWriteLock();
-		ResultSet rs = null;
 		try {
 			connection.beginTransaction();
 
@@ -5216,22 +5237,13 @@ public DerivedFile addDerivedFile(String fileName, String localPath,
 
 			// Insert a row for the derived file into the tsk_objects table.
 			// INSERT INTO tsk_objects (par_obj_id, type) VALUES (?, ?)
-			PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_OBJECT, Statement.RETURN_GENERATED_KEYS);
-			statement.clearParameters();
-			statement.setLong(1, parentId);
-			statement.setLong(2, TskData.ObjectType.ABSTRACTFILE.getObjectType());
-			connection.executeUpdate(statement);
-			rs = statement.getGeneratedKeys();
-			rs.next();
-			long newObjId = rs.getLong(1); //last_insert_rowid()
-			rs.close();
-			rs = null;
+			long newObjId = addObject(parentId, TskData.ObjectType.ABSTRACTFILE.getObjectType(), connection);
 
 			// Insert a row for the virtual directory into the tsk_files table.
 			// INSERT INTO tsk_files (obj_id, fs_obj_id, name, type, has_path, dir_type, meta_type,
 			// dir_flags, meta_flags, size, ctime, crtime, atime, mtime, parent_path, data_source_obj_id, extension)
 			// VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,?)
-			statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE);
+			PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE);
 			statement.clearParameters();
 			statement.setLong(1, newObjId);
 
@@ -5295,7 +5307,6 @@ public DerivedFile addDerivedFile(String fileName, String localPath,
 			connection.rollbackTransaction();
 			throw new TskCoreException("Failed to add derived file to case database", ex);
 		} finally {
-			closeResultSet(rs);
 			connection.close();
 			releaseSingleUserCaseWriteLock();
 		}
@@ -5475,29 +5486,17 @@ public LocalFile addLocalFile(String fileName, String localPath,
 		CaseDbConnection connection = transaction.getConnection();
 		acquireSingleUserCaseWriteLock();
 		Statement queryStatement = null;
-		ResultSet resultSet = null;
 		try {
 
 			// Insert a row for the local/logical file into the tsk_objects table.
 			// INSERT INTO tsk_objects (par_obj_id, type) VALUES (?, ?)
-			PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_OBJECT, Statement.RETURN_GENERATED_KEYS);
-			statement.clearParameters();
-			statement.setLong(1, parent.getId());
-			statement.setLong(2, TskData.ObjectType.ABSTRACTFILE.getObjectType());
-			connection.executeUpdate(statement);
-			resultSet = statement.getGeneratedKeys();
-			if (!resultSet.next()) {
-				throw new TskCoreException(String.format("Failed to INSERT local file %s (%s) with parent id %d in tsk_objects table", fileName, localPath, parent.getId()));
-			}
-			long objectId = resultSet.getLong(1); //last_insert_rowid()
-			resultSet.close();
-			resultSet = null;
+			long objectId = addObject(parent.getId(), TskData.ObjectType.ABSTRACTFILE.getObjectType(), connection);
 
 			// Insert a row for the local/logical file into the tsk_files table.
 			// INSERT INTO tsk_files (obj_id, fs_obj_id, name, type, has_path, dir_type, meta_type,
 			// dir_flags, meta_flags, size, ctime, crtime, atime, mtime, parent_path, data_source_obj_id,extension)
 			// VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,?)
-			statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE);
+			PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE);
 			statement.clearParameters();
 			statement.setLong(1, objectId);
 			statement.setNull(2, java.sql.Types.BIGINT); // Not part of a file system
@@ -5545,7 +5544,6 @@ public LocalFile addLocalFile(String fileName, String localPath,
 		} catch (SQLException ex) {
 			throw new TskCoreException(String.format("Failed to INSERT local file %s (%s) with parent id %d in tsk_files table", fileName, localPath, parent.getId()), ex);
 		} finally {
-			closeResultSet(resultSet);
 			closeStatement(queryStatement);
 			releaseSingleUserCaseWriteLock();
 		}
@@ -8161,24 +8159,14 @@ public Report addReport(String localPath, String sourceModuleName, String report
 		try {
 			// Insert a row for the report into the tsk_objects table.
 			// INSERT INTO tsk_objects (par_obj_id, type) VALUES (?, ?)
-			PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_OBJECT, Statement.RETURN_GENERATED_KEYS);
-			statement.clearParameters();
-			if (parent == null) {
-				statement.setNull(1, java.sql.Types.BIGINT);
-			} else {
-				statement.setLong(1, parent.getId());
-			}
-
-			statement.setLong(2, TskData.ObjectType.REPORT.getObjectType());
-			connection.executeUpdate(statement);
-			resultSet = statement.getGeneratedKeys();
-			if (!resultSet.next()) {
-				throw new TskCoreException(String.format("Failed to INSERT report %s (%s) in tsk_objects table", reportName, localPath));
+			long parentObjId = 0;
+			if(parent != null) {
+				parentObjId = parent.getId();
 			}
-			long objectId = resultSet.getLong(1); //last_insert_rowid()
+			long objectId = addObject(parentObjId, TskData.ObjectType.REPORT.getObjectType(), connection);
 
 			// INSERT INTO reports (obj_id, path, crtime, src_module_name, display_name) VALUES (?, ?, ?, ?, ?)
-			statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_REPORT);
+			PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_REPORT);
 			statement.clearParameters();
 			statement.setLong(1, objectId);
 			statement.setString(2, relativePath);
diff --git a/bindings/java/src/org/sleuthkit/datamodel/SleuthkitJNI.java b/bindings/java/src/org/sleuthkit/datamodel/SleuthkitJNI.java
index de51aa9c1..124e5b713 100644
--- a/bindings/java/src/org/sleuthkit/datamodel/SleuthkitJNI.java
+++ b/bindings/java/src/org/sleuthkit/datamodel/SleuthkitJNI.java
@@ -299,6 +299,7 @@ private AddImageProcess(String timeZone, boolean addUnallocSpace, boolean skipFa
 			 */
 			public void run(String deviceId, String[] imageFilePaths, int sectorSize) throws TskCoreException, TskDataException {
 				long imageHandle = 0;
+				System.out.println("\n\n#### Adding " + imageFilePaths[0] + " to database");
 				synchronized (this) {
 					if (0 != tskAutoDbPointer) {
 						throw new TskCoreException("Add image process already started");
-- 
GitLab