From aec29adcd1d29026ce7412c9afb27216adb130ac Mon Sep 17 00:00:00 2001 From: Robert von Burg Date: Wed, 25 Sep 2019 11:13:45 +0200 Subject: [PATCH] [Minor] Optimizations, reduce memory and calls in Transaction and ObjectFilter --- .../agent/impl/AuditingActivityMap.java | 12 +- .../agent/impl/AuditingElementMapFacade.java | 112 ++++++++++++++---- .../strolch/agent/impl/AuditingOrderMap.java | 3 + .../agent/impl/AuditingResourceMap.java | 12 +- .../persistence/api/AbstractTransaction.java | 51 ++++---- .../runtime/config/StrolchConfiguration.xml | 1 + .../utils/objectfilter/ObjectFilter.java | 22 +++- 7 files changed, 156 insertions(+), 57 deletions(-) diff --git a/li.strolch.agent/src/main/java/li/strolch/agent/impl/AuditingActivityMap.java b/li.strolch.agent/src/main/java/li/strolch/agent/impl/AuditingActivityMap.java index 8111233d5..6a1f57116 100644 --- a/li.strolch.agent/src/main/java/li/strolch/agent/impl/AuditingActivityMap.java +++ b/li.strolch.agent/src/main/java/li/strolch/agent/impl/AuditingActivityMap.java @@ -1,12 +1,12 @@ /* * Copyright 2015 Robert von Burg - * + * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -15,6 +15,7 @@ */ package li.strolch.agent.impl; +import java.util.HashSet; import java.util.List; import li.strolch.agent.api.ActivityMap; @@ -29,9 +30,8 @@ import li.strolch.utils.dbc.DBC; /** * This is the {@link AuditTrail} for {@link Activity Activities} - * + * * @author Robert von Burg - * * @see AuditingElementMapFacade */ public class AuditingActivityMap extends AuditingElementMapFacade implements ActivityMap { @@ -55,6 +55,8 @@ public class AuditingActivityMap extends AuditingElementMapFacade impl ActivityVisitor activityVisitor = query.getVisitor(); DBC.PRE.assertNotNull("activityVisitor on query", activityVisitor); query.setVisitor(activity -> { + if (this.read == null) + this.read = new HashSet<>(); this.read.add(activity); return activity.accept(activityVisitor); }); diff --git a/li.strolch.agent/src/main/java/li/strolch/agent/impl/AuditingElementMapFacade.java b/li.strolch.agent/src/main/java/li/strolch/agent/impl/AuditingElementMapFacade.java index 65fb8c8ac..c33ed7b53 100644 --- a/li.strolch.agent/src/main/java/li/strolch/agent/impl/AuditingElementMapFacade.java +++ b/li.strolch.agent/src/main/java/li/strolch/agent/impl/AuditingElementMapFacade.java @@ -15,11 +15,10 @@ */ package li.strolch.agent.impl; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; +import static java.util.Collections.emptyMap; +import static java.util.Collections.emptySet; + +import java.util.*; import java.util.stream.Stream; import li.strolch.agent.api.AuditTrail; @@ -65,12 +64,6 @@ public abstract class AuditingElementMapFacade imp DBC.PRE.assertNotNull("ElementMap must be set!", elementMap); //$NON-NLS-1$ this.elementMap = elementMap; this.observeAccessReads = observeAccessReads; - - this.created = new HashSet<>(); - this.read = new HashSet<>(); - this.updated = new HashSet<>(); - this.deleted = new HashSet<>(); - this.deletedAllByType = new HashMap<>(); } protected ElementMap getElementMap() { @@ -81,6 +74,8 @@ public abstract class AuditingElementMapFacade imp * @return the read */ public Set getRead() { + if (this.read == null) + return emptySet(); return this.read; } @@ -88,6 +83,8 @@ public abstract class AuditingElementMapFacade imp * @return the created */ public Set getCreated() { + if (this.created == null) + return emptySet(); return this.created; } @@ -95,6 +92,8 @@ public abstract class AuditingElementMapFacade imp * @return the updated */ public Set getUpdated() { + if (this.updated == null) + return emptySet(); return this.updated; } @@ -102,6 +101,8 @@ public abstract class AuditingElementMapFacade imp * @return the deleted */ public Set getDeleted() { + if (this.deleted == null) + return emptySet(); return this.deleted; } @@ -116,6 +117,8 @@ public abstract class AuditingElementMapFacade imp * @return the deletedAllByType */ public Map getDeletedAllByType() { + if (this.deletedAllByType == null) + return emptyMap(); return this.deletedAllByType; } @@ -142,24 +145,33 @@ public abstract class AuditingElementMapFacade imp @Override public T getTemplate(StrolchTransaction tx, String type) { T template = this.elementMap.getTemplate(tx, type); - if (this.observeAccessReads && template != null) + if (this.observeAccessReads && template != null) { + if (this.read == null) + this.read = new HashSet<>(); this.read.add(template); + } return template; } @Override public T getTemplate(StrolchTransaction tx, String type, boolean assertExists) throws StrolchException { T template = this.elementMap.getTemplate(tx, type, assertExists); - if (this.observeAccessReads && template != null) + if (this.observeAccessReads && template != null) { + if (this.read == null) + this.read = new HashSet<>(); this.read.add(template); + } return template; } @Override public T getBy(StrolchTransaction tx, String type, String id) { T element = this.elementMap.getBy(tx, type, id); - if (this.observeAccessReads && element != null) + if (this.observeAccessReads && element != null) { + if (this.read == null) + this.read = new HashSet<>(); this.read.add(element); + } return element; } @@ -168,16 +180,22 @@ public abstract class AuditingElementMapFacade imp @Override public T getBy(StrolchTransaction tx, String type, String id, boolean assertExists) throws StrolchException { T element = this.elementMap.getBy(tx, type, id, assertExists); - if (this.observeAccessReads && element != null) + if (this.observeAccessReads && element != null) { + if (this.read == null) + this.read = new HashSet<>(); this.read.add(element); + } return element; } @Override public T getBy(StrolchTransaction tx, String type, String id, int version) { T element = this.elementMap.getBy(tx, type, id, version); - if (this.observeAccessReads && element != null) + if (this.observeAccessReads && element != null) { + if (this.read == null) + this.read = new HashSet<>(); this.read.add(element); + } return element; } @@ -185,16 +203,22 @@ public abstract class AuditingElementMapFacade imp public T getBy(StrolchTransaction tx, String type, String id, int version, boolean assertExists) throws StrolchException { T element = this.elementMap.getBy(tx, type, id, version, assertExists); - if (this.observeAccessReads && element != null) + if (this.observeAccessReads && element != null) { + if (this.read == null) + this.read = new HashSet<>(); this.read.add(element); + } return element; } @Override public T getBy(StrolchTransaction tx, StringParameter refP, boolean assertExists) throws StrolchException { T element = this.elementMap.getBy(tx, refP, assertExists); - if (this.observeAccessReads && element != null) + if (this.observeAccessReads && element != null) { + if (this.read == null) + this.read = new HashSet<>(); this.read.add(element); + } return element; } @@ -202,16 +226,22 @@ public abstract class AuditingElementMapFacade imp public List getBy(StrolchTransaction tx, StringListParameter refP, boolean assertExists) throws StrolchException { List elements = this.elementMap.getBy(tx, refP, assertExists); - if (this.observeAccessReads && !elements.isEmpty()) + if (this.observeAccessReads && !elements.isEmpty()) { + if (this.read == null) + this.read = new HashSet<>(); this.read.addAll(elements); + } return elements; } @Override public List getVersionsFor(StrolchTransaction tx, String type, String id) { List versions = this.elementMap.getVersionsFor(tx, type, id); - if (this.observeAccessReads && !versions.isEmpty()) + if (this.observeAccessReads && !versions.isEmpty()) { + if (this.read == null) + this.read = new HashSet<>(); this.read.add(versions.get(versions.size() - 1)); + } return versions; } @@ -223,24 +253,33 @@ public abstract class AuditingElementMapFacade imp @Override public List getAllElements(StrolchTransaction tx) { List elements = this.elementMap.getAllElements(tx); - if (this.observeAccessReads && !elements.isEmpty()) + if (this.observeAccessReads && !elements.isEmpty()) { + if (this.read == null) + this.read = new HashSet<>(); this.read.addAll(elements); + } return elements; } @Override public List getElementsBy(StrolchTransaction tx, String type) { List elements = this.elementMap.getElementsBy(tx, type); - if (this.observeAccessReads && !elements.isEmpty()) + if (this.observeAccessReads && !elements.isEmpty()) { + if (this.read == null) + this.read = new HashSet<>(); this.read.addAll(elements); + } return elements; } @Override public Stream stream(StrolchTransaction tx, String... types) { Stream stream = this.elementMap.stream(tx, types); - if (this.observeAccessReads) + if (this.observeAccessReads) { + if (this.read == null) + this.read = new HashSet<>(); stream = stream.peek(e -> this.read.add(e)); + } return stream; } @@ -262,36 +301,48 @@ public abstract class AuditingElementMapFacade imp @Override public void add(StrolchTransaction tx, T element) { this.elementMap.add(tx, element); + if (this.created == null) + this.created = new HashSet<>(); this.created.add(element); } @Override public void addAll(StrolchTransaction tx, List elements) { this.elementMap.addAll(tx, elements); + if (this.created == null) + this.created = new HashSet<>(); this.created.addAll(elements); } @Override public void update(StrolchTransaction tx, T element) { this.elementMap.update(tx, element); + if (this.updated == null) + this.updated = new HashSet<>(); this.updated.add(element); } @Override public void updateAll(StrolchTransaction tx, List elements) { this.elementMap.updateAll(tx, elements); + if (this.updated == null) + this.updated = new HashSet<>(); this.updated.addAll(elements); } @Override public void remove(StrolchTransaction tx, T element) { this.elementMap.remove(tx, element); + if (this.deleted == null) + this.deleted = new HashSet<>(); this.deleted.add(element); } @Override public void removeAll(StrolchTransaction tx, List elements) { this.elementMap.removeAll(tx, elements); + if (this.deleted == null) + this.deleted = new HashSet<>(); this.deleted.addAll(elements); } @@ -306,6 +357,8 @@ public abstract class AuditingElementMapFacade imp public long removeAllBy(StrolchTransaction tx, String type) { long removed = this.elementMap.removeAllBy(tx, type); + if (this.deletedAllByType == null) + this.deletedAllByType = new HashMap<>(); Long byType = this.deletedAllByType.get(type); if (byType == null) byType = 0L; @@ -318,6 +371,8 @@ public abstract class AuditingElementMapFacade imp @Override public T revertToVersion(StrolchTransaction tx, String type, String id, int version) throws StrolchException { T element = this.elementMap.revertToVersion(tx, type, id, version); + if (this.updated == null) + this.updated = new HashSet<>(); this.updated.add(element); return element; } @@ -325,6 +380,8 @@ public abstract class AuditingElementMapFacade imp @Override public T revertToVersion(StrolchTransaction tx, T element) throws StrolchException { T revertedElement = this.elementMap.revertToVersion(tx, element); + if (this.updated == null) + this.updated = new HashSet<>(); this.updated.add(revertedElement); return revertedElement; } @@ -332,9 +389,14 @@ public abstract class AuditingElementMapFacade imp @Override public void undoVersion(StrolchTransaction tx, T element) throws StrolchException { this.elementMap.undoVersion(tx, element); - if (element.getVersion().isFirstVersion()) + if (element.getVersion().isFirstVersion()) { + if (this.deleted == null) + this.deleted = new HashSet<>(); this.deleted.add(element); - else + } else { + if (this.updated == null) + this.updated = new HashSet<>(); this.updated.add(element); + } } } diff --git a/li.strolch.agent/src/main/java/li/strolch/agent/impl/AuditingOrderMap.java b/li.strolch.agent/src/main/java/li/strolch/agent/impl/AuditingOrderMap.java index e8dd8587a..f765b1928 100644 --- a/li.strolch.agent/src/main/java/li/strolch/agent/impl/AuditingOrderMap.java +++ b/li.strolch.agent/src/main/java/li/strolch/agent/impl/AuditingOrderMap.java @@ -15,6 +15,7 @@ */ package li.strolch.agent.impl; +import java.util.HashSet; import java.util.List; import li.strolch.agent.api.AuditTrail; @@ -55,6 +56,8 @@ public class AuditingOrderMap extends AuditingElementMapFacade implements OrderVisitor orderVisitor = query.getVisitor(); DBC.PRE.assertNotNull("orderVisitor on query", orderVisitor); query.setVisitor(order -> { + if (this.read == null) + this.read = new HashSet<>(); this.read.add(order); return order.accept(orderVisitor); }); diff --git a/li.strolch.agent/src/main/java/li/strolch/agent/impl/AuditingResourceMap.java b/li.strolch.agent/src/main/java/li/strolch/agent/impl/AuditingResourceMap.java index acef2b1a9..e5609feaf 100644 --- a/li.strolch.agent/src/main/java/li/strolch/agent/impl/AuditingResourceMap.java +++ b/li.strolch.agent/src/main/java/li/strolch/agent/impl/AuditingResourceMap.java @@ -1,12 +1,12 @@ /* * Copyright 2013 Robert von Burg - * + * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -15,6 +15,7 @@ */ package li.strolch.agent.impl; +import java.util.HashSet; import java.util.List; import li.strolch.agent.api.AuditTrail; @@ -29,9 +30,8 @@ import li.strolch.utils.dbc.DBC; /** * This is the {@link AuditTrail} for {@link Resource Resources} - * + * * @author Robert von Burg - * * @see AuditingElementMapFacade */ public class AuditingResourceMap extends AuditingElementMapFacade implements ResourceMap { @@ -55,6 +55,8 @@ public class AuditingResourceMap extends AuditingElementMapFacade impl ResourceVisitor resourceVisitor = query.getVisitor(); DBC.PRE.assertNotNull("resourceVisitor on query", resourceVisitor); query.setVisitor(resource -> { + if (this.read == null) + this.read = new HashSet<>(); this.read.add(resource); return resource.accept(resourceVisitor); }); diff --git a/li.strolch.agent/src/main/java/li/strolch/persistence/api/AbstractTransaction.java b/li.strolch.agent/src/main/java/li/strolch/persistence/api/AbstractTransaction.java index f8f345872..6ede4f254 100644 --- a/li.strolch.agent/src/main/java/li/strolch/persistence/api/AbstractTransaction.java +++ b/li.strolch.agent/src/main/java/li/strolch/persistence/api/AbstractTransaction.java @@ -1510,34 +1510,45 @@ public abstract class AbstractTransaction implements StrolchTransaction { ObserverEvent event = new ObserverEvent(); if (this.resourceMap != null) { - if (!this.resourceMap.getCreated().isEmpty()) - event.added.addList(Tags.RESOURCE, new ArrayList<>(this.resourceMap.getCreated())); - if (!this.resourceMap.getUpdated().isEmpty()) - event.updated.addList(Tags.RESOURCE, new ArrayList<>(this.resourceMap.getUpdated())); - if (!this.resourceMap.getDeleted().isEmpty()) - event.removed.addList(Tags.RESOURCE, new ArrayList<>(this.resourceMap.getDeleted())); + Set created = this.resourceMap.getCreated(); + if (!created.isEmpty()) + event.added.addList(Tags.RESOURCE, new ArrayList<>(created)); + Set updated = this.resourceMap.getUpdated(); + if (!updated.isEmpty()) + event.updated.addList(Tags.RESOURCE, new ArrayList<>(updated)); + Set deleted = this.resourceMap.getDeleted(); + if (!deleted.isEmpty()) + event.removed.addList(Tags.RESOURCE, new ArrayList<>(deleted)); } if (this.orderMap != null) { - if (!this.orderMap.getCreated().isEmpty()) - event.added.addList(Tags.ORDER, new ArrayList<>(this.orderMap.getCreated())); - if (!this.orderMap.getUpdated().isEmpty()) - event.updated.addList(Tags.ORDER, new ArrayList<>(this.orderMap.getUpdated())); - if (!this.orderMap.getDeleted().isEmpty()) - event.removed.addList(Tags.ORDER, new ArrayList<>(this.orderMap.getDeleted())); + Set created = this.orderMap.getCreated(); + if (!created.isEmpty()) + event.added.addList(Tags.ORDER, new ArrayList<>(created)); + Set updated = this.orderMap.getUpdated(); + if (!updated.isEmpty()) + event.updated.addList(Tags.ORDER, new ArrayList<>(updated)); + Set deleted = this.orderMap.getDeleted(); + if (!deleted.isEmpty()) + event.removed.addList(Tags.ORDER, new ArrayList<>(deleted)); } if (this.activityMap != null) { - if (!this.activityMap.getCreated().isEmpty()) - event.added.addList(Tags.ACTIVITY, new ArrayList<>(this.activityMap.getCreated())); - if (!this.activityMap.getUpdated().isEmpty()) - event.updated.addList(Tags.ACTIVITY, new ArrayList<>(this.activityMap.getUpdated())); - if (!this.activityMap.getDeleted().isEmpty()) - event.removed.addList(Tags.ACTIVITY, new ArrayList<>(this.activityMap.getDeleted())); + Set created = this.activityMap.getCreated(); + if (!created.isEmpty()) + event.added.addList(Tags.ACTIVITY, new ArrayList<>(created)); + Set updated = this.activityMap.getUpdated(); + if (!updated.isEmpty()) + event.updated.addList(Tags.ACTIVITY, new ArrayList<>(updated)); + Set deleted = this.activityMap.getDeleted(); + if (!deleted.isEmpty()) + event.removed.addList(Tags.ACTIVITY, new ArrayList<>(deleted)); } - ObserverHandler observerHandler = this.realm.getObserverHandler(); - observerHandler.notify(event); + if (!(event.added.isEmpty() && event.updated.isEmpty() && event.removed.isEmpty())) { + ObserverHandler observerHandler = this.realm.getObserverHandler(); + observerHandler.notify(event); + } return System.nanoTime() - observerUpdateStart; } diff --git a/li.strolch.mvn.archetype.webapp/src/main/resources/archetype-resources/runtime/config/StrolchConfiguration.xml b/li.strolch.mvn.archetype.webapp/src/main/resources/archetype-resources/runtime/config/StrolchConfiguration.xml index 61f053266..1dc725379 100644 --- a/li.strolch.mvn.archetype.webapp/src/main/resources/archetype-resources/runtime/config/StrolchConfiguration.xml +++ b/li.strolch.mvn.archetype.webapp/src/main/resources/archetype-resources/runtime/config/StrolchConfiguration.xml @@ -6,6 +6,7 @@ en true + Europe/Zurich diff --git a/li.strolch.utils/src/main/java/li/strolch/utils/objectfilter/ObjectFilter.java b/li.strolch.utils/src/main/java/li/strolch/utils/objectfilter/ObjectFilter.java index 344bc0ba1..d6f40f9bc 100644 --- a/li.strolch.utils/src/main/java/li/strolch/utils/objectfilter/ObjectFilter.java +++ b/li.strolch.utils/src/main/java/li/strolch/utils/objectfilter/ObjectFilter.java @@ -89,8 +89,8 @@ public class ObjectFilter { * Default constructor initializing the filter */ public ObjectFilter() { - this.cache = new MapOfMaps<>(1); - this.keySet = new HashSet<>(1); + this.cache = new MapOfMaps<>(); + this.keySet = new HashSet<>(); } private void replaceKey(ObjectCache cached, Object newObjectKey, Object newObject) { @@ -455,6 +455,8 @@ public class ObjectFilter { * @return The list of all objects registered under the given key and that need to be added. */ public List getAdded(String key) { + if (!this.cache.containsMap(key)) + return Collections.emptyList(); List addedObjects = new LinkedList<>(); List allObjs = this.cache.getAllElements(key); for (ObjectCache objectCache : allObjs) { @@ -476,6 +478,8 @@ public class ObjectFilter { * @return The list of all objects registered under the given key and that need to be added. */ public List getAdded(Class clazz, String key) { + if (!this.cache.containsMap(key)) + return Collections.emptyList(); List addedObjects = new LinkedList<>(); List allObjs = this.cache.getAllElements(key); for (ObjectCache objectCache : allObjs) { @@ -499,6 +503,8 @@ public class ObjectFilter { * @return The list of all objects registered under the given key and that need to be updated. */ public List getUpdated(String key) { + if (!this.cache.containsMap(key)) + return Collections.emptyList(); List updatedObjects = new LinkedList<>(); List allObjs = this.cache.getAllElements(key); for (ObjectCache objectCache : allObjs) { @@ -520,6 +526,8 @@ public class ObjectFilter { * @return The list of all objects registered under the given key and that need to be updated. */ public List getUpdated(Class clazz, String key) { + if (!this.cache.containsMap(key)) + return Collections.emptyList(); List updatedObjects = new LinkedList<>(); List allObjs = this.cache.getAllElements(key); for (ObjectCache objectCache : allObjs) { @@ -543,6 +551,8 @@ public class ObjectFilter { * @return The list of object registered under the given key that have, as a final action, removal. */ public List getRemoved(String key) { + if (!this.cache.containsMap(key)) + return Collections.emptyList(); List removedObjects = new LinkedList<>(); List allObjs = this.cache.getAllElements(key); for (ObjectCache objectCache : allObjs) { @@ -564,6 +574,8 @@ public class ObjectFilter { * @return The list of object registered under the given key that have, as a final action, removal. */ public List getRemoved(Class clazz, String key) { + if (!this.cache.containsMap(key)) + return Collections.emptyList(); List removedObjects = new LinkedList<>(); List allObjs = this.cache.getAllElements(key); for (ObjectCache objectCache : allObjs) { @@ -589,6 +601,8 @@ public class ObjectFilter { * @return The list of object registered under the given key that have, as a final action, removal. */ public List getAll(Class clazz, String key) { + if (!this.cache.containsMap(key)) + return Collections.emptyList(); List objects = new LinkedList<>(); List allObjs = this.cache.getAllElements(key); for (ObjectCache objectCache : allObjs) { @@ -632,6 +646,8 @@ public class ObjectFilter { * @return The list of objects matching the given key. */ public List getAll(String key) { + if (!this.cache.containsMap(key)) + return Collections.emptyList(); List allObjects = new LinkedList<>(); List allObjs = this.cache.getAllElements(key); for (ObjectCache objectCache : allObjs) { @@ -650,6 +666,8 @@ public class ObjectFilter { * @return The list of objects matching the given key. */ public List getCache(String key) { + if (!this.cache.containsMap(key)) + return Collections.emptyList(); return this.cache.getAllElements(key); }