Search in sources :

Example 1 with AsyncPoolImpl

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

the class TestHttpNettyClient method testFailBackoff.

@Test
public void testFailBackoff() throws Exception {
    final int WARM_UP = 10;
    final int N = 5;
    final int MAX_RATE_LIMITING_PERIOD = 500;
    final CountDownLatch warmUpLatch = new CountDownLatch(WARM_UP);
    final CountDownLatch latch = new CountDownLatch(N);
    final AtomicReference<Boolean> isShutdown = new AtomicReference<>(false);
    AsyncPool<Channel> testPool = new AsyncPoolImpl<>("test pool", new AsyncPool.Lifecycle<Channel>() {

        @Override
        public void create(Callback<Channel> callback) {
            if (warmUpLatch.getCount() > 0) {
                warmUpLatch.countDown();
            } else {
                latch.countDown();
            }
            callback.onError(new Throwable("Oops..."));
        }

        @Override
        public boolean validateGet(Channel obj) {
            return false;
        }

        @Override
        public boolean validatePut(Channel obj) {
            return false;
        }

        @Override
        public void destroy(Channel obj, boolean error, Callback<Channel> callback) {
        }

        @Override
        public PoolStats.LifecycleStats getStats() {
            return null;
        }
    }, 200, 30000, _scheduler, Integer.MAX_VALUE, AsyncPoolImpl.Strategy.MRU, 0, new ExponentialBackOffRateLimiter(0, MAX_RATE_LIMITING_PERIOD, Math.max(10, MAX_RATE_LIMITING_PERIOD / 32), _scheduler));
    HttpNettyClient client = new HttpNettyClient(address -> testPool, _scheduler, 500, 500, 1024 * 1024 * 2);
    final RestRequest r = new RestRequestBuilder(URI.create("http://localhost:8080/")).setMethod("GET").build();
    final ExecutorService executor = Executors.newSingleThreadExecutor();
    executor.execute(() -> {
        while (!isShutdown.get()) {
            try {
                FutureCallback<RestResponse> callback = new FutureCallback<>();
                client.restRequest(r, new RequestContext(), new HashMap<>(), new TransportCallbackAdapter<RestResponse>(callback));
                callback.get();
            } catch (Exception e) {
            // ignore
            }
        }
    });
    // First ensure a bunch fail to get the rate limiting going
    warmUpLatch.await(120, TimeUnit.SECONDS);
    // Now we should be rate limited
    long start = System.currentTimeMillis();
    System.err.println("Starting at " + start);
    long lowTolerance = N * MAX_RATE_LIMITING_PERIOD * 4 / 5;
    long highTolerance = N * MAX_RATE_LIMITING_PERIOD * 5 / 4;
    Assert.assertTrue(latch.await(highTolerance, TimeUnit.MILLISECONDS), "Should have finished within " + highTolerance + "ms");
    long elapsed = System.currentTimeMillis() - start;
    Assert.assertTrue(elapsed > lowTolerance, "Should have finished after " + lowTolerance + "ms (took " + elapsed + ")");
    // shutdown everything
    isShutdown.set(true);
    executor.shutdown();
}
Also used : RequestContext(com.linkedin.r2.message.RequestContext) FutureCallback(com.linkedin.common.callback.FutureCallback) RestResponse(com.linkedin.r2.message.rest.RestResponse) Channel(io.netty.channel.Channel) AtomicReference(java.util.concurrent.atomic.AtomicReference) CountDownLatch(java.util.concurrent.CountDownLatch) EncoderException(io.netty.handler.codec.EncoderException) TimeoutException(java.util.concurrent.TimeoutException) RemoteInvocationException(com.linkedin.r2.RemoteInvocationException) TooLongFrameException(io.netty.handler.codec.TooLongFrameException) IOException(java.io.IOException) UnknownHostException(java.net.UnknownHostException) ExecutionException(java.util.concurrent.ExecutionException) NoSuchAlgorithmException(java.security.NoSuchAlgorithmException) RestRequest(com.linkedin.r2.message.rest.RestRequest) ScheduledExecutorService(java.util.concurrent.ScheduledExecutorService) ExecutorService(java.util.concurrent.ExecutorService) RestRequestBuilder(com.linkedin.r2.message.rest.RestRequestBuilder) Test(org.testng.annotations.Test)

Example 2 with AsyncPoolImpl

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

the class TestAsyncPool method testWaitTimeStats.

@Test
public void testWaitTimeStats() throws Exception {
    final int POOL_SIZE = 25;
    final int CHECKOUT = POOL_SIZE;
    final long DELAY = 100;
    final double DELTA = 0.1;
    DelayedLifecycle lifecycle = new DelayedLifecycle(DELAY);
    final AsyncPool<Object> pool = new AsyncPoolImpl<Object>("object pool", lifecycle, POOL_SIZE, 100, _executor);
    pool.start();
    PoolStats stats;
    List<Object> objects = new ArrayList<Object>(CHECKOUT);
    for (int i = 0; i < CHECKOUT; i++) {
        FutureCallback<Object> cb = new FutureCallback<Object>();
        pool.get(cb);
        Object o = cb.get();
        objects.add(o);
    }
    stats = pool.getStats();
    Assert.assertEquals(stats.getWaitTimeAvg(), DELAY, DELTA * DELAY);
}
Also used : AsyncPoolImpl(com.linkedin.r2.transport.http.client.AsyncPoolImpl) ArrayList(java.util.ArrayList) FutureCallback(com.linkedin.common.callback.FutureCallback) PoolStats(com.linkedin.r2.transport.http.client.PoolStats) Test(org.testng.annotations.Test)

Example 3 with AsyncPoolImpl

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

the class TestAsyncPool method testGetStats.

@Test
public void testGetStats() throws Exception {
    final int POOL_SIZE = 25;
    final int GET = 20;
    final int PUT_GOOD = 2;
    final int PUT_BAD = 3;
    final int DISPOSE = 4;
    final int TIMEOUT = 100;
    final int DELAY = 1200;
    final UnreliableLifecycle lifecycle = new UnreliableLifecycle();
    final AsyncPool<AtomicBoolean> pool = new AsyncPoolImpl<AtomicBoolean>("object pool", lifecycle, POOL_SIZE, TIMEOUT, _executor);
    PoolStats stats;
    final List<AtomicBoolean> objects = new ArrayList<AtomicBoolean>();
    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.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<AtomicBoolean>();
        pool.get(cb);
        AtomicBoolean obj = cb.get();
        objects.add(obj);
    }
    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);
    }
    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);
    }
    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);
    }
    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);
    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 : AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) AsyncPoolImpl(com.linkedin.r2.transport.http.client.AsyncPoolImpl) ArrayList(java.util.ArrayList) FutureCallback(com.linkedin.common.callback.FutureCallback) PoolStats(com.linkedin.r2.transport.http.client.PoolStats) Test(org.testng.annotations.Test)

Example 4 with AsyncPoolImpl

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

the class TestAsyncPool method testGetStatsWithErrors.

@Test
public void testGetStatsWithErrors() throws Exception {
    final int POOL_SIZE = 25;
    final int GET = 20;
    final int PUT_BAD = 5;
    final int DISPOSE = 7;
    final int CREATE_BAD = 9;
    final int TIMEOUT = 100;
    final UnreliableLifecycle lifecycle = new UnreliableLifecycle();
    final AsyncPool<AtomicBoolean> pool = new AsyncPoolImpl<AtomicBoolean>("object pool", lifecycle, POOL_SIZE, TIMEOUT, _executor);
    PoolStats stats;
    final List<AtomicBoolean> objects = new ArrayList<AtomicBoolean>();
    pool.start();
    // do a few gets
    for (int i = 0; i < GET; i++) {
        FutureCallback<AtomicBoolean> cb = new FutureCallback<AtomicBoolean>();
        pool.get(cb);
        AtomicBoolean obj = cb.get();
        objects.add(obj);
    }
    // put and destroy some, with errors
    lifecycle.setFail(true);
    for (int i = 0; i < PUT_BAD; i++) {
        AtomicBoolean obj = objects.remove(objects.size() - 1);
        obj.set(false);
        pool.put(obj);
    }
    for (int i = 0; i < DISPOSE; i++) {
        AtomicBoolean obj = objects.remove(objects.size() - 1);
        pool.dispose(obj);
    }
    stats = pool.getStats();
    Assert.assertEquals(stats.getTotalDestroyed(), 0);
    Assert.assertEquals(stats.getTotalCreateErrors(), 0);
    Assert.assertEquals(stats.getTotalDestroyErrors(), PUT_BAD + DISPOSE);
    Assert.assertEquals(stats.getTotalBadDestroyed(), PUT_BAD + DISPOSE);
    // create some with errors
    for (int i = 0; i < CREATE_BAD; i++) {
        FutureCallback<AtomicBoolean> cb = new FutureCallback<AtomicBoolean>();
        try {
            pool.get(cb);
        } catch (Exception e) {
        // this error is expected
        }
    }
    stats = pool.getStats();
    Assert.assertEquals(stats.getCheckedOut(), GET - PUT_BAD - DISPOSE);
    // When the each create fails, it will retry and cancel the waiter,
    // resulting in a second create error.
    Assert.assertEquals(stats.getTotalCreateErrors(), 2 * CREATE_BAD);
}
Also used : AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) AsyncPoolImpl(com.linkedin.r2.transport.http.client.AsyncPoolImpl) ArrayList(java.util.ArrayList) FutureCallback(com.linkedin.common.callback.FutureCallback) TimeoutException(java.util.concurrent.TimeoutException) ExecutionException(java.util.concurrent.ExecutionException) PoolStats(com.linkedin.r2.transport.http.client.PoolStats) Test(org.testng.annotations.Test)

Aggregations

FutureCallback (com.linkedin.common.callback.FutureCallback)4 Test (org.testng.annotations.Test)4 AsyncPoolImpl (com.linkedin.r2.transport.http.client.AsyncPoolImpl)3 PoolStats (com.linkedin.r2.transport.http.client.PoolStats)3 ArrayList (java.util.ArrayList)3 ExecutionException (java.util.concurrent.ExecutionException)2 TimeoutException (java.util.concurrent.TimeoutException)2 AtomicBoolean (java.util.concurrent.atomic.AtomicBoolean)2 RemoteInvocationException (com.linkedin.r2.RemoteInvocationException)1 RequestContext (com.linkedin.r2.message.RequestContext)1 RestRequest (com.linkedin.r2.message.rest.RestRequest)1 RestRequestBuilder (com.linkedin.r2.message.rest.RestRequestBuilder)1 RestResponse (com.linkedin.r2.message.rest.RestResponse)1 Channel (io.netty.channel.Channel)1 EncoderException (io.netty.handler.codec.EncoderException)1 TooLongFrameException (io.netty.handler.codec.TooLongFrameException)1 IOException (java.io.IOException)1 UnknownHostException (java.net.UnknownHostException)1 NoSuchAlgorithmException (java.security.NoSuchAlgorithmException)1 CountDownLatch (java.util.concurrent.CountDownLatch)1