accumulo-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ctubb...@apache.org
Subject [29/50] [abbrv] Merge branch '1.5' into 1.6
Date Sat, 01 Nov 2014 04:57:23 GMT
http://git-wip-us.apache.org/repos/asf/accumulo/blob/9b20a9d4/server/master/src/main/java/org/apache/accumulo/master/tableOps/RenameTable.java
----------------------------------------------------------------------
diff --cc server/master/src/main/java/org/apache/accumulo/master/tableOps/RenameTable.java
index b1bbb67,0000000..4f381ef
mode 100644,000000..100644
--- a/server/master/src/main/java/org/apache/accumulo/master/tableOps/RenameTable.java
+++ b/server/master/src/main/java/org/apache/accumulo/master/tableOps/RenameTable.java
@@@ -1,112 -1,0 +1,114 @@@
 +/*
 + * Licensed to the Apache Software Foundation (ASF) under one or more
 + * contributor license agreements.  See the NOTICE file distributed with
 + * this work for additional information regarding copyright ownership.
 + * The ASF licenses this file to You 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 org.apache.accumulo.master.tableOps;
 +
++import static com.google.common.base.Charsets.UTF_8;
++
 +import org.apache.accumulo.core.Constants;
 +import org.apache.accumulo.core.client.Instance;
 +import org.apache.accumulo.core.client.NamespaceNotFoundException;
 +import org.apache.accumulo.core.client.impl.Namespaces;
 +import org.apache.accumulo.core.client.impl.Tables;
 +import org.apache.accumulo.core.client.impl.thrift.TableOperation;
 +import org.apache.accumulo.core.client.impl.thrift.TableOperationExceptionType;
 +import org.apache.accumulo.core.client.impl.thrift.ThriftTableOperationException;
 +import org.apache.accumulo.core.util.Pair;
 +import org.apache.accumulo.core.zookeeper.ZooUtil;
 +import org.apache.accumulo.fate.Repo;
 +import org.apache.accumulo.fate.zookeeper.IZooReaderWriter;
 +import org.apache.accumulo.fate.zookeeper.IZooReaderWriter.Mutator;
 +import org.apache.accumulo.master.Master;
 +import org.apache.accumulo.server.client.HdfsZooInstance;
 +import org.apache.accumulo.server.zookeeper.ZooReaderWriter;
 +import org.apache.log4j.Logger;
 +
 +public class RenameTable extends MasterRepo {
 +
 +  private static final long serialVersionUID = 1L;
 +  private String tableId;
 +  private String oldTableName;
 +  private String newTableName;
 +  private String namespaceId;
 +
 +  @Override
 +  public long isReady(long tid, Master environment) throws Exception {
 +    return Utils.reserveNamespace(namespaceId, tid, false, true, TableOperation.RENAME) + Utils.reserveTable(tableId, tid, true, true, TableOperation.RENAME);
 +  }
 +
 +  public RenameTable(String tableId, String oldTableName, String newTableName) throws NamespaceNotFoundException {
 +    this.tableId = tableId;
 +    this.oldTableName = oldTableName;
 +    this.newTableName = newTableName;
 +    Instance inst = HdfsZooInstance.getInstance();
 +    this.namespaceId = Tables.getNamespaceId(inst, tableId);
 +  }
 +
 +  @Override
 +  public Repo<Master> call(long tid, Master master) throws Exception {
 +
 +    Instance instance = master.getInstance();
 +    Pair<String,String> qualifiedOldTableName = Tables.qualify(oldTableName);
 +    Pair<String,String> qualifiedNewTableName = Tables.qualify(newTableName);
 +
 +    // ensure no attempt is made to rename across namespaces
 +    if (newTableName.contains(".") && !namespaceId.equals(Namespaces.getNamespaceId(instance, qualifiedNewTableName.getFirst())))
 +      throw new ThriftTableOperationException(tableId, oldTableName, TableOperation.RENAME, TableOperationExceptionType.INVALID_NAME,
 +          "Namespace in new table name does not match the old table name");
 +
 +    IZooReaderWriter zoo = ZooReaderWriter.getInstance();
 +
 +    Utils.tableNameLock.lock();
 +    try {
 +      Utils.checkTableDoesNotExist(instance, newTableName, tableId, TableOperation.RENAME);
 +
 +      final String newName = qualifiedNewTableName.getSecond();
 +      final String oldName = qualifiedOldTableName.getSecond();
 +
 +      final String tap = ZooUtil.getRoot(instance) + Constants.ZTABLES + "/" + tableId + Constants.ZTABLE_NAME;
 +
 +      zoo.mutate(tap, null, null, new Mutator() {
 +        @Override
 +        public byte[] mutate(byte[] current) throws Exception {
-           final String currentName = new String(current, Constants.UTF8);
++          final String currentName = new String(current, UTF_8);
 +          if (currentName.equals(newName))
 +            return null; // assume in this case the operation is running again, so we are done
 +          if (!currentName.equals(oldName)) {
 +            throw new ThriftTableOperationException(null, oldTableName, TableOperation.RENAME, TableOperationExceptionType.NOTFOUND,
 +                "Name changed while processing");
 +          }
-           return newName.getBytes(Constants.UTF8);
++          return newName.getBytes(UTF_8);
 +        }
 +      });
 +      Tables.clearCache(instance);
 +    } finally {
 +      Utils.tableNameLock.unlock();
 +      Utils.unreserveTable(tableId, tid, true);
 +      Utils.unreserveNamespace(this.namespaceId, tid, false);
 +    }
 +
 +    Logger.getLogger(RenameTable.class).debug("Renamed table " + tableId + " " + oldTableName + " " + newTableName);
 +
 +    return null;
 +  }
 +
 +  @Override
 +  public void undo(long tid, Master env) throws Exception {
 +    Utils.unreserveTable(tableId, tid, true);
 +    Utils.unreserveNamespace(namespaceId, tid, false);
 +  }
 +
 +}

http://git-wip-us.apache.org/repos/asf/accumulo/blob/9b20a9d4/server/master/src/main/java/org/apache/accumulo/master/tableOps/Utils.java
----------------------------------------------------------------------
diff --cc server/master/src/main/java/org/apache/accumulo/master/tableOps/Utils.java
index 7ede305,0000000..3e8704e
mode 100644,000000..100644
--- a/server/master/src/main/java/org/apache/accumulo/master/tableOps/Utils.java
+++ b/server/master/src/main/java/org/apache/accumulo/master/tableOps/Utils.java
@@@ -1,163 -1,0 +1,165 @@@
 +/*
 + * Licensed to the Apache Software Foundation (ASF) under one or more
 + * contributor license agreements.  See the NOTICE file distributed with
 + * this work for additional information regarding copyright ownership.
 + * The ASF licenses this file to You 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 org.apache.accumulo.master.tableOps;
 +
++import static com.google.common.base.Charsets.UTF_8;
++
 +import java.math.BigInteger;
 +import java.util.concurrent.locks.Lock;
 +import java.util.concurrent.locks.ReentrantLock;
 +
 +import org.apache.accumulo.core.Constants;
 +import org.apache.accumulo.core.client.Instance;
 +import org.apache.accumulo.core.client.impl.Namespaces;
 +import org.apache.accumulo.core.client.impl.Tables;
 +import org.apache.accumulo.core.client.impl.thrift.TableOperation;
 +import org.apache.accumulo.core.client.impl.thrift.TableOperationExceptionType;
 +import org.apache.accumulo.core.client.impl.thrift.ThriftTableOperationException;
 +import org.apache.accumulo.core.util.Base64;
 +import org.apache.accumulo.core.zookeeper.ZooUtil;
 +import org.apache.accumulo.fate.zookeeper.DistributedReadWriteLock;
 +import org.apache.accumulo.fate.zookeeper.IZooReaderWriter;
 +import org.apache.accumulo.fate.zookeeper.IZooReaderWriter.Mutator;
 +import org.apache.accumulo.fate.zookeeper.ZooReservation;
 +import org.apache.accumulo.server.client.HdfsZooInstance;
 +import org.apache.accumulo.server.zookeeper.ZooQueueLock;
 +import org.apache.accumulo.server.zookeeper.ZooReaderWriter;
 +import org.apache.log4j.Logger;
 +import org.apache.zookeeper.KeeperException;
 +
 +public class Utils {
 +  private static final byte[] ZERO_BYTE = new byte[] {'0'};
 +
 +  static void checkTableDoesNotExist(Instance instance, String tableName, String tableId, TableOperation operation) throws ThriftTableOperationException {
 +
 +    String id = Tables.getNameToIdMap(instance).get(tableName);
 +
 +    if (id != null && !id.equals(tableId))
 +      throw new ThriftTableOperationException(null, tableName, operation, TableOperationExceptionType.EXISTS, null);
 +  }
 +
 +  static String getNextTableId(String tableName, Instance instance) throws ThriftTableOperationException {
 +
 +    String tableId = null;
 +    try {
 +      IZooReaderWriter zoo = ZooReaderWriter.getInstance();
 +      final String ntp = ZooUtil.getRoot(instance) + Constants.ZTABLES;
 +      byte[] nid = zoo.mutate(ntp, ZERO_BYTE, ZooUtil.PUBLIC, new Mutator() {
 +        @Override
 +        public byte[] mutate(byte[] currentValue) throws Exception {
-           BigInteger nextId = new BigInteger(new String(currentValue, Constants.UTF8), Character.MAX_RADIX);
++          BigInteger nextId = new BigInteger(new String(currentValue, UTF_8), Character.MAX_RADIX);
 +          nextId = nextId.add(BigInteger.ONE);
-           return nextId.toString(Character.MAX_RADIX).getBytes(Constants.UTF8);
++          return nextId.toString(Character.MAX_RADIX).getBytes(UTF_8);
 +        }
 +      });
-       return new String(nid, Constants.UTF8);
++      return new String(nid, UTF_8);
 +    } catch (Exception e1) {
 +      Logger.getLogger(CreateTable.class).error("Failed to assign tableId to " + tableName, e1);
 +      throw new ThriftTableOperationException(tableId, tableName, TableOperation.CREATE, TableOperationExceptionType.OTHER, e1.getMessage());
 +    }
 +  }
 +
 +  static final Lock tableNameLock = new ReentrantLock();
 +  static final Lock idLock = new ReentrantLock();
 +  private static final Logger log = Logger.getLogger(Utils.class);
 +
 +  public static long reserveTable(String tableId, long tid, boolean writeLock, boolean tableMustExist, TableOperation op) throws Exception {
 +    if (getLock(tableId, tid, writeLock).tryLock()) {
 +      if (tableMustExist) {
 +        Instance instance = HdfsZooInstance.getInstance();
 +        IZooReaderWriter zk = ZooReaderWriter.getInstance();
 +        if (!zk.exists(ZooUtil.getRoot(instance) + Constants.ZTABLES + "/" + tableId))
 +          throw new ThriftTableOperationException(tableId, "", op, TableOperationExceptionType.NOTFOUND, "Table does not exist");
 +      }
 +      log.info("table " + tableId + " (" + Long.toHexString(tid) + ") locked for " + (writeLock ? "write" : "read") + " operation: " + op);
 +      return 0;
 +    } else
 +      return 100;
 +  }
 +
 +  public static void unreserveTable(String tableId, long tid, boolean writeLock) throws Exception {
 +    getLock(tableId, tid, writeLock).unlock();
 +    log.info("table " + tableId + " (" + Long.toHexString(tid) + ") unlocked for " + (writeLock ? "write" : "read"));
 +  }
 +
 +  public static void unreserveNamespace(String namespaceId, long id, boolean writeLock) throws Exception {
 +    getLock(namespaceId, id, writeLock).unlock();
 +    log.info("namespace " + namespaceId + " (" + Long.toHexString(id) + ") unlocked for " + (writeLock ? "write" : "read"));
 +  }
 +
 +  public static long reserveNamespace(String namespaceId, long id, boolean writeLock, boolean mustExist, TableOperation op) throws Exception {
 +    if (getLock(namespaceId, id, writeLock).tryLock()) {
 +      if (mustExist) {
 +        Instance instance = HdfsZooInstance.getInstance();
 +        IZooReaderWriter zk = ZooReaderWriter.getInstance();
 +        if (!zk.exists(ZooUtil.getRoot(instance) + Constants.ZNAMESPACES + "/" + namespaceId))
 +          throw new ThriftTableOperationException(namespaceId, "", op, TableOperationExceptionType.NAMESPACE_NOTFOUND, "Namespace does not exist");
 +      }
 +      log.info("namespace " + namespaceId + " (" + Long.toHexString(id) + ") locked for " + (writeLock ? "write" : "read") + " operation: " + op);
 +      return 0;
 +    } else
 +      return 100;
 +  }
 +
 +  public static long reserveHdfsDirectory(String directory, long tid) throws KeeperException, InterruptedException {
 +    Instance instance = HdfsZooInstance.getInstance();
 +
 +    String resvPath = ZooUtil.getRoot(instance) + Constants.ZHDFS_RESERVATIONS + "/"
-         + Base64.encodeBase64String(directory.getBytes(Constants.UTF8));
++        + Base64.encodeBase64String(directory.getBytes(UTF_8));
 +
 +    IZooReaderWriter zk = ZooReaderWriter.getInstance();
 +
 +    if (ZooReservation.attempt(zk, resvPath, String.format("%016x", tid), "")) {
 +      return 0;
 +    } else
 +      return 50;
 +  }
 +
 +  public static void unreserveHdfsDirectory(String directory, long tid) throws KeeperException, InterruptedException {
 +    Instance instance = HdfsZooInstance.getInstance();
 +    String resvPath = ZooUtil.getRoot(instance) + Constants.ZHDFS_RESERVATIONS + "/"
-         + Base64.encodeBase64String(directory.getBytes(Constants.UTF8));
++        + Base64.encodeBase64String(directory.getBytes(UTF_8));
 +    ZooReservation.release(ZooReaderWriter.getInstance(), resvPath, String.format("%016x", tid));
 +  }
 +
 +  private static Lock getLock(String tableId, long tid, boolean writeLock) throws Exception {
-     byte[] lockData = String.format("%016x", tid).getBytes(Constants.UTF8);
++    byte[] lockData = String.format("%016x", tid).getBytes(UTF_8);
 +    ZooQueueLock qlock = new ZooQueueLock(ZooUtil.getRoot(HdfsZooInstance.getInstance()) + Constants.ZTABLE_LOCKS + "/" + tableId, false);
 +    Lock lock = DistributedReadWriteLock.recoverLock(qlock, lockData);
 +    if (lock == null) {
 +      DistributedReadWriteLock locker = new DistributedReadWriteLock(qlock, lockData);
 +      if (writeLock)
 +        lock = locker.writeLock();
 +      else
 +        lock = locker.readLock();
 +    }
 +    return lock;
 +  }
 +
 +  public static Lock getReadLock(String tableId, long tid) throws Exception {
 +    return Utils.getLock(tableId, tid, false);
 +  }
 +
 +  static void checkNamespaceDoesNotExist(Instance instance, String namespace, String namespaceId, TableOperation operation)
 +      throws ThriftTableOperationException {
 +
 +    String n = Namespaces.getNameToIdMap(instance).get(namespace);
 +
 +    if (n != null && !n.equals(namespaceId))
 +      throw new ThriftTableOperationException(null, namespace, operation, TableOperationExceptionType.NAMESPACE_EXISTS, null);
 +  }
 +}

http://git-wip-us.apache.org/repos/asf/accumulo/blob/9b20a9d4/server/master/src/main/java/org/apache/accumulo/master/tserverOps/ShutdownTServer.java
----------------------------------------------------------------------
diff --cc server/master/src/main/java/org/apache/accumulo/master/tserverOps/ShutdownTServer.java
index 20b7328,0000000..a9058b7
mode 100644,000000..100644
--- a/server/master/src/main/java/org/apache/accumulo/master/tserverOps/ShutdownTServer.java
+++ b/server/master/src/main/java/org/apache/accumulo/master/tserverOps/ShutdownTServer.java
@@@ -1,92 -1,0 +1,94 @@@
 +/*
 + * Licensed to the Apache Software Foundation (ASF) under one or more
 + * contributor license agreements.  See the NOTICE file distributed with
 + * this work for additional information regarding copyright ownership.
 + * The ASF licenses this file to You 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 org.apache.accumulo.master.tserverOps;
 +
++import static com.google.common.base.Charsets.UTF_8;
++
 +import org.apache.accumulo.core.Constants;
 +import org.apache.accumulo.core.master.thrift.TabletServerStatus;
 +import org.apache.accumulo.core.zookeeper.ZooUtil;
 +import org.apache.accumulo.fate.Repo;
 +import org.apache.accumulo.fate.zookeeper.IZooReaderWriter;
 +import org.apache.accumulo.fate.zookeeper.ZooUtil.NodeExistsPolicy;
 +import org.apache.accumulo.master.Master;
 +import org.apache.accumulo.master.EventCoordinator.Listener;
 +import org.apache.accumulo.master.tableOps.MasterRepo;
 +import org.apache.accumulo.server.master.LiveTServerSet.TServerConnection;
 +import org.apache.accumulo.server.master.state.TServerInstance;
 +import org.apache.accumulo.server.zookeeper.ZooLock;
 +import org.apache.accumulo.server.zookeeper.ZooReaderWriter;
 +import org.apache.log4j.Logger;
 +import org.apache.thrift.transport.TTransportException;
 +
 +public class ShutdownTServer extends MasterRepo {
 +  
 +  private static final long serialVersionUID = 1L;
 +  private static final Logger log = Logger.getLogger(ShutdownTServer.class);
 +  private TServerInstance server;
 +  private boolean force;
 +  
 +  public ShutdownTServer(TServerInstance server, boolean force) {
 +    this.server = server;
 +    this.force = force;
 +  }
 +  
 +  @Override
 +  public long isReady(long tid, Master environment) throws Exception {
 +    return 0;
 +  }
 +  
 +  @Override
 +  public Repo<Master> call(long tid, Master master) throws Exception {
 +    // suppress assignment of tablets to the server
 +    if (force) {
 +      String path = ZooUtil.getRoot(master.getInstance()) + Constants.ZTSERVERS + "/" + server.getLocation();
 +      ZooLock.deleteLock(path);
 +      path = ZooUtil.getRoot(master.getInstance()) + Constants.ZDEADTSERVERS + "/" + server.getLocation();
 +      IZooReaderWriter zoo = ZooReaderWriter.getInstance();
-       zoo.putPersistentData(path, "forced down".getBytes(Constants.UTF8), NodeExistsPolicy.OVERWRITE);
++      zoo.putPersistentData(path, "forced down".getBytes(UTF_8), NodeExistsPolicy.OVERWRITE);
 +      return null;
 +    }
 +    
 +    // TODO move this to isReady() and drop while loop? - ACCUMULO-1259
 +    Listener listener = master.getEventCoordinator().getListener();
 +    master.shutdownTServer(server);
 +    while (master.onlineTabletServers().contains(server)) {
 +      TServerConnection connection = master.getConnection(server);
 +      if (connection != null) {
 +        try {
 +          TabletServerStatus status = connection.getTableMap(false);
 +          if (status.tableMap != null && status.tableMap.isEmpty()) {
 +            log.info("tablet server hosts no tablets " + server);
 +            connection.halt(master.getMasterLock());
 +            log.info("tablet server asked to halt " + server);
 +            break;
 +          }
 +        } catch (TTransportException ex) {
 +          // expected
 +        } catch (Exception ex) {
 +          log.error("Error talking to tablet server " + server + ": " + ex);
 +        }
 +      }
 +      listener.waitForEvents(1000);
 +    }
 +    
 +    return null;
 +  }
 +  
 +  @Override
 +  public void undo(long tid, Master m) throws Exception {}
 +}

http://git-wip-us.apache.org/repos/asf/accumulo/blob/9b20a9d4/server/monitor/src/main/java/org/apache/accumulo/monitor/Monitor.java
----------------------------------------------------------------------
diff --cc server/monitor/src/main/java/org/apache/accumulo/monitor/Monitor.java
index c4ab6e6,0000000..75d1e9e
mode 100644,000000..100644
--- a/server/monitor/src/main/java/org/apache/accumulo/monitor/Monitor.java
+++ b/server/monitor/src/main/java/org/apache/accumulo/monitor/Monitor.java
@@@ -1,817 -1,0 +1,819 @@@
 +/*
 + * Licensed to the Apache Software Foundation (ASF) under one or more
 + * contributor license agreements.  See the NOTICE file distributed with
 + * this work for additional information regarding copyright ownership.
 + * The ASF licenses this file to You 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 org.apache.accumulo.monitor;
 +
++import static com.google.common.base.Charsets.UTF_8;
++
 +import java.net.InetAddress;
 +import java.util.ArrayList;
 +import java.util.Collections;
 +import java.util.HashMap;
 +import java.util.HashSet;
 +import java.util.Iterator;
 +import java.util.LinkedList;
 +import java.util.List;
 +import java.util.Map;
 +import java.util.Map.Entry;
 +import java.util.Set;
 +import java.util.TreeMap;
 +
 +import org.apache.accumulo.core.Constants;
 +import org.apache.accumulo.core.client.Connector;
 +import org.apache.accumulo.core.client.Instance;
 +import org.apache.accumulo.core.client.impl.MasterClient;
 +import org.apache.accumulo.core.conf.AccumuloConfiguration;
 +import org.apache.accumulo.core.conf.Property;
 +import org.apache.accumulo.core.gc.thrift.GCMonitorService;
 +import org.apache.accumulo.core.gc.thrift.GCStatus;
 +import org.apache.accumulo.core.master.thrift.MasterClientService;
 +import org.apache.accumulo.core.master.thrift.MasterMonitorInfo;
 +import org.apache.accumulo.core.master.thrift.TableInfo;
 +import org.apache.accumulo.core.master.thrift.TabletServerStatus;
 +import org.apache.accumulo.core.security.SecurityUtil;
 +import org.apache.accumulo.core.tabletserver.thrift.ActiveScan;
 +import org.apache.accumulo.core.tabletserver.thrift.TabletClientService.Client;
 +import org.apache.accumulo.core.util.Daemon;
 +import org.apache.accumulo.core.util.LoggingRunnable;
 +import org.apache.accumulo.core.util.Pair;
 +import org.apache.accumulo.core.util.ServerServices;
 +import org.apache.accumulo.core.util.ServerServices.Service;
 +import org.apache.accumulo.core.util.ThriftUtil;
 +import org.apache.accumulo.core.util.UtilWaitThread;
 +import org.apache.accumulo.core.zookeeper.ZooUtil;
 +import org.apache.accumulo.fate.zookeeper.ZooLock.LockLossReason;
 +import org.apache.accumulo.fate.zookeeper.ZooUtil.NodeExistsPolicy;
 +import org.apache.accumulo.fate.zookeeper.ZooUtil.NodeMissingPolicy;
 +import org.apache.accumulo.monitor.servlets.DefaultServlet;
 +import org.apache.accumulo.monitor.servlets.GcStatusServlet;
 +import org.apache.accumulo.monitor.servlets.JSONServlet;
 +import org.apache.accumulo.monitor.servlets.LogServlet;
 +import org.apache.accumulo.monitor.servlets.MasterServlet;
 +import org.apache.accumulo.monitor.servlets.OperationServlet;
 +import org.apache.accumulo.monitor.servlets.ProblemServlet;
 +import org.apache.accumulo.monitor.servlets.ScanServlet;
 +import org.apache.accumulo.monitor.servlets.ShellServlet;
 +import org.apache.accumulo.monitor.servlets.TServersServlet;
 +import org.apache.accumulo.monitor.servlets.TablesServlet;
 +import org.apache.accumulo.monitor.servlets.VisServlet;
 +import org.apache.accumulo.monitor.servlets.XMLServlet;
 +import org.apache.accumulo.monitor.servlets.trace.ListType;
 +import org.apache.accumulo.monitor.servlets.trace.ShowTrace;
 +import org.apache.accumulo.monitor.servlets.trace.Summary;
 +import org.apache.accumulo.server.Accumulo;
 +import org.apache.accumulo.server.ServerOpts;
 +import org.apache.accumulo.server.client.HdfsZooInstance;
 +import org.apache.accumulo.server.conf.ServerConfiguration;
 +import org.apache.accumulo.server.fs.VolumeManager;
 +import org.apache.accumulo.server.fs.VolumeManagerImpl;
 +import org.apache.accumulo.server.monitor.LogService;
 +import org.apache.accumulo.server.problems.ProblemReports;
 +import org.apache.accumulo.server.problems.ProblemType;
 +import org.apache.accumulo.server.security.SystemCredentials;
 +import org.apache.accumulo.server.util.Halt;
 +import org.apache.accumulo.server.util.TableInfoUtil;
 +import org.apache.accumulo.server.zookeeper.ZooLock;
 +import org.apache.accumulo.server.zookeeper.ZooReaderWriter;
 +import org.apache.accumulo.trace.instrument.Tracer;
 +import org.apache.log4j.Logger;
 +import org.apache.zookeeper.KeeperException;
 +
 +import com.google.common.net.HostAndPort;
 +
 +/**
 + * Serve master statistics with an embedded web server.
 + */
 +public class Monitor {
 +  private static final Logger log = Logger.getLogger(Monitor.class);
 +
 +  private static final int REFRESH_TIME = 5;
 +  private static long lastRecalc = 0L;
 +  private static double totalIngestRate = 0.0;
 +  private static double totalIngestByteRate = 0.0;
 +  private static double totalQueryRate = 0.0;
 +  private static double totalScanRate = 0.0;
 +  private static double totalQueryByteRate = 0.0;
 +  private static long totalEntries = 0L;
 +  private static int totalTabletCount = 0;
 +  private static int onlineTabletCount = 0;
 +  private static long totalHoldTime = 0;
 +  private static long totalLookups = 0;
 +  private static int totalTables = 0;
 +
 +  private static class MaxList<T> extends LinkedList<Pair<Long,T>> {
 +    private static final long serialVersionUID = 1L;
 +
 +    private long maxDelta;
 +
 +    public MaxList(long maxDelta) {
 +      this.maxDelta = maxDelta;
 +    }
 +
 +    @Override
 +    public boolean add(Pair<Long,T> obj) {
 +      boolean result = super.add(obj);
 +
 +      if (obj.getFirst() - get(0).getFirst() > maxDelta)
 +        remove(0);
 +
 +      return result;
 +    }
 +
 +  }
 +
 +  private static final int MAX_TIME_PERIOD = 60 * 60 * 1000;
 +  private static final List<Pair<Long,Double>> loadOverTime = Collections.synchronizedList(new MaxList<Double>(MAX_TIME_PERIOD));
 +  private static final List<Pair<Long,Double>> ingestRateOverTime = Collections.synchronizedList(new MaxList<Double>(MAX_TIME_PERIOD));
 +  private static final List<Pair<Long,Double>> ingestByteRateOverTime = Collections.synchronizedList(new MaxList<Double>(MAX_TIME_PERIOD));
 +  private static final List<Pair<Long,Integer>> recoveriesOverTime = Collections.synchronizedList(new MaxList<Integer>(MAX_TIME_PERIOD));
 +  private static final List<Pair<Long,Integer>> minorCompactionsOverTime = Collections.synchronizedList(new MaxList<Integer>(MAX_TIME_PERIOD));
 +  private static final List<Pair<Long,Integer>> majorCompactionsOverTime = Collections.synchronizedList(new MaxList<Integer>(MAX_TIME_PERIOD));
 +  private static final List<Pair<Long,Double>> lookupsOverTime = Collections.synchronizedList(new MaxList<Double>(MAX_TIME_PERIOD));
 +  private static final List<Pair<Long,Integer>> queryRateOverTime = Collections.synchronizedList(new MaxList<Integer>(MAX_TIME_PERIOD));
 +  private static final List<Pair<Long,Integer>> scanRateOverTime = Collections.synchronizedList(new MaxList<Integer>(MAX_TIME_PERIOD));
 +  private static final List<Pair<Long,Double>> queryByteRateOverTime = Collections.synchronizedList(new MaxList<Double>(MAX_TIME_PERIOD));
 +  private static final List<Pair<Long,Double>> indexCacheHitRateOverTime = Collections.synchronizedList(new MaxList<Double>(MAX_TIME_PERIOD));
 +  private static final List<Pair<Long,Double>> dataCacheHitRateOverTime = Collections.synchronizedList(new MaxList<Double>(MAX_TIME_PERIOD));
 +  private static EventCounter lookupRateTracker = new EventCounter();
 +  private static EventCounter indexCacheHitTracker = new EventCounter();
 +  private static EventCounter indexCacheRequestTracker = new EventCounter();
 +  private static EventCounter dataCacheHitTracker = new EventCounter();
 +  private static EventCounter dataCacheRequestTracker = new EventCounter();
 +
 +  private static volatile boolean fetching = false;
 +  private static MasterMonitorInfo mmi;
 +  private static Map<String,Map<ProblemType,Integer>> problemSummary = Collections.emptyMap();
 +  private static Exception problemException;
 +  private static GCStatus gcStatus;
 +
 +  private static Instance instance;
 +
 +  private static ServerConfiguration config;
 +
 +  private static EmbeddedWebServer server;
 +
 +  private ZooLock monitorLock;
 +
 +  private static class EventCounter {
 +
 +    Map<String,Pair<Long,Long>> prevSamples = new HashMap<String,Pair<Long,Long>>();
 +    Map<String,Pair<Long,Long>> samples = new HashMap<String,Pair<Long,Long>>();
 +    Set<String> serversUpdated = new HashSet<String>();
 +
 +    void startingUpdates() {
 +      serversUpdated.clear();
 +    }
 +
 +    void updateTabletServer(String name, long sampleTime, long numEvents) {
 +      Pair<Long,Long> newSample = new Pair<Long,Long>(sampleTime, numEvents);
 +      Pair<Long,Long> lastSample = samples.get(name);
 +
 +      if (lastSample == null || !lastSample.equals(newSample)) {
 +        samples.put(name, newSample);
 +        if (lastSample != null) {
 +          prevSamples.put(name, lastSample);
 +        }
 +      }
 +      serversUpdated.add(name);
 +    }
 +
 +    void finishedUpdating() {
 +      // remove any tablet servers not updated
 +      samples.keySet().retainAll(serversUpdated);
 +      prevSamples.keySet().retainAll(serversUpdated);
 +    }
 +
 +    double calculateRate() {
 +      double totalRate = 0;
 +
 +      for (Entry<String,Pair<Long,Long>> entry : prevSamples.entrySet()) {
 +        Pair<Long,Long> prevSample = entry.getValue();
 +        Pair<Long,Long> sample = samples.get(entry.getKey());
 +
 +        totalRate += (sample.getSecond() - prevSample.getSecond()) / ((sample.getFirst() - prevSample.getFirst()) / (double) 1000);
 +      }
 +
 +      return totalRate;
 +    }
 +
 +    long calculateCount() {
 +      long count = 0;
 +
 +      for (Entry<String,Pair<Long,Long>> entry : prevSamples.entrySet()) {
 +        Pair<Long,Long> prevSample = entry.getValue();
 +        Pair<Long,Long> sample = samples.get(entry.getKey());
 +
 +        count += sample.getSecond() - prevSample.getSecond();
 +      }
 +
 +      return count;
 +    }
 +  }
 +
 +  public static void fetchData() {
 +    double totalIngestRate = 0.;
 +    double totalIngestByteRate = 0.;
 +    double totalQueryRate = 0.;
 +    double totalQueryByteRate = 0.;
 +    double totalScanRate = 0.;
 +    long totalEntries = 0;
 +    int totalTabletCount = 0;
 +    int onlineTabletCount = 0;
 +    long totalHoldTime = 0;
 +    long totalLookups = 0;
 +    boolean retry = true;
 +
 +    // only recalc every so often
 +    long currentTime = System.currentTimeMillis();
 +    if (currentTime - lastRecalc < REFRESH_TIME * 1000)
 +      return;
 +
 +    synchronized (Monitor.class) {
 +      if (fetching)
 +        return;
 +      fetching = true;
 +    }
 +
 +    try {
 +      while (retry) {
 +        MasterClientService.Iface client = null;
 +        try {
 +          client = MasterClient.getConnection(HdfsZooInstance.getInstance());
 +          if (client != null) {
 +            mmi = client.getMasterStats(Tracer.traceInfo(), SystemCredentials.get().toThrift(HdfsZooInstance.getInstance()));
 +            retry = false;
 +          } else {
 +            mmi = null;
 +          }
 +          Monitor.gcStatus = fetchGcStatus();
 +        } catch (Exception e) {
 +          mmi = null;
 +          log.info("Error fetching stats: " + e);
 +        } finally {
 +          if (client != null) {
 +            MasterClient.close(client);
 +          }
 +        }
 +        if (mmi == null)
 +          UtilWaitThread.sleep(1000);
 +      }
 +      if (mmi != null) {
 +        int majorCompactions = 0;
 +        int minorCompactions = 0;
 +
 +        lookupRateTracker.startingUpdates();
 +        indexCacheHitTracker.startingUpdates();
 +        indexCacheRequestTracker.startingUpdates();
 +        dataCacheHitTracker.startingUpdates();
 +        dataCacheRequestTracker.startingUpdates();
 +
 +        for (TabletServerStatus server : mmi.tServerInfo) {
 +          TableInfo summary = TableInfoUtil.summarizeTableStats(server);
 +          totalIngestRate += summary.ingestRate;
 +          totalIngestByteRate += summary.ingestByteRate;
 +          totalQueryRate += summary.queryRate;
 +          totalScanRate += summary.scanRate;
 +          totalQueryByteRate += summary.queryByteRate;
 +          totalEntries += summary.recs;
 +          totalHoldTime += server.holdTime;
 +          totalLookups += server.lookups;
 +          majorCompactions += summary.majors.running;
 +          minorCompactions += summary.minors.running;
 +          lookupRateTracker.updateTabletServer(server.name, server.lastContact, server.lookups);
 +          indexCacheHitTracker.updateTabletServer(server.name, server.lastContact, server.indexCacheHits);
 +          indexCacheRequestTracker.updateTabletServer(server.name, server.lastContact, server.indexCacheRequest);
 +          dataCacheHitTracker.updateTabletServer(server.name, server.lastContact, server.dataCacheHits);
 +          dataCacheRequestTracker.updateTabletServer(server.name, server.lastContact, server.dataCacheRequest);
 +        }
 +
 +        lookupRateTracker.finishedUpdating();
 +        indexCacheHitTracker.finishedUpdating();
 +        indexCacheRequestTracker.finishedUpdating();
 +        dataCacheHitTracker.finishedUpdating();
 +        dataCacheRequestTracker.finishedUpdating();
 +
 +        int totalTables = 0;
 +        for (TableInfo tInfo : mmi.tableMap.values()) {
 +          totalTabletCount += tInfo.tablets;
 +          onlineTabletCount += tInfo.onlineTablets;
 +          totalTables++;
 +        }
 +        Monitor.totalIngestRate = totalIngestRate;
 +        Monitor.totalTables = totalTables;
 +        totalIngestByteRate = totalIngestByteRate / 1000000.0;
 +        Monitor.totalIngestByteRate = totalIngestByteRate;
 +        Monitor.totalQueryRate = totalQueryRate;
 +        Monitor.totalScanRate = totalScanRate;
 +        totalQueryByteRate = totalQueryByteRate / 1000000.0;
 +        Monitor.totalQueryByteRate = totalQueryByteRate;
 +        Monitor.totalEntries = totalEntries;
 +        Monitor.totalTabletCount = totalTabletCount;
 +        Monitor.onlineTabletCount = onlineTabletCount;
 +        Monitor.totalHoldTime = totalHoldTime;
 +        Monitor.totalLookups = totalLookups;
 +
 +        ingestRateOverTime.add(new Pair<Long,Double>(currentTime, totalIngestRate));
 +        ingestByteRateOverTime.add(new Pair<Long,Double>(currentTime, totalIngestByteRate));
 +
 +        double totalLoad = 0.;
 +        for (TabletServerStatus status : mmi.tServerInfo) {
 +          if (status != null)
 +            totalLoad += status.osLoad;
 +        }
 +        loadOverTime.add(new Pair<Long,Double>(currentTime, totalLoad));
 +
 +        minorCompactionsOverTime.add(new Pair<Long,Integer>(currentTime, minorCompactions));
 +        majorCompactionsOverTime.add(new Pair<Long,Integer>(currentTime, majorCompactions));
 +
 +        lookupsOverTime.add(new Pair<Long,Double>(currentTime, lookupRateTracker.calculateRate()));
 +
 +        queryRateOverTime.add(new Pair<Long,Integer>(currentTime, (int) totalQueryRate));
 +        queryByteRateOverTime.add(new Pair<Long,Double>(currentTime, totalQueryByteRate));
 +
 +        scanRateOverTime.add(new Pair<Long,Integer>(currentTime, (int) totalScanRate));
 +
 +        calcCacheHitRate(indexCacheHitRateOverTime, currentTime, indexCacheHitTracker, indexCacheRequestTracker);
 +        calcCacheHitRate(dataCacheHitRateOverTime, currentTime, dataCacheHitTracker, dataCacheRequestTracker);
 +      }
 +      try {
 +        Monitor.problemSummary = ProblemReports.getInstance().summarize();
 +        Monitor.problemException = null;
 +      } catch (Exception e) {
 +        log.info("Failed to obtain problem reports ", e);
 +        Monitor.problemSummary = Collections.emptyMap();
 +        Monitor.problemException = e;
 +      }
 +
 +    } finally {
 +      synchronized (Monitor.class) {
 +        fetching = false;
 +        lastRecalc = currentTime;
 +      }
 +    }
 +  }
 +
 +  private static void calcCacheHitRate(List<Pair<Long,Double>> hitRate, long currentTime, EventCounter cacheHits, EventCounter cacheReq) {
 +    long req = cacheReq.calculateCount();
 +    if (req > 0)
 +      hitRate.add(new Pair<Long,Double>(currentTime, cacheHits.calculateCount() / (double) cacheReq.calculateCount()));
 +    else
 +      hitRate.add(new Pair<Long,Double>(currentTime, null));
 +  }
 +
 +  private static GCStatus fetchGcStatus() {
 +    GCStatus result = null;
 +    HostAndPort address = null;
 +    try {
 +      // Read the gc location from its lock
 +      ZooReaderWriter zk = ZooReaderWriter.getInstance();
 +      String path = ZooUtil.getRoot(instance) + Constants.ZGC_LOCK;
 +      List<String> locks = zk.getChildren(path, null);
 +      if (locks != null && locks.size() > 0) {
 +        Collections.sort(locks);
-         address = new ServerServices(new String(zk.getData(path + "/" + locks.get(0), null), Constants.UTF8)).getAddress(Service.GC_CLIENT);
++        address = new ServerServices(new String(zk.getData(path + "/" + locks.get(0), null), UTF_8)).getAddress(Service.GC_CLIENT);
 +        GCMonitorService.Client client = ThriftUtil.getClient(new GCMonitorService.Client.Factory(), address, config.getConfiguration());
 +        try {
 +          result = client.getStatus(Tracer.traceInfo(), SystemCredentials.get().toThrift(instance));
 +        } finally {
 +          ThriftUtil.returnClient(client);
 +        }
 +      }
 +    } catch (Exception ex) {
 +      log.warn("Unable to contact the garbage collector at " + address, ex);
 +    }
 +    return result;
 +  }
 +
 +  public static void main(String[] args) throws Exception {
 +    SecurityUtil.serverLogin(ServerConfiguration.getSiteConfiguration());
 +
 +    ServerOpts opts = new ServerOpts();
 +    final String app = "monitor";
 +    opts.parseArgs(app, args);
 +    String hostname = opts.getAddress();
 +
 +    Accumulo.setupLogging(app);
 +    VolumeManager fs = VolumeManagerImpl.get();
 +    instance = HdfsZooInstance.getInstance();
 +    config = new ServerConfiguration(instance);
 +    Accumulo.init(fs, config, app);
 +    Monitor monitor = new Monitor();
 +    Accumulo.enableTracing(hostname, app);
 +    monitor.run(hostname);
 +  }
 +
 +  private static long START_TIME;
 +
 +  public void run(String hostname) {
 +    try {
 +      getMonitorLock();
 +    } catch (Exception e) {
 +      log.error("Failed to get Monitor ZooKeeper lock");
 +      throw new RuntimeException(e);
 +    }
 +
 +    Monitor.START_TIME = System.currentTimeMillis();
 +    int port = config.getConfiguration().getPort(Property.MONITOR_PORT);
 +    try {
 +      log.debug("Creating monitor on port " + port);
 +      server = new EmbeddedWebServer(hostname, port);
 +    } catch (Throwable ex) {
 +      log.error("Unable to start embedded web server", ex);
 +      throw new RuntimeException(ex);
 +    }
 +
 +    server.addServlet(DefaultServlet.class, "/");
 +    server.addServlet(OperationServlet.class, "/op");
 +    server.addServlet(MasterServlet.class, "/master");
 +    server.addServlet(TablesServlet.class, "/tables");
 +    server.addServlet(TServersServlet.class, "/tservers");
 +    server.addServlet(ProblemServlet.class, "/problems");
 +    server.addServlet(GcStatusServlet.class, "/gc");
 +    server.addServlet(LogServlet.class, "/log");
 +    server.addServlet(XMLServlet.class, "/xml");
 +    server.addServlet(JSONServlet.class, "/json");
 +    server.addServlet(VisServlet.class, "/vis");
 +    server.addServlet(ScanServlet.class, "/scans");
 +    server.addServlet(Summary.class, "/trace/summary");
 +    server.addServlet(ListType.class, "/trace/listType");
 +    server.addServlet(ShowTrace.class, "/trace/show");
 +    if (server.isUsingSsl())
 +      server.addServlet(ShellServlet.class, "/shell");
 +    server.start();
 +
 +    try {
 +      hostname = InetAddress.getLocalHost().getHostName();
 +
 +      log.debug("Using " + hostname + " to advertise monitor location in ZooKeeper");
 +
 +      String monitorAddress = HostAndPort.fromParts(hostname, server.getPort()).toString();
 +
-       ZooReaderWriter.getInstance().putPersistentData(ZooUtil.getRoot(instance) + Constants.ZMONITOR_HTTP_ADDR, monitorAddress.getBytes(Constants.UTF8),
++      ZooReaderWriter.getInstance().putPersistentData(ZooUtil.getRoot(instance) + Constants.ZMONITOR_HTTP_ADDR, monitorAddress.getBytes(UTF_8),
 +          NodeExistsPolicy.OVERWRITE);
 +      log.info("Set monitor address in zookeeper to " + monitorAddress);
 +    } catch (Exception ex) {
 +      log.error("Unable to set monitor HTTP address in zookeeper", ex);
 +    }
 +
 +    if (null != hostname) {
 +      LogService.startLogListener(Monitor.getSystemConfiguration(), instance.getInstanceID(), hostname);
 +    } else {
 +      log.warn("Not starting log4j listener as we could not determine address to use");
 +    }
 +
 +    new Daemon(new LoggingRunnable(log, new ZooKeeperStatus()), "ZooKeeperStatus").start();
 +
 +    // need to regularly fetch data so plot data is updated
 +    new Daemon(new LoggingRunnable(log, new Runnable() {
 +
 +      @Override
 +      public void run() {
 +        while (true) {
 +          try {
 +            Monitor.fetchData();
 +          } catch (Exception e) {
 +            log.warn(e.getMessage(), e);
 +          }
 +
 +          UtilWaitThread.sleep(333);
 +        }
 +
 +      }
 +    }), "Data fetcher").start();
 +
 +    new Daemon(new LoggingRunnable(log, new Runnable() {
 +      @Override
 +      public void run() {
 +        while (true) {
 +          try {
 +            Monitor.fetchScans();
 +          } catch (Exception e) {
 +            log.warn(e.getMessage(), e);
 +          }
 +          UtilWaitThread.sleep(5000);
 +        }
 +      }
 +    }), "Scan scanner").start();
 +  }
 +
 +  public static class ScanStats {
 +    public final List<ActiveScan> scans;
 +    public final long fetched;
 +    ScanStats(List<ActiveScan> active) {
 +      this.scans = active;
 +      this.fetched = System.currentTimeMillis();
 +    }
 +  }
 +  static final Map<String, ScanStats> allScans = new HashMap<String, ScanStats>();
 +  public static Map<String, ScanStats> getScans() {
 +    synchronized (allScans) {
 +      return new TreeMap<String, ScanStats>(allScans);
 +    }
 +  }
 +
 +  protected static void fetchScans() throws Exception {
 +    if (instance == null)
 +      return;
 +    Connector c = instance.getConnector(SystemCredentials.get().getPrincipal(), SystemCredentials.get().getToken());
 +    for (String server : c.instanceOperations().getTabletServers()) {
 +      Client tserver = ThriftUtil.getTServerClient(server, Monitor.getSystemConfiguration());
 +      try {
 +        List<ActiveScan> scans = tserver.getActiveScans(null, SystemCredentials.get().toThrift(instance));
 +        synchronized (allScans) {
 +          allScans.put(server, new ScanStats(scans));
 +        }
 +      } catch (Exception ex) {
 +        log.debug(ex, ex);
 +      } finally {
 +        ThriftUtil.returnClient(tserver);
 +      }
 +    }
 +    // Age off old scan information
 +    Iterator<Entry<String,ScanStats>> entryIter = allScans.entrySet().iterator();
 +    long now = System.currentTimeMillis();
 +    while (entryIter.hasNext()) {
 +      Entry<String,ScanStats> entry = entryIter.next();
 +      if (now - entry.getValue().fetched > 5 * 60 * 1000) {
 +        entryIter.remove();
 +      }
 +    }
 +  }
 +
 +  /**
 +   * Get the monitor lock in ZooKeeper
 +   */
 +  private void getMonitorLock() throws KeeperException, InterruptedException {
 +    final String zRoot = ZooUtil.getRoot(instance);
 +    final String monitorPath = zRoot + Constants.ZMONITOR;
 +    final String monitorLockPath = zRoot + Constants.ZMONITOR_LOCK;
 +
 +    // Ensure that everything is kosher with ZK as this has changed.
 +    ZooReaderWriter zoo = ZooReaderWriter.getInstance();
 +    if (zoo.exists(monitorPath)) {
 +      byte[] data = zoo.getData(monitorPath, null);
 +      // If the node isn't empty, it's from a previous install (has hostname:port for HTTP server)
 +      if (0 != data.length) {
 +        // Recursively delete from that parent node
 +        zoo.recursiveDelete(monitorPath, NodeMissingPolicy.SKIP);
 +
 +        // And then make the nodes that we expect for the incoming ephemeral nodes
 +        zoo.putPersistentData(monitorPath, new byte[0], NodeExistsPolicy.FAIL);
 +        zoo.putPersistentData(monitorLockPath, new byte[0], NodeExistsPolicy.FAIL);
 +      } else if (!zoo.exists(monitorLockPath)) {
 +        // monitor node in ZK exists and is empty as we expect
 +        // but the monitor/lock node does not
 +        zoo.putPersistentData(monitorLockPath, new byte[0], NodeExistsPolicy.FAIL);
 +      }
 +    } else {
 +      // 1.5.0 and earlier
 +      zoo.putPersistentData(zRoot + Constants.ZMONITOR, new byte[0], NodeExistsPolicy.FAIL);
 +      if (!zoo.exists(monitorLockPath)) {
 +        // Somehow the monitor node exists but not monitor/lock
 +        zoo.putPersistentData(monitorLockPath, new byte[0], NodeExistsPolicy.FAIL);
 +      }
 +    }
 +
 +    // Get a ZooLock for the monitor
 +    while (true) {
 +      MoniterLockWatcher monitorLockWatcher = new MoniterLockWatcher();
 +      monitorLock = new ZooLock(monitorLockPath);
 +      monitorLock.lockAsync(monitorLockWatcher, new byte[0]);
 +
 +      monitorLockWatcher.waitForChange();
 +
 +      if (monitorLockWatcher.acquiredLock) {
 +        break;
 +      }
 +
 +      if (!monitorLockWatcher.failedToAcquireLock) {
 +        throw new IllegalStateException("monitor lock in unknown state");
 +      }
 +
 +      monitorLock.tryToCancelAsyncLockOrUnlock();
 +
 +      UtilWaitThread.sleep(getSystemConfiguration().getTimeInMillis(Property.MONITOR_LOCK_CHECK_INTERVAL));
 +    }
 +
 +    log.info("Got Monitor lock.");
 +  }
 +
 +  /**
 +   * Async Watcher for monitor lock
 +   */
 +  private static class MoniterLockWatcher implements ZooLock.AsyncLockWatcher {
 +
 +    boolean acquiredLock = false;
 +    boolean failedToAcquireLock = false;
 +
 +    @Override
 +    public void lostLock(LockLossReason reason) {
 +      Halt.halt("Monitor lock in zookeeper lost (reason = " + reason + "), exiting!", -1);
 +    }
 +
 +    @Override
 +    public void unableToMonitorLockNode(final Throwable e) {
 +      Halt.halt(-1, new Runnable() {
 +        @Override
 +        public void run() {
 +          log.fatal("No longer able to monitor Monitor lock node", e);
 +        }
 +      });
 +
 +    }
 +
 +    @Override
 +    public synchronized void acquiredLock() {
 +      if (acquiredLock || failedToAcquireLock) {
 +        Halt.halt("Zoolock in unexpected state AL " + acquiredLock + " " + failedToAcquireLock, -1);
 +      }
 +
 +      acquiredLock = true;
 +      notifyAll();
 +    }
 +
 +    @Override
 +    public synchronized void failedToAcquireLock(Exception e) {
 +      log.warn("Failed to get monitor lock " + e);
 +
 +      if (acquiredLock) {
 +        Halt.halt("Zoolock in unexpected state FAL " + acquiredLock + " " + failedToAcquireLock, -1);
 +      }
 +
 +      failedToAcquireLock = true;
 +      notifyAll();
 +    }
 +
 +    public synchronized void waitForChange() {
 +      while (!acquiredLock && !failedToAcquireLock) {
 +        try {
 +          wait();
 +        } catch (InterruptedException e) {}
 +      }
 +    }
 +  }
 +
 +  public static MasterMonitorInfo getMmi() {
 +    return mmi;
 +  }
 +
 +  public static int getTotalTables() {
 +    return totalTables;
 +  }
 +
 +  public static int getTotalTabletCount() {
 +    return totalTabletCount;
 +  }
 +
 +  public static int getOnlineTabletCount() {
 +    return onlineTabletCount;
 +  }
 +
 +  public static long getTotalEntries() {
 +    return totalEntries;
 +  }
 +
 +  public static double getTotalIngestRate() {
 +    return totalIngestRate;
 +  }
 +
 +  public static double getTotalIngestByteRate() {
 +    return totalIngestByteRate;
 +  }
 +
 +  public static double getTotalQueryRate() {
 +    return totalQueryRate;
 +  }
 +
 +  public static double getTotalScanRate() {
 +    return totalScanRate;
 +  }
 +
 +  public static double getTotalQueryByteRate() {
 +    return totalQueryByteRate;
 +  }
 +
 +  public static long getTotalHoldTime() {
 +    return totalHoldTime;
 +  }
 +
 +  public static Exception getProblemException() {
 +    return problemException;
 +  }
 +
 +  public static Map<String,Map<ProblemType,Integer>> getProblemSummary() {
 +    return problemSummary;
 +  }
 +
 +  public static GCStatus getGcStatus() {
 +    return gcStatus;
 +  }
 +
 +  public static long getTotalLookups() {
 +    return totalLookups;
 +  }
 +
 +  public static long getStartTime() {
 +    return START_TIME;
 +  }
 +
 +  public static List<Pair<Long,Double>> getLoadOverTime() {
 +    synchronized (loadOverTime) {
 +      return new ArrayList<Pair<Long,Double>>(loadOverTime);
 +    }
 +  }
 +
 +  public static List<Pair<Long,Double>> getIngestRateOverTime() {
 +    synchronized (ingestRateOverTime) {
 +      return new ArrayList<Pair<Long,Double>>(ingestRateOverTime);
 +    }
 +  }
 +
 +  public static List<Pair<Long,Double>> getIngestByteRateOverTime() {
 +    synchronized (ingestByteRateOverTime) {
 +      return new ArrayList<Pair<Long,Double>>(ingestByteRateOverTime);
 +    }
 +  }
 +
 +  public static List<Pair<Long,Integer>> getRecoveriesOverTime() {
 +    synchronized (recoveriesOverTime) {
 +      return new ArrayList<Pair<Long,Integer>>(recoveriesOverTime);
 +    }
 +  }
 +
 +  public static List<Pair<Long,Integer>> getMinorCompactionsOverTime() {
 +    synchronized (minorCompactionsOverTime) {
 +      return new ArrayList<Pair<Long,Integer>>(minorCompactionsOverTime);
 +    }
 +  }
 +
 +  public static List<Pair<Long,Integer>> getMajorCompactionsOverTime() {
 +    synchronized (majorCompactionsOverTime) {
 +      return new ArrayList<Pair<Long,Integer>>(majorCompactionsOverTime);
 +    }
 +  }
 +
 +  public static List<Pair<Long,Double>> getLookupsOverTime() {
 +    synchronized (lookupsOverTime) {
 +      return new ArrayList<Pair<Long,Double>>(lookupsOverTime);
 +    }
 +  }
 +
 +  public static double getLookupRate() {
 +    return lookupRateTracker.calculateRate();
 +  }
 +
 +  public static List<Pair<Long,Integer>> getQueryRateOverTime() {
 +    synchronized (queryRateOverTime) {
 +      return new ArrayList<Pair<Long,Integer>>(queryRateOverTime);
 +    }
 +  }
 +
 +  public static List<Pair<Long,Integer>> getScanRateOverTime() {
 +    synchronized (scanRateOverTime) {
 +      return new ArrayList<Pair<Long,Integer>>(scanRateOverTime);
 +    }
 +  }
 +
 +  public static List<Pair<Long,Double>> getQueryByteRateOverTime() {
 +    synchronized (queryByteRateOverTime) {
 +      return new ArrayList<Pair<Long,Double>>(queryByteRateOverTime);
 +    }
 +  }
 +
 +  public static List<Pair<Long,Double>> getIndexCacheHitRateOverTime() {
 +    synchronized (indexCacheHitRateOverTime) {
 +      return new ArrayList<Pair<Long,Double>>(indexCacheHitRateOverTime);
 +    }
 +  }
 +
 +  public static List<Pair<Long,Double>> getDataCacheHitRateOverTime() {
 +    synchronized (dataCacheHitRateOverTime) {
 +      return new ArrayList<Pair<Long,Double>>(dataCacheHitRateOverTime);
 +    }
 +  }
 +
 +  public static AccumuloConfiguration getSystemConfiguration() {
 +    return config.getConfiguration();
 +  }
 +
 +  public static Instance getInstance() {
 +    return instance;
 +  }
 +
 +  public static boolean isUsingSsl() {
 +    return server.isUsingSsl();
 +  }
 +}

http://git-wip-us.apache.org/repos/asf/accumulo/blob/9b20a9d4/server/monitor/src/main/java/org/apache/accumulo/monitor/ZooKeeperStatus.java
----------------------------------------------------------------------
diff --cc server/monitor/src/main/java/org/apache/accumulo/monitor/ZooKeeperStatus.java
index 5e3e475,0000000..78dd95e
mode 100644,000000..100644
--- a/server/monitor/src/main/java/org/apache/accumulo/monitor/ZooKeeperStatus.java
+++ b/server/monitor/src/main/java/org/apache/accumulo/monitor/ZooKeeperStatus.java
@@@ -1,140 -1,0 +1,141 @@@
 +/*
 + * Licensed to the Apache Software Foundation (ASF) under one or more
 + * contributor license agreements.  See the NOTICE file distributed with
 + * this work for additional information regarding copyright ownership.
 + * The ASF licenses this file to You 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 org.apache.accumulo.monitor;
 +
++import static com.google.common.base.Charsets.UTF_8;
++
 +import java.util.Collection;
 +import java.util.SortedSet;
 +import java.util.TreeSet;
 +
- import org.apache.accumulo.core.Constants;
 +import org.apache.accumulo.core.conf.Property;
 +import org.apache.accumulo.core.util.TTimeoutTransport;
 +import org.apache.accumulo.core.util.UtilWaitThread;
 +import org.apache.accumulo.server.conf.ServerConfiguration;
 +import org.apache.log4j.Logger;
 +import org.apache.thrift.transport.TTransport;
 +import org.apache.thrift.transport.TTransportException;
 +
 +import com.google.common.net.HostAndPort;
 +
 +public class ZooKeeperStatus implements Runnable {
 +  
 +  private static final Logger log = Logger.getLogger(ZooKeeperStatus.class);
 +  
 +  private volatile boolean stop = false;
 +  
 +  public static class ZooKeeperState implements Comparable<ZooKeeperState> {
 +    public final String keeper;
 +    public final String mode;
 +    public final int clients;
 +    
 +    public ZooKeeperState(String keeper, String mode, int clients) {
 +      this.keeper = keeper;
 +      this.mode = mode;
 +      this.clients = clients;
 +    }
 +    
 +    @Override
 +    public int compareTo(ZooKeeperState other) {
 +      if (this == other) {
 +        return 0;
 +      } else if (other == null) {
 +        return 1;
 +      } else {
 +        if (this.keeper == other.keeper) {
 +          return 0;
 +        } else if (null == this.keeper) {
 +          return -1;
 +        } else if (null == other.keeper) {
 +          return 1;
 +        } else {
 +          return this.keeper.compareTo(other.keeper);
 +        }
 +      }
 +    }
 +  }
 +  
 +  private static SortedSet<ZooKeeperState> status = new TreeSet<ZooKeeperState>();
 +  
 +  public static Collection<ZooKeeperState> getZooKeeperStatus() {
 +    return status;
 +  }
 +  
 +  public void stop() {
 +    this.stop = true;
 +  }
 +  
 +  @Override
 +  public void run() {
 +    
 +    while (!stop) {
 +      
 +      TreeSet<ZooKeeperState> update = new TreeSet<ZooKeeperState>();
 +      
 +      String zookeepers[] = ServerConfiguration.getSiteConfiguration().get(Property.INSTANCE_ZK_HOST).split(",");
 +      for (String keeper : zookeepers) {
 +        int clients = 0;
 +        String mode = "unknown";
 +        
 +        String[] parts = keeper.split(":");
 +        TTransport transport = null;
 +        try {
 +          HostAndPort addr;
 +          if (parts.length > 1)
 +            addr = HostAndPort.fromParts(parts[0], Integer.parseInt(parts[1]));
 +          else
 +            addr = HostAndPort.fromParts(parts[0], 2181);
 +          
 +          transport = TTimeoutTransport.create(addr, 10 * 1000l);
-           transport.write("stat\n".getBytes(Constants.UTF8), 0, 5);
++          transport.write("stat\n".getBytes(UTF_8), 0, 5);
 +          StringBuilder response = new StringBuilder();
 +          try {
 +            transport.flush();
 +            byte[] buffer = new byte[1024 * 100];
 +            int n = 0;
 +            while ((n = transport.read(buffer, 0, buffer.length)) > 0) {
-               response.append(new String(buffer, 0, n, Constants.UTF8));
++              response.append(new String(buffer, 0, n, UTF_8));
 +            }
 +          } catch (TTransportException ex) {
 +            // happens at EOF
 +          }
 +          for (String line : response.toString().split("\n")) {
 +            if (line.startsWith(" "))
 +              clients++;
 +            if (line.startsWith("Mode"))
 +              mode = line.split(":")[1];
 +          }
 +          update.add(new ZooKeeperState(keeper, mode, clients));
 +        } catch (Exception ex) {
 +          log.info("Exception talking to zookeeper " + keeper, ex);
 +          update.add(new ZooKeeperState(keeper, "Down", -1));
 +        } finally {
 +          if (transport != null) {
 +            try {
 +              transport.close();
 +            } catch (Exception ex) {
 +              log.error(ex, ex);
 +            }
 +          }
 +        }
 +      }
 +      status = update;
 +      UtilWaitThread.sleep(5 * 1000);
 +    }
 +  }
 +  
 +}

http://git-wip-us.apache.org/repos/asf/accumulo/blob/9b20a9d4/server/monitor/src/main/java/org/apache/accumulo/monitor/servlets/BasicServlet.java
----------------------------------------------------------------------
diff --cc server/monitor/src/main/java/org/apache/accumulo/monitor/servlets/BasicServlet.java
index d896040,0000000..7812603
mode 100644,000000..100644
--- a/server/monitor/src/main/java/org/apache/accumulo/monitor/servlets/BasicServlet.java
+++ b/server/monitor/src/main/java/org/apache/accumulo/monitor/servlets/BasicServlet.java
@@@ -1,283 -1,0 +1,285 @@@
 +/*
 + * Licensed to the Apache Software Foundation (ASF) under one or more
 + * contributor license agreements.  See the NOTICE file distributed with
 + * this work for additional information regarding copyright ownership.
 + * The ASF licenses this file to You 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 org.apache.accumulo.monitor.servlets;
 +
++import static com.google.common.base.Charsets.UTF_8;
++
 +import java.io.IOException;
 +import java.io.PrintWriter;
 +import java.io.StringWriter;
 +import java.io.UnsupportedEncodingException;
 +import java.net.URLDecoder;
 +import java.net.URLEncoder;
 +import java.util.Date;
 +import java.util.List;
 +import java.util.TimerTask;
 +
 +import javax.servlet.ServletException;
 +import javax.servlet.http.Cookie;
 +import javax.servlet.http.HttpServlet;
 +import javax.servlet.http.HttpServletRequest;
 +import javax.servlet.http.HttpServletResponse;
 +
 +import org.apache.accumulo.core.Constants;
 +import org.apache.accumulo.core.conf.Property;
 +import org.apache.accumulo.monitor.Monitor;
 +import org.apache.accumulo.server.client.HdfsZooInstance;
 +import org.apache.accumulo.server.monitor.DedupedLogEvent;
 +import org.apache.accumulo.server.monitor.LogService;
 +import org.apache.accumulo.server.util.time.SimpleTimer;
 +import org.apache.log4j.Level;
 +import org.apache.log4j.Logger;
 +
 +abstract public class BasicServlet extends HttpServlet {
 +
 +  private static final long serialVersionUID = 1L;
 +  protected static final Logger log = Logger.getLogger(BasicServlet.class);
 +  static String cachedInstanceName = null;
 +  private static String bannerText;
 +  private static String bannerColor;
 +  private static String bannerBackground;
 +
 +  abstract protected String getTitle(HttpServletRequest req);
 +
 +  @Override
 +  public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
 +    StringBuilder sb = new StringBuilder();
 +    try {
 +      Monitor.fetchData();
 +      bannerText = sanitize(Monitor.getSystemConfiguration().get(Property.MONITOR_BANNER_TEXT));
 +      bannerColor = Monitor.getSystemConfiguration().get(Property.MONITOR_BANNER_COLOR).replace("'", "&#39;");
 +      bannerBackground = Monitor.getSystemConfiguration().get(Property.MONITOR_BANNER_BACKGROUND).replace("'", "&#39;");
 +      pageStart(req, resp, sb);
 +      pageBody(req, resp, sb);
 +      pageEnd(req, resp, sb);
 +    } catch (Throwable t) {
 +      log.error("Error building page " + req.getRequestURI(), t);
 +      sb.append("\n<pre>\n");
 +      StringWriter sw = new StringWriter();
 +      t.printStackTrace(new PrintWriter(sw));
 +      sb.append(sanitize(sw.getBuffer().toString()));
 +      sb.append("</pre>\n");
 +    } finally {
 +      resp.getWriter().print(sb);
 +      resp.getWriter().flush();
 +    }
 +  }
 +
 +  @Override
 +  protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
 +    doGet(req, resp);
 +  }
 +
 +  private static final String DEFAULT_CONTENT_TYPE = "text/html";
 +
 +  public static final void setCookie(HttpServletResponse resp, String name, String value) {
 +    resp.addCookie(new Cookie(name, value));
 +  }
 +
 +  public static final String getCookieValue(HttpServletRequest req, String name) {
 +    if (req.getCookies() != null)
 +      for (Cookie c : req.getCookies())
 +        if (c.getName().equals(name))
 +          return c.getValue();
 +    return null;
 +  }
 +
 +  protected void pageStart(HttpServletRequest req, HttpServletResponse resp, StringBuilder sb) throws Exception {
 +    resp.setContentType(DEFAULT_CONTENT_TYPE);
 +    int refresh = -1;
 +    String refreshStr = getCookieValue(req, "page.refresh.rate");
 +    if (refreshStr != null) {
 +      try {
 +        refresh = Integer.parseInt(BasicServlet.decode(refreshStr));
 +      } catch (NumberFormatException e) {
 +        // ignore improperly formatted user cookie
 +      }
 +    }
 +    synchronized (BasicServlet.class) {
 +      // Learn our instance name asynchronously so we don't hang up if zookeeper is down
 +      if (cachedInstanceName == null) {
 +        SimpleTimer.getInstance().schedule(new TimerTask() {
 +          @Override
 +          public void run() {
 +            synchronized (BasicServlet.class) {
 +              if (cachedInstanceName == null) {
 +                cachedInstanceName = HdfsZooInstance.getInstance().getInstanceName();
 +              }
 +            }
 +          }
 +        }, 1000);
 +      }
 +    }
 +
 +    // BEGIN PAGE
 +    sb.append("<!--\n");
 +    sb.append("  Licensed to the Apache Software Foundation (ASF) under one or more\n");
 +    sb.append("  contributor license agreements.  See the NOTICE file distributed with\n");
 +    sb.append("  this work for additional information regarding copyright ownership.\n");
 +    sb.append("  The ASF licenses this file to You under the Apache License, Version 2.0\n");
 +    sb.append("  (the \"License\"); you may not use this file except in compliance with\n");
 +    sb.append("  the License.  You may obtain a copy of the License at\n");
 +    sb.append("\n");
 +    sb.append("    http://www.apache.org/licenses/LICENSE-2.0\n");
 +    sb.append("\n");
 +    sb.append("  Unless required by applicable law or agreed to in writing, software\n");
 +    sb.append("  distributed under the License is distributed on an \"AS IS\" BASIS,\n");
 +    sb.append("  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n");
 +    sb.append("  See the License for the specific language governing permissions and\n");
 +    sb.append("  limitations under the License.\n");
 +    sb.append("-->\n");
 +    sb.append("<html>\n");
 +
 +    // BEGIN HEADER
 +    sb.append("<head>\n");
 +    sb.append("<title>").append(getTitle(req)).append(" - Accumulo ").append(Constants.VERSION).append("</title>\n");
 +    if ((refresh > 0) && (req.getRequestURI().startsWith("/vis") == false) && (req.getRequestURI().startsWith("/shell") == false))
 +      sb.append("<meta http-equiv='refresh' content='" + refresh + "' />\n");
 +    sb.append("<meta http-equiv='Content-Type' content='").append(DEFAULT_CONTENT_TYPE).append("' />\n");
 +    sb.append("<meta http-equiv='Content-Script-Type' content='text/javascript' />\n");
 +    sb.append("<meta http-equiv='Content-Style-Type' content='text/css' />\n");
 +    sb.append("<link rel='shortcut icon' type='image/jpg' href='/web/favicon.png' />\n");
 +    sb.append("<link rel='stylesheet' type='text/css' href='/web/screen.css' media='screen' />\n");
 +    sb.append("<script src='/web/functions.js' type='text/javascript'></script>\n");
 +
 +    sb.append("<!--[if lte IE 8]><script language=\"javascript\" type=\"text/javascript\" src=\"/web/flot/excanvas.min.js\"></script><![endif]-->\n");
 +    sb.append("<script language=\"javascript\" type=\"text/javascript\" src=\"/web/flot/jquery.js\"></script>\n");
 +    sb.append("<script language=\"javascript\" type=\"text/javascript\" src=\"/web/flot/jquery.flot.js\"></script>\n");
 +
 +    sb.append("</head>\n");
 +
 +    // BEGIN BODY OPENING
 +    sb.append("\n<body ").append(getBodyAttributes()).append(">\n");
 +    sb.append("<div id='content-wrapper'>\n");
 +    sb.append("<div id='content'>\n");
 +    sb.append("<div id='header'>");
 +    if (!bannerText.isEmpty()) {
 +      sb.append("<div id='banner' style='color:").append(bannerColor).append(";background:").append(bannerBackground).append("'>").append(bannerText)
 +          .append("</div>\n");
 +    }
 +    sb.append("<div id='headertitle'>");
 +    sb.append("<h1>").append(getTitle(req)).append("</h1></div>\n");
 +    sb.append("<div id='subheader'>Instance&nbsp;Name:&nbsp;").append(cachedInstanceName).append("&nbsp;&nbsp;&nbsp;Version:&nbsp;").append(Constants.VERSION)
 +        .append("\n");
 +    sb.append("<br><span class='smalltext'>Instance&nbsp;ID:&nbsp;").append(HdfsZooInstance.getInstance().getInstanceID()).append("</span>\n");
 +    sb.append("<br><span class='smalltext'>").append(new Date().toString().replace(" ", "&nbsp;")).append("</span>");
 +    sb.append("</div>\n"); // end <div id='subheader'>
 +    sb.append("</div>\n"); // end <div id='header'>
 +
 +    // BEGIN LEFT SIDE
 +    sb.append("<div id='nav'>\n");
 +    sb.append("<span id='nav-title'><a href='/'>Overview</a></span><br />\n");
 +    sb.append("<hr />\n");
 +    sb.append("<a href='/master'>Master&nbsp;Server</a><br />\n");
 +    sb.append("<a href='/tservers'>Tablet&nbsp;Servers</a><br />\n");
 +    sb.append("<a href='/scans'>Active&nbsp;Scans</a><br />\n");
 +    sb.append("<a href='/vis'>Server Activity</a><br />\n");
 +    sb.append("<a href='/gc'>Garbage&nbsp;Collector</a><br />\n");
 +    sb.append("<a href='/tables'>Tables</a><br />\n");
 +    sb.append("<a href='/trace/summary?minutes=10'>Recent&nbsp;Traces</a><br />\n");
 +    List<DedupedLogEvent> dedupedLogEvents = LogService.getInstance().getEvents();
 +    int numLogs = dedupedLogEvents.size();
 +    boolean logsHaveError = false;
 +    for (DedupedLogEvent dedupedLogEvent : dedupedLogEvents)
 +      if (dedupedLogEvent.getEvent().getLevel().isGreaterOrEqual(Level.ERROR)) {
 +        logsHaveError = true;
 +        break;
 +      }
 +    if (numLogs > 0)
 +      sb.append("<span class='" + (logsHaveError ? "error" : "warning") + "'><a href='/log'>Recent&nbsp;Logs&nbsp;<span class='smalltext'>(" + numLogs
 +          + ")</a></span></span><br />\n");
 +    int numProblems = Monitor.getProblemSummary().entrySet().size();
 +    if (numProblems > 0)
 +      sb.append("<span class='error'><a href='/problems'>Table&nbsp;Problems&nbsp;<span class='smalltext'>(" + numProblems + ")</a></span></span><br />\n");
 +    sb.append("<hr />\n");
 +    sb.append("<a href='/xml'>XML</a><br />\n");
 +    sb.append("<a href='/json'>JSON</a><hr />\n");
 +    if (Monitor.isUsingSsl())
 +      sb.append("<a href='/shell'>Shell</a><hr />\n");
 +    sb.append("<div class='smalltext'>[<a href='").append("/op?action=refresh&value=").append(refresh < 1 ? "5" : "-1");
 +    sb.append("&redir=").append(currentPage(req)).append("'>");
 +    sb.append(refresh < 1 ? "en" : "dis").append("able&nbsp;auto-refresh</a>]</div>\n");
 +    sb.append("</div>\n"); // end <div id='nav'>
 +
 +    sb.append("<div id='main'");
 +    if (bannerText.isEmpty())
 +      sb.append(" style='bottom:0'");
 +    sb.append(">\n");
 +    sb.append("<!-- BEGIN MAIN BODY CONTENT -->\n\n");
 +  }
 +
 +  protected void pageBody(HttpServletRequest req, HttpServletResponse resp, StringBuilder sb) throws Exception {
 +    sb.append("This page intentionally left blank.");
 +  }
 +
 +  protected void pageEnd(HttpServletRequest req, HttpServletResponse resp, StringBuilder sb) throws Exception {
 +    sb.append("\n<!-- END MAIN BODY CONTENT -->\n");
 +    sb.append("</div>\n"); // end <div id='main'>
 +
 +    // BEGIN FOOTER
 +    sb.append("</div>\n"); // end <div id='content'>
 +    sb.append("</div>\n"); // end <div id='content-wrapper'>
 +    if (!bannerText.isEmpty()) {
 +      sb.append("<div id='footer' style='color:").append(bannerColor).append(";background:").append(bannerBackground).append("'>").append(bannerText)
 +          .append("</div>\n");
 +    }
 +    sb.append("</body>\n");
 +    sb.append("</html>\n");
 +  }
 +
 +  /**
 +   * Allow the concrete servlet implementation to provide attributes on the body HTML tag, such as 'onload', which can be used to call Javascript methods on
 +   * page load. By default, nothing is specified.
 +   */
 +  protected String getBodyAttributes() {
 +    return "";
 +  }
 +
 +  public static String encode(String s) {
 +    try {
-       return URLEncoder.encode(s, Constants.UTF8.name());
++      return URLEncoder.encode(s, UTF_8.name());
 +    } catch (UnsupportedEncodingException e) {
-       Logger.getLogger(BasicServlet.class).fatal(Constants.UTF8.name() + " is not a recognized encoding", e);
++      Logger.getLogger(BasicServlet.class).fatal(UTF_8.name() + " is not a recognized encoding", e);
 +      throw new AssertionError(e); // can't happen with UTF-8
 +    }
 +  }
 +
 +  public static String decode(String s) {
 +    try {
-       return URLDecoder.decode(s, Constants.UTF8.name());
++      return URLDecoder.decode(s, UTF_8.name());
 +    } catch (UnsupportedEncodingException e) {
-       Logger.getLogger(BasicServlet.class).fatal(Constants.UTF8.name() + " is not a recognized encoding", e);
++      Logger.getLogger(BasicServlet.class).fatal(UTF_8.name() + " is not a recognized encoding", e);
 +      throw new AssertionError(e); // can't happen with UTF-8
 +    }
 +  }
 +
 +  public static String sanitize(String xml) {
 +    return xml.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
 +  }
 +
 +  public static String currentPage(HttpServletRequest req) {
 +    String redir = req.getRequestURI();
 +    if (req.getQueryString() != null)
 +      redir += "?" + req.getQueryString();
 +    return encode(redir);
 +  }
 +
 +  protected static void banner(StringBuilder sb, String klass, String text) {
 +    sb.append("<br />\n<h2 class='").append(klass).append("'>").append(text).append("</h2>\n");
 +  }
 +
 +}

http://git-wip-us.apache.org/repos/asf/accumulo/blob/9b20a9d4/server/monitor/src/main/java/org/apache/accumulo/monitor/servlets/DefaultServlet.java
----------------------------------------------------------------------
diff --cc server/monitor/src/main/java/org/apache/accumulo/monitor/servlets/DefaultServlet.java
index d88bd7c,0000000..bb7e690
mode 100644,000000..100644
--- a/server/monitor/src/main/java/org/apache/accumulo/monitor/servlets/DefaultServlet.java
+++ b/server/monitor/src/main/java/org/apache/accumulo/monitor/servlets/DefaultServlet.java
@@@ -1,346 -1,0 +1,347 @@@
 +/*
 + * Licensed to the Apache Software Foundation (ASF) under one or more
 + * contributor license agreements.  See the NOTICE file distributed with
 + * this work for additional information regarding copyright ownership.
 + * The ASF licenses this file to You 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 org.apache.accumulo.monitor.servlets;
 +
++import static com.google.common.base.Charsets.UTF_8;
++
 +import java.io.IOException;
 +import java.io.InputStream;
 +import java.util.ArrayList;
 +import java.util.Arrays;
 +import java.util.Calendar;
 +import java.util.Date;
 +import java.util.List;
 +import java.util.TimeZone;
 +
 +import javax.servlet.ServletException;
 +import javax.servlet.ServletOutputStream;
 +import javax.servlet.http.HttpServletRequest;
 +import javax.servlet.http.HttpServletResponse;
 +
- import org.apache.accumulo.core.Constants;
 +import org.apache.accumulo.core.master.thrift.MasterMonitorInfo;
 +import org.apache.accumulo.core.util.Duration;
 +import org.apache.accumulo.core.util.NumUtil;
 +import org.apache.accumulo.core.util.Pair;
 +import org.apache.accumulo.core.volume.VolumeConfiguration;
 +import org.apache.accumulo.monitor.Monitor;
 +import org.apache.accumulo.monitor.ZooKeeperStatus;
 +import org.apache.accumulo.monitor.ZooKeeperStatus.ZooKeeperState;
 +import org.apache.accumulo.monitor.util.celltypes.NumberType;
 +import org.apache.accumulo.server.conf.ServerConfiguration;
 +import org.apache.accumulo.server.fs.VolumeManager;
 +import org.apache.accumulo.server.fs.VolumeManagerImpl;
 +import org.apache.hadoop.fs.ContentSummary;
 +import org.apache.hadoop.fs.FileSystem;
 +import org.apache.hadoop.fs.Path;
 +
 +public class DefaultServlet extends BasicServlet {
 +
 +  private static final long serialVersionUID = 1L;
 +
 +  @Override
 +  protected String getTitle(HttpServletRequest req) {
 +    return "Accumulo Overview";
 +  }
 +
 +  private void getResource(HttpServletRequest req, HttpServletResponse resp) throws IOException {
 +    try {
 +      String path = req.getRequestURI();
 +
 +      if (path.endsWith(".jpg"))
 +        resp.setContentType("image/jpeg");
 +
 +      if (path.endsWith(".html"))
 +        resp.setContentType("text/html");
 +
 +      path = path.substring(1);
 +      InputStream data = BasicServlet.class.getClassLoader().getResourceAsStream(path);
 +      ServletOutputStream out = resp.getOutputStream();
 +      try {
 +        if (data != null) {
 +          byte[] buffer = new byte[1024];
 +          int n;
 +          while ((n = data.read(buffer)) > 0)
 +            out.write(buffer, 0, n);
 +        } else {
-           out.write(("could not get resource " + path + "").getBytes(Constants.UTF8));
++          out.write(("could not get resource " + path + "").getBytes(UTF_8));
 +        }
 +      } finally {
 +        if (data != null)
 +          data.close();
 +      }
 +    } catch (Throwable t) {
 +      log.error(t, t);
 +      throw new IOException(t);
 +    }
 +  }
 +
 +  @Override
 +  public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
 +    if (req.getRequestURI().startsWith("/web"))
 +      getResource(req, resp);
 +    else if (req.getRequestURI().startsWith("/monitor"))
 +      resp.sendRedirect("/master");
 +    else if (req.getRequestURI().startsWith("/errors"))
 +      resp.sendRedirect("/problems");
 +    else
 +      super.doGet(req, resp);
 +  }
 +
 +  public static final int GRAPH_WIDTH = 450;
 +  public static final int GRAPH_HEIGHT = 150;
 +
 +  private static void plotData(StringBuilder sb, String title, @SuppressWarnings("rawtypes") List data, boolean points) {
 +    plotData(sb, title, points, new ArrayList<String>(), data);
 +  }
 +
 +  @SuppressWarnings("rawtypes")
 +  private static void plotData(StringBuilder sb, String title, boolean points, List<String> labels, List... series) {
 +    sb.append("<div class=\"plotHeading\">");
 +    sb.append(title);
 +    sb.append("</div>");
 +    sb.append("</br>");
 +    String id = "c" + title.hashCode();
 +    sb.append("<div id=\"" + id + "\" style=\"width:" + GRAPH_WIDTH + "px;height:" + GRAPH_HEIGHT + "px;\"></div>\n");
 +
 +    sb.append("<script type=\"text/javascript\">\n");
 +    sb.append("$(function () {\n");
 +
 +    for (int i = 0; i < series.length; i++) {
 +
 +      @SuppressWarnings("unchecked")
 +      List<Pair<Long,? extends Number>> data = series[i];
 +      sb.append("    var d" + i + " = [");
 +
 +      String sep = "";
 +      for (Pair<Long,? extends Number> point : data) {
 +        if (point.getSecond() == null)
 +          continue;
 +
 +        String y;
 +        if (point.getSecond() instanceof Double)
 +          y = String.format("%1.2f", point.getSecond());
 +        else
 +          y = point.getSecond().toString();
 +
 +        sb.append(sep);
 +        sep = ",";
 +        sb.append("[" + utc2local(point.getFirst()) + "," + y + "]");
 +      }
 +      sb.append("    ];\n");
 +    }
 +
 +    String opts = "lines: { show: true }";
 +    if (points)
 +      opts = "points: { show: true, radius: 1 }";
 +
 +    sb.append("    $.plot($(\"#" + id + "\"),");
 +    String sep = "";
 +
 +    String colors[] = new String[] {"red", "blue", "green", "black"};
 +
 +    sb.append("[");
 +    for (int i = 0; i < series.length; i++) {
 +      sb.append(sep);
 +      sep = ",";
 +      sb.append("{ ");
 +      if (labels.size() > 0) {
 +        sb.append("label: \"" + labels.get(i) + "\", ");
 +      }
 +      sb.append("data: d" + i + ", " + opts + ", color:\"" + colors[i] + "\" }");
 +    }
 +    sb.append("], ");
 +    sb.append("{yaxis:{}, xaxis:{mode:\"time\",minTickSize: [1, \"minute\"],timeformat: \"%H:%M<br />" + getShortTZName() + "\", ticks:3}});");
 +    sb.append("   });\n");
 +    sb.append("</script>\n");
 +  }
 +
 +  /**
 +   * Shows the current time zone (based on the current time) short name
 +   */
 +  private static String getShortTZName() {
 +    TimeZone tz = TimeZone.getDefault();
 +    return tz.getDisplayName(tz.inDaylightTime(new Date()), TimeZone.SHORT);
 +  }
 +
 +  /**
 +   * Converts a unix timestamp in UTC to one that is relative to the local timezone
 +   */
 +  private static Long utc2local(Long utcMillis) {
 +    Calendar currentCalendar = Calendar.getInstance(); // default timezone
 +    currentCalendar.setTimeInMillis(utcMillis + currentCalendar.getTimeZone().getOffset(utcMillis));
 +    return currentCalendar.getTime().getTime();
 +  }
 +
 +  @Override
 +  protected void pageBody(HttpServletRequest req, HttpServletResponse resp, StringBuilder sb) throws IOException {
 +
 +    sb.append("<table class='noborder'>\n");
 +    sb.append("<tr>\n");
 +
 +    sb.append("<td class='noborder'>\n");
 +    doAccumuloTable(sb);
 +    sb.append("</td>\n");
 +
 +    sb.append("<td class='noborder'>\n");
 +    doZooKeeperTable(sb);
 +    sb.append("</td>\n");
 +
 +    sb.append("</tr></table>\n");
 +    sb.append("<br/>\n");
 +
 +    sb.append("<p/><table class=\"noborder\">\n");
 +
 +    sb.append("<tr><td>\n");
 +    plotData(sb, "Ingest (Entries/s)", Monitor.getIngestRateOverTime(), false);
 +    sb.append("</td><td>\n");
 +    plotData(sb, "Scan (Entries/s)", false, Arrays.asList("Read", "Returned"), Monitor.getScanRateOverTime(), Monitor.getQueryRateOverTime());
 +    sb.append("</td></tr>\n");
 +
 +    sb.append("<tr><td>\n");
 +    plotData(sb, "Ingest (MB/s)", Monitor.getIngestByteRateOverTime(), false);
 +    sb.append("</td><td>\n");
 +    plotData(sb, "Scan (MB/s)", Monitor.getQueryByteRateOverTime(), false);
 +    sb.append("</td></tr>\n");
 +
 +    sb.append("<tr><td>\n");
 +    plotData(sb, "Load Average", Monitor.getLoadOverTime(), false);
 +    sb.append("</td><td>\n");
 +    plotData(sb, "Seeks", Monitor.getLookupsOverTime(), false);
 +    sb.append("</td></tr>\n");
 +
 +    sb.append("<tr><td>\n");
 +    plotData(sb, "Minor Compactions", Monitor.getMinorCompactionsOverTime(), false);
 +    sb.append("</td><td>\n");
 +    plotData(sb, "Major Compactions", Monitor.getMajorCompactionsOverTime(), false);
 +    sb.append("</td></tr>\n");
 +
 +    sb.append("<tr><td>\n");
 +    plotData(sb, "Index Cache Hit Rate", Monitor.getIndexCacheHitRateOverTime(), true);
 +    sb.append("</td><td>\n");
 +    plotData(sb, "Data Cache Hit Rate", Monitor.getDataCacheHitRateOverTime(), true);
 +    sb.append("</td></tr>\n");
 +
 +    sb.append("</table>\n");
 +  }
 +
 +  private void doAccumuloTable(StringBuilder sb) throws IOException {
 +    // Accumulo
 +    VolumeManager vm = VolumeManagerImpl.get(ServerConfiguration.getSiteConfiguration());
 +    MasterMonitorInfo info = Monitor.getMmi();
 +    sb.append("<table>\n");
 +    sb.append("<tr><th colspan='2'><a href='/master'>Accumulo Master</a></th></tr>\n");
 +    if (info == null) {
 +      sb.append("<tr><td colspan='2'><span class='error'>Master is Down</span></td></tr>\n");
 +    } else {
 +      long totalAcuBytesUsed = 0l;
 +      long totalHdfsBytesUsed = 0l;
 +
 +      try {
 +        for (String baseDir : VolumeConfiguration.getVolumeUris(ServerConfiguration.getSiteConfiguration())) {
 +          final Path basePath = new Path(baseDir);
 +          final FileSystem fs = vm.getVolumeByPath(basePath).getFileSystem();
 +
 +          try {
 +            // Calculate the amount of space used by Accumulo on the FileSystem
 +            ContentSummary accumuloSummary = fs.getContentSummary(basePath);
 +            long bytesUsedByAcuOnFs = accumuloSummary.getSpaceConsumed();
 +            totalAcuBytesUsed += bytesUsedByAcuOnFs;
 +
 +            // Catch the overflow -- this is big data
 +            if (totalAcuBytesUsed < bytesUsedByAcuOnFs) {
 +              log.debug("Overflowed long in bytes used by Accumulo for " + baseDir);
 +              totalAcuBytesUsed = 0l;
 +              break;
 +            }
 +
 +            // Calculate the total amount of space used on the FileSystem
 +            ContentSummary volumeSummary = fs.getContentSummary(new Path("/"));
 +            long bytesUsedOnVolume = volumeSummary.getSpaceConsumed();
 +            totalHdfsBytesUsed += bytesUsedOnVolume;
 +
 +            // Catch the overflow -- this is big data
 +            if (totalHdfsBytesUsed < bytesUsedOnVolume) {
 +              log.debug("Overflowed long in bytes used in HDFS for " + baseDir);
 +              totalHdfsBytesUsed = 0;
 +              break;
 +            }
 +          } catch (Exception ex) {
 +            log.trace("Unable to get disk usage information for " + baseDir, ex);
 +          }
 +        }
 +
 +        String diskUsed = "Unknown";
 +        String consumed = null;
 +        if (totalAcuBytesUsed > 0) {
 +          // Convert Accumulo usage to a readable String
 +          diskUsed = bytes(totalAcuBytesUsed);
 +
 +          if (totalHdfsBytesUsed > 0) {
 +            // Compute amount of space used by Accumulo as a percentage of total space usage.
 +            consumed = String.format("%.2f%%", totalAcuBytesUsed * 100. / totalHdfsBytesUsed);
 +          }
 +        }
 +
 +        boolean highlight = false;
 +        tableRow(sb, (highlight = !highlight), "Disk&nbsp;Used", diskUsed);
 +        if (null != consumed)
 +          tableRow(sb, (highlight = !highlight), "%&nbsp;of&nbsp;Used&nbsp;DFS", consumed);
 +        tableRow(sb, (highlight = !highlight), "<a href='/tables'>Tables</a>", NumberType.commas(Monitor.getTotalTables()));
 +        tableRow(sb, (highlight = !highlight), "<a href='/tservers'>Tablet&nbsp;Servers</a>", NumberType.commas(info.tServerInfo.size(), 1, Long.MAX_VALUE));
 +        tableRow(sb, (highlight = !highlight), "<a href='/tservers'>Dead&nbsp;Tablet&nbsp;Servers</a>", NumberType.commas(info.deadTabletServers.size(), 0, 0));
 +        tableRow(sb, (highlight = !highlight), "Tablets", NumberType.commas(Monitor.getTotalTabletCount(), 1, Long.MAX_VALUE));
 +        tableRow(sb, (highlight = !highlight), "Entries", NumberType.commas(Monitor.getTotalEntries()));
 +        tableRow(sb, (highlight = !highlight), "Lookups", NumberType.commas(Monitor.getTotalLookups()));
 +        tableRow(sb, (highlight = !highlight), "Uptime", Duration.format(System.currentTimeMillis() - Monitor.getStartTime()));
 +      } catch (Exception e) {
 +        log.debug(e, e);
 +      }
 +    }
 +    sb.append("</table>\n");
 +  }
 +
 +  private void doZooKeeperTable(StringBuilder sb) throws IOException {
 +    // Zookeepers
 +    sb.append("<table>\n");
 +    sb.append("<tr><th colspan='3'>Zookeeper</th></tr>\n");
 +    sb.append("<tr><th>Server</th><th>Mode</th><th>Clients</th></tr>\n");
 +
 +    boolean highlight = false;
 +    for (ZooKeeperState k : ZooKeeperStatus.getZooKeeperStatus()) {
 +      if (k.clients >= 0) {
 +        tableRow(sb, (highlight = !highlight), k.keeper, k.mode, k.clients);
 +      } else {
 +        tableRow(sb, false, k.keeper, "<span class='error'>Down</span>", "");
 +      }
 +    }
 +    sb.append("</table>\n");
 +  }
 +
 +  private static String bytes(long big) {
 +    return NumUtil.bigNumberForSize(big);
 +  }
 +
 +  public static void tableRow(StringBuilder sb, boolean highlight, Object... cells) {
 +    sb.append(highlight ? "<tr class='highlight'>" : "<tr>");
 +    for (int i = 0; i < cells.length; ++i) {
 +      Object cell = cells[i];
 +      String cellValue = cell == null ? "" : String.valueOf(cell).trim();
 +      sb.append("<td class='").append(i < cells.length - 1 ? "left" : "right").append("'>").append(cellValue.isEmpty() ? "-" : cellValue).append("</td>");
 +    }
 +    sb.append("</tr>\n");
 +  }
 +}


Mime
View raw message