Search in sources :

Example 11 with AsyncPool

use of com.linkedin.r2.transport.http.client.AsyncPool in project rest.li by linkedin.

the class HttpNettyStreamClient method doWriteRequest.

@Override
protected void doWriteRequest(Request request, RequestContext context, SocketAddress address, TimeoutTransportCallback<StreamResponse> callback) {
    final AsyncPool<Channel> pool;
    try {
        pool = _channelPoolManager.getPoolForAddress(address);
    } catch (IllegalStateException e) {
        errorResponse(callback, e);
        return;
    }
    context.putLocalAttr(R2Constants.HTTP_PROTOCOL_VERSION, HttpProtocolVersion.HTTP_1_1);
    Callback<Channel> getCallback = new ChannelPoolGetCallback(pool, request, callback);
    final Cancellable pendingGet = pool.get(getCallback);
    if (pendingGet != null) {
        callback.addTimeoutTask(() -> pendingGet.cancel());
    }
}
Also used : Cancellable(com.linkedin.r2.util.Cancellable) NioSocketChannel(io.netty.channel.socket.nio.NioSocketChannel) Channel(io.netty.channel.Channel)

Example 12 with AsyncPool

use of com.linkedin.r2.transport.http.client.AsyncPool in project rest.li by linkedin.

the class TestAsyncPool method testGetStats.

@Test(retryAnalyzer = SingleRetry.class)
public void testGetStats() throws Exception {
    final int POOL_SIZE = 25;
    final int MIN_SIZE = 0;
    final int MAX_WAITER_SIZE = Integer.MAX_VALUE;
    final SettableClock clock = new SettableClock();
    final LongTracking waitTimeTracker = new LongTracking();
    final int GET = 20;
    final int PUT_GOOD = 2;
    final int PUT_BAD = 3;
    final int DISPOSE = 4;
    final int TIMEOUT = 100;
    final int WAITER_TIMEOUT = 200;
    final int DELAY = 1200;
    final UnreliableLifecycle lifecycle = new UnreliableLifecycle();
    final AsyncPool<AtomicBoolean> pool = new AsyncPoolImpl<>("object pool", lifecycle, POOL_SIZE, TIMEOUT, WAITER_TIMEOUT, _executor, MAX_WAITER_SIZE, AsyncPoolImpl.Strategy.MRU, MIN_SIZE, new NoopRateLimiter(), clock, waitTimeTracker);
    PoolStats stats;
    final List<AtomicBoolean> objects = new ArrayList<>();
    pool.start();
    // test values at initialization
    stats = pool.getStats();
    Assert.assertEquals(stats.getTotalCreated(), 0);
    Assert.assertEquals(stats.getTotalDestroyed(), 0);
    Assert.assertEquals(stats.getTotalCreateErrors(), 0);
    Assert.assertEquals(stats.getTotalDestroyErrors(), 0);
    Assert.assertEquals(stats.getCheckedOut(), 0);
    Assert.assertEquals(stats.getTotalTimedOut(), 0);
    Assert.assertEquals(stats.getTotalWaiterTimedOut(), 0);
    Assert.assertEquals(stats.getTotalBadDestroyed(), 0);
    Assert.assertEquals(stats.getMaxPoolSize(), POOL_SIZE);
    Assert.assertEquals(stats.getMinPoolSize(), 0);
    Assert.assertEquals(stats.getPoolSize(), 0);
    Assert.assertEquals(stats.getSampleMaxCheckedOut(), 0);
    Assert.assertEquals(stats.getSampleMaxPoolSize(), 0);
    // do a few gets
    for (int i = 0; i < GET; i++) {
        FutureCallback<AtomicBoolean> cb = new FutureCallback<>();
        pool.get(cb);
        AtomicBoolean obj = cb.get();
        objects.add(obj);
    }
    clock.addDuration(SAMPLING_DURATION_INCREMENT);
    stats = pool.getStats();
    Assert.assertEquals(stats.getTotalCreated(), GET);
    Assert.assertEquals(stats.getTotalDestroyed(), 0);
    Assert.assertEquals(stats.getTotalCreateErrors(), 0);
    Assert.assertEquals(stats.getTotalDestroyErrors(), 0);
    Assert.assertEquals(stats.getCheckedOut(), GET);
    Assert.assertEquals(stats.getTotalTimedOut(), 0);
    Assert.assertEquals(stats.getTotalBadDestroyed(), 0);
    Assert.assertEquals(stats.getMaxPoolSize(), POOL_SIZE);
    Assert.assertEquals(stats.getMinPoolSize(), 0);
    Assert.assertEquals(stats.getPoolSize(), GET);
    Assert.assertEquals(stats.getSampleMaxCheckedOut(), GET);
    Assert.assertEquals(stats.getSampleMaxPoolSize(), GET);
    // do some puts with good objects
    for (int i = 0; i < PUT_GOOD; i++) {
        AtomicBoolean obj = objects.remove(objects.size() - 1);
        pool.put(obj);
    }
    clock.addDuration(SAMPLING_DURATION_INCREMENT);
    stats = pool.getStats();
    Assert.assertEquals(stats.getTotalCreated(), GET);
    Assert.assertEquals(stats.getTotalDestroyed(), 0);
    Assert.assertEquals(stats.getTotalCreateErrors(), 0);
    Assert.assertEquals(stats.getTotalDestroyErrors(), 0);
    Assert.assertEquals(stats.getCheckedOut(), GET - PUT_GOOD);
    Assert.assertEquals(stats.getTotalTimedOut(), 0);
    Assert.assertEquals(stats.getTotalBadDestroyed(), 0);
    Assert.assertEquals(stats.getMaxPoolSize(), POOL_SIZE);
    Assert.assertEquals(stats.getMinPoolSize(), 0);
    Assert.assertEquals(stats.getPoolSize(), GET);
    Assert.assertEquals(stats.getSampleMaxCheckedOut(), GET);
    Assert.assertEquals(stats.getSampleMaxPoolSize(), GET);
    // do some puts with bad objects
    for (int i = 0; i < PUT_BAD; i++) {
        AtomicBoolean obj = objects.remove(objects.size() - 1);
        // invalidate the object
        obj.set(false);
        pool.put(obj);
    }
    clock.addDuration(SAMPLING_DURATION_INCREMENT);
    stats = pool.getStats();
    Assert.assertEquals(stats.getTotalCreated(), GET);
    Assert.assertEquals(stats.getTotalDestroyed(), PUT_BAD);
    Assert.assertEquals(stats.getTotalCreateErrors(), 0);
    Assert.assertEquals(stats.getTotalDestroyErrors(), 0);
    Assert.assertEquals(stats.getCheckedOut(), GET - PUT_GOOD - PUT_BAD);
    Assert.assertEquals(stats.getTotalTimedOut(), 0);
    Assert.assertEquals(stats.getTotalBadDestroyed(), PUT_BAD);
    Assert.assertEquals(stats.getMaxPoolSize(), POOL_SIZE);
    Assert.assertEquals(stats.getMinPoolSize(), 0);
    Assert.assertEquals(stats.getPoolSize(), GET - PUT_BAD);
    Assert.assertEquals(stats.getSampleMaxCheckedOut(), GET - PUT_GOOD);
    Assert.assertEquals(stats.getSampleMaxPoolSize(), GET);
    // do some disposes
    for (int i = 0; i < DISPOSE; i++) {
        AtomicBoolean obj = objects.remove(objects.size() - 1);
        pool.dispose(obj);
    }
    clock.addDuration(SAMPLING_DURATION_INCREMENT);
    stats = pool.getStats();
    Assert.assertEquals(stats.getTotalCreated(), GET);
    Assert.assertEquals(stats.getTotalDestroyed(), PUT_BAD + DISPOSE);
    Assert.assertEquals(stats.getTotalCreateErrors(), 0);
    Assert.assertEquals(stats.getTotalDestroyErrors(), 0);
    Assert.assertEquals(stats.getCheckedOut(), GET - PUT_GOOD - PUT_BAD - DISPOSE);
    Assert.assertEquals(stats.getTotalTimedOut(), 0);
    Assert.assertEquals(stats.getTotalBadDestroyed(), PUT_BAD + DISPOSE);
    Assert.assertEquals(stats.getMaxPoolSize(), POOL_SIZE);
    Assert.assertEquals(stats.getMinPoolSize(), 0);
    Assert.assertEquals(stats.getPoolSize(), GET - PUT_BAD - DISPOSE);
    Assert.assertEquals(stats.getSampleMaxCheckedOut(), GET - PUT_GOOD - PUT_BAD);
    Assert.assertEquals(stats.getSampleMaxPoolSize(), GET - PUT_BAD);
    // wait for a reap -- should destroy the PUT_GOOD objects
    Thread.sleep(DELAY);
    clock.addDuration(SAMPLING_DURATION_INCREMENT);
    stats = pool.getStats();
    Assert.assertEquals(stats.getTotalCreated(), GET);
    Assert.assertEquals(stats.getTotalDestroyed(), PUT_GOOD + PUT_BAD + DISPOSE);
    Assert.assertEquals(stats.getTotalCreateErrors(), 0);
    Assert.assertEquals(stats.getTotalDestroyErrors(), 0);
    Assert.assertEquals(stats.getCheckedOut(), GET - PUT_GOOD - PUT_BAD - DISPOSE);
    Assert.assertEquals(stats.getTotalTimedOut(), PUT_GOOD);
    Assert.assertEquals(stats.getTotalBadDestroyed(), PUT_BAD + DISPOSE);
    Assert.assertEquals(stats.getMaxPoolSize(), POOL_SIZE);
    Assert.assertEquals(stats.getMinPoolSize(), 0);
    Assert.assertEquals(stats.getPoolSize(), GET - PUT_GOOD - PUT_BAD - DISPOSE);
    Assert.assertEquals(stats.getSampleMaxCheckedOut(), GET - PUT_GOOD - PUT_BAD - DISPOSE);
    Assert.assertEquals(stats.getSampleMaxPoolSize(), GET - PUT_BAD - DISPOSE);
}
Also used : LongTracking(com.linkedin.common.stats.LongTracking) ArrayList(java.util.ArrayList) PoolStats(com.linkedin.r2.transport.http.client.PoolStats) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) NoopRateLimiter(com.linkedin.r2.transport.http.client.NoopRateLimiter) AsyncPoolImpl(com.linkedin.r2.transport.http.client.AsyncPoolImpl) SettableClock(com.linkedin.util.clock.SettableClock) FutureCallback(com.linkedin.common.callback.FutureCallback) Test(org.testng.annotations.Test)

Example 13 with AsyncPool

use of com.linkedin.r2.transport.http.client.AsyncPool in project rest.li by linkedin.

the class TestAsyncPool method testCancelTriggerShutdown.

/**
 * Tests {@link AsyncPool}'s shutdown sequence is properly triggered when outstanding
 * waiters cancel the previous get calls.
 */
@Test
public void testCancelTriggerShutdown() throws Exception {
    SynchronousLifecycle lifecycle = new SynchronousLifecycle();
    AsyncPool<Object> pool = new AsyncPoolImpl<>("object pool", lifecycle, 1, 100, _executor);
    pool.start();
    FutureCallback<Object> callback1 = new FutureCallback<>();
    Cancellable cancellable1 = pool.get(callback1);
    FutureCallback<Object> callback2 = new FutureCallback<>();
    Cancellable cancellable2 = pool.get(callback2);
    FutureCallback<None> shutdownCallback = new FutureCallback<>();
    pool.shutdown(shutdownCallback);
    // Disposes the previously checked out object. The pool now has no outstanding checkouts but waiter
    // size is still one due to the second #get call above.
    pool.dispose(callback1.get(5, TimeUnit.SECONDS));
    // Caller cancels the second #get call. The pool should be in the right condition and initiate shutdown.
    cancellable2.cancel();
    // Pool should shutdown successfully without the callback timeout
    shutdownCallback.get(5, TimeUnit.SECONDS);
}
Also used : Cancellable(com.linkedin.r2.util.Cancellable) AsyncPoolImpl(com.linkedin.r2.transport.http.client.AsyncPoolImpl) None(com.linkedin.common.util.None) FutureCallback(com.linkedin.common.callback.FutureCallback) Test(org.testng.annotations.Test)

Example 14 with AsyncPool

use of com.linkedin.r2.transport.http.client.AsyncPool in project rest.li by linkedin.

the class TestAsyncPool method performCheckout.

private List<Object> performCheckout(int numberOfCheckouts, AsyncPool<Object> pool) {
    List<Object> checkedOutObjects = new ArrayList<>(numberOfCheckouts);
    ScheduledExecutorService checkoutExecutor = Executors.newScheduledThreadPool(50);
    CountDownLatch checkoutLatch = new CountDownLatch(numberOfCheckouts);
    Runnable checkoutTask = getCheckoutTask(pool, checkedOutObjects, new Object(), checkoutLatch, new CountDownLatch(numberOfCheckouts));
    for (int i = 0; i < numberOfCheckouts; i++) {
        checkoutExecutor.execute(checkoutTask);
    }
    try {
        checkoutLatch.await(5, TimeUnit.SECONDS);
        checkoutExecutor.shutdownNow();
    } catch (Exception ex) {
        Assert.fail("Too long to perform checkout operation");
    }
    return checkedOutObjects;
}
Also used : ScheduledExecutorService(java.util.concurrent.ScheduledExecutorService) ArrayList(java.util.ArrayList) CountDownLatch(java.util.concurrent.CountDownLatch) ObjectCreationTimeoutException(com.linkedin.r2.transport.http.client.ObjectCreationTimeoutException) TimeoutException(java.util.concurrent.TimeoutException) ExecutionException(java.util.concurrent.ExecutionException)

Example 15 with AsyncPool

use of com.linkedin.r2.transport.http.client.AsyncPool in project rest.li by linkedin.

the class AsyncSharedPoolImpl method get.

@Override
public Cancellable get(Callback<T> callback) {
    ArgumentUtil.notNull(callback, "callback");
    final TimeTrackingCallback timeTrackingCallback = new TimeTrackingCallback(callback);
    final LinkedDeque.Node<Callback<T>> node;
    T item = null;
    boolean create = false;
    while (true) {
        final State state;
        synchronized (_lock) {
            state = _state;
            if (state == State.RUNNING) {
                item = _item.get();
                if (item == null) {
                    node = _waiters.size() < _maxWaiters ? _waiters.addLastNode(timeTrackingCallback) : null;
                    if (_isCreateInProgress) {
                        LOG.debug("{}: item creation is in progress", _name);
                    } else {
                        _isCreateInProgress = true;
                        create = true;
                    }
                    break;
                }
                _checkedOut++;
                _statsTracker.sampleMaxCheckedOut();
            }
        }
        if (state != State.RUNNING) {
            // Defer execution of the callback until we are out of the synchronized block
            timeTrackingCallback.onError(new IllegalStateException(_name + " is " + _state));
            return () -> false;
        }
        // through the item lifecycle before passing back to user callback
        if (_lifecycle.validateGet(item)) {
            timeTrackingCallback.onSuccess(item);
            return () -> false;
        }
        boolean disposed;
        synchronized (_lock) {
            // The connection has gone bad so we proceed to destroy it
            disposed = doDispose(item);
        }
        if (disposed) {
            doDestroy(item, BAD, () -> {
            });
        }
    }
    if (node == null) {
        // This is a recoverable exception. User can simply retry the failed get() operation.
        timeTrackingCallback.onError(new SizeLimitExceededException("AsyncPool " + _name + " reached maximum waiter size: " + _maxWaiters));
        return () -> false;
    }
    // The pool is currently empty we need to construct a new item
    if (create) {
        doCreate();
    }
    return () -> {
        synchronized (_lock) {
            return _waiters.removeNode(node) != null;
        }
    };
}
Also used : SizeLimitExceededException(com.linkedin.r2.SizeLimitExceededException) SimpleCallback(com.linkedin.common.callback.SimpleCallback) Callback(com.linkedin.common.callback.Callback) LinkedDeque(com.linkedin.r2.util.LinkedDeque)

Aggregations

Channel (io.netty.channel.Channel)12 TimeoutException (java.util.concurrent.TimeoutException)10 Test (org.testng.annotations.Test)10 Cancellable (com.linkedin.r2.util.Cancellable)9 FutureCallback (com.linkedin.common.callback.FutureCallback)7 AsyncPoolImpl (com.linkedin.r2.transport.http.client.AsyncPoolImpl)7 ExecutionException (java.util.concurrent.ExecutionException)7 ObjectCreationTimeoutException (com.linkedin.r2.transport.http.client.ObjectCreationTimeoutException)6 PoolStats (com.linkedin.r2.transport.http.client.PoolStats)6 ArrayList (java.util.ArrayList)6 ScheduledExecutorService (java.util.concurrent.ScheduledExecutorService)6 None (com.linkedin.common.util.None)5 LongTracking (com.linkedin.common.stats.LongTracking)4 RestRequest (com.linkedin.r2.message.rest.RestRequest)4 InetSocketAddress (java.net.InetSocketAddress)4 SocketAddress (java.net.SocketAddress)4 RestRequestBuilder (com.linkedin.r2.message.rest.RestRequestBuilder)3 RestResponse (com.linkedin.r2.message.rest.RestResponse)3 ExponentialBackOffRateLimiter (com.linkedin.r2.transport.http.client.ExponentialBackOffRateLimiter)3 NioSocketChannel (io.netty.channel.socket.nio.NioSocketChannel)3