Search in sources :

Example 1 with SimpleCallback

use of com.linkedin.common.callback.SimpleCallback in project rest.li by linkedin.

the class SimpleLoadBalancerState method shutdown.

@Override
public void shutdown(final PropertyEventShutdownCallback shutdown) {
    trace(_log, "shutdown");
    // shutdown all three registries, all tracker clients, and the event thread
    _executor.execute(new PropertyEvent("shutdown load balancer state") {

        @Override
        public void innerRun() {
            // Need to shutdown loadBalancerStrategies before the transportClients are shutdown
            for (Map<String, LoadBalancerStrategy> strategyEntry : _serviceStrategies.values()) {
                strategyEntry.values().forEach(LoadBalancerStrategy::shutdown);
            }
            // put all tracker clients into a single set for convenience
            Set<TransportClient> transportClients = new HashSet<TransportClient>();
            for (Map<String, TransportClient> clientsByScheme : _serviceClients.values()) {
                transportClients.addAll(clientsByScheme.values());
            }
            Callback<None> trackerCallback = Callbacks.countDown(Callbacks.<None>adaptSimple(new SimpleCallback() {

                @Override
                public void onDone() {
                    shutdown.done();
                }
            }), transportClients.size());
            info(_log, "shutting down cluster clients");
            for (TransportClient transportClient : transportClients) {
                transportClient.shutdown(trackerCallback);
            }
            // so it is needed to notify all the listeners
            for (SimpleLoadBalancerStateListener listener : _listeners) {
                // Notify the strategy removal
                for (Map.Entry<String, Map<String, LoadBalancerStrategy>> serviceStrategy : _serviceStrategies.entrySet()) {
                    for (Map.Entry<String, LoadBalancerStrategy> strategyEntry : serviceStrategy.getValue().entrySet()) {
                        listener.onStrategyRemoved(serviceStrategy.getKey(), strategyEntry.getKey(), strategyEntry.getValue());
                    }
                    // Also notify the client removal
                    Map<URI, TrackerClient> trackerClients = _trackerClients.get(serviceStrategy.getKey());
                    if (trackerClients != null) {
                        for (TrackerClient client : trackerClients.values()) {
                            listener.onClientRemoved(serviceStrategy.getKey(), client);
                        }
                    }
                }
            }
        }
    });
}
Also used : TransportClient(com.linkedin.r2.transport.common.bridge.client.TransportClient) Set(java.util.Set) HashSet(java.util.HashSet) PropertyEvent(com.linkedin.d2.discovery.event.PropertyEventThread.PropertyEvent) LoadBalancerStrategy(com.linkedin.d2.balancer.strategies.LoadBalancerStrategy) PropertyEventShutdownCallback(com.linkedin.d2.discovery.event.PropertyEventThread.PropertyEventShutdownCallback) Callback(com.linkedin.common.callback.Callback) SimpleCallback(com.linkedin.common.callback.SimpleCallback) TrackerClient(com.linkedin.d2.balancer.clients.TrackerClient) Map(java.util.Map) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) HashMap(java.util.HashMap) ConcurrentMap(java.util.concurrent.ConcurrentMap) None(com.linkedin.common.util.None) SimpleCallback(com.linkedin.common.callback.SimpleCallback)

Example 2 with SimpleCallback

use of com.linkedin.common.callback.SimpleCallback in project rest.li by linkedin.

the class AsyncPoolImpl method create.

/**
   * DO NOT call this method while holding the lock!  It invokes user code.
   */
private void create() {
    trc("initiating object creation");
    _rateLimiter.submit(new Task() {

        @Override
        public void run(final SimpleCallback callback) {
            _lifecycle.create(new Callback<T>() {

                @Override
                public void onSuccess(T t) {
                    synchronized (_lock) {
                        _statsTracker.incrementCreated();
                        _lastCreateError = null;
                    }
                    add(t);
                    callback.onDone();
                }

                @Override
                public void onError(final Throwable e) {
                    _rateLimiter.incrementPeriod();
                    // Note we drain all waiters and cancel all pending creates if a create fails.
                    // When a create fails, rate-limiting logic will be applied.  In this case,
                    // we may be initiating creations at a lower rate than incoming requests.  While
                    // creations are suppressed, it is better to deny all waiters and let them see
                    // the real reason (this exception) rather than keep them around to eventually
                    // get an unhelpful timeout error
                    final Collection<Callback<T>> waitersDenied;
                    final Collection<Task> cancelledCreate = _rateLimiter.cancelPendingTasks();
                    boolean create;
                    synchronized (_lock) {
                        _statsTracker.incrementCreateErrors();
                        _lastCreateError = e;
                        create = objectDestroyed(1 + cancelledCreate.size());
                        if (!_waiters.isEmpty()) {
                            waitersDenied = cancelWaiters();
                        } else {
                            waitersDenied = Collections.<Callback<T>>emptyList();
                        }
                    }
                    for (Callback<T> denied : waitersDenied) {
                        try {
                            denied.onError(e);
                        } catch (Exception ex) {
                            LOG.error("Encountered error while invoking error waiter callback", ex);
                        }
                    }
                    if (create) {
                        create();
                    }
                    LOG.error(_poolName + ": object creation failed", e);
                    callback.onDone();
                }
            });
        }
    });
}
Also used : Task(com.linkedin.r2.transport.http.client.RateLimiter.Task) SimpleCallback(com.linkedin.common.callback.SimpleCallback) Callback(com.linkedin.common.callback.Callback) SimpleCallback(com.linkedin.common.callback.SimpleCallback) SizeLimitExceededException(com.linkedin.r2.SizeLimitExceededException)

Example 3 with SimpleCallback

use of com.linkedin.common.callback.SimpleCallback in project rest.li by linkedin.

the class TestRateLimiter method testSimple.

@Test
public void testSimple() throws Exception {
    final int total = 10;
    // NB on Solaris x86 there seems to be an extra 10ms that gets added to the period; need
    // to figure this out.  For now set the period high enough that period + 10 will be within
    // the tolerance.
    final int period = 100;
    final CountDownLatch latch = new CountDownLatch(total);
    final Task incr = new Task() {

        @Override
        public void run(SimpleCallback doneCallback) {
            latch.countDown();
            doneCallback.onDone();
        }
    };
    RateLimiter limiter = new ExponentialBackOffRateLimiter(period, period, period, _executor);
    limiter.setPeriod(period);
    long start = System.currentTimeMillis();
    long lowTolerance = (total * period) * 4 / 5;
    long highTolerance = (total * period) * 5 / 4;
    for (int i = 0; i < total * period; i++) {
        limiter.submit(incr);
    }
    Assert.assertTrue(latch.await(highTolerance, TimeUnit.MILLISECONDS), "Should have finished within " + highTolerance + "ms");
    long t = System.currentTimeMillis() - start;
    Assert.assertTrue(t > lowTolerance, "Should have finished after " + lowTolerance + "ms (took " + t + ")");
}
Also used : Task(com.linkedin.r2.transport.http.client.RateLimiter.Task) CountDownLatch(java.util.concurrent.CountDownLatch) ExponentialBackOffRateLimiter(com.linkedin.r2.transport.http.client.ExponentialBackOffRateLimiter) SimpleCallback(com.linkedin.common.callback.SimpleCallback) ExponentialBackOffRateLimiter(com.linkedin.r2.transport.http.client.ExponentialBackOffRateLimiter) RateLimiter(com.linkedin.r2.transport.http.client.RateLimiter) Test(org.testng.annotations.Test)

Example 4 with SimpleCallback

use of com.linkedin.common.callback.SimpleCallback in project rest.li by linkedin.

the class TestRateLimiter method testMaxRunningTasks.

@Test
public void testMaxRunningTasks() throws Exception {
    final int total = 20;
    final int maxRunning = 5;
    final int period = 100;
    final Random rand = new Random();
    final CountDownLatch latch = new CountDownLatch(total);
    final AtomicInteger totalStarted = new AtomicInteger();
    final AtomicInteger totalFinished = new AtomicInteger();
    final Task r = new Task() {

        @Override
        public void run(final SimpleCallback callback) {
            totalStarted.incrementAndGet();
            int delay = period + rand.nextInt(period);
            _executor.schedule(new Runnable() {

                @Override
                public void run() {
                    totalFinished.incrementAndGet();
                    callback.onDone();
                }
            }, delay, TimeUnit.MILLISECONDS);
            latch.countDown();
        }
    };
    RateLimiter limiter = new ExponentialBackOffRateLimiter(period, period, period, _executor, maxRunning);
    limiter.setPeriod(period);
    for (int i = 0; i < total; ++i) {
        limiter.submit(r);
    }
    // check the current number of concurrent tasks every 100ms.
    for (int i = 0; i < total * 2; ++i) {
        int currentRunning = totalStarted.get() - totalFinished.get();
        Assert.assertTrue(currentRunning <= maxRunning, "Should have less than " + maxRunning + " concurrent tasks");
        Thread.sleep(period);
    }
    Assert.assertTrue(latch.await(30, TimeUnit.SECONDS));
    Assert.assertEquals(total, totalStarted.get());
}
Also used : Task(com.linkedin.r2.transport.http.client.RateLimiter.Task) Random(java.util.Random) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) CountDownLatch(java.util.concurrent.CountDownLatch) ExponentialBackOffRateLimiter(com.linkedin.r2.transport.http.client.ExponentialBackOffRateLimiter) SimpleCallback(com.linkedin.common.callback.SimpleCallback) ExponentialBackOffRateLimiter(com.linkedin.r2.transport.http.client.ExponentialBackOffRateLimiter) RateLimiter(com.linkedin.r2.transport.http.client.RateLimiter) Test(org.testng.annotations.Test)

Aggregations

SimpleCallback (com.linkedin.common.callback.SimpleCallback)4 Task (com.linkedin.r2.transport.http.client.RateLimiter.Task)3 Callback (com.linkedin.common.callback.Callback)2 ExponentialBackOffRateLimiter (com.linkedin.r2.transport.http.client.ExponentialBackOffRateLimiter)2 RateLimiter (com.linkedin.r2.transport.http.client.RateLimiter)2 CountDownLatch (java.util.concurrent.CountDownLatch)2 Test (org.testng.annotations.Test)2 None (com.linkedin.common.util.None)1 TrackerClient (com.linkedin.d2.balancer.clients.TrackerClient)1 LoadBalancerStrategy (com.linkedin.d2.balancer.strategies.LoadBalancerStrategy)1 PropertyEvent (com.linkedin.d2.discovery.event.PropertyEventThread.PropertyEvent)1 PropertyEventShutdownCallback (com.linkedin.d2.discovery.event.PropertyEventThread.PropertyEventShutdownCallback)1 SizeLimitExceededException (com.linkedin.r2.SizeLimitExceededException)1 TransportClient (com.linkedin.r2.transport.common.bridge.client.TransportClient)1 HashMap (java.util.HashMap)1 HashSet (java.util.HashSet)1 Map (java.util.Map)1 Random (java.util.Random)1 Set (java.util.Set)1 ConcurrentHashMap (java.util.concurrent.ConcurrentHashMap)1