package com.vip.saturn.job.reg.zookeeper; import java.io.IOException; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Map.Entry; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import org.apache.curator.framework.CuratorFramework; import org.apache.curator.framework.recipes.cache.NodeCache; import org.apache.curator.framework.recipes.cache.NodeCacheListener; import org.apache.curator.framework.recipes.cache.TreeCache; import org.apache.curator.framework.recipes.cache.TreeCacheListener; import org.apache.curator.utils.CloseableExecutorService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.vip.saturn.job.internal.storage.JobNodePath; import com.vip.saturn.job.threads.SaturnThreadFactory; /** * @author chembo.huang * */ public class ZkCacheManager { static Logger log = LoggerFactory.getLogger(ZkCacheManager.class); private Map<String/*path-depth*/, TreeCache> treeCacheMap = new HashMap<>(); private Map<String/*path*/, NodeCache> nodeCacheMap = new HashMap<>(); private CuratorFramework client; private String jobName; private String executorName; private ExecutorService executorService; public ZkCacheManager(CuratorFramework client, String jobName, String executorName) { this.client = client; this.jobName = jobName; this.executorName = executorName; executorService = Executors.newSingleThreadExecutor(new SaturnThreadFactory(executorName + "-" + jobName + "-watcher", false)); log.info("ZkCacheManager for executor:{} - job:{} created.", executorName, jobName); } public NodeCache buildAndStartNodeCache(String path) { try { NodeCache nc = nodeCacheMap.get(path); if (nc == null) { nc = new NodeCache(client, path); nodeCacheMap.put(path, nc); nc.start(); log.info("{} - {} builds nodeCache for path = {}", executorName, jobName, path); } return nc; } catch (Exception e) { log.error("{} - {} fails in building nodeCache for path = {}, saturn will not work correctly.", executorName, jobName, path); log.error(e.getMessage(), e); } return null; } private TreeCache buildAndStartTreeCache(String path, int depth) { try { String key = buildMapKey(path, depth); TreeCache tc = treeCacheMap.get(key); if (tc == null) { tc = TreeCache.newBuilder(client, path).setMaxDepth(depth).setExecutor(new CloseableExecutorService(executorService, false)).build(); treeCacheMap.put(key, tc); tc.start(); log.info("{} - {} builds treeCache for path = {}, depth = {}", executorName, jobName, path, depth); } return tc; } catch (Exception e) { log.error("{} - {} fails in building treeCache for path = {}, depth = {}, saturn will not work correctly.", executorName, jobName, path, depth); log.error(e.getMessage(), e); } return null; } public void addTreeCacheListener(final TreeCacheListener listener, final String path, final int depth) { TreeCache tc = buildAndStartTreeCache(path, depth); if (tc != null) { tc.getListenable().addListener(listener); } } public void closeTreeCache(String path, int depth) { String key = buildMapKey(path, depth); TreeCache tc = treeCacheMap.get(key); if (tc != null) { try { tc.close(); treeCacheMap.remove(key); log.info("{} - {} closed treeCache, path and depth is {}", executorName, jobName, key); } catch (Exception e) { log.error(e.getMessage(), e); } } } public void closeAllTreeCache() { Iterator<Entry<String, TreeCache>> iterator = treeCacheMap.entrySet().iterator(); while(iterator.hasNext()) { Entry<String, TreeCache> next = iterator.next(); TreeCache tc = next.getValue(); String path = next.getKey(); try { tc.close(); iterator.remove(); log.info("{} - {} closed treeCache, path and depth is {}", executorName, jobName, path); } catch (Exception e) { log.error(e.getMessage(), e); } } } public void closeNodeCache(String path) { NodeCache nc = nodeCacheMap.get(path); if (nc != null) { try { nc.close(); nodeCacheMap.remove(path); log.info("{} - {} closed nodeCache, path is {}", executorName, jobName, path); } catch (Exception e) { log.error(e.getMessage(), e); } } } public void closeAllNodeCache() { Iterator<Entry<String, NodeCache>> iterator = nodeCacheMap.entrySet().iterator(); while(iterator.hasNext()) { Entry<String, NodeCache> next = iterator.next(); NodeCache nc = next.getValue(); String path = next.getKey(); try { nc.close(); iterator.remove(); log.info("{} - {} closed nodeCache, path is {}", executorName, jobName, path); } catch (Exception e) { log.error(e.getMessage(), e); } } } private static String buildMapKey(String path, int depth) { return path + "-" + depth; } public void addNodeCacheListener(final NodeCacheListener listener, final String path) { NodeCache nc = buildAndStartNodeCache(path); if (nc != null) { nc.getListenable().addListener(listener); } } public ExecutorService getExecutorService() { return executorService; } public void shutdown() { closeAllTreeCache(); closeAllNodeCache(); if (executorService != null && !executorService.isShutdown()) { // Cannot use shutdownNow, because the current thread maybe is running in the pool, and there are codes after this. // Such as JobDeleteListener executorService.shutdown(); } } }