diff --git a/src/main/java/net/helenus/core/PostCommitFunction.java b/src/main/java/net/helenus/core/PostCommitFunction.java index 0c823cf..a7e152c 100644 --- a/src/main/java/net/helenus/core/PostCommitFunction.java +++ b/src/main/java/net/helenus/core/PostCommitFunction.java @@ -4,18 +4,17 @@ import java.util.List; import java.util.Objects; public class PostCommitFunction implements java.util.function.Function { + public static final PostCommitFunction NULL_ABORT = new PostCommitFunction<>(null, null, false); + public static final PostCommitFunction NULL_COMMIT = new PostCommitFunction<>(null, null, true); - private final UnitOfWork uow; private final List commitThunks; private final List abortThunks; private boolean committed; PostCommitFunction( - UnitOfWork uow, List postCommit, List abortThunks, boolean committed) { - this.uow = uow; this.commitThunks = postCommit; this.abortThunks = abortThunks; this.committed = committed; diff --git a/src/main/java/net/helenus/core/UnitOfWork.java b/src/main/java/net/helenus/core/UnitOfWork.java index 454a318..9dca27d 100644 --- a/src/main/java/net/helenus/core/UnitOfWork.java +++ b/src/main/java/net/helenus/core/UnitOfWork.java @@ -26,8 +26,6 @@ import java.util.*; import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; -import java.util.regex.Matcher; -import java.util.regex.Pattern; import java.util.stream.Collectors; import javax.cache.Cache; import javax.cache.CacheManager; @@ -48,9 +46,7 @@ import org.slf4j.LoggerFactory; /** Encapsulates the concept of a "transaction" as a unit-of-work. */ public class UnitOfWork implements AutoCloseable { - private static final Logger LOG = LoggerFactory.getLogger(UnitOfWork.class); - private static final Pattern classNameRegex = Pattern.compile("^(?:\\w+\\.)+(?:(\\w+)|(\\w+)\\$.*)$"); public final UnitOfWork parent; private final List nested = new ArrayList<>(); @@ -65,7 +61,7 @@ public class UnitOfWork implements AutoCloseable { protected int databaseLookups = 0; protected final Stopwatch elapsedTime; protected Map databaseTime = new HashMap<>(); - protected double cacheLookupTimeMSecs = 0.0; + protected double cacheLookupTimeMSecs = 0.0d; private List commitThunks = new ArrayList(); private List abortThunks = new ArrayList(); private List> asyncOperationFutures = new ArrayList>(); @@ -74,17 +70,6 @@ public class UnitOfWork implements AutoCloseable { private long committedAt = 0L; private BatchOperation batch; - private String extractClassNameFromStackFrame(String classNameOnStack) { - String name = null; - Matcher m = classNameRegex.matcher(classNameOnStack); - if (m.find()) { - name = (m.group(1) != null) ? m.group(1) : ((m.group(2) != null) ? m.group(2) : name); - } else { - name = classNameOnStack; - } - return name; - } - public UnitOfWork(HelenusSession session) { this(session, null); } @@ -97,7 +82,7 @@ public class UnitOfWork implements AutoCloseable { parent.addNestedUnitOfWork(this); } this.session = session; - CacheLoader cacheLoader = null; + CacheLoader cacheLoader = null; if (parent != null) { cacheLoader = new CacheLoader() { @@ -363,7 +348,7 @@ public class UnitOfWork implements AutoCloseable { throws HelenusException, TimeoutException { if (isDone()) { - return new PostCommitFunction(this, null, null, false); + return PostCommitFunction.NULL_ABORT; } // Only the outer-most UOW batches statements for commit time, execute them. @@ -399,7 +384,7 @@ public class UnitOfWork implements AutoCloseable { } } - return new PostCommitFunction(this, null, null, false); + return PostCommitFunction.NULL_ABORT; } else { committed = true; aborted = false; @@ -453,11 +438,11 @@ public class UnitOfWork implements AutoCloseable { LOG.info(logTimers("committed")); } - return new PostCommitFunction(this, null, null, true); + return PostCommitFunction.NULL_COMMIT; } else { - // Merge cache and statistics into parent if there is one. parent.statementCache.putAll(statementCache.unwrap(Map.class)); + parent.statementCache.removeAll(statementCache.getDeletions()); parent.mergeCache(cache); parent.addBatched(batch); if (purpose != null) { @@ -483,15 +468,15 @@ public class UnitOfWork implements AutoCloseable { // Constructor ctor = clazz.getConstructor(conflictExceptionClass); // T object = ctor.newInstance(new Object[] { String message }); // } - return new PostCommitFunction(this, commitThunks, abortThunks, true); + return new PostCommitFunction(commitThunks, abortThunks, true); } - private void addBatched(BatchOperation batch) { - if (batch != null) { + private void addBatched(BatchOperation batchArg) { + if (batchArg != null) { if (this.batch == null) { - this.batch = batch; + this.batch = batchArg; } else { - this.batch.addAll(batch); + this.batch.addAll(batchArg); } } } diff --git a/src/main/java/net/helenus/core/cache/MapCache.java b/src/main/java/net/helenus/core/cache/MapCache.java index 2cef0b6..7418efd 100644 --- a/src/main/java/net/helenus/core/cache/MapCache.java +++ b/src/main/java/net/helenus/core/cache/MapCache.java @@ -1,6 +1,6 @@ package net.helenus.core.cache; - +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; @@ -22,15 +22,16 @@ import javax.cache.processor.MutableEntry; public class MapCache implements Cache { private final CacheManager manager; private final String name; - private Map map = new ConcurrentHashMap(); - private Set cacheEntryRemovedListeners = new HashSet<>(); + private Map map = new ConcurrentHashMap<>(); + private Set deletes = Collections.synchronizedSet(new HashSet<>()); + private Set> cacheEntryRemovedListeners = new HashSet<>(); private CacheLoader cacheLoader = null; private boolean isReadThrough = false; - private Configuration configuration = new MapConfiguration(); private static class MapConfiguration implements Configuration { + private static final long serialVersionUID = 6093947542772516209L; - @Override + @Override public Class getKeyType() { return null; } @@ -54,6 +55,11 @@ public class MapCache implements Cache { this.isReadThrough = isReadThrough; } + /** Non-interface method; should only be called by UnitOfWork when merging to an enclosing UnitOfWork. */ + public Set getDeletions() { + return new HashSet<>(deletes); + } + /** {@inheritDoc} */ @Override public V get(K key) { @@ -193,6 +199,7 @@ public class MapCache implements Cache { boolean removed = false; synchronized (map) { removed = map.remove(key) != null; + deletes.add(key); notifyRemovedListeners(key); } return removed; @@ -205,6 +212,7 @@ public class MapCache implements Cache { V value = map.get(key); if (value != null && oldValue.equals(value)) { map.remove(key); + deletes.add(key); notifyRemovedListeners(key); return true; } @@ -219,6 +227,7 @@ public class MapCache implements Cache { V oldValue = null; oldValue = map.get(key); map.remove(key); + deletes.add(key); notifyRemovedListeners(key); return oldValue; } @@ -273,6 +282,7 @@ public class MapCache implements Cache { keys.remove(key); } } + deletes.addAll(keys); } notifyRemovedListeners(keys); } @@ -283,6 +293,7 @@ public class MapCache implements Cache { synchronized (map) { Set keys = map.keySet(); map.clear(); + deletes.addAll(keys); notifyRemovedListeners(keys); } } @@ -291,6 +302,7 @@ public class MapCache implements Cache { @Override public void clear() { map.clear(); + deletes.clear(); } /** {@inheritDoc} */ @@ -386,6 +398,7 @@ public class MapCache implements Cache { /** {@inheritDoc} */ @Override + @SuppressWarnings("unchecked") public T unwrap(Class clazz) { return (T) map; }