package redis.clients.jedis; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import redis.clients.jedis.exceptions.JedisConnectionException; import redis.clients.jedis.exceptions.JedisMovedDataException; import redis.clients.jedis.exceptions.JedisRedirectionException; import redis.clients.util.JedisClusterCRC16; import java.util.*; /** * Created by yijunzhang on 14-5-26. */ public abstract class PipelineClusterCommand<T> { private final Logger logger = LoggerFactory.getLogger(this.getClass()); private JedisClusterConnectionHandler connectionHandler; protected final PipelineCluster pipelineCluster; public PipelineClusterCommand(PipelineCluster pipelineCluster, JedisClusterConnectionHandler connectionHandler) { this.pipelineCluster = pipelineCluster; this.connectionHandler = connectionHandler; } /** * 执行批处理命令 * * @param pipeline */ public abstract void pipelineCommand(Pipeline pipeline, List<String> pipelineKeys); public abstract T getResult(Map<String, Object> resultMap); public T run(List<String> keys) { if (keys == null || keys.isEmpty()) { return null; } Map<JedisPool, List<String>> poolKeysMap = getPoolKeyMap(keys); Map<String, Object> resultMap = new HashMap<String, Object>(); for (Map.Entry<JedisPool, List<String>> entry : poolKeysMap.entrySet()) { JedisPool jedisPool = entry.getKey(); List<String> subkeys = entry.getValue(); if (subkeys == null || subkeys.isEmpty()) { continue; } //申请jedis对象 Jedis jedis = null; Pipeline pipeline = null; List<Object> subResultList = null; try { jedis = jedisPool.getResource(); pipeline = jedis.pipelined(); pipelineCommand(pipeline, subkeys); subResultList = pipeline.syncAndReturnAll(); } catch (JedisConnectionException e) { logger.error("RedisConnectionError-{}:{} keys={}", jedisPool.getHost(), jedisPool.getPort(), subkeys); logger.error(e.getMessage(), e); } catch (Exception e) { logger.error(e.getMessage(), e); } finally { if (pipeline != null) pipeline.clean(); //释放jedis对象 if (jedis != null) { jedis.close(); } } if (subResultList == null || subResultList.isEmpty()) { continue; } if (subResultList.size() == subkeys.size()) { for (int i = 0; i < subkeys.size(); i++) { String key = subkeys.get(i); Object result = subResultList.get(i); resultMap.put(key, result); } } else { logger.error("PipelineClusterCommand:subkeys={} subResultList={}", subkeys, subResultList); } } return getResult(resultMap); } private Map<JedisPool, List<String>> getPoolKeyMap(List<String> keys) { Map<JedisPool, List<String>> poolKeysMap = new LinkedHashMap<JedisPool, List<String>>(); try { for (String key : keys) { JedisPool jedisPool; int slot = JedisClusterCRC16.getSlot(key); jedisPool = connectionHandler.getJedisPoolFromSlot(slot); if (poolKeysMap.containsKey(jedisPool)) { poolKeysMap.get(jedisPool).add(key); } else { List<String> subKeyList = new ArrayList<String>(); subKeyList.add(key); poolKeysMap.put(jedisPool, subKeyList); } } } catch (Exception e) { logger.error(e.getMessage(), e); } return poolKeysMap; } protected boolean checkException(Object obj) { if (obj instanceof Exception) { Exception e = (Exception) obj; if (e instanceof JedisRedirectionException) { //重定向slot 映射. if (e instanceof JedisMovedDataException) { // it rebuilds cluster's slot cache // recommended by Redis cluster specification this.connectionHandler.renewSlotCache(); logger.warn("JedisMovedDataException:" + e.getMessage(), e); } else { logger.error("pipeline-error:" + e.getMessage(), e); } } else { logger.error(e.getMessage(), e); } return true; } return false; } }