1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package io.netty5.resolver.dns;
18
19 import io.netty5.resolver.NameResolver;
20 import io.netty5.util.concurrent.EventExecutor;
21 import io.netty5.util.concurrent.Future;
22 import io.netty5.util.concurrent.Promise;
23 import io.netty5.util.internal.StringUtil;
24
25 import java.util.List;
26 import java.util.concurrent.ConcurrentMap;
27
28 import static java.util.Objects.requireNonNull;
29
30
31 final class InflightNameResolver<T> implements NameResolver<T> {
32
33 private final EventExecutor executor;
34 private final NameResolver<T> delegate;
35 private final ConcurrentMap<String, Promise<T>> resolvesInProgress;
36 private final ConcurrentMap<String, Promise<List<T>>> resolveAllsInProgress;
37
38 InflightNameResolver(EventExecutor executor, NameResolver<T> delegate,
39 ConcurrentMap<String, Promise<T>> resolvesInProgress,
40 ConcurrentMap<String, Promise<List<T>>> resolveAllsInProgress) {
41
42 this.executor = requireNonNull(executor, "executor");
43 this.delegate = requireNonNull(delegate, "delegate");
44 this.resolvesInProgress = requireNonNull(resolvesInProgress, "resolvesInProgress");
45 this.resolveAllsInProgress = requireNonNull(resolveAllsInProgress, "resolveAllsInProgress");
46 }
47
48 @Override
49 public Future<T> resolve(String inetHost) {
50 return resolve(inetHost, executor.newPromise());
51 }
52
53 @Override
54 public Future<List<T>> resolveAll(String inetHost) {
55 return resolveAll(inetHost, executor.newPromise());
56 }
57
58 @Override
59 public void close() {
60 delegate.close();
61 }
62
63 @Override
64 public Future<T> resolve(String inetHost, Promise<T> promise) {
65 return resolve(resolvesInProgress, inetHost, promise, false);
66 }
67
68 @Override
69 public Future<List<T>> resolveAll(String inetHost, Promise<List<T>> promise) {
70 return resolve(resolveAllsInProgress, inetHost, promise, true);
71 }
72
73 private <U> Future<U> resolve(
74 final ConcurrentMap<String, Promise<U>> resolveMap,
75 final String inetHost, final Promise<U> promise, boolean resolveAll) {
76
77 final Promise<U> earlyPromise = resolveMap.putIfAbsent(inetHost, promise);
78 if (earlyPromise != null) {
79
80 Future<U> earlyFuture = earlyPromise.asFuture();
81 if (earlyFuture.isDone()) {
82 transferResult(earlyFuture, promise);
83 } else {
84 earlyFuture.addListener(f -> transferResult(f, promise));
85 }
86 } else {
87 try {
88 if (resolveAll) {
89 @SuppressWarnings("unchecked")
90 final Promise<List<T>> castPromise = (Promise<List<T>>) promise;
91 delegate.resolveAll(inetHost, castPromise);
92 } else {
93 @SuppressWarnings("unchecked")
94 final Promise<T> castPromise = (Promise<T>) promise;
95 delegate.resolve(inetHost, castPromise);
96 }
97 } finally {
98 if (promise.isDone()) {
99 resolveMap.remove(inetHost);
100 } else {
101 promise.asFuture().addListener(f -> resolveMap.remove(inetHost));
102 }
103 }
104 }
105
106 return promise.asFuture();
107 }
108
109 private static <T> void transferResult(Future<? extends T> src, Promise<T> dst) {
110 if (src.isSuccess()) {
111 dst.trySuccess(src.getNow());
112 } else {
113 dst.tryFailure(src.cause());
114 }
115 }
116
117 @Override
118 public String toString() {
119 return StringUtil.simpleClassName(this) + '(' + delegate + ')';
120 }
121 }