FrankChen021 commented on code in PR #20273:
URL: https://github.com/apache/druid/pull/20273#discussion_r3957843147


##########
processing/src/main/java/org/apache/druid/java/util/http/client/pool/ResourcePool.java:
##########
@@ -355,6 +451,184 @@ public void close()
     }
   }
 
+  private static class AdaptiveResourceHolderPerKey<K, V> extends 
PooledResources<V>
+  {
+    private final int maxSize;
+    private final K key;
+    private final ResourceFactory<K, V> factory;
+    private final long unusedResourceTimeoutMillis;
+    private final Semaphore permits;
+    private final Deque<ResourceHolder<V>> idleResources = new 
ConcurrentLinkedDeque<>();
+    private final AtomicBoolean closed = new AtomicBoolean(false);
+
+    private AdaptiveResourceHolderPerKey(
+        int maxSize,
+        long unusedResourceTimeoutMillis,
+        K key,
+        ResourceFactory<K, V> factory
+    )
+    {
+      this.maxSize = maxSize;
+      this.key = key;
+      this.factory = factory;
+      this.unusedResourceTimeoutMillis = unusedResourceTimeoutMillis;
+      this.permits = new Semaphore(maxSize);
+    }
+
+    /**
+     * Fills the pool to its maximum size, closing what it created if that 
fails.
+     */
+    void preload()
+    {
+      try {
+        for (int i = 0; i < maxSize; i++) {
+          idleResources.addLast(new 
ResourceHolder<>(System.currentTimeMillis(), generate()));
+        }
+      }
+      catch (Throwable t) {
+        closeIdleResources();
+        throw t;
+      }
+    }
+
+    @Nullable
+    @Override
+    V get()
+    {
+      if (!acquirePermit()) {
+        return null;
+      }
+
+      boolean lent = false;
+      try {
+        V resource = takeIdleResource();
+        if (resource == null) {
+          resource = createResource();
+        }
+        lent = true;
+        return resource;
+      }
+      finally {
+        if (!lent) {
+          permits.release();
+        }
+      }
+    }
+
+    @Override
+    void giveBack(V object)
+    {
+      Preconditions.checkNotNull(object, "object");
+
+      if (closed.get()) {
+        log.info("giveBack called after being closed. key[%s]", key);
+        closeQuietly(object);
+        permits.release();
+        return;
+      }
+
+      idleResources.addLast(new ResourceHolder<>(System.currentTimeMillis(), 
object));
+      permits.release();
+
+      if (closed.get()) {
+        // close() may have drained the idle resources before this one was 
parked.
+        closeIdleResources();
+      }
+    }
+
+    @Override
+    public void close()
+    {
+      if (closed.compareAndSet(false, true)) {
+        permits.release(maxSize);

Review Comment:
   [P2] Wake zero-sized adaptive pools on close
   
   `numConnections` is validated with `@Min(0)`, so an adaptive pool can 
legitimately be constructed with `maxSize == 0`. Its semaphore then starts with 
zero permits, and `close()` calls `release(maxSize)`, i.e. `release(0)`, which 
wakes no thread blocked in `acquirePermit()`. A request already blocked in 
`ResourcePool.take()` therefore remains stuck through client shutdown, whereas 
the retaining implementation's `notifyAll()` unblocks it. Release at least one 
permit for the zero-size case (or use an explicit close signal) so close can 
always wake waiters.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to