All Downloads are FREE. Search and download functionalities are using the official Maven repository.

nl.topicus.jdbc.shaded.io.netty.util.concurrent.UnorderedThreadPoolEventExecutor Maven / Gradle / Ivy

/*
 * Copyright 2016 The Netty Project
 *
 * The Netty Project licenses this file to you under the Apache License,
 * version 2.0 (the "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at:
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations
 * under the License.
 */
package nl.topicus.jdbc.shaded.io.netty.util.concurrent;

import nl.topicus.jdbc.shaded.io.netty.util.internal.logging.InternalLogger;
import nl.topicus.jdbc.shaded.io.netty.util.internal.logging.InternalLoggerFactory;

import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.Delayed;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.RunnableScheduledFuture;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;

import static java.util.concurrent.TimeUnit.NANOSECONDS;

/**
 * {@link EventExecutor} implementation which makes no guarantees about the ordering of task execution that
 * are submitted because there may be multiple threads executing these tasks.
 * This implementation is most useful for protocols that do not need strict ordering.
 *
 * Because it provides no ordering care should be taken when using it!
 */
public final class UnorderedThreadPoolEventExecutor extends ScheduledThreadPoolExecutor implements EventExecutor {
    private static final InternalLogger logger = InternalLoggerFactory.getInstance(
            UnorderedThreadPoolEventExecutor.class);

    private final Promise terminationFuture = GlobalEventExecutor.INSTANCE.newPromise();
    private final Set executorSet = Collections.singleton((EventExecutor) this);

    /**
     * Calls {@link UnorderedThreadPoolEventExecutor#UnorderedThreadPoolEventExecutor(int, ThreadFactory)}
     * using {@link DefaultThreadFactory}.
     */
    public UnorderedThreadPoolEventExecutor(int corePoolSize) {
        this(corePoolSize, new DefaultThreadFactory(UnorderedThreadPoolEventExecutor.class));
    }

    /**
     * See {@link ScheduledThreadPoolExecutor#ScheduledThreadPoolExecutor(int, ThreadFactory)}
     */
    public UnorderedThreadPoolEventExecutor(int corePoolSize, ThreadFactory threadFactory) {
        super(corePoolSize, threadFactory);
    }

    /**
     * Calls {@link UnorderedThreadPoolEventExecutor#UnorderedThreadPoolEventExecutor(int,
     * ThreadFactory, java.util.concurrent.RejectedExecutionHandler)} using {@link DefaultThreadFactory}.
     */
    public UnorderedThreadPoolEventExecutor(int corePoolSize, RejectedExecutionHandler handler) {
        this(corePoolSize, new DefaultThreadFactory(UnorderedThreadPoolEventExecutor.class), handler);
    }

    /**
     * See {@link ScheduledThreadPoolExecutor#ScheduledThreadPoolExecutor(int, ThreadFactory, RejectedExecutionHandler)}
     */
    public UnorderedThreadPoolEventExecutor(int corePoolSize, ThreadFactory threadFactory,
                                            RejectedExecutionHandler handler) {
        super(corePoolSize, threadFactory, handler);
    }

    @Override
    public EventExecutor next() {
        return this;
    }

    @Override
    public EventExecutorGroup parent() {
        return this;
    }

    @Override
    public boolean inEventLoop() {
        return false;
    }

    @Override
    public boolean inEventLoop(Thread thread) {
        return false;
    }

    @Override
    public  Promise newPromise() {
        return new DefaultPromise(this);
    }

    @Override
    public  ProgressivePromise newProgressivePromise() {
        return new DefaultProgressivePromise(this);
    }

    @Override
    public  Future newSucceededFuture(V result) {
        return new SucceededFuture(this, result);
    }

    @Override
    public  Future newFailedFuture(Throwable cause) {
        return new FailedFuture(this, cause);
    }

    @Override
    public boolean isShuttingDown() {
        return isShutdown();
    }

    @Override
    public List shutdownNow() {
        List tasks = super.shutdownNow();
        terminationFuture.trySuccess(null);
        return tasks;
    }

    @Override
    public void shutdown() {
        super.shutdown();
        terminationFuture.trySuccess(null);
    }

    @Override
    public Future shutdownGracefully() {
        return shutdownGracefully(2, 15, TimeUnit.SECONDS);
    }

    @Override
    public Future shutdownGracefully(long quietPeriod, long timeout, TimeUnit unit) {
        // TODO: At the moment this just calls shutdown but we may be able to do something more smart here which
        //       respects the quietPeriod and timeout.
        shutdown();
        return terminationFuture();
    }

    @Override
    public Future terminationFuture() {
        return terminationFuture;
    }

    @Override
    public Iterator iterator() {
        return executorSet.iterator();
    }

    @Override
    protected  RunnableScheduledFuture decorateTask(Runnable runnable, RunnableScheduledFuture task) {
        return runnable instanceof NonNotifyRunnable ?
                task : new RunnableScheduledFutureTask(this, runnable, task);
    }

    @Override
    protected  RunnableScheduledFuture decorateTask(Callable callable, RunnableScheduledFuture task) {
        return new RunnableScheduledFutureTask(this, callable, task);
    }

    @Override
    public ScheduledFuture schedule(Runnable command, long delay, TimeUnit unit) {
        return (ScheduledFuture) super.schedule(command, delay, unit);
    }

    @Override
    public  ScheduledFuture schedule(Callable callable, long delay, TimeUnit unit) {
        return (ScheduledFuture) super.schedule(callable, delay, unit);
    }

    @Override
    public ScheduledFuture scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit) {
        return (ScheduledFuture) super.scheduleAtFixedRate(command, initialDelay, period, unit);
    }

    @Override
    public ScheduledFuture scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit) {
        return (ScheduledFuture) super.scheduleWithFixedDelay(command, initialDelay, delay, unit);
    }

    @Override
    public Future submit(Runnable task) {
        return (Future) super.submit(task);
    }

    @Override
    public  Future submit(Runnable task, T result) {
        return (Future) super.submit(task, result);
    }

    @Override
    public  Future submit(Callable task) {
        return (Future) super.submit(task);
    }

    @Override
    public void execute(Runnable command) {
        super.schedule(new NonNotifyRunnable(command), 0, NANOSECONDS);
    }

    private static final class RunnableScheduledFutureTask extends PromiseTask
            implements RunnableScheduledFuture, ScheduledFuture {
        private final RunnableScheduledFuture future;

        RunnableScheduledFutureTask(EventExecutor executor, Runnable runnable,
                                           RunnableScheduledFuture future) {
            super(executor, runnable, null);
            this.future = future;
        }

        RunnableScheduledFutureTask(EventExecutor executor, Callable callable,
                                           RunnableScheduledFuture future) {
            super(executor, callable);
            this.future = future;
        }

        @Override
        public void run() {
            if (!isPeriodic()) {
                super.run();
            } else if (!isDone()) {
                try {
                    // Its a periodic task so we need to ignore the return value
                    task.call();
                } catch (Throwable cause) {
                    if (!tryFailureInternal(cause)) {
                        logger.warn("Failure during execution of task", cause);
                    }
                }
            }
        }

        @Override
        public boolean isPeriodic() {
            return future.isPeriodic();
        }

        @Override
        public long getDelay(TimeUnit unit) {
            return future.getDelay(unit);
        }

        @Override
        public int compareTo(Delayed o) {
            return future.compareTo(o);
        }
    }

    // This is a special wrapper which we will be used in execute(...) to wrap the submitted Runnable. This is needed as
    // ScheduledThreadPoolExecutor.execute(...) will delegate to submit(...) which will then use decorateTask(...).
    // The problem with this is that decorateTask(...) needs to ensure we only do our own decoration if we not call
    // from execute(...) as otherwise we may end up creating an endless loop because DefaultPromise will call
    // EventExecutor.execute(...) when notify the listeners of the promise.
    //
    // See https://github.com/netty/netty/issues/6507
    private static final class NonNotifyRunnable implements Runnable {

        private final Runnable task;

        NonNotifyRunnable(Runnable task) {
            this.task = task;
        }

        @Override
        public void run() {
            task.run();
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy