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.DataSource;
import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.SleuthkitCase.CaseDbTransaction;
import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.TskData;
@ -769,7 +770,7 @@ public final class ImageGalleryController {
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
public void run() {
@ -777,6 +778,9 @@ public final class ImageGalleryController {
progressHandle.start();
updateMessage(Bundle.CopyAnalyzedFiles_populatingDb_status());
DrawableDB.DrawableTransaction drawableDbTransaction = null;
CaseDbTransaction caseDbTransaction = null;
try {
//grab all files with supported extension or detected mime types
final List<AbstractFile> files = getFiles();
@ -784,23 +788,23 @@ public final class ImageGalleryController {
updateProgress(0.0);
taskCompletionStatus = true;
taskCompletionStatus = true;
int workDone = 0;
//do in transaction
DrawableDB.DrawableTransaction tr = taskDB.beginTransaction();
int workDone = 0;
drawableDbTransaction = taskDB.beginTransaction();
caseDbTransaction = tskCase.beginTransaction();
for (final AbstractFile f : files) {
if (isCancelled()) {
LOGGER.log(Level.WARNING, "Task cancelled: not all contents may be transfered to drawable database."); //NON-NLS
if (isCancelled() || Thread.interrupted()) {
LOGGER.log(Level.WARNING, "Task cancelled or interrupted: not all contents may be transfered to drawable database."); //NON-NLS
taskCompletionStatus = false;
progressHandle.finish();
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++;
progressHandle.progress(f.getName(), workDone);
@ -814,9 +818,20 @@ public final class ImageGalleryController {
updateProgress(1.0);
progressHandle.start();
taskDB.commitTransaction(tr, true);
taskDB.commitTransaction(drawableDbTransaction, true);
caseDbTransaction.commit();
} 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());
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());
@ -865,7 +880,7 @@ public final class ImageGalleryController {
}
@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;
if (known) {
@ -875,15 +890,16 @@ public final class ImageGalleryController {
try {
//supported mimetype => analyzed
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 (null == f.getMIMEType()) {
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) {
throw new TskCoreException("Failed to initialize FileTypeDetector.", ex);
@ -927,8 +943,8 @@ public final class ImageGalleryController {
}
@Override
void processFile(final AbstractFile f, DrawableDB.DrawableTransaction tr) {
taskDB.insertFile(DrawableFile.create(f, false, false), tr);
void processFile(final AbstractFile f, DrawableDB.DrawableTransaction tr, CaseDbTransaction caseDBTransaction) {
taskDB.insertFile(DrawableFile.create(f, false, false), tr, caseDBTransaction);
}
@Override
@ -996,13 +1012,12 @@ public final class ImageGalleryController {
}
}
} 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
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.");
}
}
} else { //TODO: keep track of what we missed for later
} else {
setStale(true);
}
}
@ -1041,7 +1056,7 @@ public final class ImageGalleryController {
Content newDataSource = (Content) evt.getNewValue();
if (isListeningEnabled()) {
queueDBTask(new PrePopulateDataSourceFiles(newDataSource, ImageGalleryController.this, getDatabase(), getSleuthKitCase()));
} else {//TODO: keep track of what we missed for later
} else {
setStale(true);
}
}

View File

@ -63,6 +63,7 @@ import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.ContentTag;
import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.CaseDbAccessManager.CaseDbAccessQueryCallback;
import org.sleuthkit.datamodel.SleuthkitCase.CaseDbTransaction;
import org.sleuthkit.datamodel.TagName;
import org.sleuthkit.datamodel.TskCoreException;
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
for (DhsImageCategory cat : DhsImageCategory.values()) {
insertGroup(cat.getDisplayName(), DrawableAttribute.CATEGORY);
CaseDbTransaction caseDbTransaction = null;
try {
caseDbTransaction = tskCase.beginTransaction();
for (DhsImageCategory cat : DhsImageCategory.values()) {
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();
} else {
throw new ExceptionInInitializerError();
@ -599,23 +616,63 @@ public final class DrawableDB {
}
public void updateFile(DrawableFile f) {
DrawableTransaction trans = beginTransaction();
updateFile(f, trans);
commitTransaction(trans, true);
DrawableTransaction trans = null;
CaseDbTransaction caseDbTransaction = null;
try {
trans = beginTransaction();
caseDbTransaction = tskCase.beginTransaction();
updateFile(f, trans, caseDbTransaction);
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) {
DrawableTransaction trans = beginTransaction();
insertFile(f, trans);
commitTransaction(trans, true);
DrawableTransaction trans = null;
CaseDbTransaction caseDbTransaction = null;
try {
trans = beginTransaction();
caseDbTransaction = tskCase.beginTransaction();
insertFile(f, trans, caseDbTransaction);
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) {
insertOrUpdateFile(f, tr, insertFileStmt);
public void insertFile(DrawableFile f, DrawableTransaction tr, CaseDbTransaction caseDbTransaction) {
insertOrUpdateFile(f, tr, insertFileStmt, caseDbTransaction);
}
public void updateFile(DrawableFile f, DrawableTransaction tr) {
insertOrUpdateFile(f, tr, updateFileStmt);
public void updateFile(DrawableFile f, DrawableTransaction tr, CaseDbTransaction caseDbTransaction) {
insertOrUpdateFile(f, tr, updateFileStmt, caseDbTransaction);
}
/**
@ -631,7 +688,7 @@ public final class DrawableDB {
* @param tr a transaction to use, must not be null
* @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()) {
throw new IllegalArgumentException("can't update database with closed transaction");
@ -683,7 +740,7 @@ public final class DrawableDB {
for (Comparable<?> val : vals) {
//use empty string for null values (mime_type), this shouldn't happen!
if (null != val) {
insertGroup(val.toString(), attr);
insertGroup(val.toString(), attr, caseDbTransaction);
}
}
}
@ -776,6 +833,13 @@ public final class DrawableDB {
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) {
return isFileAnalyzed(f.getId());
}
@ -1008,8 +1072,9 @@ public final class DrawableDB {
* Insert new group into DB
* @param value Value of the group (unique to the type)
* @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 = "";
try {
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());
}
tskCase.getCaseDbAccessManager().insertOrUpdate(GROUPS_TABLENAME, insertSQL);
tskCase.getCaseDbAccessManager().insertOrUpdate(GROUPS_TABLENAME, insertSQL, caseDbTransaction);
} catch (TskCoreException ex) {
// Don't need to report it if the case was closed
if (Case.isCaseOpen()) {