Merge pull request #4000 from raman-bt/1003_casedbaccessmgr_transactions

1003 : add transactions support in CaseDbAccessManager api
This commit is contained in:
Richard Cordovano 2018-08-01 13:16:53 -04:00 committed by GitHub
commit e12c35ad5c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 119 additions and 39 deletions

View File

@ -88,6 +88,7 @@ import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.DataSource; import org.sleuthkit.datamodel.DataSource;
import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.SleuthkitCase.CaseDbTransaction;
import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.TskData; import org.sleuthkit.datamodel.TskData;
@ -769,7 +770,7 @@ public final class ImageGalleryController {
abstract List<AbstractFile> getFiles() throws TskCoreException; abstract List<AbstractFile> getFiles() throws TskCoreException;
abstract void processFile(final AbstractFile f, DrawableDB.DrawableTransaction tr) throws TskCoreException; abstract void processFile(final AbstractFile f, DrawableDB.DrawableTransaction tr, CaseDbTransaction caseDBTransaction) throws TskCoreException;
@Override @Override
public void run() { public void run() {
@ -777,6 +778,9 @@ public final class ImageGalleryController {
progressHandle.start(); progressHandle.start();
updateMessage(Bundle.CopyAnalyzedFiles_populatingDb_status()); updateMessage(Bundle.CopyAnalyzedFiles_populatingDb_status());
DrawableDB.DrawableTransaction drawableDbTransaction = null;
CaseDbTransaction caseDbTransaction = null;
try { try {
//grab all files with supported extension or detected mime types //grab all files with supported extension or detected mime types
final List<AbstractFile> files = getFiles(); final List<AbstractFile> files = getFiles();
@ -785,22 +789,22 @@ public final class ImageGalleryController {
updateProgress(0.0); updateProgress(0.0);
taskCompletionStatus = true; taskCompletionStatus = true;
int workDone = 0;
//do in transaction //do in transaction
DrawableDB.DrawableTransaction tr = taskDB.beginTransaction(); drawableDbTransaction = taskDB.beginTransaction();
int workDone = 0; caseDbTransaction = tskCase.beginTransaction();
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 or interrupted: not all contents may be transfered to drawable database."); //NON-NLS
taskCompletionStatus = false;
progressHandle.finish(); progressHandle.finish();
break; break;
} }
if (Thread.interrupted()) {
LOGGER.log(Level.WARNING, "BulkTransferTask interrupted. Ignoring it to update the contents of drawable database."); //NON-NLS
}
processFile(f, tr); processFile(f, drawableDbTransaction, caseDbTransaction);
workDone++; workDone++;
progressHandle.progress(f.getName(), workDone); progressHandle.progress(f.getName(), workDone);
@ -814,9 +818,20 @@ public final class ImageGalleryController {
updateProgress(1.0); updateProgress(1.0);
progressHandle.start(); progressHandle.start();
taskDB.commitTransaction(tr, true); taskDB.commitTransaction(drawableDbTransaction, true);
caseDbTransaction.commit();
} catch (TskCoreException ex) { } catch (TskCoreException ex) {
if (null != drawableDbTransaction) {
taskDB.rollbackTransaction(drawableDbTransaction);
}
if (null != caseDbTransaction) {
try {
caseDbTransaction.rollback();
} catch (TskCoreException ex2) {
LOGGER.log(Level.SEVERE, "Error in trying to rollback transaction", ex2); //NON-NLS
}
}
progressHandle.progress(Bundle.BulkTask_stopCopy_status()); progressHandle.progress(Bundle.BulkTask_stopCopy_status());
LOGGER.log(Level.WARNING, "Stopping copy to drawable db task. Failed to transfer all database contents", ex); //NON-NLS LOGGER.log(Level.WARNING, "Stopping copy to drawable db task. Failed to transfer all database contents", ex); //NON-NLS
MessageNotifyUtil.Notify.warn(Bundle.BulkTask_errPopulating_errMsg(), ex.getMessage()); MessageNotifyUtil.Notify.warn(Bundle.BulkTask_errPopulating_errMsg(), ex.getMessage());
@ -865,7 +880,7 @@ public final class ImageGalleryController {
} }
@Override @Override
void processFile(AbstractFile f, DrawableDB.DrawableTransaction tr) throws TskCoreException { void processFile(AbstractFile f, DrawableDB.DrawableTransaction tr, CaseDbTransaction caseDbTransaction) throws TskCoreException {
final boolean known = f.getKnown() == TskData.FileKnown.KNOWN; final boolean known = f.getKnown() == TskData.FileKnown.KNOWN;
if (known) { if (known) {
@ -875,16 +890,17 @@ public final class ImageGalleryController {
try { try {
//supported mimetype => analyzed //supported mimetype => analyzed
if ( null != f.getMIMEType() && FileTypeUtils.hasDrawableMIMEType(f)) { if ( null != f.getMIMEType() && FileTypeUtils.hasDrawableMIMEType(f)) {
taskDB.updateFile(DrawableFile.create(f, true, false), tr); taskDB.updateFile(DrawableFile.create(f, true, false), tr, caseDbTransaction );
} }
else { //unsupported mimtype => analyzed but shouldn't include else {
// if mimetype of the file hasn't been ascertained, ingest might not have completed yet. // if mimetype of the file hasn't been ascertained, ingest might not have completed yet.
if (null == f.getMIMEType()) { if (null == f.getMIMEType()) {
this.setTaskCompletionStatus(false); this.setTaskCompletionStatus(false);
} } else {
//unsupported mimtype => analyzed but shouldn't include
taskDB.removeFile(f.getId(), tr); taskDB.removeFile(f.getId(), tr);
} }
}
} catch (FileTypeDetector.FileTypeDetectorInitException ex) { } catch (FileTypeDetector.FileTypeDetectorInitException ex) {
throw new TskCoreException("Failed to initialize FileTypeDetector.", ex); throw new TskCoreException("Failed to initialize FileTypeDetector.", ex);
} }
@ -927,8 +943,8 @@ public final class ImageGalleryController {
} }
@Override @Override
void processFile(final AbstractFile f, DrawableDB.DrawableTransaction tr) { void processFile(final AbstractFile f, DrawableDB.DrawableTransaction tr, CaseDbTransaction caseDBTransaction) {
taskDB.insertFile(DrawableFile.create(f, false, false), tr); taskDB.insertFile(DrawableFile.create(f, false, false), tr, caseDBTransaction);
} }
@Override @Override
@ -996,13 +1012,12 @@ public final class ImageGalleryController {
} }
} }
} catch (TskCoreException | FileTypeDetector.FileTypeDetectorInitException ex) { } catch (TskCoreException | FileTypeDetector.FileTypeDetectorInitException ex) {
//TODO: What to do here?
LOGGER.log(Level.SEVERE, "Unable to determine if file is drawable and not known. Not making any changes to DB", ex); //NON-NLS LOGGER.log(Level.SEVERE, "Unable to determine if file is drawable and not known. Not making any changes to DB", ex); //NON-NLS
MessageNotifyUtil.Notify.error("Image Gallery Error", MessageNotifyUtil.Notify.error("Image Gallery Error",
"Unable to determine if file is drawable and not known. Not making any changes to DB. See the logs for details."); "Unable to determine if file is drawable and not known. Not making any changes to DB. See the logs for details.");
} }
} }
} else { //TODO: keep track of what we missed for later } else {
setStale(true); setStale(true);
} }
} }
@ -1041,7 +1056,7 @@ public final class ImageGalleryController {
Content newDataSource = (Content) evt.getNewValue(); Content newDataSource = (Content) evt.getNewValue();
if (isListeningEnabled()) { if (isListeningEnabled()) {
queueDBTask(new PrePopulateDataSourceFiles(newDataSource, ImageGalleryController.this, getDatabase(), getSleuthKitCase())); queueDBTask(new PrePopulateDataSourceFiles(newDataSource, ImageGalleryController.this, getDatabase(), getSleuthKitCase()));
} else {//TODO: keep track of what we missed for later } else {
setStale(true); setStale(true);
} }
} }

View File

@ -63,6 +63,7 @@ import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.ContentTag;
import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.CaseDbAccessManager.CaseDbAccessQueryCallback; import org.sleuthkit.datamodel.CaseDbAccessManager.CaseDbAccessQueryCallback;
import org.sleuthkit.datamodel.SleuthkitCase.CaseDbTransaction;
import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TagName;
import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.TskData.DbType; import org.sleuthkit.datamodel.TskData.DbType;
@ -230,9 +231,25 @@ public final class DrawableDB {
insertHashHitStmt = prepareStatement("INSERT OR IGNORE INTO hash_set_hits (hash_set_id, obj_id) VALUES (?,?)"); //NON-NLS insertHashHitStmt = prepareStatement("INSERT OR IGNORE INTO hash_set_hits (hash_set_id, obj_id) VALUES (?,?)"); //NON-NLS
CaseDbTransaction caseDbTransaction = null;
try {
caseDbTransaction = tskCase.beginTransaction();
for (DhsImageCategory cat : DhsImageCategory.values()) { for (DhsImageCategory cat : DhsImageCategory.values()) {
insertGroup(cat.getDisplayName(), DrawableAttribute.CATEGORY); insertGroup(cat.getDisplayName(), DrawableAttribute.CATEGORY, caseDbTransaction);
} }
caseDbTransaction.commit();
} catch (TskCoreException ex) {
if (null != caseDbTransaction) {
try {
caseDbTransaction.rollback();
}
catch(TskCoreException ex2) {
LOGGER.log(Level.SEVERE, "Error in trying to rollback transaction", ex2);
}
}
throw new ExceptionInInitializerError(ex);
}
initializeImageList(); initializeImageList();
} else { } else {
throw new ExceptionInInitializerError(); throw new ExceptionInInitializerError();
@ -599,23 +616,63 @@ public final class DrawableDB {
} }
public void updateFile(DrawableFile f) { public void updateFile(DrawableFile f) {
DrawableTransaction trans = beginTransaction(); DrawableTransaction trans = null;
updateFile(f, trans); CaseDbTransaction caseDbTransaction = null;
try {
trans = beginTransaction();
caseDbTransaction = tskCase.beginTransaction();
updateFile(f, trans, caseDbTransaction);
commitTransaction(trans, true); commitTransaction(trans, true);
caseDbTransaction.commit();
}
catch (TskCoreException ex) {
if (null != trans) {
rollbackTransaction(trans);
}
if (null != caseDbTransaction) {
try {
caseDbTransaction.rollback();
} catch (TskCoreException ex2) {
LOGGER.log(Level.SEVERE, "Error in trying to rollback transaction", ex2); //NON-NLS
}
}
LOGGER.log(Level.SEVERE, "Error updating file", ex); //NON-NLS
}
} }
public void insertFile(DrawableFile f) { public void insertFile(DrawableFile f) {
DrawableTransaction trans = beginTransaction(); DrawableTransaction trans = null;
insertFile(f, trans); CaseDbTransaction caseDbTransaction = null;
try {
trans = beginTransaction();
caseDbTransaction = tskCase.beginTransaction();
insertFile(f, trans, caseDbTransaction);
commitTransaction(trans, true); commitTransaction(trans, true);
caseDbTransaction.commit();
}
catch (TskCoreException ex) {
if (null != trans) {
rollbackTransaction(trans);
}
if (null != caseDbTransaction) {
try {
caseDbTransaction.rollback();
} catch (TskCoreException ex2) {
LOGGER.log(Level.SEVERE, "Error in trying to rollback transaction", ex2); //NON-NLS
}
}
LOGGER.log(Level.SEVERE, "Error inserting file", ex); //NON-NLS
}
} }
public void insertFile(DrawableFile f, DrawableTransaction tr) { public void insertFile(DrawableFile f, DrawableTransaction tr, CaseDbTransaction caseDbTransaction) {
insertOrUpdateFile(f, tr, insertFileStmt); insertOrUpdateFile(f, tr, insertFileStmt, caseDbTransaction);
} }
public void updateFile(DrawableFile f, DrawableTransaction tr) { public void updateFile(DrawableFile f, DrawableTransaction tr, CaseDbTransaction caseDbTransaction) {
insertOrUpdateFile(f, tr, updateFileStmt); insertOrUpdateFile(f, tr, updateFileStmt, caseDbTransaction);
} }
/** /**
@ -631,7 +688,7 @@ public final class DrawableDB {
* @param tr a transaction to use, must not be null * @param tr a transaction to use, must not be null
* @param stmt the statement that does the actull inserting * @param stmt the statement that does the actull inserting
*/ */
private void insertOrUpdateFile(DrawableFile f, @Nonnull DrawableTransaction tr, @Nonnull PreparedStatement stmt) { private void insertOrUpdateFile(DrawableFile f, @Nonnull DrawableTransaction tr, @Nonnull PreparedStatement stmt, @Nonnull CaseDbTransaction caseDbTransaction) {
if (tr.isClosed()) { if (tr.isClosed()) {
throw new IllegalArgumentException("can't update database with closed transaction"); throw new IllegalArgumentException("can't update database with closed transaction");
@ -683,7 +740,7 @@ public final class DrawableDB {
for (Comparable<?> val : vals) { for (Comparable<?> val : vals) {
//use empty string for null values (mime_type), this shouldn't happen! //use empty string for null values (mime_type), this shouldn't happen!
if (null != val) { if (null != val) {
insertGroup(val.toString(), attr); insertGroup(val.toString(), attr, caseDbTransaction);
} }
} }
} }
@ -776,6 +833,13 @@ public final class DrawableDB {
tr.commit(notify); tr.commit(notify);
} }
public void rollbackTransaction(DrawableTransaction tr) {
if (tr.isClosed()) {
throw new IllegalArgumentException("can't rollback already closed transaction");
}
tr.rollback();
}
public Boolean isFileAnalyzed(DrawableFile f) { public Boolean isFileAnalyzed(DrawableFile f) {
return isFileAnalyzed(f.getId()); return isFileAnalyzed(f.getId());
} }
@ -1008,8 +1072,9 @@ public final class DrawableDB {
* Insert new group into DB * Insert new group into DB
* @param value Value of the group (unique to the type) * @param value Value of the group (unique to the type)
* @param groupBy Type of the grouping (CATEGORY, MAKE, etc.) * @param groupBy Type of the grouping (CATEGORY, MAKE, etc.)
* @param caseDbTransaction transaction to use for CaseDB insert/updates
*/ */
private void insertGroup(final String value, DrawableAttribute<?> groupBy) { private void insertGroup(final String value, DrawableAttribute<?> groupBy, CaseDbTransaction caseDbTransaction) {
String insertSQL = ""; String insertSQL = "";
try { try {
insertSQL = String.format(" (value, attribute) VALUES (\'%s\', \'%s\')", value, groupBy.attrName.toString());; insertSQL = String.format(" (value, attribute) VALUES (\'%s\', \'%s\')", value, groupBy.attrName.toString());;
@ -1018,7 +1083,7 @@ public final class DrawableDB {
insertSQL += String.format(" ON CONFLICT (value, attribute) DO UPDATE SET value = \'%s\', attribute=\'%s\'", value, groupBy.attrName.toString()); insertSQL += String.format(" ON CONFLICT (value, attribute) DO UPDATE SET value = \'%s\', attribute=\'%s\'", value, groupBy.attrName.toString());
} }
tskCase.getCaseDbAccessManager().insertOrUpdate(GROUPS_TABLENAME, insertSQL); tskCase.getCaseDbAccessManager().insertOrUpdate(GROUPS_TABLENAME, insertSQL, caseDbTransaction);
} catch (TskCoreException ex) { } catch (TskCoreException ex) {
// Don't need to report it if the case was closed // Don't need to report it if the case was closed
if (Case.isCaseOpen()) { if (Case.isCaseOpen()) {