From 6b20182f4d2eb4e52b82949604a7a03cd48e60d4 Mon Sep 17 00:00:00 2001 From: Patrick Strawderman Date: Fri, 10 Nov 2023 12:11:57 -0800 Subject: [PATCH] Avoid allocations in DataLoaderHelper.dispatch when there's no work Bail out early in DataLoaderHelper.dispatch when loaderQueue is empty to avoid unnecessary allocations; additionally, when there is work, size the allocated Lists precisely based on the loaderQueue size. --- .../java/org/dataloader/DataLoaderHelper.java | 30 ++++++++++++++----- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/src/main/java/org/dataloader/DataLoaderHelper.java b/src/main/java/org/dataloader/DataLoaderHelper.java index 67db4e2..066214c 100644 --- a/src/main/java/org/dataloader/DataLoaderHelper.java +++ b/src/main/java/org/dataloader/DataLoaderHelper.java @@ -162,12 +162,21 @@ Object getCacheKeyWithContext(K key, Object context) { DispatchResult dispatch() { boolean batchingEnabled = loaderOptions.batchingEnabled(); - // - // we copy the pre-loaded set of futures ready for dispatch - final List keys = new ArrayList<>(); - final List callContexts = new ArrayList<>(); - final List> queuedFutures = new ArrayList<>(); + final List keys; + final List callContexts; + final List> queuedFutures; synchronized (dataLoader) { + int queueSize = loaderQueue.size(); + if (queueSize == 0) { + lastDispatchTime.set(now()); + return emptyDispatchResult(); + } + + // we copy the pre-loaded set of futures ready for dispatch + keys = new ArrayList<>(queueSize); + callContexts = new ArrayList<>(queueSize); + queuedFutures = new ArrayList<>(queueSize); + loaderQueue.forEach(entry -> { keys.add(entry.getKey()); queuedFutures.add(entry.getValue()); @@ -176,8 +185,8 @@ DispatchResult dispatch() { loaderQueue.clear(); lastDispatchTime.set(now()); } - if (!batchingEnabled || keys.isEmpty()) { - return new DispatchResult<>(completedFuture(emptyList()), 0); + if (!batchingEnabled) { + return emptyDispatchResult(); } final int totalEntriesHandled = keys.size(); // @@ -524,4 +533,11 @@ private CompletableFuture> setToValueCache(List assembledValues, List } return CompletableFuture.completedFuture(assembledValues); } + + private static final DispatchResult EMPTY_DISPATCH_RESULT = new DispatchResult<>(completedFuture(emptyList()), 0); + + @SuppressWarnings("unchecked") // Casting to any type is safe since the underlying list is empty + private static DispatchResult emptyDispatchResult() { + return (DispatchResult) EMPTY_DISPATCH_RESULT; + } }