From 789b8ca53b2e3478139a01ae1837a810b145968c Mon Sep 17 00:00:00 2001 From: Patrick Strawderman Date: Fri, 10 Nov 2023 11:50:39 -0800 Subject: [PATCH 1/2] Lazily initialize Executor in ScheduledDataLoaderRegistry builder Calling ScheduledDataLoaderRegistry.newScheduledRegistry would create a new ScheduledExecutorService on every call, regardless of whether a custom one was supplied. Move creation of the default ScheduledExecutorService from the builder field to the build method to avoid the issue. --- .../dataloader/registries/ScheduledDataLoaderRegistry.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/dataloader/registries/ScheduledDataLoaderRegistry.java b/src/main/java/org/dataloader/registries/ScheduledDataLoaderRegistry.java index fada66d..28b13e0 100644 --- a/src/main/java/org/dataloader/registries/ScheduledDataLoaderRegistry.java +++ b/src/main/java/org/dataloader/registries/ScheduledDataLoaderRegistry.java @@ -257,7 +257,7 @@ public static class Builder { private final Map> dataLoaders = new LinkedHashMap<>(); private final Map, DispatchPredicate> dataLoaderPredicates = new LinkedHashMap<>(); private DispatchPredicate dispatchPredicate = DispatchPredicate.DISPATCH_ALWAYS; - private ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor(); + private ScheduledExecutorService scheduledExecutorService; private Duration schedule = Duration.ofMillis(10); private boolean tickerMode = false; @@ -348,6 +348,9 @@ public Builder tickerMode(boolean tickerMode) { * @return the newly built {@link ScheduledDataLoaderRegistry} */ public ScheduledDataLoaderRegistry build() { + if (scheduledExecutorService == null) { + scheduledExecutorService = Executors.newSingleThreadScheduledExecutor(); + } return new ScheduledDataLoaderRegistry(this); } } From 6b20182f4d2eb4e52b82949604a7a03cd48e60d4 Mon Sep 17 00:00:00 2001 From: Patrick Strawderman Date: Fri, 10 Nov 2023 12:11:57 -0800 Subject: [PATCH 2/2] 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; + } } pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy