diff --git a/src/main/java/org/dataloader/DataLoaderHelper.java b/src/main/java/org/dataloader/DataLoaderHelper.java index dbd9383..41f6801 100644 --- a/src/main/java/org/dataloader/DataLoaderHelper.java +++ b/src/main/java/org/dataloader/DataLoaderHelper.java @@ -1,5 +1,6 @@ package org.dataloader; +import org.dataloader.annotations.GuardedBy; import org.dataloader.annotations.Internal; import org.dataloader.impl.CompletableFutureKit; import org.dataloader.stats.StatisticsCollector; @@ -287,6 +288,7 @@ private void possiblyClearCacheEntriesOnExceptions(List keys) { } } + @GuardedBy("dataLoader") private CompletableFuture loadFromCache(K key, Object loadContext, boolean batchingEnabled) { final Object cacheKey = loadContext == null ? getCacheKey(key) : getCacheKeyWithContext(key, loadContext); @@ -296,15 +298,12 @@ private CompletableFuture loadFromCache(K key, Object loadContext, boolean ba return futureCache.get(cacheKey); } - CompletableFuture loadCallFuture; - synchronized (dataLoader) { - loadCallFuture = queueOrInvokeLoader(key, loadContext, batchingEnabled, true); - } - + CompletableFuture loadCallFuture = queueOrInvokeLoader(key, loadContext, batchingEnabled, true); futureCache.set(cacheKey, loadCallFuture); return loadCallFuture; } + @GuardedBy("dataLoader") private CompletableFuture queueOrInvokeLoader(K key, Object loadContext, boolean batchingEnabled, boolean cachingEnabled) { if (batchingEnabled) { CompletableFuture loadCallFuture = new CompletableFuture<>(); diff --git a/src/main/java/org/dataloader/annotations/GuardedBy.java b/src/main/java/org/dataloader/annotations/GuardedBy.java new file mode 100644 index 0000000..c26b2ef --- /dev/null +++ b/src/main/java/org/dataloader/annotations/GuardedBy.java @@ -0,0 +1,21 @@ +package org.dataloader.annotations; + +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.RetentionPolicy.CLASS; + +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +/** + * Indicates that the annotated element should be used only while holding the specified lock. + */ +@Target({FIELD, METHOD}) +@Retention(CLASS) +public @interface GuardedBy { + + /** + * The lock that should be held. + */ + String value(); +}