From e708a43a935ef790a18b691277ec715a3a6752cd Mon Sep 17 00:00:00 2001 From: jmillman Date: Tue, 25 Aug 2015 14:46:53 -0400 Subject: [PATCH] fix bug in inserting Tags into new table, cleanup in EventDB cleanup member order in FilteredEventsModel --- .../datamodel/FilteredEventsModel.java | 141 +++++++++--------- .../autopsy/timeline/db/EventDB.java | 47 +++--- .../autopsy/timeline/db/EventsRepository.java | 12 +- 3 files changed, 102 insertions(+), 98 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/timeline/datamodel/FilteredEventsModel.java b/Core/src/org/sleuthkit/autopsy/timeline/datamodel/FilteredEventsModel.java index ae45ae7ded..337c9e30b0 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/datamodel/FilteredEventsModel.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/datamodel/FilteredEventsModel.java @@ -20,7 +20,6 @@ package org.sleuthkit.autopsy.timeline.datamodel; import com.google.common.eventbus.EventBus; import java.util.Collection; -import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; @@ -121,34 +120,6 @@ public final class FilteredEventsModel { private final EventsRepository repo; private final Case autoCase; - /** - * @return the default filter used at startup - */ - public RootFilter getDefaultFilter() { - DataSourcesFilter dataSourcesFilter = new DataSourcesFilter(); - - repo.getDatasourcesMap().entrySet().stream().forEach((Map.Entry t) -> { - DataSourceFilter dataSourceFilter = new DataSourceFilter(t.getValue(), t.getKey()); - dataSourceFilter.setSelected(Boolean.TRUE); - dataSourcesFilter.addSubFilter(dataSourceFilter); - }); - - HashHitsFilter hashHitsFilter = new HashHitsFilter(); - repo.getHashSetMap().entrySet().stream().forEach((Map.Entry t) -> { - HashSetFilter hashSetFilter = new HashSetFilter(t.getValue(), t.getKey()); - hashSetFilter.setSelected(Boolean.TRUE); - hashHitsFilter.addSubFilter(hashSetFilter); - }); - - TagsFilter tagsFilter = new TagsFilter(); - repo.getTagNames().stream().forEach(t -> { - TagNameFilter tagNameFilter = new TagNameFilter(t, autoCase); - tagNameFilter.setSelected(Boolean.TRUE); - tagsFilter.addSubFilter(tagNameFilter); - }); - return new RootFilter(new HideKnownFilter(), tagsFilter, hashHitsFilter, new TextFilter(), new TypeFilter(RootEventType.getInstance()), dataSourcesFilter); - } - public FilteredEventsModel(EventsRepository repo, ReadOnlyObjectProperty currentStateProperty) { this.repo = repo; this.autoCase = repo.getAutoCase(); @@ -192,14 +163,77 @@ public final class FilteredEventsModel { requestedZoomParamters.bind(currentStateProperty); } - public Interval getBoundingEventsInterval() { - return repo.getBoundingEventsInterval(zoomParamtersProperty().get().getTimeRange(), zoomParamtersProperty().get().getFilter()); - } - synchronized public ReadOnlyObjectProperty zoomParamtersProperty() { return requestedZoomParamters.getReadOnlyProperty(); } + /** + * @return a read only view of the time range requested via + * {@link #requestTimeRange(org.joda.time.Interval)} + */ + synchronized public ReadOnlyObjectProperty timeRangeProperty() { + if (requestedTimeRange.get() == null) { + requestedTimeRange.set(getSpanningInterval()); + } + return requestedTimeRange.getReadOnlyProperty(); + } + + synchronized public ReadOnlyObjectProperty descriptionLODProperty() { + return requestedLOD.getReadOnlyProperty(); + } + + synchronized public ReadOnlyObjectProperty filterProperty() { + return requestedFilter.getReadOnlyProperty(); + } + + synchronized public ReadOnlyObjectProperty eventTypeZoomProperty() { + return requestedTypeZoom.getReadOnlyProperty(); + } + + synchronized public DescriptionLOD getDescriptionLOD() { + return requestedLOD.get(); + } + + synchronized public RootFilter getFilter() { + return requestedFilter.get(); + } + + synchronized public EventTypeZoomLevel getEventTypeZoom() { + return requestedTypeZoom.get(); + } + + /** + * @return the default filter used at startup + */ + public RootFilter getDefaultFilter() { + DataSourcesFilter dataSourcesFilter = new DataSourcesFilter(); + + repo.getDatasourcesMap().entrySet().stream().forEach((Map.Entry t) -> { + DataSourceFilter dataSourceFilter = new DataSourceFilter(t.getValue(), t.getKey()); + dataSourceFilter.setSelected(Boolean.TRUE); + dataSourcesFilter.addSubFilter(dataSourceFilter); + }); + + HashHitsFilter hashHitsFilter = new HashHitsFilter(); + repo.getHashSetMap().entrySet().stream().forEach((Map.Entry t) -> { + HashSetFilter hashSetFilter = new HashSetFilter(t.getValue(), t.getKey()); + hashSetFilter.setSelected(Boolean.TRUE); + hashHitsFilter.addSubFilter(hashSetFilter); + }); + + TagsFilter tagsFilter = new TagsFilter(); + repo.getTagNames().stream().forEach(t -> { + TagNameFilter tagNameFilter = new TagNameFilter(t, autoCase); + tagNameFilter.setSelected(Boolean.TRUE); + tagsFilter.addSubFilter(tagNameFilter); + }); + return new RootFilter(new HideKnownFilter(), tagsFilter, hashHitsFilter, new TextFilter(), new TypeFilter(RootEventType.getInstance()), dataSourcesFilter); + } + + public Interval getBoundingEventsInterval() { + return repo.getBoundingEventsInterval(zoomParamtersProperty().get().getTimeRange(), zoomParamtersProperty().get().getFilter()); + } + public TimeLineEvent getEventById(Long eventID) { return repo.getEventById(eventID); } @@ -240,25 +274,6 @@ public final class FilteredEventsModel { return repo.countEvents(new ZoomParams(timeRange, typeZoom, filter, null)); } - /** - * @return a read only view of the time range requested via - * {@link #requestTimeRange(org.joda.time.Interval)} - */ - synchronized public ReadOnlyObjectProperty timeRangeProperty() { - if (requestedTimeRange.get() == null) { - requestedTimeRange.set(getSpanningInterval()); - } - return requestedTimeRange.getReadOnlyProperty(); - } - - synchronized public ReadOnlyObjectProperty descriptionLODProperty() { - return requestedLOD.getReadOnlyProperty(); - } - - synchronized public ReadOnlyObjectProperty filterProperty() { - return requestedFilter.getReadOnlyProperty(); - } - /** * @return the smallest interval spanning all the events from the * repository, ignoring any filters or requested ranges @@ -324,29 +339,17 @@ public final class FilteredEventsModel { return repo.getAggregatedEvents(params); } - synchronized public ReadOnlyObjectProperty eventTypeZoomProperty() { - return requestedTypeZoom.getReadOnlyProperty(); - } - - synchronized public EventTypeZoomLevel getEventTypeZoom() { - return requestedTypeZoom.get(); - } - - synchronized public DescriptionLOD getDescriptionLOD() { - return requestedLOD.get(); - } - synchronized public boolean handleContentTagAdded(ContentTagAddedEvent evt) { ContentTag contentTag = evt.getTag(); Content content = contentTag.getContent(); - HashSet updatedEventIDs = repo.addTag(content.getId(), null, contentTag); + Set updatedEventIDs = repo.addTag(content.getId(), null, contentTag); return postTagsUpdated(updatedEventIDs); } synchronized public boolean handleArtifactTagAdded(BlackBoardArtifactTagAddedEvent evt) { BlackboardArtifactTag artifactTag = evt.getTag(); BlackboardArtifact artifact = artifactTag.getArtifact(); - HashSet updatedEventIDs = repo.addTag(artifact.getObjectID(), artifact.getArtifactID(), artifactTag);; + Set updatedEventIDs = repo.addTag(artifact.getObjectID(), artifact.getArtifactID(), artifactTag);; return postTagsUpdated(updatedEventIDs); } @@ -355,7 +358,7 @@ public final class FilteredEventsModel { Content content = contentTag.getContent(); try { boolean tagged = autoCase.getServices().getTagsManager().getContentTagsByContent(content).isEmpty() == false; - HashSet updatedEventIDs = repo.deleteTag(content.getId(), null, contentTag, tagged); + Set updatedEventIDs = repo.deleteTag(content.getId(), null, contentTag, tagged); return postTagsUpdated(updatedEventIDs); } catch (TskCoreException ex) { LOGGER.log(Level.SEVERE, "unable to determine tagged status of content.", ex); @@ -368,7 +371,7 @@ public final class FilteredEventsModel { BlackboardArtifact artifact = artifactTag.getArtifact(); try { boolean tagged = autoCase.getServices().getTagsManager().getBlackboardArtifactTagsByArtifact(artifact).isEmpty() == false; - HashSet updatedEventIDs = repo.deleteTag(artifact.getObjectID(), artifact.getArtifactID(), artifactTag, tagged); + Set updatedEventIDs = repo.deleteTag(artifact.getObjectID(), artifact.getArtifactID(), artifactTag, tagged); return postTagsUpdated(updatedEventIDs); } catch (TskCoreException ex) { LOGGER.log(Level.SEVERE, "unable to determine tagged status of artifact.", ex); @@ -376,7 +379,7 @@ public final class FilteredEventsModel { return false; } - private boolean postTagsUpdated(HashSet updatedEventIDs) { + private boolean postTagsUpdated(Set updatedEventIDs) { boolean tagsUpdated = !updatedEventIDs.isEmpty(); if (tagsUpdated) { eventbus.post(new TagsUpdatedEvent(updatedEventIDs)); diff --git a/Core/src/org/sleuthkit/autopsy/timeline/db/EventDB.java b/Core/src/org/sleuthkit/autopsy/timeline/db/EventDB.java index f51cdb13f1..e600ddc080 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/db/EventDB.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/db/EventDB.java @@ -731,48 +731,47 @@ public class EventDB { } } - HashSet addTag(long objectID, Long artifactID, Tag tag) { - HashSet eventIDs = new HashSet<>(); - + Set addTag(long objectID, Long artifactID, Tag tag) { DBLock.lock(); try { - markEventsTagged(objectID, artifactID, eventIDs, true); + Set eventIDs = markEventsTagged(objectID, artifactID, true); for (Long eventID : eventIDs) { //could this be one insert? is there a performance win? //"INSERT OR IGNORE INTO tags (tag_id, tag_name_id, event_id) values (?,?,?)" insertTagStmt.clearParameters(); insertTagStmt.setLong(1, tag.getId()); insertTagStmt.setLong(2, tag.getName().getId()); - insertTagStmt.setLong(1, eventID); + insertTagStmt.setLong(3, eventID); insertTagStmt.executeUpdate(); } + return eventIDs; } catch (SQLException ex) { LOGGER.log(Level.SEVERE, "failed to add tag to event", ex); // NON-NLS } finally { DBLock.unlock(); } - return eventIDs; + return Collections.emptySet(); } - HashSet deleteTag(long objectID, Long artifactID, Tag tag, boolean stillTagged) { - HashSet eventIDs = new HashSet<>(); - + Set deleteTag(long objectID, Long artifactID, Tag tag, boolean stillTagged) { DBLock.lock(); try { - markEventsTagged(objectID, artifactID, eventIDs, stillTagged); + Set eventIDs = markEventsTagged(objectID, artifactID, stillTagged); //"DELETE FROM tags WHERE tag_id = ? deleteTagStmt.clearParameters(); deleteTagStmt.setLong(1, tag.getId()); deleteTagStmt.executeUpdate(); + return eventIDs; } catch (SQLException ex) { LOGGER.log(Level.SEVERE, "failed to add tag to event", ex); // NON-NLS } finally { DBLock.unlock(); } - return eventIDs; + return Collections.emptySet(); } - private void markEventsTagged(long objectID, Long artifactID, HashSet eventIDs, boolean tagged) throws SQLException { + private Set markEventsTagged(long objectID, Long artifactID, boolean tagged) throws SQLException { + HashSet eventIDs = new HashSet<>(); selectEventIDsFromOBjectAndArtifactStmt.clearParameters(); selectEventIDsFromOBjectAndArtifactStmt.setLong(1, objectID); if (Objects.isNull(artifactID)) { @@ -789,6 +788,7 @@ public class EventDB { + " WHERE event_id IN (" + StringUtils.join(eventIDs, ",") + ")"); } } + return eventIDs; } void recordLastArtifactID(long lastArtfID) { @@ -830,16 +830,16 @@ public class EventDB { DBLock.lock(); //this should match Sleuthkit db setup try (Statement statement = con.createStatement()) { - String autopsyDBFileName = Paths.get(dbPath).getParent().resolve("autopsy.db").toString(); - - ResultSet rs = statement.executeQuery("PRAGMA database_list"); - boolean found = false; - while (rs.next() && !found) { - found |= "autopsy".equalsIgnoreCase(rs.getString("name")); - } - if (!found) { - statement.execute("ATTACH DATABASE 'file:" + autopsyDBFileName + "?mode=ro' AS autopsy"); - } +// String autopsyDBFileName = Paths.get(dbPath).getParent().resolve("autopsy.db").toString(); +// +// ResultSet rs = statement.executeQuery("PRAGMA database_list"); +// boolean found = false; +// while (rs.next() && !found) { +// found |= "autopsy".equalsIgnoreCase(rs.getString("name")); +// } +// if (!found) { +// statement.execute("ATTACH DATABASE 'file:" + autopsyDBFileName + "?mode=ro' AS autopsy"); +// } //reduce i/o operations, we have no OS crash recovery anyway statement.execute("PRAGMA synchronous = OFF;"); // NON-NLS //we don't use this feature, so turn it off for minimal speed up on queries @@ -907,10 +907,11 @@ public class EventDB { final boolean useSubTypes = (zoomLevel == EventTypeZoomLevel.SUB_TYPE); //get some info about the range of dates requested - final String queryString = "SELECT count(DISTINCT event_id) AS count, " + typeColumnHelper(useSubTypes) + final String queryString = "SELECT count(DISTINCT events.event_id) AS count, " + typeColumnHelper(useSubTypes) + " FROM events" + useHashHitTablesHelper(filter) + useTagTablesHelper(filter) + " WHERE time >= " + startTime + " AND time < " + endTime + " AND " + SQLHelper.getSQLWhere(filter) // NON-NLS + " GROUP BY " + typeColumnHelper(useSubTypes); // NON-NLS + System.out.println(queryString); DBLock.lock(); try (Statement stmt = con.createStatement(); ResultSet rs = stmt.executeQuery(queryString);) { diff --git a/Core/src/org/sleuthkit/autopsy/timeline/db/EventsRepository.java b/Core/src/org/sleuthkit/autopsy/timeline/db/EventsRepository.java index a9483c48e2..e590c68038 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/db/EventsRepository.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/db/EventsRepository.java @@ -24,7 +24,6 @@ import com.google.common.cache.LoadingCache; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; -import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; @@ -457,23 +456,24 @@ public class EventsRepository { } } - synchronized public HashSet addTag(long objID, Long artifactID, Tag tag) { - HashSet updatedEventIDs = eventDB.addTag(objID, artifactID, tag); + synchronized public Set addTag(long objID, Long artifactID, Tag tag) { + Set updatedEventIDs = eventDB.addTag(objID, artifactID, tag); if (!updatedEventIDs.isEmpty()) { invalidateCaches(updatedEventIDs); } return updatedEventIDs; } - synchronized public HashSet deleteTag(long objID, Long artifactID, Tag tag, boolean tagged) { - HashSet updatedEventIDs = eventDB.deleteTag(objID, artifactID, tag, tagged); + synchronized public Set deleteTag(long objID, Long artifactID, Tag tag, boolean tagged) { + Set updatedEventIDs = eventDB.deleteTag(objID, artifactID, tag, tagged); if (!updatedEventIDs.isEmpty()) { invalidateCaches(updatedEventIDs); } return updatedEventIDs; } - synchronized private void invalidateCaches(HashSet updatedEventIDs) { + synchronized private void invalidateCaches(Set updatedEventIDs) { + eventCountsCache.invalidateAll(); aggregateEventsCache.invalidateAll(); idToEventCache.invalidateAll(updatedEventIDs); try {