Skip to content

Commit 59d81fe

Browse files
BURJA Lucianbbakerman
BURJA Lucian
authored andcommitted
Fix dispatch hanging when load() is called twice with the same key
1 parent 026b5b4 commit 59d81fe

File tree

2 files changed

+24
-8
lines changed

2 files changed

+24
-8
lines changed

src/main/java/org/dataloader/DataLoader.java

+7-8
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,10 @@
2020
import org.dataloader.stats.Statistics;
2121
import org.dataloader.stats.StatisticsCollector;
2222

23+
import java.util.AbstractMap.SimpleImmutableEntry;
2324
import java.util.ArrayList;
2425
import java.util.Collection;
25-
import java.util.LinkedHashMap;
2626
import java.util.List;
27-
import java.util.Map;
2827
import java.util.concurrent.CompletableFuture;
2928
import java.util.concurrent.CompletionStage;
3029
import java.util.stream.Collectors;
@@ -66,7 +65,7 @@ public class DataLoader<K, V> {
6665
private final BatchLoader<K, V> batchLoadFunction;
6766
private final DataLoaderOptions loaderOptions;
6867
private final CacheMap<Object, CompletableFuture<V>> futureCache;
69-
private final Map<K, CompletableFuture<V>> loaderQueue;
68+
private final List<SimpleImmutableEntry<K, CompletableFuture<V>>> loaderQueue;
7069
private final StatisticsCollector stats;
7170

7271
/**
@@ -156,7 +155,7 @@ public DataLoader(BatchLoader<K, V> batchLoadFunction, DataLoaderOptions options
156155
this.loaderOptions = options == null ? new DataLoaderOptions() : options;
157156
this.futureCache = determineCacheMap(loaderOptions);
158157
// order of keys matter in data loader
159-
this.loaderQueue = new LinkedHashMap<>();
158+
this.loaderQueue = new ArrayList<>();
160159
this.stats = nonNull(this.loaderOptions.getStatisticsCollector());
161160
}
162161

@@ -192,7 +191,7 @@ public CompletableFuture<V> load(K key) {
192191
CompletableFuture<V> future = new CompletableFuture<>();
193192
if (loaderOptions.batchingEnabled()) {
194193
synchronized (loaderQueue) {
195-
loaderQueue.put(key, future);
194+
loaderQueue.add(new SimpleImmutableEntry<>(key, future));
196195
}
197196
} else {
198197
stats.incrementBatchLoadCountBy(1);
@@ -247,9 +246,9 @@ public CompletableFuture<List<V>> dispatch() {
247246
final List<K> keys = new ArrayList<>();
248247
final List<CompletableFuture<V>> queuedFutures = new ArrayList<>();
249248
synchronized (loaderQueue) {
250-
loaderQueue.forEach((key, future) -> {
251-
keys.add(key);
252-
queuedFutures.add(future);
249+
loaderQueue.forEach(entry -> {
250+
keys.add(entry.getKey());
251+
queuedFutures.add(entry.getValue());
253252
});
254253
loaderQueue.clear();
255254
}

src/test/java/org/dataloader/DataLoaderTest.java

+17
Original file line numberDiff line numberDiff line change
@@ -575,6 +575,23 @@ public void should_Disable_caching() throws ExecutionException, InterruptedExcep
575575
assertThat(loadCalls, equalTo(asList(asList("A", "B"),
576576
asList("A", "C"), asList("A", "B", "C"))));
577577
}
578+
@Test
579+
public void should_work_with_duplicate_keys() throws ExecutionException, InterruptedException {
580+
List<Collection<String>> loadCalls = new ArrayList<>();
581+
DataLoader<String, String> identityLoader =
582+
idLoader(newOptions().setCachingEnabled(false), loadCalls);
583+
584+
CompletableFuture<String> future1 = identityLoader.load("A");
585+
CompletableFuture<String> future2 = identityLoader.load("B");
586+
CompletableFuture<String> future3 = identityLoader.load("A");
587+
identityLoader.dispatch();
588+
589+
await().until(() -> future1.isDone() && future2.isDone() && future3.isDone());
590+
assertThat(future1.get(), equalTo("A"));
591+
assertThat(future2.get(), equalTo("B"));
592+
assertThat(future3.get(), equalTo("A"));
593+
assertThat(loadCalls, equalTo(singletonList(asList("A", "B", "A"))));
594+
}
578595

579596
// It is resilient to job queue ordering
580597

0 commit comments

Comments
 (0)