redis.client.jedis.CustomShardedJedisFactory.java Source code

Java tutorial

Introduction

Here is the source code for redis.client.jedis.CustomShardedJedisFactory.java

Source

/*
 * Copyright 2002-2014 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 redis.client.jedis;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.regex.Pattern;

import org.apache.commons.pool2.PooledObject;
import org.apache.commons.pool2.PooledObjectFactory;
import org.apache.commons.pool2.impl.DefaultPooledObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import redis.client.util.GenericTimer;
import redis.clients.jedis.Client;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisShardInfo;
import redis.clients.jedis.ShardedJedis;
import redis.clients.util.Hashing;

/**
 * "?Jedis"{@link PooledObjectFactory<ShardedJedis>}
 * 
 * @author huagang.li 2014128 ?6:58:03
 */
public class CustomShardedJedisFactory implements PooledObjectFactory<ShardedJedis> {

    private static final Logger logger = LoggerFactory.getLogger(CustomShardedJedisFactory.class);

    /** Jedis? */
    private List<JedisShardInfo> shards;
    /** ?Jedis?? */
    private final int originalShardListSize;
    /**  */
    private final Hashing algo;
    /** ? */
    private final Pattern keyTagPattern;

    /*
     * Redis??
     */
    /** "??"? */
    private final Object serverStateCheckLock = new Object();
    /** "Redis??" */
    // @GuardedBy("serverStateCheckLock")
    private JedisServerStateCheckTimerTask serverStateCheckTimerTask = null;

    /**
     * "?Jedis"
     * 
     * @param shards Jedis?
     * @param algo 
     * @param keyTagPattern ?
     * @param timeBetweenServerStateCheckRunsMillis "Redis??"?
     * @param pingRetryTimes Redis PING?
     */
    public CustomShardedJedisFactory(List<JedisShardInfo> shards, Hashing algo, Pattern keyTagPattern,
            int timeBetweenServerStateCheckRunsMillis, int pingRetryTimes) {
        this.shards = shards;
        this.originalShardListSize = shards.size();
        this.algo = algo;
        this.keyTagPattern = keyTagPattern;

        this.startServerStateCheckTimerTask(timeBetweenServerStateCheckRunsMillis, pingRetryTimes);
    }

    /**
     * ?"Redis??"
     */
    private final void startServerStateCheckTimerTask(long delay, int pingRetryTimes) {
        synchronized (serverStateCheckLock) { // ??
            if (null != serverStateCheckTimerTask) {
                // ?
                GenericTimer.cancel(serverStateCheckTimerTask);
                serverStateCheckTimerTask = null;
            }
            if (delay > 0) {
                serverStateCheckTimerTask = new JedisServerStateCheckTimerTask(shards, pingRetryTimes);
                GenericTimer.schedule(serverStateCheckTimerTask, delay, delay);
            }
        }
    }

    /**
     * {@link ShardedJedis}?{@link PooledObject}?
     * <p>
     * {@inheritDoc}
     */
    @Override
    public PooledObject<ShardedJedis> makeObject() throws Exception {
        ShardedJedis shardedJedis = new ShardedJedis(shards, algo, keyTagPattern);
        return new DefaultPooledObject<ShardedJedis>(shardedJedis);
    }

    /**
     * ?{@link PooledObject<ShardedJedis>}
     * <p>
     * {@inheritDoc}
     */
    @Override
    public void destroyObject(PooledObject<ShardedJedis> pooledShardedJedis) throws Exception {
        final ShardedJedis shardedJedis = pooledShardedJedis.getObject();

        // shardedJedis.disconnect(); // "?"
        for (Jedis jedis : shardedJedis.getAllShards()) {
            try {
                // 1. ?
                jedis.quit();
            } catch (Exception e) {
                // ignore the exception node, so that all other normal nodes can release all connections.

                // java.lang.ClassCastException: java.lang.Long cannot be cast to [B
                // (zadd/zcard  long  quit  string ?)
                logger.warn("quit jedis connection for server fail: " + toServerString(jedis), e);
            }

            try {
                // 2. 
                jedis.disconnect();
            } catch (Exception e) {
                // ignore the exception node, so that all other normal nodes can release all connections.

                logger.warn("disconnect jedis connection fail: " + toServerString(jedis), e);
            }
        }
    }

    /**
     * <pre>
     * ?
     *      host:port
     * </pre>
     */
    private static String toServerString(Jedis jedis) {
        final Client client = jedis.getClient();
        return client.getHost() + ':' + client.getPort();
    }

    /**
     * {@link ShardedJedis}Jedis?
     * <p>
     * <font color="red">'PING'???"Jedis"?</font>
     * <p>
     * {@inheritDoc}
     */
    @Override
    public boolean validateObject(PooledObject<ShardedJedis> pooledShardedJedis) {
        final ShardedJedis shardedJedis = pooledShardedJedis.getObject();
        // "Sharded.getAllShardInfo() returns 160*shards info list not returns the original shards list"
        // https://github.com/xetorthio/jedis/issues/837
        Collection<JedisShardInfo> allClusterShardInfos = shardedJedis.getAllShardInfo(); // ?160??ShardedJedisTest.getAllShardInfo()
        // ??Shard?
        Set<JedisShardInfo> checkedShards = new HashSet<JedisShardInfo>(originalShardListSize);
        checkedShards.addAll(allClusterShardInfos);
        logger.debug("Active Shard list for current validated sharded Jedis: {}", checkedShards);

        // "?"
        if (serverStateCheckTimerTask.isActiveShardListUpdated()) {
            shards = new ArrayList<JedisShardInfo>(serverStateCheckTimerTask.getAllActiveJedisShards());
            logger.debug("Active Shard list after updated: {}", shards);
        }

        if (checkedShards.size() != shards.size()) { // ?
            logger.debug("Find a pooled sharded Jedis is updated: {}", checkedShards);
            return false;
        } else { // ????(?????)
            if (!checkedShards.containsAll(shards)) {
                logger.debug("Find a pooled sharded Jedis is updated: {}", checkedShards);
                return false;
            }
        }

        return true;
    }

    /**
     * ??{@link ShardedJedis}
     * <p>
     * {@inheritDoc}
     */
    @Override
    public void activateObject(PooledObject<ShardedJedis> p) throws Exception {
        //
    }

    /**
     * ??{@link ShardedJedis}(idleObjects)
     * <p>
     * {@inheritDoc}
     */
    @Override
    public void passivateObject(PooledObject<ShardedJedis> p) throws Exception {
        //
    }

}