Java tutorial
/* * Copyright (C) 2011 Near Infinity Corporation * * 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.nearinfinity.blur.manager.clusterstatus; import java.io.Closeable; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; import org.apache.hadoop.io.compress.CompressionCodec; import org.apache.hadoop.io.compress.DeflateCodec; import org.apache.lucene.search.Similarity; import org.apache.thrift.TBase; import org.apache.thrift.TException; import org.apache.thrift.protocol.TJSONProtocol; import org.apache.thrift.transport.TMemoryInputTransport; import org.apache.zookeeper.CreateMode; import org.apache.zookeeper.KeeperException; import org.apache.zookeeper.WatchedEvent; import org.apache.zookeeper.Watcher; import org.apache.zookeeper.ZooDefs.Ids; import org.apache.zookeeper.ZooKeeper; import org.apache.zookeeper.data.Stat; import com.nearinfinity.blur.analysis.BlurAnalyzer; import com.nearinfinity.blur.log.Log; import com.nearinfinity.blur.log.LogFactory; import com.nearinfinity.blur.lucene.search.FairSimilarity; import com.nearinfinity.blur.thrift.generated.AnalyzerDefinition; import com.nearinfinity.blur.thrift.generated.ColumnPreCache; import com.nearinfinity.blur.thrift.generated.TableDescriptor; import com.nearinfinity.blur.utils.BlurUtil; import com.nearinfinity.blur.zookeeper.WatchChildren; import com.nearinfinity.blur.zookeeper.WatchChildren.OnChange; import com.nearinfinity.blur.zookeeper.WatchNodeData; import com.nearinfinity.blur.zookeeper.WatchNodeExistance; import com.nearinfinity.blur.zookeeper.ZkUtils; public class ZookeeperClusterStatus extends ClusterStatus { private static final Log LOG = LogFactory.getLog(ZookeeperClusterStatus.class); private ZooKeeper _zk; private AtomicBoolean _running = new AtomicBoolean(); private ConcurrentMap<String, Long> _safeModeMap = new ConcurrentHashMap<String, Long>(); private ConcurrentMap<String, List<String>> _onlineShardsNodes = new ConcurrentHashMap<String, List<String>>(); private ConcurrentMap<String, Set<String>> _tablesPerCluster = new ConcurrentHashMap<String, Set<String>>(); private AtomicReference<Set<String>> _clusters = new AtomicReference<Set<String>>(new HashSet<String>()); private ConcurrentMap<String, Boolean> _enabled = new ConcurrentHashMap<String, Boolean>(); private ConcurrentMap<String, Boolean> _readOnly = new ConcurrentHashMap<String, Boolean>(); private WatchChildren _clusterWatcher; private ConcurrentMap<String, WatchChildren> _onlineShardsNodesWatchers = new ConcurrentHashMap<String, WatchChildren>(); private ConcurrentMap<String, WatchChildren> _tableWatchers = new ConcurrentHashMap<String, WatchChildren>(); private ConcurrentMap<String, WatchNodeExistance> _safeModeWatchers = new ConcurrentHashMap<String, WatchNodeExistance>(); private ConcurrentMap<String, WatchNodeData> _safeModeDataWatchers = new ConcurrentHashMap<String, WatchNodeData>(); private ConcurrentMap<String, WatchNodeExistance> _enabledWatchNodeExistance = new ConcurrentHashMap<String, WatchNodeExistance>(); private ConcurrentMap<String, WatchNodeExistance> _readOnlyWatchNodeExistance = new ConcurrentHashMap<String, WatchNodeExistance>(); public ZookeeperClusterStatus(ZooKeeper zooKeeper) { _zk = zooKeeper; _running.set(true); watchForClusters(); try { Thread.sleep(1000); } catch (InterruptedException e) { throw new RuntimeException(e); } } class Clusters extends OnChange { @Override public void action(List<String> clusters) { _clusters.set(new HashSet<String>(clusters)); for (String cluster : clusters) { if (!_tableWatchers.containsKey(cluster)) { String tablesPath = ZookeeperPathConstants.getTablesPath(cluster); ZkUtils.waitUntilExists(_zk, tablesPath); WatchChildren clusterWatcher = new WatchChildren(_zk, tablesPath).watch(new Tables(cluster)); _tableWatchers.put(cluster, clusterWatcher); String safemodePath = ZookeeperPathConstants.getSafemodePath(cluster); ZkUtils.waitUntilExists(_zk, safemodePath); WatchNodeExistance watchNodeExistance = new WatchNodeExistance(_zk, safemodePath) .watch(new SafeExistance(cluster)); _safeModeWatchers.put(cluster, watchNodeExistance); } } List<String> clustersToCloseAndRemove = new ArrayList<String>(clusters); clustersToCloseAndRemove.removeAll(_tableWatchers.keySet()); for (String cluster : clustersToCloseAndRemove) { WatchChildren watcher = _tableWatchers.remove(cluster); if (watcher == null) { LOG.error("Error watcher is null [" + cluster + "] "); } else { watcher.close(); } } } } class SafeExistance extends WatchNodeExistance.OnChange { private String cluster; public SafeExistance(String cluster) { this.cluster = cluster; } @Override public void action(Stat stat) { if (stat != null) { WatchNodeData watchNodeData = new WatchNodeData(_zk, ZookeeperPathConstants.getSafemodePath(cluster)); watchNodeData.watch(new WatchNodeData.OnChange() { @Override public void action(byte[] data) { if (data == null) { LOG.debug("Safe mode value for cluster [" + cluster + "] is not set."); _safeModeMap.put(cluster, Long.MIN_VALUE); } else { String value = new String(data); LOG.debug("Safe mode value for cluster [" + cluster + "] is [" + value + "]."); _safeModeMap.put(cluster, Long.parseLong(value)); } } }); WatchNodeData nodeData = _safeModeDataWatchers.put(cluster, watchNodeData); if (nodeData != null) { nodeData.close(); } } } } class Tables extends OnChange { private String cluster; public Tables(String cluster) { this.cluster = cluster; } @Override public void action(List<String> tables) { Set<String> newSet = new HashSet<String>(tables); Set<String> oldSet = _tablesPerCluster.put(cluster, newSet); Set<String> newTables = getNewTables(newSet, oldSet); for (String table : newTables) { final String clusterTableKey = getClusterTableKey(cluster, table); WatchNodeExistance readOnlyWatcher = new WatchNodeExistance(_zk, ZookeeperPathConstants.getTableReadOnlyPath(cluster, table)); readOnlyWatcher.watch(new WatchNodeExistance.OnChange() { @Override public void action(Stat stat) { if (stat == null) { _readOnly.put(clusterTableKey, Boolean.FALSE); } else { _readOnly.put(clusterTableKey, Boolean.TRUE); } } }); if (_readOnlyWatchNodeExistance.putIfAbsent(clusterTableKey, readOnlyWatcher) != null) { readOnlyWatcher.close(); } WatchNodeExistance enabledWatcher = new WatchNodeExistance(_zk, ZookeeperPathConstants.getTableEnabledPath(cluster, table)); enabledWatcher.watch(new WatchNodeExistance.OnChange() { @Override public void action(Stat stat) { if (stat == null) { _enabled.put(clusterTableKey, Boolean.FALSE); } else { _enabled.put(clusterTableKey, Boolean.TRUE); } } }); if (_enabledWatchNodeExistance.putIfAbsent(clusterTableKey, enabledWatcher) != null) { enabledWatcher.close(); } } } private Set<String> getNewTables(Set<String> newSet, Set<String> oldSet) { Set<String> newTables = new HashSet<String>(newSet); if (oldSet != null) { newTables.removeAll(oldSet); } return newTables; } } private void watchForClusters() { _clusterWatcher = new WatchChildren(_zk, ZookeeperPathConstants.getClustersPath()).watch(new Clusters()); } public ZookeeperClusterStatus(String connectionStr) throws IOException { this(new ZooKeeper(connectionStr, 30000, new Watcher() { @Override public void process(WatchedEvent event) { } })); } private String getClusterTableKey(String cluster, String table) { return cluster + "." + table; } @Override public List<String> getClusterList(boolean useCache) { if (useCache) { return new ArrayList<String>(_clusters.get()); } long s = System.nanoTime(); try { checkIfOpen(); return _zk.getChildren(ZookeeperPathConstants.getClustersPath(), false); } catch (KeeperException e) { throw new RuntimeException(e); } catch (InterruptedException e) { throw new RuntimeException(e); } finally { long e = System.nanoTime(); LOG.debug("trace getClusterList [" + (e - s) / 1000000.0 + " ms]"); } } private void checkIfOpen() { if (_running.get()) { return; } throw new RuntimeException("not open"); } @Override public List<String> getControllerServerList() { long s = System.nanoTime(); try { checkIfOpen(); return _zk.getChildren(ZookeeperPathConstants.getOnlineControllersPath(), false); } catch (KeeperException e) { throw new RuntimeException(e); } catch (InterruptedException e) { throw new RuntimeException(e); } finally { long e = System.nanoTime(); LOG.debug("trace getControllerServerList [" + (e - s) / 1000000.0 + " ms]"); } } @Override public List<String> getOnlineShardServers(boolean useCache, String cluster) { if (useCache) { List<String> shards = _onlineShardsNodes.get(cluster); if (shards != null) { return shards; } else { watchForOnlineShardNodes(cluster); } } long s = System.nanoTime(); try { checkIfOpen(); return _zk.getChildren(ZookeeperPathConstants.getClustersPath() + "/" + cluster + "/online/shard-nodes", false); } catch (KeeperException e) { throw new RuntimeException(e); } catch (InterruptedException e) { throw new RuntimeException(e); } finally { long e = System.nanoTime(); LOG.debug("trace getOnlineShardServers took [" + (e - s) / 1000000.0 + " ms]"); } } private void watchForOnlineShardNodes(final String cluster) { WatchChildren watch = new WatchChildren(_zk, ZookeeperPathConstants.getOnlineShardsPath(cluster)) .watch(new OnChange() { @Override public void action(List<String> children) { _onlineShardsNodes.put(cluster, children); } }); if (_onlineShardsNodesWatchers.putIfAbsent(cluster, watch) != null) { // There was already a watch created. Close the extra watcher. watch.close(); } } @Override public List<String> getShardServerList(String cluster) { long s = System.nanoTime(); try { checkIfOpen(); return _zk.getChildren(ZookeeperPathConstants.getClustersPath() + "/" + cluster + "/shard-nodes", false); } catch (KeeperException e) { throw new RuntimeException(e); } catch (InterruptedException e) { throw new RuntimeException(e); } finally { long e = System.nanoTime(); LOG.debug("trace getShardServerList took [" + (e - s) / 1000000.0 + " ms]"); } } @Override public boolean exists(boolean useCache, String cluster, String table) { if (useCache) { Set<String> tables = _tablesPerCluster.get(cluster); if (tables != null) { if (tables.contains(table)) { return true; } } } long s = System.nanoTime(); try { checkIfOpen(); if (_zk.exists(ZookeeperPathConstants.getTablePath(cluster, table), false) == null) { return false; } return true; } catch (KeeperException e) { throw new RuntimeException(e); } catch (InterruptedException e) { throw new RuntimeException(e); } finally { long e = System.nanoTime(); LOG.debug("trace exists took [" + (e - s) / 1000000.0 + " ms]"); } } @Override public boolean isEnabled(boolean useCache, String cluster, String table) { if (useCache) { Boolean e = _enabled.get(getClusterTableKey(cluster, table)); if (e != null) { return e; } } long s = System.nanoTime(); String tablePathIsEnabled = ZookeeperPathConstants.getTableEnabledPath(cluster, table); try { checkIfOpen(); if (_zk.exists(tablePathIsEnabled, false) == null) { return false; } } catch (KeeperException e) { throw new RuntimeException(e); } catch (InterruptedException e) { throw new RuntimeException(e); } finally { long e = System.nanoTime(); LOG.debug("trace isEnabled took [" + (e - s) / 1000000.0 + " ms]"); } return true; } private Map<String, TableDescriptor> _tableDescriptorCache = new ConcurrentHashMap<String, TableDescriptor>(); @Override public TableDescriptor getTableDescriptor(boolean useCache, String cluster, String table) { if (useCache) { TableDescriptor tableDescriptor = _tableDescriptorCache.get(table); updateReadOnlyAndEnabled(useCache, tableDescriptor, cluster, table); if (tableDescriptor != null) { return tableDescriptor; } } long s = System.nanoTime(); TableDescriptor tableDescriptor = new TableDescriptor(); try { checkIfOpen(); tableDescriptor.shardCount = Integer .parseInt(new String(getData(ZookeeperPathConstants.getTableShardCountPath(cluster, table)))); tableDescriptor.tableUri = new String(getData(ZookeeperPathConstants.getTableUriPath(cluster, table))); tableDescriptor.compressionClass = new String( getData(ZookeeperPathConstants.getTableCompressionCodecPath(cluster, table))); tableDescriptor.compressionBlockSize = Integer.parseInt( new String(getData(ZookeeperPathConstants.getTableCompressionBlockSizePath(cluster, table)))); tableDescriptor.analyzerDefinition = fromBytes( getData(ZookeeperPathConstants.getTablePath(cluster, table)), AnalyzerDefinition.class); tableDescriptor.blockCaching = isBlockCacheEnabled(cluster, table); tableDescriptor.blockCachingFileTypes = getBlockCacheFileTypes(cluster, table); tableDescriptor.name = table; tableDescriptor.columnPreCache = fromBytes( getData(ZookeeperPathConstants.getTableColumnsToPreCache(cluster, table)), ColumnPreCache.class); byte[] data = getData(ZookeeperPathConstants.getTableSimilarityPath(cluster, table)); if (data != null) { tableDescriptor.similarityClass = new String(data); } updateReadOnlyAndEnabled(useCache, tableDescriptor, cluster, table); } catch (KeeperException e) { throw new RuntimeException(e); } catch (InterruptedException e) { throw new RuntimeException(e); } finally { long e = System.nanoTime(); LOG.debug("trace getTableDescriptor took [" + (e - s) / 1000000.0 + " ms]"); } tableDescriptor.cluster = cluster; _tableDescriptorCache.put(table, tableDescriptor); return tableDescriptor; } private void updateReadOnlyAndEnabled(boolean useCache, TableDescriptor tableDescriptor, String cluster, String table) { if (tableDescriptor != null) { tableDescriptor.setReadOnly(isReadOnly(useCache, cluster, table)); tableDescriptor.setIsEnabled(isEnabled(useCache, cluster, table)); } } @SuppressWarnings("unchecked") private <T extends TBase<?, ?>> T fromBytes(byte[] data, Class<T> clazz) { try { if (data == null) { return null; } TBase<?, ?> base = clazz.newInstance(); TMemoryInputTransport trans = new TMemoryInputTransport(data); TJSONProtocol protocol = new TJSONProtocol(trans); base.read(protocol); trans.close(); return (T) base; } catch (InstantiationException e) { throw new RuntimeException(e); } catch (IllegalAccessException e) { throw new RuntimeException(e); } catch (TException e) { throw new RuntimeException(e); } } private byte[] getData(String path) throws KeeperException, InterruptedException { Stat stat = _zk.exists(path, false); if (stat == null) { return null; } return _zk.getData(path, false, stat); } @Override public List<String> getTableList(boolean useCache, String cluster) { if (useCache) { Set<String> tables = _tablesPerCluster.get(cluster); if (tables != null) { return new ArrayList<String>(tables); } } long s = System.nanoTime(); try { checkIfOpen(); return _zk.getChildren(ZookeeperPathConstants.getTablesPath(cluster), false); } catch (KeeperException e) { throw new RuntimeException(e); } catch (InterruptedException e) { throw new RuntimeException(e); } finally { long e = System.nanoTime(); LOG.debug("trace getTableList took [" + (e - s) / 1000000.0 + " ms]"); } } public void close() { if (_running.get()) { _running.set(false); close(_clusterWatcher); close(_onlineShardsNodesWatchers); close(_tableWatchers); close(_safeModeWatchers); close(_safeModeDataWatchers); close(_enabledWatchNodeExistance); close(_readOnlyWatchNodeExistance); } } private void close(ConcurrentMap<String, ? extends Closeable> closableMap) { Collection<? extends Closeable> values = closableMap.values(); for (Closeable closeable : values) { close(closeable); } } private void close(Closeable closeable) { try { closeable.close(); } catch (IOException e) { LOG.error("Unknown error while trying to close [{0}]", closeable); } } @Override public String getCluster(boolean useCache, String table) { if (useCache) { for (Entry<String, Set<String>> entry : _tablesPerCluster.entrySet()) { if (entry.getValue().contains(table)) { return entry.getKey(); } } } List<String> clusterList = getClusterList(useCache); for (String cluster : clusterList) { long s = System.nanoTime(); try { checkIfOpen(); Stat stat = _zk.exists(ZookeeperPathConstants.getTablePath(cluster, table), false); if (stat != null) { // _tableToClusterCache.put(table, cluster); return cluster; } } catch (KeeperException e) { throw new RuntimeException(e); } catch (InterruptedException e) { throw new RuntimeException(e); } finally { long e = System.nanoTime(); LOG.debug("trace getCluster took [" + (e - s) / 1000000.0 + " ms]"); } } return null; } @Override public boolean isInSafeMode(boolean useCache, String cluster) { if (useCache) { Long safeModeTimestamp = _safeModeMap.get(cluster); if (safeModeTimestamp != null && safeModeTimestamp != Long.MIN_VALUE) { return safeModeTimestamp < System.currentTimeMillis() ? false : true; } } long s = System.nanoTime(); try { checkIfOpen(); String blurSafemodePath = ZookeeperPathConstants.getSafemodePath(cluster); Stat stat = _zk.exists(blurSafemodePath, false); if (stat == null) { return false; } byte[] data = _zk.getData(blurSafemodePath, false, stat); if (data == null) { return false; } long timestamp = Long.parseLong(new String(data)); long waitTime = timestamp - System.currentTimeMillis(); if (waitTime > 0) { return true; } return false; } catch (KeeperException e) { throw new RuntimeException(e); } catch (InterruptedException e) { throw new RuntimeException(e); } finally { long e = System.nanoTime(); LOG.debug("trace isInSafeMode took [" + (e - s) / 1000000.0 + " ms]"); } } @Override public int getShardCount(boolean useCache, String cluster, String table) { if (useCache) { TableDescriptor tableDescriptor = getTableDescriptor(true, cluster, table); return tableDescriptor.shardCount; } long s = System.nanoTime(); try { return Integer .parseInt(new String(getData(ZookeeperPathConstants.getTableShardCountPath(cluster, table)))); } catch (NumberFormatException e) { throw new RuntimeException(e); } catch (KeeperException e) { throw new RuntimeException(e); } catch (InterruptedException e) { throw new RuntimeException(e); } finally { long e = System.nanoTime(); LOG.debug("trace getShardCount took [" + (e - s) / 1000000.0 + " ms]"); } } @Override public Set<String> getBlockCacheFileTypes(String cluster, String table) { long s = System.nanoTime(); try { byte[] data = getData(ZookeeperPathConstants.getTableBlockCachingFileTypesPath(cluster, table)); if (data == null) { return null; } String str = new String(data); if (str.isEmpty()) { return null; } Set<String> types = new HashSet<String>(Arrays.asList(str.split(","))); if (types.isEmpty()) { return null; } return types; } catch (KeeperException e) { throw new RuntimeException(e); } catch (InterruptedException e) { throw new RuntimeException(e); } finally { long e = System.nanoTime(); LOG.debug("trace getBlockCacheFileTypes took [" + (e - s) / 1000000.0 + " ms]"); } } @Override public boolean isBlockCacheEnabled(String cluster, String table) { long s = System.nanoTime(); try { checkIfOpen(); if (_zk.exists(ZookeeperPathConstants.getTableBlockCachingFileTypesPath(cluster, table), false) == null) { return false; } } catch (KeeperException e) { throw new RuntimeException(e); } catch (InterruptedException e) { throw new RuntimeException(e); } finally { long e = System.nanoTime(); LOG.debug("trace isBlockCacheEnabled took [" + (e - s) / 1000000.0 + " ms]"); } return true; } @Override public boolean isReadOnly(boolean useCache, String cluster, String table) { if (useCache) { Boolean ro = _readOnly.get(getClusterTableKey(cluster, table)); if (ro != null) { return ro; } } long s = System.nanoTime(); String path = ZookeeperPathConstants.getTableReadOnlyPath(cluster, table); try { checkIfOpen(); if (_zk.exists(path, false) == null) { return false; } return true; } catch (KeeperException e) { throw new RuntimeException(e); } catch (InterruptedException e) { throw new RuntimeException(e); } finally { long e = System.nanoTime(); LOG.debug("trace isReadOnly took [" + (e - s) / 1000000.0 + " ms]"); } } @Override public void createTable(TableDescriptor tableDescriptor) { long s = System.nanoTime(); try { checkIfOpen(); if (tableDescriptor.getCompressionClass() == null) { tableDescriptor.setCompressionClass(DeflateCodec.class.getName()); } if (tableDescriptor.getSimilarityClass() == null) { tableDescriptor.setSimilarityClass(FairSimilarity.class.getName()); } if (tableDescriptor.getAnalyzerDefinition() == null) { tableDescriptor.setAnalyzerDefinition(new AnalyzerDefinition()); } String table = BlurUtil.nullCheck(tableDescriptor.name, "tableDescriptor.name cannot be null."); String cluster = BlurUtil.nullCheck(tableDescriptor.cluster, "tableDescriptor.cluster cannot be null."); BlurAnalyzer analyzer = new BlurAnalyzer(BlurUtil.nullCheck(tableDescriptor.analyzerDefinition, "tableDescriptor.analyzerDefinition cannot be null.")); String uri = BlurUtil.nullCheck(tableDescriptor.tableUri, "tableDescriptor.tableUri cannot be null."); int shardCount = BlurUtil.zeroCheck(tableDescriptor.shardCount, "tableDescriptor.shardCount cannot be less than 1"); CompressionCodec compressionCodec = BlurUtil.getInstance(tableDescriptor.compressionClass, CompressionCodec.class); // @TODO check block size int compressionBlockSize = tableDescriptor.compressionBlockSize; Similarity similarity = BlurUtil.getInstance(tableDescriptor.similarityClass, Similarity.class); boolean blockCaching = tableDescriptor.blockCaching; Set<String> blockCachingFileTypes = tableDescriptor.blockCachingFileTypes; String blurTablePath = ZookeeperPathConstants.getTablePath(cluster, table); ColumnPreCache columnPreCache = tableDescriptor.columnPreCache; if (_zk.exists(blurTablePath, false) != null) { throw new IOException("Table [" + table + "] already exists."); } BlurUtil.setupFileSystem(uri, shardCount); BlurUtil.createPath(_zk, blurTablePath, analyzer.toJSON().getBytes()); BlurUtil.createPath(_zk, ZookeeperPathConstants.getTableColumnsToPreCache(cluster, table), BlurUtil.read(columnPreCache)); BlurUtil.createPath(_zk, ZookeeperPathConstants.getTableUriPath(cluster, table), uri.getBytes()); BlurUtil.createPath(_zk, ZookeeperPathConstants.getTableShardCountPath(cluster, table), Integer.toString(shardCount).getBytes()); BlurUtil.createPath(_zk, ZookeeperPathConstants.getTableCompressionCodecPath(cluster, table), compressionCodec.getClass().getName().getBytes()); BlurUtil.createPath(_zk, ZookeeperPathConstants.getTableCompressionBlockSizePath(cluster, table), Integer.toString(compressionBlockSize).getBytes()); BlurUtil.createPath(_zk, ZookeeperPathConstants.getTableSimilarityPath(cluster, table), similarity.getClass().getName().getBytes()); BlurUtil.createPath(_zk, ZookeeperPathConstants.getLockPath(cluster, table), null); BlurUtil.createPath(_zk, ZookeeperPathConstants.getTableFieldNamesPath(cluster, table), null); if (tableDescriptor.readOnly) { BlurUtil.createPath(_zk, ZookeeperPathConstants.getTableReadOnlyPath(cluster, table), null); } if (blockCaching) { BlurUtil.createPath(_zk, ZookeeperPathConstants.getTableBlockCachingPath(cluster, table), null); } BlurUtil.createPath(_zk, ZookeeperPathConstants.getTableBlockCachingFileTypesPath(cluster, table), toBytes(blockCachingFileTypes)); } catch (IOException e) { throw new RuntimeException(e); } catch (KeeperException e) { throw new RuntimeException(e); } catch (InterruptedException e) { throw new RuntimeException(e); } finally { long e = System.nanoTime(); LOG.debug("trace createTable took [" + (e - s) / 1000000.0 + " ms]"); } } @Override public void disableTable(String cluster, String table) { long s = System.nanoTime(); try { checkIfOpen(); if (_zk.exists(ZookeeperPathConstants.getTablePath(cluster, table), false) == null) { throw new IOException("Table [" + table + "] does not exist."); } String blurTableEnabledPath = ZookeeperPathConstants.getTableEnabledPath(cluster, table); if (_zk.exists(blurTableEnabledPath, false) == null) { throw new IOException("Table [" + table + "] already disabled."); } _zk.delete(blurTableEnabledPath, -1); } catch (IOException e) { throw new RuntimeException(e); } catch (InterruptedException e) { throw new RuntimeException(e); } catch (KeeperException e) { throw new RuntimeException(e); } finally { long e = System.nanoTime(); LOG.debug("trace disableTable took [" + (e - s) / 1000000.0 + " ms]"); } } @Override public void enableTable(String cluster, String table) { long s = System.nanoTime(); try { checkIfOpen(); if (_zk.exists(ZookeeperPathConstants.getTablePath(cluster, table), false) == null) { throw new IOException("Table [" + table + "] does not exist."); } String blurTableEnabledPath = ZookeeperPathConstants.getTableEnabledPath(cluster, table); if (_zk.exists(blurTableEnabledPath, false) != null) { throw new IOException("Table [" + table + "] already enabled."); } _zk.create(blurTableEnabledPath, null, Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); } catch (IOException e) { throw new RuntimeException(e); } catch (InterruptedException e) { throw new RuntimeException(e); } catch (KeeperException e) { throw new RuntimeException(e); } finally { long e = System.nanoTime(); LOG.debug("trace enableTable took [" + (e - s) / 1000000.0 + " ms]"); } } @Override public void removeTable(String cluster, String table, boolean deleteIndexFiles) { long s = System.nanoTime(); try { checkIfOpen(); String blurTablePath = ZookeeperPathConstants.getTablePath(cluster, table); if (_zk.exists(blurTablePath, false) == null) { throw new IOException("Table [" + table + "] does not exist."); } if (_zk.exists(ZookeeperPathConstants.getTableEnabledPath(cluster, table), false) != null) { throw new IOException("Table [" + table + "] must be disabled before it can be removed."); } byte[] data = getData(ZookeeperPathConstants.getTableUriPath(cluster, table)); String uri = new String(data); BlurUtil.removeAll(_zk, blurTablePath); if (deleteIndexFiles) { BlurUtil.removeIndexFiles(uri); } } catch (IOException e) { throw new RuntimeException(e); } catch (InterruptedException e) { throw new RuntimeException(e); } catch (KeeperException e) { throw new RuntimeException(e); } finally { long e = System.nanoTime(); LOG.debug("trace removeTable took [" + (e - s) / 1000000.0 + " ms]"); } } private static byte[] toBytes(Set<String> blockCachingFileTypes) { if (blockCachingFileTypes == null || blockCachingFileTypes.isEmpty()) { return null; } StringBuilder builder = new StringBuilder(); for (String type : blockCachingFileTypes) { builder.append(type).append(','); } return builder.substring(0, builder.length() - 1).getBytes(); } @Override public boolean isOpen() { return _running.get(); } }