Java tutorial
/* * 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 { // } }