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

com.lambdaworks.redis.resource.DefaultEventLoopGroupProvider Maven / Gradle / Ivy

/*
 * Copyright 2011-2016 the original author or authors.
 *
 * Licensed 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 com.lambdaworks.redis.resource;

import static com.lambdaworks.redis.resource.Futures.toBooleanPromise;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.TimeUnit;

import com.lambdaworks.redis.EpollProvider;

import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.util.concurrent.*;
import io.netty.util.internal.logging.InternalLogger;
import io.netty.util.internal.logging.InternalLoggerFactory;

/**
 * Default implementation which manages one event loop group instance per type.
 * 
 * @author Mark Paluch
 * @since 3.4
 */
public class DefaultEventLoopGroupProvider implements EventLoopGroupProvider {

    protected static final InternalLogger logger = InternalLoggerFactory.getInstance(DefaultEventLoopGroupProvider.class);

    private final Map, EventExecutorGroup> eventLoopGroups = new ConcurrentHashMap<>(2);
    private final Map refCounter = new ConcurrentHashMap<>(2);

    private final int numberOfThreads;

    private volatile boolean shutdownCalled = false;

    /**
     * Creates a new instance of {@link DefaultEventLoopGroupProvider}.
     * 
     * @param numberOfThreads number of threads (pool size)
     */
    public DefaultEventLoopGroupProvider(int numberOfThreads) {
        this.numberOfThreads = numberOfThreads;
    }

    @Override
    public  T allocate(Class type) {
        synchronized (this) {
            return addReference(getOrCreate(type));
        }
    }

    private  T addReference(T reference) {

        synchronized (refCounter){
            long counter = 0;
            if(refCounter.containsKey(reference)){
                counter = refCounter.get(reference);
            }

            logger.debug("Adding reference to {}, existing ref count {}", reference, counter);
            counter++;
            refCounter.put(reference, counter);
        }

        return reference;
    }

    private  T release(T reference) {

        synchronized (refCounter) {
            long counter = 0;
            if (refCounter.containsKey(reference)) {
                counter = refCounter.get(reference);
            }

            if (counter < 1) {
                logger.debug("Attempting to release {} but ref count is {}", reference, counter);
            }

            counter--;
            if (counter == 0) {
                refCounter.remove(reference);
            } else {
                refCounter.put(reference, counter);
            }
        }

        return reference;
    }

    @SuppressWarnings("unchecked")
    private  T getOrCreate(Class type) {

        if (shutdownCalled) {
            throw new IllegalStateException("Provider is shut down and can not longer provide resources");
        }

        if (!eventLoopGroups.containsKey(type)) {
            eventLoopGroups.put(type, createEventLoopGroup(type, numberOfThreads));
        }

        return (T) eventLoopGroups.get(type);
    }

    /**
     * Create an instance of a {@link EventExecutorGroup}. Supported types are:
     * 
    *
  • DefaultEventExecutorGroup
  • *
  • NioEventLoopGroup
  • *
  • EpollEventLoopGroup
  • *
* * @param type the type * @param numberOfThreads the number of threads to use for the {@link EventExecutorGroup} * @param type parameter * @return a new instance of a {@link EventExecutorGroup} * @throws IllegalArgumentException if the {@code type} is not supported. */ public static EventExecutorGroup createEventLoopGroup(Class type, int numberOfThreads) { if (DefaultEventExecutorGroup.class.equals(type)) { return new DefaultEventExecutorGroup(numberOfThreads, new DefaultThreadFactory("lettuce-eventExecutorLoop", true)); } if (NioEventLoopGroup.class.equals(type)) { return new NioEventLoopGroup(numberOfThreads, new DefaultThreadFactory("lettuce-nioEventLoop", true)); } if (EpollProvider.epollEventLoopGroupClass != null && EpollProvider.epollEventLoopGroupClass.equals(type)) { return EpollProvider.newEventLoopGroup(numberOfThreads, new DefaultThreadFactory("lettuce-epollEventLoop", true)); } throw new IllegalArgumentException("Type " + type.getName() + " not supported"); } @Override public Promise release(EventExecutorGroup eventLoopGroup, long quietPeriod, long timeout, TimeUnit unit) { Class key = getKey(release(eventLoopGroup)); if ((key == null && eventLoopGroup.isShuttingDown()) || refCounter.containsKey(eventLoopGroup)) { DefaultPromise promise = new DefaultPromise(GlobalEventExecutor.INSTANCE); promise.setSuccess(true); return promise; } if (key != null) { eventLoopGroups.remove(key); } Future shutdownFuture = eventLoopGroup.shutdownGracefully(quietPeriod, timeout, unit); return toBooleanPromise(shutdownFuture); } private Class getKey(EventExecutorGroup eventLoopGroup) { Class key = null; Map, EventExecutorGroup> copy = new HashMap<>(eventLoopGroups); for (Map.Entry, EventExecutorGroup> entry : copy.entrySet()) { if (entry.getValue() == eventLoopGroup) { key = entry.getKey(); break; } } return key; } @Override public int threadPoolSize() { return numberOfThreads; } @Override @SuppressWarnings("unchecked") public Future shutdown(long quietPeriod, long timeout, TimeUnit timeUnit) { shutdownCalled = true; Map, EventExecutorGroup> copy = new HashMap<>(eventLoopGroups); DefaultPromise overall = new DefaultPromise(GlobalEventExecutor.INSTANCE); DefaultPromise lastRelease = new DefaultPromise(GlobalEventExecutor.INSTANCE); Futures.PromiseAggregator> aggregator = new Futures.PromiseAggregator>( overall); aggregator.expectMore(1 + copy.size()); aggregator.arm(); for (EventExecutorGroup executorGroup : copy.values()) { Promise shutdown = toBooleanPromise(release(executorGroup, quietPeriod, timeout, timeUnit)); aggregator.add(shutdown); } aggregator.add(lastRelease); lastRelease.setSuccess(null); return toBooleanPromise(overall); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy