Search in sources :

Example 16 with Cancellable

use of com.linkedin.r2.util.Cancellable in project rest.li by linkedin.

the class AsyncPoolImpl method get.

@Override
public Cancellable get(final Callback<T> callback) {
    // getter needs to add to wait queue atomically with check for empty pool
    // putter needs to add to pool atomically with check for empty wait queue
    boolean create = false;
    boolean reject = false;
    final LinkedDeque.Node<Callback<T>> node;
    Callback<T> callbackWithTracking = new TimeTrackingCallback<>(callback);
    for (; ; ) {
        TimedObject<T> obj = null;
        final State state;
        synchronized (_lock) {
            state = _state;
            if (state == State.RUNNING) {
                if (_strategy == Strategy.LRU) {
                    obj = _idle.pollFirst();
                } else {
                    obj = _idle.pollLast();
                }
                if (obj == null) {
                    if (_waiters.size() < _maxWaiters) {
                        if (isWaiterTimeoutEnabled()) {
                            callbackWithTracking = new WaiterTimeoutCallback(callbackWithTracking);
                        }
                        // No objects available and the waiter list is not full; add to waiter list and break out of loop
                        node = _waiters.addLastNode(callbackWithTracking);
                        create = shouldCreate();
                    } else {
                        reject = true;
                        node = null;
                    }
                    break;
                }
            }
        }
        if (state != State.RUNNING) {
            // Defer execution of the callback until we are out of the synchronized block
            callbackWithTracking.onError(new IllegalStateException(_poolName + " is " + _state));
            return () -> false;
        }
        T rawObj = obj.get();
        if (_lifecycle.validateGet(rawObj)) {
            trc("dequeued an idle object");
            // Valid object; done
            synchronized (_lock) {
                _checkedOut++;
                _statsTracker.sampleMaxCheckedOut();
            }
            callbackWithTracking.onSuccess(rawObj);
            return () -> false;
        }
        // Invalid object, discard it and keep trying
        destroy(rawObj, true);
        trc("dequeued and disposed an invalid idle object");
    }
    if (reject) {
        // This is a recoverable exception. User can simply retry the failed get() operation.
        callbackWithTracking.onError(new SizeLimitExceededException("AsyncPool " + _poolName + " reached maximum waiter size: " + _maxWaiters));
        return () -> false;
    }
    trc("enqueued a waiter");
    if (create) {
        create();
    }
    return new Cancellable() {

        @Override
        public boolean cancel() {
            synchronized (_lock) {
                boolean cancelled = _waiters.removeNode(node) != null;
                if (cancelled) {
                    shutdownIfNeeded();
                }
                return cancelled;
            }
        }
    };
}
Also used : Cancellable(com.linkedin.r2.util.Cancellable) SizeLimitExceededException(com.linkedin.r2.SizeLimitExceededException) Callback(com.linkedin.common.callback.Callback) SimpleCallback(com.linkedin.common.callback.SimpleCallback) LinkedDeque(com.linkedin.r2.util.LinkedDeque)

Example 17 with Cancellable

use of com.linkedin.r2.util.Cancellable in project rest.li by linkedin.

the class TestAsyncSharedPoolImpl method testMixedPutAndDisposeItemSucceeds.

@Test
public void testMixedPutAndDisposeItemSucceeds() throws Exception {
    AsyncSharedPoolImpl<Object> pool = new AsyncSharedPoolImpl<>(POOL_NAME, LIFECYCLE, SCHEDULER, LIMITER, NO_POOL_TIMEOUT, MAX_WAITERS);
    pool.start();
    final List<Object> items = new ArrayList<>(GET_COUNT);
    for (int i = 0; i < GET_COUNT; i++) {
        FutureCallback<Object> getCallback = new FutureCallback<>();
        Cancellable cancellable = pool.get(getCallback);
        // Operation should not be cancellable
        Assert.assertNotNull(cancellable);
        Assert.assertEquals(cancellable.cancel(), false);
        Object item = getCallback.get(GET_TIMEOUT, TIME_UNIT);
        Assert.assertNotNull(item);
        items.add(item);
    }
    // All items should essentially be the same instance
    Assert.assertEquals(items.size(), GET_COUNT);
    items.stream().forEach(item -> Assert.assertSame(item, items.get(0)));
    verifyStats(pool.getStats(), 1, GET_COUNT, 0, 0, 0, 0, 1, 0, 0);
    FutureCallback<None> shutdownCallback = new FutureCallback<>();
    pool.shutdown(shutdownCallback);
    // Put items back to the pool
    IntStream.range(0, GET_COUNT).forEach(i -> {
        if (i % 2 == 0) {
            pool.put(items.get(i));
        } else {
            pool.dispose(items.get(i));
        }
    });
    shutdownCallback.get(SHUTDOWN_TIMEOUT, TIME_UNIT);
}
Also used : AsyncSharedPoolImpl(com.linkedin.r2.transport.http.client.AsyncSharedPoolImpl) Cancellable(com.linkedin.r2.util.Cancellable) ArrayList(java.util.ArrayList) None(com.linkedin.common.util.None) FutureCallback(com.linkedin.common.callback.FutureCallback) Test(org.testng.annotations.Test)

Example 18 with Cancellable

use of com.linkedin.r2.util.Cancellable in project rest.li by linkedin.

the class TestAsyncSharedPoolImpl method testGetItemCancelled.

@Test
public void testGetItemCancelled() throws Exception {
    final LifecycleMock lifecycle = new LifecycleMock();
    final CountDownLatch createLatch = new CountDownLatch(1);
    lifecycle.setCreateConsumer(callback -> {
        try {
            createLatch.await();
            callback.onSuccess(ITEM);
        } catch (Exception e) {
            callback.onError(e);
        }
    });
    AsyncSharedPoolImpl<Object> pool = new AsyncSharedPoolImpl<>(POOL_NAME, lifecycle, SCHEDULER, LIMITER, NO_POOL_TIMEOUT, MAX_WAITERS);
    pool.start();
    // Only one thread will perform the actual item creation task and the rest
    // will return immediately. Therefore we wait for GET_COUNT - 1 threads to complete.
    final CountDownLatch getLatch = new CountDownLatch(GET_COUNT - 1);
    final ConcurrentLinkedQueue<Cancellable> cancellables = new ConcurrentLinkedQueue<>();
    for (int i = 0; i < GET_COUNT; i++) {
        SCHEDULER.execute(() -> {
            cancellables.add(pool.get(new FutureCallback<>()));
            getLatch.countDown();
        });
    }
    if (!getLatch.await(GET_TIMEOUT, TIME_UNIT)) {
        Assert.fail("Timed out awaiting for get");
    }
    Assert.assertEquals(cancellables.size(), GET_COUNT - 1);
    // Cancelling waiters should all succeed
    cancellables.stream().forEach(cancellable -> Assert.assertTrue(cancellable.cancel()));
    // Cancel the last waiter blocking item creation
    Assert.assertEquals(pool.cancelWaiters().size(), 1);
    createLatch.countDown();
    FutureCallback<None> shutdownCallback = new FutureCallback<>();
    pool.shutdown(shutdownCallback);
    shutdownCallback.get(SHUTDOWN_TIMEOUT, TIME_UNIT);
}
Also used : Cancellable(com.linkedin.r2.util.Cancellable) CountDownLatch(java.util.concurrent.CountDownLatch) ExecutionException(java.util.concurrent.ExecutionException) AsyncSharedPoolImpl(com.linkedin.r2.transport.http.client.AsyncSharedPoolImpl) ConcurrentLinkedQueue(java.util.concurrent.ConcurrentLinkedQueue) None(com.linkedin.common.util.None) FutureCallback(com.linkedin.common.callback.FutureCallback) Test(org.testng.annotations.Test)

Aggregations

Cancellable (com.linkedin.r2.util.Cancellable)17 FutureCallback (com.linkedin.common.callback.FutureCallback)9 Test (org.testng.annotations.Test)9 None (com.linkedin.common.util.None)8 AsyncSharedPoolImpl (com.linkedin.r2.transport.http.client.AsyncSharedPoolImpl)8 Channel (io.netty.channel.Channel)7 RestRequest (com.linkedin.r2.message.rest.RestRequest)3 NioSocketChannel (io.netty.channel.socket.nio.NioSocketChannel)3 ArrayList (java.util.ArrayList)3 ExecutionException (java.util.concurrent.ExecutionException)3 TimeoutException (java.util.concurrent.TimeoutException)3 Callback (com.linkedin.common.callback.Callback)2 SimpleCallback (com.linkedin.common.callback.SimpleCallback)2 SizeLimitExceededException (com.linkedin.r2.SizeLimitExceededException)2 RestRequestBuilder (com.linkedin.r2.message.rest.RestRequestBuilder)2 NettyClientState (com.linkedin.r2.netty.common.NettyClientState)2 LinkedDeque (com.linkedin.r2.util.LinkedDeque)2 InetSocketAddress (java.net.InetSocketAddress)2 SocketAddress (java.net.SocketAddress)2 UnknownHostException (java.net.UnknownHostException)2