You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@accumulo.apache.org by ib...@apache.org on 2017/07/23 16:57:55 UTC

[1/3] accumulo git commit: ACCUMULO-4655 Added a Response Time column to the monitor

Repository: accumulo
Updated Branches:
  refs/heads/1.8 1ab2431c9 -> ef78423e2
  refs/heads/master 1910e25be -> 66d8956bf


ACCUMULO-4655 Added a Response Time column to the monitor

Added a Response Time column to the monitor which shows how long it took to get status from that tserver.
This is useful in determining whether long Last Contact times are dues to one or more tservers or whether
this is due to churn in the master.

Closes #271


Project: http://git-wip-us.apache.org/repos/asf/accumulo/repo
Commit: http://git-wip-us.apache.org/repos/asf/accumulo/commit/ef78423e
Tree: http://git-wip-us.apache.org/repos/asf/accumulo/tree/ef78423e
Diff: http://git-wip-us.apache.org/repos/asf/accumulo/diff/ef78423e

Branch: refs/heads/1.8
Commit: ef78423e23a800d9b9371ba46408d95145d46bd6
Parents: 1ab2431
Author: Ivan Bella <iv...@bella.name>
Authored: Mon Jun 19 12:55:01 2017 -0400
Committer: Ivan Bella <iv...@bella.name>
Committed: Sun Jul 23 11:42:18 2017 -0400

----------------------------------------------------------------------
 .../core/master/thrift/TabletServerStatus.java  | 107 ++++++++++++++++++-
 core/src/main/thrift/master.thrift              |   1 +
 .../accumulo/server/master/LiveTServerSet.java  |   8 +-
 .../monitor/servlets/TServersServlet.java       |  15 ++-
 .../apache/accumulo/tserver/TabletServer.java   |   2 +
 5 files changed, 126 insertions(+), 7 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/accumulo/blob/ef78423e/core/src/main/java/org/apache/accumulo/core/master/thrift/TabletServerStatus.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/accumulo/core/master/thrift/TabletServerStatus.java b/core/src/main/java/org/apache/accumulo/core/master/thrift/TabletServerStatus.java
index 07444b5..c00558c 100644
--- a/core/src/main/java/org/apache/accumulo/core/master/thrift/TabletServerStatus.java
+++ b/core/src/main/java/org/apache/accumulo/core/master/thrift/TabletServerStatus.java
@@ -68,6 +68,7 @@ public class TabletServerStatus implements org.apache.thrift.TBase<TabletServerS
   private static final org.apache.thrift.protocol.TField FLUSHS_FIELD_DESC = new org.apache.thrift.protocol.TField("flushs", org.apache.thrift.protocol.TType.I64, (short)15);
   private static final org.apache.thrift.protocol.TField SYNCS_FIELD_DESC = new org.apache.thrift.protocol.TField("syncs", org.apache.thrift.protocol.TType.I64, (short)16);
   private static final org.apache.thrift.protocol.TField BULK_IMPORTS_FIELD_DESC = new org.apache.thrift.protocol.TField("bulkImports", org.apache.thrift.protocol.TType.LIST, (short)17);
+  private static final org.apache.thrift.protocol.TField RESPONSE_TIME_FIELD_DESC = new org.apache.thrift.protocol.TField("responseTime", org.apache.thrift.protocol.TType.I64, (short)18);
 
   private static final Map<Class<? extends IScheme>, SchemeFactory> schemes = new HashMap<Class<? extends IScheme>, SchemeFactory>();
   static {
@@ -89,6 +90,7 @@ public class TabletServerStatus implements org.apache.thrift.TBase<TabletServerS
   public long flushs; // required
   public long syncs; // required
   public List<BulkImportStatus> bulkImports; // required
+  public long responseTime; // required
 
   /** The set of fields this struct contains, along with convenience methods for finding and manipulating them. */
   public enum _Fields implements org.apache.thrift.TFieldIdEnum {
@@ -105,7 +107,8 @@ public class TabletServerStatus implements org.apache.thrift.TBase<TabletServerS
     LOG_SORTS((short)14, "logSorts"),
     FLUSHS((short)15, "flushs"),
     SYNCS((short)16, "syncs"),
-    BULK_IMPORTS((short)17, "bulkImports");
+    BULK_IMPORTS((short)17, "bulkImports"),
+    RESPONSE_TIME((short)18, "responseTime");
 
     private static final Map<String, _Fields> byName = new HashMap<String, _Fields>();
 
@@ -148,6 +151,8 @@ public class TabletServerStatus implements org.apache.thrift.TBase<TabletServerS
           return SYNCS;
         case 17: // BULK_IMPORTS
           return BULK_IMPORTS;
+        case 18: // RESPONSE_TIME
+          return RESPONSE_TIME;
         default:
           return null;
       }
@@ -198,6 +203,7 @@ public class TabletServerStatus implements org.apache.thrift.TBase<TabletServerS
   private static final int __DATACACHEREQUEST_ISSET_ID = 7;
   private static final int __FLUSHS_ISSET_ID = 8;
   private static final int __SYNCS_ISSET_ID = 9;
+  private static final int __RESPONSETIME_ISSET_ID = 10;
   private short __isset_bitfield = 0;
   public static final Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> metaDataMap;
   static {
@@ -234,6 +240,8 @@ public class TabletServerStatus implements org.apache.thrift.TBase<TabletServerS
     tmpMap.put(_Fields.BULK_IMPORTS, new org.apache.thrift.meta_data.FieldMetaData("bulkImports", org.apache.thrift.TFieldRequirementType.DEFAULT, 
         new org.apache.thrift.meta_data.ListMetaData(org.apache.thrift.protocol.TType.LIST, 
             new org.apache.thrift.meta_data.StructMetaData(org.apache.thrift.protocol.TType.STRUCT, BulkImportStatus.class))));
+    tmpMap.put(_Fields.RESPONSE_TIME, new org.apache.thrift.meta_data.FieldMetaData("responseTime", org.apache.thrift.TFieldRequirementType.DEFAULT, 
+        new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.I64)));
     metaDataMap = Collections.unmodifiableMap(tmpMap);
     org.apache.thrift.meta_data.FieldMetaData.addStructMetaDataMap(TabletServerStatus.class, metaDataMap);
   }
@@ -255,7 +263,8 @@ public class TabletServerStatus implements org.apache.thrift.TBase<TabletServerS
     List<RecoveryStatus> logSorts,
     long flushs,
     long syncs,
-    List<BulkImportStatus> bulkImports)
+    List<BulkImportStatus> bulkImports,
+    long responseTime)
   {
     this();
     this.tableMap = tableMap;
@@ -282,6 +291,8 @@ public class TabletServerStatus implements org.apache.thrift.TBase<TabletServerS
     this.syncs = syncs;
     setSyncsIsSet(true);
     this.bulkImports = bulkImports;
+    this.responseTime = responseTime;
+    setResponseTimeIsSet(true);
   }
 
   /**
@@ -331,6 +342,7 @@ public class TabletServerStatus implements org.apache.thrift.TBase<TabletServerS
       }
       this.bulkImports = __this__bulkImports;
     }
+    this.responseTime = other.responseTime;
   }
 
   public TabletServerStatus deepCopy() {
@@ -363,6 +375,8 @@ public class TabletServerStatus implements org.apache.thrift.TBase<TabletServerS
     setSyncsIsSet(false);
     this.syncs = 0;
     this.bulkImports = null;
+    setResponseTimeIsSet(false);
+    this.responseTime = 0;
   }
 
   public int getTableMapSize() {
@@ -732,6 +746,29 @@ public class TabletServerStatus implements org.apache.thrift.TBase<TabletServerS
     }
   }
 
+  public long getResponseTime() {
+    return this.responseTime;
+  }
+
+  public TabletServerStatus setResponseTime(long responseTime) {
+    this.responseTime = responseTime;
+    setResponseTimeIsSet(true);
+    return this;
+  }
+
+  public void unsetResponseTime() {
+    __isset_bitfield = EncodingUtils.clearBit(__isset_bitfield, __RESPONSETIME_ISSET_ID);
+  }
+
+  /** Returns true if field responseTime is set (has been assigned a value) and false otherwise */
+  public boolean isSetResponseTime() {
+    return EncodingUtils.testBit(__isset_bitfield, __RESPONSETIME_ISSET_ID);
+  }
+
+  public void setResponseTimeIsSet(boolean value) {
+    __isset_bitfield = EncodingUtils.setBit(__isset_bitfield, __RESPONSETIME_ISSET_ID, value);
+  }
+
   public void setFieldValue(_Fields field, Object value) {
     switch (field) {
     case TABLE_MAP:
@@ -846,6 +883,14 @@ public class TabletServerStatus implements org.apache.thrift.TBase<TabletServerS
       }
       break;
 
+    case RESPONSE_TIME:
+      if (value == null) {
+        unsetResponseTime();
+      } else {
+        setResponseTime((Long)value);
+      }
+      break;
+
     }
   }
 
@@ -893,6 +938,9 @@ public class TabletServerStatus implements org.apache.thrift.TBase<TabletServerS
     case BULK_IMPORTS:
       return getBulkImports();
 
+    case RESPONSE_TIME:
+      return getResponseTime();
+
     }
     throw new IllegalStateException();
   }
@@ -932,6 +980,8 @@ public class TabletServerStatus implements org.apache.thrift.TBase<TabletServerS
       return isSetSyncs();
     case BULK_IMPORTS:
       return isSetBulkImports();
+    case RESPONSE_TIME:
+      return isSetResponseTime();
     }
     throw new IllegalStateException();
   }
@@ -1075,6 +1125,15 @@ public class TabletServerStatus implements org.apache.thrift.TBase<TabletServerS
         return false;
     }
 
+    boolean this_present_responseTime = true;
+    boolean that_present_responseTime = true;
+    if (this_present_responseTime || that_present_responseTime) {
+      if (!(this_present_responseTime && that_present_responseTime))
+        return false;
+      if (this.responseTime != that.responseTime)
+        return false;
+    }
+
     return true;
   }
 
@@ -1152,6 +1211,11 @@ public class TabletServerStatus implements org.apache.thrift.TBase<TabletServerS
     if (present_bulkImports)
       list.add(bulkImports);
 
+    boolean present_responseTime = true;
+    list.add(present_responseTime);
+    if (present_responseTime)
+      list.add(responseTime);
+
     return list.hashCode();
   }
 
@@ -1303,6 +1367,16 @@ public class TabletServerStatus implements org.apache.thrift.TBase<TabletServerS
         return lastComparison;
       }
     }
+    lastComparison = Boolean.valueOf(isSetResponseTime()).compareTo(other.isSetResponseTime());
+    if (lastComparison != 0) {
+      return lastComparison;
+    }
+    if (isSetResponseTime()) {
+      lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.responseTime, other.responseTime);
+      if (lastComparison != 0) {
+        return lastComparison;
+      }
+    }
     return 0;
   }
 
@@ -1394,6 +1468,10 @@ public class TabletServerStatus implements org.apache.thrift.TBase<TabletServerS
       sb.append(this.bulkImports);
     }
     first = false;
+    if (!first) sb.append(", ");
+    sb.append("responseTime:");
+    sb.append(this.responseTime);
+    first = false;
     sb.append(")");
     return sb.toString();
   }
@@ -1586,6 +1664,14 @@ public class TabletServerStatus implements org.apache.thrift.TBase<TabletServerS
               org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type);
             }
             break;
+          case 18: // RESPONSE_TIME
+            if (schemeField.type == org.apache.thrift.protocol.TType.I64) {
+              struct.responseTime = iprot.readI64();
+              struct.setResponseTimeIsSet(true);
+            } else { 
+              org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type);
+            }
+            break;
           default:
             org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type);
         }
@@ -1673,6 +1759,9 @@ public class TabletServerStatus implements org.apache.thrift.TBase<TabletServerS
         }
         oprot.writeFieldEnd();
       }
+      oprot.writeFieldBegin(RESPONSE_TIME_FIELD_DESC);
+      oprot.writeI64(struct.responseTime);
+      oprot.writeFieldEnd();
       oprot.writeFieldStop();
       oprot.writeStructEnd();
     }
@@ -1733,7 +1822,10 @@ public class TabletServerStatus implements org.apache.thrift.TBase<TabletServerS
       if (struct.isSetBulkImports()) {
         optionals.set(13);
       }
-      oprot.writeBitSet(optionals, 14);
+      if (struct.isSetResponseTime()) {
+        optionals.set(14);
+      }
+      oprot.writeBitSet(optionals, 15);
       if (struct.isSetTableMap()) {
         {
           oprot.writeI32(struct.tableMap.size());
@@ -1795,12 +1887,15 @@ public class TabletServerStatus implements org.apache.thrift.TBase<TabletServerS
           }
         }
       }
+      if (struct.isSetResponseTime()) {
+        oprot.writeI64(struct.responseTime);
+      }
     }
 
     @Override
     public void read(org.apache.thrift.protocol.TProtocol prot, TabletServerStatus struct) throws org.apache.thrift.TException {
       TTupleProtocol iprot = (TTupleProtocol) prot;
-      BitSet incoming = iprot.readBitSet(14);
+      BitSet incoming = iprot.readBitSet(15);
       if (incoming.get(0)) {
         {
           org.apache.thrift.protocol.TMap _map16 = new org.apache.thrift.protocol.TMap(org.apache.thrift.protocol.TType.STRING, org.apache.thrift.protocol.TType.STRUCT, iprot.readI32());
@@ -1889,6 +1984,10 @@ public class TabletServerStatus implements org.apache.thrift.TBase<TabletServerS
         }
         struct.setBulkImportsIsSet(true);
       }
+      if (incoming.get(14)) {
+        struct.responseTime = iprot.readI64();
+        struct.setResponseTimeIsSet(true);
+      }
     }
   }
 

http://git-wip-us.apache.org/repos/asf/accumulo/blob/ef78423e/core/src/main/thrift/master.thrift
----------------------------------------------------------------------
diff --git a/core/src/main/thrift/master.thrift b/core/src/main/thrift/master.thrift
index 6104fea..b959074 100644
--- a/core/src/main/thrift/master.thrift
+++ b/core/src/main/thrift/master.thrift
@@ -85,6 +85,7 @@ struct TabletServerStatus {
   15:i64 flushs
   16:i64 syncs
   17:list<BulkImportStatus> bulkImports
+  18:i64 responseTime
 }
 
 enum MasterState {

http://git-wip-us.apache.org/repos/asf/accumulo/blob/ef78423e/server/base/src/main/java/org/apache/accumulo/server/master/LiveTServerSet.java
----------------------------------------------------------------------
diff --git a/server/base/src/main/java/org/apache/accumulo/server/master/LiveTServerSet.java b/server/base/src/main/java/org/apache/accumulo/server/master/LiveTServerSet.java
index 7d1d6e1..df135d6 100644
--- a/server/base/src/main/java/org/apache/accumulo/server/master/LiveTServerSet.java
+++ b/server/base/src/main/java/org/apache/accumulo/server/master/LiveTServerSet.java
@@ -120,11 +120,17 @@ public class LiveTServerSet implements Watcher {
       if (usePooledConnection == true)
         throw new UnsupportedOperationException();
 
+      long start = System.currentTimeMillis();
+
       TTransport transport = ThriftUtil.createTransport(address, context);
 
       try {
         TabletClientService.Client client = ThriftUtil.createClient(new TabletClientService.Client.Factory(), transport);
-        return client.getTabletServerStatus(Tracer.traceInfo(), context.rpcCreds());
+        TabletServerStatus status = client.getTabletServerStatus(Tracer.traceInfo(), context.rpcCreds());
+        if (status != null) {
+          status.setResponseTime(System.currentTimeMillis() - start);
+        }
+        return status;
       } finally {
         if (transport != null)
           transport.close();

http://git-wip-us.apache.org/repos/asf/accumulo/blob/ef78423e/server/monitor/src/main/java/org/apache/accumulo/monitor/servlets/TServersServlet.java
----------------------------------------------------------------------
diff --git a/server/monitor/src/main/java/org/apache/accumulo/monitor/servlets/TServersServlet.java b/server/monitor/src/main/java/org/apache/accumulo/monitor/servlets/TServersServlet.java
index 858192b..04a6511 100644
--- a/server/monitor/src/main/java/org/apache/accumulo/monitor/servlets/TServersServlet.java
+++ b/server/monitor/src/main/java/org/apache/accumulo/monitor/servlets/TServersServlet.java
@@ -309,18 +309,28 @@ public class TServersServlet extends BasicServlet {
     }
   }
 
+  static final long SECOND = 1000;
+  static final long RESPONSE_TIME_MAX_ERR = 3 * SECOND;
+  static final long MINUTE = 60 * SECOND;
+  static final long LAST_CONTEXT_MAX_ERR = 3 * MINUTE;
+
   static void doTserverList(HttpServletRequest req, StringBuilder sb, List<TabletServerStatus> tservers, String tableId, Table tServerList) {
     int guessHighLoad = ManagementFactory.getOperatingSystemMXBean().getAvailableProcessors();
     long now = System.currentTimeMillis();
 
     double avgLastContact = 0.;
+    double avgResponseTime = 0.;
+    int count = 0;
     for (TabletServerStatus status : tservers) {
+      count++;
       avgLastContact += (now - status.lastContact);
+      avgResponseTime += status.responseTime;
     }
-    final long MINUTES = 3 * 60 * 1000;
+    avgResponseTime /= count;
     tServerList.addSortableColumn("Server", new TServerLinkType(), null);
     tServerList.addSortableColumn("Hosted&nbsp;Tablets", new NumberType<>(0, Integer.MAX_VALUE), null);
-    tServerList.addSortableColumn("Last&nbsp;Contact", new DurationType(0l, (long) Math.min(avgLastContact * 4, MINUTES)), null);
+    tServerList.addSortableColumn("Last&nbsp;Contact", new DurationType(0l, (long) Math.min(avgLastContact * 4, LAST_CONTEXT_MAX_ERR)), null);
+    tServerList.addSortableColumn("Response&nbsp;Time", new DurationType(0l, (long) Math.min(avgResponseTime * 4, RESPONSE_TIME_MAX_ERR)), null);
     tServerList.addSortableColumn("Entries", new NumberType<Long>(), "The number of key/value pairs.");
     tServerList.addSortableColumn("Ingest", new NumberType<Long>(), "The number of key/value pairs inserted. (Note that deletes are also 'inserted')");
     tServerList.addSortableColumn("Query", new NumberType<Long>(), "The number of key/value pairs returned to clients. (Not the number of scans)");
@@ -352,6 +362,7 @@ public class TServersServlet extends BasicServlet {
       row.add(status); // add for server name
       row.add(summary.tablets);
       row.add(now - status.lastContact);
+      row.add(status.responseTime);
       row.add(summary.recs);
       row.add(summary.ingestRate);
       row.add(summary.queryRate);

http://git-wip-us.apache.org/repos/asf/accumulo/blob/ef78423e/server/tserver/src/main/java/org/apache/accumulo/tserver/TabletServer.java
----------------------------------------------------------------------
diff --git a/server/tserver/src/main/java/org/apache/accumulo/tserver/TabletServer.java b/server/tserver/src/main/java/org/apache/accumulo/tserver/TabletServer.java
index 6ead6b8..9c2d3e3 100644
--- a/server/tserver/src/main/java/org/apache/accumulo/tserver/TabletServer.java
+++ b/server/tserver/src/main/java/org/apache/accumulo/tserver/TabletServer.java
@@ -2856,6 +2856,7 @@ public class TabletServer extends AccumuloServerContext implements Runnable {
   }
 
   public TabletServerStatus getStats(Map<String,MapCounter<ScanRunState>> scanCounts) {
+    long start = System.currentTimeMillis();
     TabletServerStatus result = new TabletServerStatus();
 
     Map<KeyExtent,Tablet> onlineTabletsCopy;
@@ -2943,6 +2944,7 @@ public class TabletServer extends AccumuloServerContext implements Runnable {
     result.bulkImports = new ArrayList<>();
     result.bulkImports.addAll(clientHandler.getBulkLoadStatus());
     result.bulkImports.addAll(bulkImportStatus.getBulkLoadStatus());
+    result.responseTime = System.currentTimeMillis() - start;
     return result;
   }
 


[3/3] accumulo git commit: Merge branch '1.8'

Posted by ib...@apache.org.
Merge branch '1.8'

Closes #281


Project: http://git-wip-us.apache.org/repos/asf/accumulo/repo
Commit: http://git-wip-us.apache.org/repos/asf/accumulo/commit/66d8956b
Tree: http://git-wip-us.apache.org/repos/asf/accumulo/tree/66d8956b
Diff: http://git-wip-us.apache.org/repos/asf/accumulo/diff/66d8956b

Branch: refs/heads/master
Commit: 66d8956bfd041e72fd09de03f2832b7084c5bf04
Parents: 1910e25 ef78423
Author: Ivan Bella <iv...@bella.name>
Authored: Sun Jul 23 12:23:36 2017 -0400
Committer: Ivan Bella <iv...@bella.name>
Committed: Sun Jul 23 12:24:12 2017 -0400

----------------------------------------------------------------------
 .../core/master/thrift/TabletServerStatus.java  | 104 ++++++++++++++++++-
 core/src/main/thrift/master.thrift              |   1 +
 .../accumulo/server/master/LiveTServerSet.java  |   8 +-
 .../rest/tservers/TabletServerInformation.java  |   2 +
 .../src/main/resources/resources/js/global.js   |   1 +
 .../src/main/resources/resources/js/tservers.js |   7 +-
 .../apache/accumulo/tserver/TabletServer.java   |   2 +
 7 files changed, 118 insertions(+), 7 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/accumulo/blob/66d8956b/core/src/main/java/org/apache/accumulo/core/master/thrift/TabletServerStatus.java
----------------------------------------------------------------------
diff --cc core/src/main/java/org/apache/accumulo/core/master/thrift/TabletServerStatus.java
index 3406a03,c00558c..32b4c3e
--- a/core/src/main/java/org/apache/accumulo/core/master/thrift/TabletServerStatus.java
+++ b/core/src/main/java/org/apache/accumulo/core/master/thrift/TabletServerStatus.java
@@@ -41,14 -68,17 +41,15 @@@ public class TabletServerStatus impleme
    private static final org.apache.thrift.protocol.TField FLUSHS_FIELD_DESC = new org.apache.thrift.protocol.TField("flushs", org.apache.thrift.protocol.TType.I64, (short)15);
    private static final org.apache.thrift.protocol.TField SYNCS_FIELD_DESC = new org.apache.thrift.protocol.TField("syncs", org.apache.thrift.protocol.TType.I64, (short)16);
    private static final org.apache.thrift.protocol.TField BULK_IMPORTS_FIELD_DESC = new org.apache.thrift.protocol.TField("bulkImports", org.apache.thrift.protocol.TType.LIST, (short)17);
 -  private static final org.apache.thrift.protocol.TField RESPONSE_TIME_FIELD_DESC = new org.apache.thrift.protocol.TField("responseTime", org.apache.thrift.protocol.TType.I64, (short)18);
 +  private static final org.apache.thrift.protocol.TField VERSION_FIELD_DESC = new org.apache.thrift.protocol.TField("version", org.apache.thrift.protocol.TType.STRING, (short)18);
++  private static final org.apache.thrift.protocol.TField RESPONSE_TIME_FIELD_DESC = new org.apache.thrift.protocol.TField("responseTime", org.apache.thrift.protocol.TType.I64, (short)19);
  
 -  private static final Map<Class<? extends IScheme>, SchemeFactory> schemes = new HashMap<Class<? extends IScheme>, SchemeFactory>();
 -  static {
 -    schemes.put(StandardScheme.class, new TabletServerStatusStandardSchemeFactory());
 -    schemes.put(TupleScheme.class, new TabletServerStatusTupleSchemeFactory());
 -  }
 +  private static final org.apache.thrift.scheme.SchemeFactory STANDARD_SCHEME_FACTORY = new TabletServerStatusStandardSchemeFactory();
 +  private static final org.apache.thrift.scheme.SchemeFactory TUPLE_SCHEME_FACTORY = new TabletServerStatusTupleSchemeFactory();
  
 -  public Map<String,TableInfo> tableMap; // required
 +  public java.util.Map<java.lang.String,TableInfo> tableMap; // required
    public long lastContact; // required
 -  public String name; // required
 +  public java.lang.String name; // required
    public double osLoad; // required
    public long holdTime; // required
    public long lookups; // required
@@@ -56,11 -86,11 +57,12 @@@
    public long indexCacheRequest; // required
    public long dataCacheHits; // required
    public long dataCacheRequest; // required
 -  public List<RecoveryStatus> logSorts; // required
 +  public java.util.List<RecoveryStatus> logSorts; // required
    public long flushs; // required
    public long syncs; // required
 -  public List<BulkImportStatus> bulkImports; // required
 +  public java.util.List<BulkImportStatus> bulkImports; // required
 +  public java.lang.String version; // required
+   public long responseTime; // required
  
    /** The set of fields this struct contains, along with convenience methods for finding and manipulating them. */
    public enum _Fields implements org.apache.thrift.TFieldIdEnum {
@@@ -78,12 -108,12 +80,13 @@@
      FLUSHS((short)15, "flushs"),
      SYNCS((short)16, "syncs"),
      BULK_IMPORTS((short)17, "bulkImports"),
-     VERSION((short)18, "version");
 -    RESPONSE_TIME((short)18, "responseTime");
++    VERSION((short)18, "version"),
++    RESPONSE_TIME((short)19, "responseTime");
  
 -    private static final Map<String, _Fields> byName = new HashMap<String, _Fields>();
 +    private static final java.util.Map<java.lang.String, _Fields> byName = new java.util.HashMap<java.lang.String, _Fields>();
  
      static {
 -      for (_Fields field : EnumSet.allOf(_Fields.class)) {
 +      for (_Fields field : java.util.EnumSet.allOf(_Fields.class)) {
          byName.put(field.getFieldName(), field);
        }
      }
@@@ -121,8 -151,8 +124,10 @@@
            return SYNCS;
          case 17: // BULK_IMPORTS
            return BULK_IMPORTS;
 -        case 18: // RESPONSE_TIME
 +        case 18: // VERSION
 +          return VERSION;
++        case 19: // RESPONSE_TIME
+           return RESPONSE_TIME;
          default:
            return null;
        }
@@@ -173,10 -203,11 +178,11 @@@
    private static final int __DATACACHEREQUEST_ISSET_ID = 7;
    private static final int __FLUSHS_ISSET_ID = 8;
    private static final int __SYNCS_ISSET_ID = 9;
+   private static final int __RESPONSETIME_ISSET_ID = 10;
    private short __isset_bitfield = 0;
 -  public static final Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> metaDataMap;
 +  public static final java.util.Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> metaDataMap;
    static {
 -    Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> tmpMap = new EnumMap<_Fields, org.apache.thrift.meta_data.FieldMetaData>(_Fields.class);
 +    java.util.Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> tmpMap = new java.util.EnumMap<_Fields, org.apache.thrift.meta_data.FieldMetaData>(_Fields.class);
      tmpMap.put(_Fields.TABLE_MAP, new org.apache.thrift.meta_data.FieldMetaData("tableMap", org.apache.thrift.TFieldRequirementType.DEFAULT, 
          new org.apache.thrift.meta_data.MapMetaData(org.apache.thrift.protocol.TType.MAP, 
              new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.STRING), 
@@@ -209,9 -240,9 +215,11 @@@
      tmpMap.put(_Fields.BULK_IMPORTS, new org.apache.thrift.meta_data.FieldMetaData("bulkImports", org.apache.thrift.TFieldRequirementType.DEFAULT, 
          new org.apache.thrift.meta_data.ListMetaData(org.apache.thrift.protocol.TType.LIST, 
              new org.apache.thrift.meta_data.StructMetaData(org.apache.thrift.protocol.TType.STRUCT, BulkImportStatus.class))));
 +    tmpMap.put(_Fields.VERSION, new org.apache.thrift.meta_data.FieldMetaData("version", org.apache.thrift.TFieldRequirementType.DEFAULT, 
 +        new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.STRING)));
+     tmpMap.put(_Fields.RESPONSE_TIME, new org.apache.thrift.meta_data.FieldMetaData("responseTime", org.apache.thrift.TFieldRequirementType.DEFAULT, 
+         new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.I64)));
 -    metaDataMap = Collections.unmodifiableMap(tmpMap);
 +    metaDataMap = java.util.Collections.unmodifiableMap(tmpMap);
      org.apache.thrift.meta_data.FieldMetaData.addStructMetaDataMap(TabletServerStatus.class, metaDataMap);
    }
  
@@@ -229,11 -260,11 +237,12 @@@
      long indexCacheRequest,
      long dataCacheHits,
      long dataCacheRequest,
 -    List<RecoveryStatus> logSorts,
 +    java.util.List<RecoveryStatus> logSorts,
      long flushs,
      long syncs,
 -    List<BulkImportStatus> bulkImports,
 +    java.util.List<BulkImportStatus> bulkImports,
-     java.lang.String version)
++    java.lang.String version,
+     long responseTime)
    {
      this();
      this.tableMap = tableMap;
@@@ -260,7 -291,8 +269,9 @@@
      this.syncs = syncs;
      setSyncsIsSet(true);
      this.bulkImports = bulkImports;
 +    this.version = version;
+     this.responseTime = responseTime;
+     setResponseTimeIsSet(true);
    }
  
    /**
@@@ -310,9 -342,7 +321,10 @@@
        }
        this.bulkImports = __this__bulkImports;
      }
 +    if (other.isSetVersion()) {
 +      this.version = other.version;
 +    }
+     this.responseTime = other.responseTime;
    }
  
    public TabletServerStatus deepCopy() {
@@@ -345,7 -375,8 +357,9 @@@
      setSyncsIsSet(false);
      this.syncs = 0;
      this.bulkImports = null;
 +    this.version = null;
+     setResponseTimeIsSet(false);
+     this.responseTime = 0;
    }
  
    public int getTableMapSize() {
@@@ -715,31 -746,30 +729,54 @@@
      }
    }
  
 +  public java.lang.String getVersion() {
 +    return this.version;
 +  }
 +
 +  public TabletServerStatus setVersion(java.lang.String version) {
 +    this.version = version;
 +    return this;
 +  }
 +
 +  public void unsetVersion() {
 +    this.version = null;
 +  }
 +
 +  /** Returns true if field version is set (has been assigned a value) and false otherwise */
 +  public boolean isSetVersion() {
 +    return this.version != null;
 +  }
 +
 +  public void setVersionIsSet(boolean value) {
 +    if (!value) {
 +      this.version = null;
 +    }
 +  }
 +
+   public long getResponseTime() {
+     return this.responseTime;
+   }
+ 
+   public TabletServerStatus setResponseTime(long responseTime) {
+     this.responseTime = responseTime;
+     setResponseTimeIsSet(true);
+     return this;
+   }
+ 
+   public void unsetResponseTime() {
 -    __isset_bitfield = EncodingUtils.clearBit(__isset_bitfield, __RESPONSETIME_ISSET_ID);
++    __isset_bitfield = org.apache.thrift.EncodingUtils.clearBit(__isset_bitfield, __RESPONSETIME_ISSET_ID);
+   }
+ 
+   /** Returns true if field responseTime is set (has been assigned a value) and false otherwise */
+   public boolean isSetResponseTime() {
 -    return EncodingUtils.testBit(__isset_bitfield, __RESPONSETIME_ISSET_ID);
++    return org.apache.thrift.EncodingUtils.testBit(__isset_bitfield, __RESPONSETIME_ISSET_ID);
+   }
+ 
+   public void setResponseTimeIsSet(boolean value) {
 -    __isset_bitfield = EncodingUtils.setBit(__isset_bitfield, __RESPONSETIME_ISSET_ID, value);
++    __isset_bitfield = org.apache.thrift.EncodingUtils.setBit(__isset_bitfield, __RESPONSETIME_ISSET_ID, value);
+   }
+ 
 -  public void setFieldValue(_Fields field, Object value) {
 +  public void setFieldValue(_Fields field, java.lang.Object value) {
      switch (field) {
      case TABLE_MAP:
        if (value == null) {
@@@ -861,6 -883,14 +898,14 @@@
        }
        break;
  
+     case RESPONSE_TIME:
+       if (value == null) {
+         unsetResponseTime();
+       } else {
 -        setResponseTime((Long)value);
++        setResponseTime((java.lang.Long)value);
+       }
+       break;
+ 
      }
    }
  
@@@ -908,11 -938,11 +953,14 @@@
      case BULK_IMPORTS:
        return getBulkImports();
  
 +    case VERSION:
 +      return getVersion();
 +
+     case RESPONSE_TIME:
+       return getResponseTime();
+ 
      }
 -    throw new IllegalStateException();
 +    throw new java.lang.IllegalStateException();
    }
  
    /** Returns true if field corresponding to fieldID is set (has been assigned a value) and false otherwise */
@@@ -950,10 -980,10 +998,12 @@@
        return isSetSyncs();
      case BULK_IMPORTS:
        return isSetBulkImports();
 +    case VERSION:
 +      return isSetVersion();
+     case RESPONSE_TIME:
+       return isSetResponseTime();
      }
 -    throw new IllegalStateException();
 +    throw new java.lang.IllegalStateException();
    }
  
    @Override
@@@ -1097,63 -1125,98 +1147,74 @@@
          return false;
      }
  
 +    boolean this_present_version = true && this.isSetVersion();
 +    boolean that_present_version = true && that.isSetVersion();
 +    if (this_present_version || that_present_version) {
 +      if (!(this_present_version && that_present_version))
 +        return false;
 +      if (!this.version.equals(that.version))
 +        return false;
 +    }
 +
+     boolean this_present_responseTime = true;
+     boolean that_present_responseTime = true;
+     if (this_present_responseTime || that_present_responseTime) {
+       if (!(this_present_responseTime && that_present_responseTime))
+         return false;
+       if (this.responseTime != that.responseTime)
+         return false;
+     }
+ 
      return true;
    }
  
    @Override
    public int hashCode() {
 -    List<Object> list = new ArrayList<Object>();
 -
 -    boolean present_tableMap = true && (isSetTableMap());
 -    list.add(present_tableMap);
 -    if (present_tableMap)
 -      list.add(tableMap);
 -
 -    boolean present_lastContact = true;
 -    list.add(present_lastContact);
 -    if (present_lastContact)
 -      list.add(lastContact);
 -
 -    boolean present_name = true && (isSetName());
 -    list.add(present_name);
 -    if (present_name)
 -      list.add(name);
 -
 -    boolean present_osLoad = true;
 -    list.add(present_osLoad);
 -    if (present_osLoad)
 -      list.add(osLoad);
 -
 -    boolean present_holdTime = true;
 -    list.add(present_holdTime);
 -    if (present_holdTime)
 -      list.add(holdTime);
 -
 -    boolean present_lookups = true;
 -    list.add(present_lookups);
 -    if (present_lookups)
 -      list.add(lookups);
 -
 -    boolean present_indexCacheHits = true;
 -    list.add(present_indexCacheHits);
 -    if (present_indexCacheHits)
 -      list.add(indexCacheHits);
 -
 -    boolean present_indexCacheRequest = true;
 -    list.add(present_indexCacheRequest);
 -    if (present_indexCacheRequest)
 -      list.add(indexCacheRequest);
 -
 -    boolean present_dataCacheHits = true;
 -    list.add(present_dataCacheHits);
 -    if (present_dataCacheHits)
 -      list.add(dataCacheHits);
 -
 -    boolean present_dataCacheRequest = true;
 -    list.add(present_dataCacheRequest);
 -    if (present_dataCacheRequest)
 -      list.add(dataCacheRequest);
 -
 -    boolean present_logSorts = true && (isSetLogSorts());
 -    list.add(present_logSorts);
 -    if (present_logSorts)
 -      list.add(logSorts);
 -
 -    boolean present_flushs = true;
 -    list.add(present_flushs);
 -    if (present_flushs)
 -      list.add(flushs);
 -
 -    boolean present_syncs = true;
 -    list.add(present_syncs);
 -    if (present_syncs)
 -      list.add(syncs);
 -
 -    boolean present_bulkImports = true && (isSetBulkImports());
 -    list.add(present_bulkImports);
 -    if (present_bulkImports)
 -      list.add(bulkImports);
 -
 -    boolean present_responseTime = true;
 -    list.add(present_responseTime);
 -    if (present_responseTime)
 -      list.add(responseTime);
 -
 -    return list.hashCode();
 +    int hashCode = 1;
 +
 +    hashCode = hashCode * 8191 + ((isSetTableMap()) ? 131071 : 524287);
 +    if (isSetTableMap())
 +      hashCode = hashCode * 8191 + tableMap.hashCode();
 +
 +    hashCode = hashCode * 8191 + org.apache.thrift.TBaseHelper.hashCode(lastContact);
 +
 +    hashCode = hashCode * 8191 + ((isSetName()) ? 131071 : 524287);
 +    if (isSetName())
 +      hashCode = hashCode * 8191 + name.hashCode();
 +
 +    hashCode = hashCode * 8191 + org.apache.thrift.TBaseHelper.hashCode(osLoad);
 +
 +    hashCode = hashCode * 8191 + org.apache.thrift.TBaseHelper.hashCode(holdTime);
 +
 +    hashCode = hashCode * 8191 + org.apache.thrift.TBaseHelper.hashCode(lookups);
 +
 +    hashCode = hashCode * 8191 + org.apache.thrift.TBaseHelper.hashCode(indexCacheHits);
 +
 +    hashCode = hashCode * 8191 + org.apache.thrift.TBaseHelper.hashCode(indexCacheRequest);
 +
 +    hashCode = hashCode * 8191 + org.apache.thrift.TBaseHelper.hashCode(dataCacheHits);
 +
 +    hashCode = hashCode * 8191 + org.apache.thrift.TBaseHelper.hashCode(dataCacheRequest);
 +
 +    hashCode = hashCode * 8191 + ((isSetLogSorts()) ? 131071 : 524287);
 +    if (isSetLogSorts())
 +      hashCode = hashCode * 8191 + logSorts.hashCode();
 +
 +    hashCode = hashCode * 8191 + org.apache.thrift.TBaseHelper.hashCode(flushs);
 +
 +    hashCode = hashCode * 8191 + org.apache.thrift.TBaseHelper.hashCode(syncs);
 +
 +    hashCode = hashCode * 8191 + ((isSetBulkImports()) ? 131071 : 524287);
 +    if (isSetBulkImports())
 +      hashCode = hashCode * 8191 + bulkImports.hashCode();
 +
 +    hashCode = hashCode * 8191 + ((isSetVersion()) ? 131071 : 524287);
 +    if (isSetVersion())
 +      hashCode = hashCode * 8191 + version.hashCode();
 +
++    hashCode = hashCode * 8191 + org.apache.thrift.TBaseHelper.hashCode(responseTime);
++
 +    return hashCode;
    }
  
    @Override
@@@ -1304,16 -1367,16 +1365,26 @@@
          return lastComparison;
        }
      }
 -    lastComparison = Boolean.valueOf(isSetResponseTime()).compareTo(other.isSetResponseTime());
 +    lastComparison = java.lang.Boolean.valueOf(isSetVersion()).compareTo(other.isSetVersion());
 +    if (lastComparison != 0) {
 +      return lastComparison;
 +    }
 +    if (isSetVersion()) {
 +      lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.version, other.version);
 +      if (lastComparison != 0) {
 +        return lastComparison;
 +      }
 +    }
++    lastComparison = java.lang.Boolean.valueOf(isSetResponseTime()).compareTo(other.isSetResponseTime());
+     if (lastComparison != 0) {
+       return lastComparison;
+     }
+     if (isSetResponseTime()) {
+       lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.responseTime, other.responseTime);
+       if (lastComparison != 0) {
+         return lastComparison;
+       }
+     }
      return 0;
    }
  
@@@ -1406,13 -1469,9 +1477,17 @@@
      }
      first = false;
      if (!first) sb.append(", ");
 +    sb.append("version:");
 +    if (this.version == null) {
 +      sb.append("null");
 +    } else {
 +      sb.append(this.version);
 +    }
 +    first = false;
++    if (!first) sb.append(", ");
+     sb.append("responseTime:");
+     sb.append(this.responseTime);
+     first = false;
      sb.append(")");
      return sb.toString();
    }
@@@ -1605,14 -1664,14 +1680,22 @@@
                org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type);
              }
              break;
 -          case 18: // RESPONSE_TIME
 +          case 18: // VERSION
 +            if (schemeField.type == org.apache.thrift.protocol.TType.STRING) {
 +              struct.version = iprot.readString();
 +              struct.setVersionIsSet(true);
 +            } else { 
 +              org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type);
 +            }
 +            break;
++          case 19: // RESPONSE_TIME
+             if (schemeField.type == org.apache.thrift.protocol.TType.I64) {
+               struct.responseTime = iprot.readI64();
+               struct.setResponseTimeIsSet(true);
+             } else { 
+               org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type);
+             }
+             break;
            default:
              org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type);
          }
@@@ -1700,11 -1759,9 +1783,14 @@@
          }
          oprot.writeFieldEnd();
        }
 +      if (struct.version != null) {
 +        oprot.writeFieldBegin(VERSION_FIELD_DESC);
 +        oprot.writeString(struct.version);
 +        oprot.writeFieldEnd();
 +      }
+       oprot.writeFieldBegin(RESPONSE_TIME_FIELD_DESC);
+       oprot.writeI64(struct.responseTime);
+       oprot.writeFieldEnd();
        oprot.writeFieldStop();
        oprot.writeStructEnd();
      }
@@@ -1765,10 -1822,10 +1851,13 @@@
        if (struct.isSetBulkImports()) {
          optionals.set(13);
        }
 -      if (struct.isSetResponseTime()) {
 +      if (struct.isSetVersion()) {
          optionals.set(14);
        }
--      oprot.writeBitSet(optionals, 15);
++      if (struct.isSetResponseTime()) {
++        optionals.set(15);
++      }
++      oprot.writeBitSet(optionals, 16);
        if (struct.isSetTableMap()) {
          {
            oprot.writeI32(struct.tableMap.size());
@@@ -1830,15 -1887,15 +1919,18 @@@
            }
          }
        }
 +      if (struct.isSetVersion()) {
 +        oprot.writeString(struct.version);
 +      }
+       if (struct.isSetResponseTime()) {
+         oprot.writeI64(struct.responseTime);
+       }
      }
  
      @Override
      public void read(org.apache.thrift.protocol.TProtocol prot, TabletServerStatus struct) throws org.apache.thrift.TException {
 -      TTupleProtocol iprot = (TTupleProtocol) prot;
 -      BitSet incoming = iprot.readBitSet(15);
 +      org.apache.thrift.protocol.TTupleProtocol iprot = (org.apache.thrift.protocol.TTupleProtocol) prot;
-       java.util.BitSet incoming = iprot.readBitSet(15);
++      java.util.BitSet incoming = iprot.readBitSet(16);
        if (incoming.get(0)) {
          {
            org.apache.thrift.protocol.TMap _map16 = new org.apache.thrift.protocol.TMap(org.apache.thrift.protocol.TType.STRING, org.apache.thrift.protocol.TType.STRUCT, iprot.readI32());
@@@ -1928,9 -1985,9 +2020,13 @@@
          struct.setBulkImportsIsSet(true);
        }
        if (incoming.get(14)) {
 +        struct.version = iprot.readString();
 +        struct.setVersionIsSet(true);
 +      }
++      if (incoming.get(15)) {
+         struct.responseTime = iprot.readI64();
+         struct.setResponseTimeIsSet(true);
+       }
      }
    }
  

http://git-wip-us.apache.org/repos/asf/accumulo/blob/66d8956b/core/src/main/thrift/master.thrift
----------------------------------------------------------------------
diff --cc core/src/main/thrift/master.thrift
index 8633890,b959074..2117c34
--- a/core/src/main/thrift/master.thrift
+++ b/core/src/main/thrift/master.thrift
@@@ -85,7 -85,7 +85,8 @@@ struct TabletServerStatus 
    15:i64 flushs
    16:i64 syncs
    17:list<BulkImportStatus> bulkImports
 -  18:i64 responseTime
 +  18:string version
++  19:i64 responseTime
  }
  
  enum MasterState {

http://git-wip-us.apache.org/repos/asf/accumulo/blob/66d8956b/server/base/src/main/java/org/apache/accumulo/server/master/LiveTServerSet.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/accumulo/blob/66d8956b/server/monitor/src/main/java/org/apache/accumulo/monitor/rest/tservers/TabletServerInformation.java
----------------------------------------------------------------------
diff --cc server/monitor/src/main/java/org/apache/accumulo/monitor/rest/tservers/TabletServerInformation.java
index f641c57,0000000..eef202b
mode 100644,000000..100644
--- a/server/monitor/src/main/java/org/apache/accumulo/monitor/rest/tservers/TabletServerInformation.java
+++ b/server/monitor/src/main/java/org/apache/accumulo/monitor/rest/tservers/TabletServerInformation.java
@@@ -1,159 -1,0 +1,161 @@@
 +/*
 + * 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.rest.tservers;
 +
 +import java.util.ArrayList;
 +import java.util.List;
 +
 +import javax.xml.bind.annotation.XmlAttribute;
 +
 +import org.apache.accumulo.core.master.thrift.RecoveryStatus;
 +import org.apache.accumulo.core.master.thrift.TableInfo;
 +import org.apache.accumulo.core.master.thrift.TabletServerStatus;
 +import org.apache.accumulo.monitor.Monitor;
 +import org.apache.accumulo.monitor.rest.tables.CompactionsList;
 +import org.apache.accumulo.monitor.rest.tables.CompactionsTypes;
 +import org.apache.accumulo.monitor.rest.trace.RecoveryStatusInformation;
 +import org.apache.accumulo.server.util.TableInfoUtil;
 +
 +/**
 + *
 + * Generates tserver information
 + *
 + * @since 2.0.0
 + *
 + */
 +public class TabletServerInformation {
 +
 +  // Variable names become JSON keys
 +  @XmlAttribute(name = "id")
 +  public String server;
 +
 +  public String hostname;
 +  public long lastContact;
++  public long responseTime;
 +  public double osload;
 +
 +  public CompactionsTypes compactions;
 +
 +  public int tablets;
 +  public double ingest;
 +  public double query;
 +  public double ingestMB;
 +  public double queryMB;
 +  public Integer scans; // For backwards compatibility, has same information as scansRunning
 +  public Double scansessions;
 +  public Double scanssessions; // For backwards compatibility
 +  public long holdtime;
 +
 +  // New variables
 +
 +  public String ip;
 +  private Integer scansRunning;
 +  private Integer scansQueued;
 +  private Integer minorRunning;
 +  private Integer minorQueued;
 +  private Integer majorRunning;
 +  private Integer majorQueued;
 +  private CompactionsList scansCompacting; // if scans is removed, change scansCompacting to scans
 +  private CompactionsList major;
 +  private CompactionsList minor;
 +  public long entries;
 +  public long lookups;
 +  public long indexCacheHits;
 +  public long indexCacheRequests;
 +  public long dataCacheHits;
 +  public long dataCacheRequests;
 +  public double indexCacheHitRate;
 +  public double dataCacheHitRate;
 +  public List<RecoveryStatusInformation> logRecoveries;
 +
 +  public TabletServerInformation() {}
 +
 +  /**
 +   * Generate tserver information from thrift status
 +   *
 +   * @param thriftStatus
 +   *          Thrift status to obtain information
 +   */
 +  public TabletServerInformation(TabletServerStatus thriftStatus) {
 +    TableInfo summary = TableInfoUtil.summarizeTableStats(thriftStatus);
 +    updateTabletServerInfo(thriftStatus, summary);
 +  }
 +
 +  /**
 +   * Generate tserver information from thrift status and table summary
 +   *
 +   * @param thriftStatus
 +   *          Thrift status to obtain information
 +   * @param summary
 +   *          Table info summary
 +   */
 +  public void updateTabletServerInfo(TabletServerStatus thriftStatus, TableInfo summary) {
 +
 +    long now = System.currentTimeMillis();
 +
 +    this.server = this.ip = this.hostname = thriftStatus.name;
 +    this.tablets = summary.tablets;
 +    this.lastContact = now - thriftStatus.lastContact;
++    this.responseTime = thriftStatus.responseTime;
 +    this.entries = summary.recs;
 +    this.ingest = summary.ingestRate;
 +    this.query = summary.queryRate;
 +
 +    this.holdtime = thriftStatus.holdTime;
 +
 +    this.scansRunning = summary.scans != null ? summary.scans.running : null;
 +    this.scansQueued = summary.scans != null ? summary.scans.queued : null;
 +
 +    this.scans = this.scansRunning;
 +
 +    this.scansCompacting = new CompactionsList(this.scansRunning, this.scansQueued);
 +
 +    this.minorRunning = summary.minors != null ? summary.minors.running : null;
 +    this.minorQueued = summary.minors != null ? summary.minors.running : null;
 +
 +    this.minor = new CompactionsList(this.minorRunning, this.minorQueued);
 +
 +    this.majorRunning = summary.majors != null ? summary.majors.running : null;
 +    this.majorQueued = summary.majors != null ? summary.majors.running : null;
 +
 +    this.major = new CompactionsList(this.majorRunning, this.majorQueued);
 +
 +    this.compactions = new CompactionsTypes(scansCompacting, major, minor);
 +
 +    this.osload = thriftStatus.osLoad;
 +    this.lookups = thriftStatus.lookups;
 +
 +    this.dataCacheHits = thriftStatus.dataCacheHits;
 +    this.dataCacheRequests = thriftStatus.dataCacheRequest;
 +    this.indexCacheHits = thriftStatus.indexCacheHits;
 +    this.indexCacheRequests = thriftStatus.indexCacheRequest;
 +
 +    this.indexCacheHitRate = this.indexCacheHits / (double) Math.max(this.indexCacheRequests, 1);
 +    this.dataCacheHitRate = this.dataCacheHits / (double) Math.max(this.dataCacheRequests, 1);
 +
 +    this.ingestMB = summary.ingestByteRate;
 +    this.queryMB = summary.queryByteRate;
 +
 +    this.scansessions = Monitor.getLookupRate();
 +    this.scanssessions = this.scansessions; // For backwards compatibility
 +
 +    this.logRecoveries = new ArrayList<>(thriftStatus.logSorts.size());
 +    for (RecoveryStatus recovery : thriftStatus.logSorts) {
 +      logRecoveries.add(new RecoveryStatusInformation(recovery));
 +    }
 +  }
 +}

http://git-wip-us.apache.org/repos/asf/accumulo/blob/66d8956b/server/monitor/src/main/resources/resources/js/global.js
----------------------------------------------------------------------
diff --cc server/monitor/src/main/resources/resources/js/global.js
index d31cd1a,0000000..07eb342
mode 100644,000000..100644
--- a/server/monitor/src/main/resources/resources/js/global.js
+++ b/server/monitor/src/main/resources/resources/js/global.js
@@@ -1,96 -1,0 +1,97 @@@
 +/*
 +* 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.
 +*/
 +
 +/**
 + * Descriptions used for table columns
 + */
 +var descriptions = {
 +  '# Tablets' : 'Tables are broken down into ranges of rows called tablets.',
 +  '# Offline Tablets' : 'Tablets unavailable for query or ingest. May be a' +
 +      ' transient condition when tablets are moved for balancing.',
 +  'Entries' : 'Key/value pairs over each instance, table or tablet.',
 +  'Entries in Memory' : 'The total number of key/value pairs stored in' +
 +      ' memory and not yet written to disk.',
 +  'Ingest' : 'The number of Key/Value pairs inserted. (Note that deletes' +
 +      ' are "inserted")',
++  'Response Time' : 'The time it took for the tserver to return its status.',
 +  'Entries Read' : 'The number of Key/Value pairs read on the server side.' +
 +      'Not all key values read may be returned to client because of filtering.',
 +  'Entries Returned' : 'The number of Key/Value pairs returned to clients' +
 +      'during queries. This is not the number of scans.',
 +  'Hold Time' : 'The amount of time that ingest operations are suspended' +
 +      ' while waiting for data to be written to disk.',
 +  'Running Scans' : 'Information about the scans threads. Shows how many' +
 +      ' threads are running and how much work is queued for the threads.',
 +  'Minor Compactions' : 'Flushing memory to disk is called a "Minor' +
 +      ' Compaction." Multiple tablets can be minor compacted simultaneously,' +
 +      ' but sometimes they must wait for resources to be available.' +
 +      ' These tablets that are waiting for compaction are "queued"' +
 +      ' and are indicated using parentheses. So 2 (3) indicates there' +
 +      ' are two compactions running and three queued waiting for resources.',
 +  'Major Compactions' : 'Gathering up many small files and rewriting them' +
 +      ' as one larger file is called a "Major Compaction". Major Compactions' +
 +      ' are performed as a consequence of new files created from Minor' +
 +      ' Compactions and Bulk Load operations. They reduce the number of' +
 +      ' files used during queries.',
 +  'Master' : 'The hostname of the master server',
 +  '# Online Tablet Servers' : 'Number of tablet servers currently available',
 +  '# Total Tablet Servers' : 'The total number of tablet servers configured',
 +  'Last GC' : 'The last time files were cleaned-up from HDFS.',
 +  'Total Entries' : 'The total number of key/value pairs in Accumulo',
 +  'Total Ingest' : 'The number of Key/Value pairs inserted, per second.' +
 +      ' Note that deleted records are "inserted" and will make the ingest' +
 +      ' rate increase in the near-term.',
 +  'Total Entries Read' : 'The total number of Key/Value pairs read on the' +
 +      ' server side.  Not all may be returned because of filtering.',
 +  'Total Entries Returned' : 'The total number of Key/Value pairs returned' +
 +      ' as a result of scans.',
 +  'Max Hold Time' : 'The maximum amount of time that ingest has been held' +
 +      ' across all servers due to a lack of memory to store the records',
 +  'OS Load' : 'The Unix one minute load average. The average number of' +
 +      ' processes in the run queue over a one minute interval.',
 +  'Query' : 'The number of key/value pairs returned to clients.' +
 +      ' (Not the number of scans)',
 +  'Index Cache Hit Rate' : 'The recent index cache hit rate.',
 +  'Data Cache Hit Rate' : 'The recent data cache hit rate.',
 +  '# Scans' : 'Number of scans presently running',
 +  'Oldest Scan' : 'The age of the oldest scan on this server.',
 +  'Import Age' : 'The age of the import.',
 +  'Import State' : 'The current state of the bulk import',
 +  '# Imports' : 'Number of imports presently running',
 +  'Oldest Age' : 'The age of the oldest import running on this server.',
 +  'Trace Start' : 'Start Time of selected trace type',
 +  'Span Time' : 'Span Time of selected trace type',
 +  'Source' : 'Service and Location of selected trace type',
 +  'Trace Type' : 'Trace Type',
 +  'Total Spans' : 'Number of spans of this type',
 +  'Short Span' : 'Shortest span duration',
 +  'Long Span' : 'Longest span duration',
 +  'Avg Span' : 'Average span duration',
 +  'Histogram' : 'Counts of spans of different duration. Columns start' +
 +      ' at milliseconds, and each column is ten times longer: tens of' +
 +      ' milliseconds, seconds, tens of seconds, etc.'
 +};
 +
 +/**
 + * List of namespaces in Accumulo
 + */
 +var NAMESPACES = '';
 +
 +/**
 + * Timer object
 + */
 +var TIMER;

http://git-wip-us.apache.org/repos/asf/accumulo/blob/66d8956b/server/monitor/src/main/resources/resources/js/tservers.js
----------------------------------------------------------------------
diff --cc server/monitor/src/main/resources/resources/js/tservers.js
index 4c7ac20,0000000..29f505d
mode 100644,000000..100644
--- a/server/monitor/src/main/resources/resources/js/tservers.js
+++ b/server/monitor/src/main/resources/resources/js/tservers.js
@@@ -1,314 -1,0 +1,317 @@@
 +/*
 +* 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.
 +*/
 +
 +/**
 + * Creates tservers initial table
 + */
 +$(document).ready(function() {
 +  createHeader();
 +  refreshTServers();
 +
 +  // Create tooltip for table column information
 +  $(document).tooltip();
 +});
 +
 +/**
 + * Makes the REST calls, generates the tables with the new information
 + */
 +function refreshTServers() {
 +  $.ajaxSetup({
 +    async: false
 +  });
 +  getTServers();
 +  $.ajaxSetup({
 +    async: true
 +  });
 +  refreshBadTServersTable();
 +  refreshDeadTServersTable();
 +  refreshTServersTable();
 +}
 +
 +/**
 + * Used to redraw the page
 + */
 +function refresh() {
 +  refreshTServers();
 +}
 +
 +/**
 + * Generates the tservers table
 + */
 +function refreshBadTServersTable() {
 +  var data = sessionStorage.tservers === undefined ?
 +      [] : JSON.parse(sessionStorage.tservers);
 +
 +  $('#badtservers tr').remove();
 +  $('#badtservers caption').remove();
 +
 +  if (data.length === 0 || data.badServers.length === 0) {
 +
 +    $('#badtservers').hide();
 +  } else {
 +
 +    $('#badtservers').show();
 +
 +    var caption = [];
 +
 +    caption.push('<span class="table-caption">Non-Functioning&nbsp;' +
 +        'Tablet&nbsp;Servers</span><br>');
 +    caption.push('<span class="table-subcaption">The following tablet' +
 +        ' servers reported a status other than Online</span><br>');
 +
 +    $('<caption/>', {
 +      html: caption.join('')
 +    }).appendTo('#badtservers');
 +
 +    var items = [];
 +
 +    var columns = ['Tablet&nbsp;Server&nbsp;',
 +        'Tablet&nbsp;Server&nbsp;Status&nbsp;'];
 +
 +    for (i = 0; i < columns.length; i++) {
 +      var first = i == 0 ? true : false;
 +      items.push(createHeaderCell(first, 'sortTable(0,' + i + ')',
 +          '', columns[i]));
 +    }
 +
 +    $('<tr/>', {
 +      html: items.join('')
 +    }).appendTo('#badtservers');
 +
 +    $.each(data.badServers, function(key, val) {
 +      var items = [];
 +      items.push(createFirstCell(val.id, val.id));
 +      items.push(createRightCell(val.status, val.status));
 +
 +      $('<tr/>', {
 +        html: items.join('')
 +      }).appendTo('#badtservers');
 +    });
 +  }
 +}
 +
 +/**
 + * Generates the deadtservers table
 + */
 +function refreshDeadTServersTable() {
 +  var data = sessionStorage.tservers === undefined ?
 +      [] : JSON.parse(sessionStorage.tservers);
 +
 +  $('#deadtservers tr').remove();
 +  $('#deadtservers caption').remove();
 +
 +  if (data.length === 0 || data.deadServers.length === 0) {
 +
 +    $('#deadtservers').hide();
 +  } else {
 +
 +    $('#deadtservers').show();
 +
 +
 +    var caption = [];
 +
 +    caption.push('<span class="table-caption">Dead&nbsp;' +
 +        'Tablet&nbsp;Servers</span><br>');
 +    caption.push('<span class="table-subcaption">The following' +
 +        ' tablet servers are no longer reachable.</span><br>');
 +
 +    $('<caption/>', {
 +      html: caption.join('')
 +    }).appendTo('#deadtservers');
 +
 +    var items = [];
 +
 +    var columns = ['Server&nbsp;', 'Last&nbsp;Updated&nbsp;', 'Event&nbsp;',
 +        'Clear'];
 +
 +    for (i = 0; i < columns.length; i++) {
 +      var first = i == 0 ? true : false;
 +      var sort = i == columns.length - 1 ? '' : 'sortTable(1,' + i + ')';
 +      items.push(createHeaderCell(first, sort, '', columns[i]));
 +    }
 +
 +    $('<tr/>', {
 +      html: items.join('')
 +    }).appendTo('#deadtservers');
 +
 +    $.each(data.deadServers, function(key, val) {
 +      var items = [];
 +      items.push(createFirstCell(val.server, val.server));
 +
 +      var date = new Date(val.lastStatus);
 +      date = date.toLocaleString().split(' ').join('&nbsp;');
 +      items.push(createRightCell(val.lastStatus, date));
 +      items.push(createRightCell(val.status, val.status));
 +      items.push(createRightCell('', '<a href="javascript:clearDeadTServers(\'' +
 +          val.server + '\');">clear</a>'));
 +
 +      $('<tr/>', {
 +        html: items.join('')
 +      }).appendTo('#deadtservers');
 +    });
 +  }
 +}
 +
 +/**
 + * Makes the REST POST call to clear dead table server
 + *
 + * @param {string} server Dead TServer to clear
 + */
 +function clearDeadTServers(server) {
 +  clearDeadServers(server);
 +  refreshTServers();
 +  refreshNavBar();
 +}
 +
 +/**
 + * Generates the tserver table
 + */
 +function refreshTServersTable() {
 +  var data = sessionStorage.tservers === undefined ?
 +      [] : JSON.parse(sessionStorage.tservers);
 +
 +  $('#tservers tr:gt(0)').remove();
 +
 +  if (data.length === 0 || data.servers.length === 0) {
 +    var item = createEmptyRow(13, 'Empty');
 +
 +    $('<tr/>', {
 +      html: item
 +    }).appendTo('#tservers');
 +  } else {
 +
 +    $.each(data.servers, function(key, val) {
 +      var items = [];
 +      items.push(createFirstCell(val.hostname,
 +          '<a href="/tservers?s=' + val.id + '">' + val.hostname + '</a>'));
 +
 +      items.push(createRightCell(val.tablets,
 +          bigNumberForQuantity(val.tablets)));
 +
 +      items.push(createRightCell(val.lastContact,
 +          timeDuration(val.lastContact)));
 +
++      items.push(createRightCell(val.responseTime,
++          timeDuration(val.responseTime)));
++
 +      items.push(createRightCell(val.entries,
 +          bigNumberForQuantity(val.entries)));
 +
 +      items.push(createRightCell(val.ingest,
 +          bigNumberForQuantity(Math.floor(val.ingest))));
 +
 +      items.push(createRightCell(val.query,
 +          bigNumberForQuantity(Math.floor(val.query))));
 +
 +      items.push(createRightCell(val.holdtime,
 +          timeDuration(val.holdtime)));
 +
 +      items.push(createRightCell((val.compactions.scans.running +
 +          val.compactions.scans.queued),
 +          bigNumberForQuantity(val.compactions.scans.running) +
 +          '&nbsp;(' + bigNumberForQuantity(val.compactions.scans.queued) +
 +          ')'));
 +
 +      items.push(createRightCell((val.compactions.minor.running +
 +          val.compactions.minor.queued),
 +          bigNumberForQuantity(val.compactions.minor.running) +
 +          '&nbsp;(' + bigNumberForQuantity(val.compactions.minor.queued) +
 +          ')'));
 +
 +      items.push(createRightCell((val.compactions.major.running +
 +          val.compactions.major.queued),
 +          bigNumberForQuantity(val.compactions.major.running) +
 +          '&nbsp;(' + bigNumberForQuantity(val.compactions.major.queued) +
 +          ')'));
 +
 +      items.push(createRightCell(val.indexCacheHitRate * 100,
 +          Math.round(val.indexCacheHitRate * 100) + '%'));
 +
 +      items.push(createRightCell(val.dataCacheHitRate * 100,
 +          Math.round(val.dataCacheHitRate * 100) + '%'));
 +
 +      items.push(createRightCell(val.osload, bigNumberForQuantity(val.osload)));
 +
 +      $('<tr/>', {
 +        html: items.join('')
 +      }).appendTo('#tservers');
 +    });
 +  }
 +}
 +
 +/**
 + * Sorts the tservers table on the selected column
 + *
 + * @param {string} table Table ID to sort
 + * @param {number} n Column number to sort by
 + */
 +function sortTable(table, n) {
 +  var tableIDs = ['badtservers', 'deadtservers', 'tservers'];
 +
 +  if (sessionStorage.tableColumnSort !== undefined &&
 +      sessionStorage.tableColumnSort == n &&
 +      sessionStorage.direction !== undefined) {
 +    direction = sessionStorage.direction === 'asc' ? 'desc' : 'asc';
 +  } else {
 +    direction = sessionStorage.direction === undefined ?
 +        'asc' : sessionStorage.direction;
 +  }
 +  sessionStorage.tableColumn = tableIDs[table];
 +  sessionStorage.tableColumnSort = n;
 +  sortTables(tableIDs[table], direction, n);
 +}
 +
 +/**
 + * Creates the tservers header
 + */
 +function createHeader() {
 +  var caption = [];
 +
 +  caption.push('<span class="table-caption">Tablet&nbsp;Servers</span><br>');
 +  caption.push('<span class="table-subcaption">Click on the ' +
 +      '<span style="color: #0000ff;">server address</span> to ' +
 +      'view detailed performance statistics for that server.</span><br>');
 +
 +  $('<caption/>', {
 +    html: caption.join('')
 +  }).appendTo('#tservers');
 +
 +  var items = [];
 +
 +  var columns = ['Server&nbsp;', 'Hosted&nbsp;Tablets&nbsp;',
-       'Last&nbsp;Contact&nbsp;', 'Entries&nbsp;', 'Ingest&nbsp;',
++      'Last&nbsp;Contact&nbsp;', 'Response&nbsp;Time&nbsp;', 'Entries&nbsp;', 'Ingest&nbsp;',
 +      'Query&nbsp;', 'Hold&nbsp;Time&nbsp;', 'Running<br>Scans&nbsp;',
 +      'Minor<br>Compactions&nbsp;', 'Major<br>Compactions&nbsp;',
 +      'Index Cache<br>Hit Rate&nbsp;', 'Data Cache<br>Hit Rate&nbsp;',
 +      'OS&nbsp;Load&nbsp;'];
 +
-   var titles = ['', '', '', descriptions['Entries'], descriptions['Ingest'],
++  var titles = ['', '', '', descriptions['Response Time'], descriptions['Entries'], descriptions['Ingest'],
 +      descriptions['Query'], descriptions['Hold Time'],
 +      descriptions['Running Scans'], descriptions['Minor Compactions'],
 +      descriptions['Major Compactions'], descriptions['Index Cache Hit Rate'],
 +      descriptions['Data Cache Hit Rate'], descriptions['OS Load']];
 +
 +  for (i = 0; i < columns.length; i++) {
 +    var first = i == 0 ? true : false;
 +    items.push(createHeaderCell(first, 'sortTable(2,' + i + ')',
 +        titles[i], columns[i]));
 +  }
 +
 +  $('<tr/>', {
 +    html: items.join('')
 +  }).appendTo('#tservers');
 +}

http://git-wip-us.apache.org/repos/asf/accumulo/blob/66d8956b/server/tserver/src/main/java/org/apache/accumulo/tserver/TabletServer.java
----------------------------------------------------------------------
diff --cc server/tserver/src/main/java/org/apache/accumulo/tserver/TabletServer.java
index e0230a9,9c2d3e3..b4cb43d
--- a/server/tserver/src/main/java/org/apache/accumulo/tserver/TabletServer.java
+++ b/server/tserver/src/main/java/org/apache/accumulo/tserver/TabletServer.java
@@@ -2977,7 -2855,8 +2977,8 @@@ public class TabletServer extends Accum
      SimpleTimer.getInstance(aconf).schedule(constraintTask, 0, 1000);
    }
  
 -  public TabletServerStatus getStats(Map<String,MapCounter<ScanRunState>> scanCounts) {
 +  public TabletServerStatus getStats(Map<Table.ID,MapCounter<ScanRunState>> scanCounts) {
+     long start = System.currentTimeMillis();
      TabletServerStatus result = new TabletServerStatus();
  
      Map<KeyExtent,Tablet> onlineTabletsCopy;
@@@ -3065,7 -2944,7 +3066,8 @@@
      result.bulkImports = new ArrayList<>();
      result.bulkImports.addAll(clientHandler.getBulkLoadStatus());
      result.bulkImports.addAll(bulkImportStatus.getBulkLoadStatus());
 +    result.version = getVersion();
+     result.responseTime = System.currentTimeMillis() - start;
      return result;
    }
  


[2/3] accumulo git commit: ACCUMULO-4655 Added a Response Time column to the monitor

Posted by ib...@apache.org.
ACCUMULO-4655 Added a Response Time column to the monitor

Added a Response Time column to the monitor which shows how long it took to get status from that tserver.
This is useful in determining whether long Last Contact times are dues to one or more tservers or whether
this is due to churn in the master.

Closes #271


Project: http://git-wip-us.apache.org/repos/asf/accumulo/repo
Commit: http://git-wip-us.apache.org/repos/asf/accumulo/commit/ef78423e
Tree: http://git-wip-us.apache.org/repos/asf/accumulo/tree/ef78423e
Diff: http://git-wip-us.apache.org/repos/asf/accumulo/diff/ef78423e

Branch: refs/heads/master
Commit: ef78423e23a800d9b9371ba46408d95145d46bd6
Parents: 1ab2431
Author: Ivan Bella <iv...@bella.name>
Authored: Mon Jun 19 12:55:01 2017 -0400
Committer: Ivan Bella <iv...@bella.name>
Committed: Sun Jul 23 11:42:18 2017 -0400

----------------------------------------------------------------------
 .../core/master/thrift/TabletServerStatus.java  | 107 ++++++++++++++++++-
 core/src/main/thrift/master.thrift              |   1 +
 .../accumulo/server/master/LiveTServerSet.java  |   8 +-
 .../monitor/servlets/TServersServlet.java       |  15 ++-
 .../apache/accumulo/tserver/TabletServer.java   |   2 +
 5 files changed, 126 insertions(+), 7 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/accumulo/blob/ef78423e/core/src/main/java/org/apache/accumulo/core/master/thrift/TabletServerStatus.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/accumulo/core/master/thrift/TabletServerStatus.java b/core/src/main/java/org/apache/accumulo/core/master/thrift/TabletServerStatus.java
index 07444b5..c00558c 100644
--- a/core/src/main/java/org/apache/accumulo/core/master/thrift/TabletServerStatus.java
+++ b/core/src/main/java/org/apache/accumulo/core/master/thrift/TabletServerStatus.java
@@ -68,6 +68,7 @@ public class TabletServerStatus implements org.apache.thrift.TBase<TabletServerS
   private static final org.apache.thrift.protocol.TField FLUSHS_FIELD_DESC = new org.apache.thrift.protocol.TField("flushs", org.apache.thrift.protocol.TType.I64, (short)15);
   private static final org.apache.thrift.protocol.TField SYNCS_FIELD_DESC = new org.apache.thrift.protocol.TField("syncs", org.apache.thrift.protocol.TType.I64, (short)16);
   private static final org.apache.thrift.protocol.TField BULK_IMPORTS_FIELD_DESC = new org.apache.thrift.protocol.TField("bulkImports", org.apache.thrift.protocol.TType.LIST, (short)17);
+  private static final org.apache.thrift.protocol.TField RESPONSE_TIME_FIELD_DESC = new org.apache.thrift.protocol.TField("responseTime", org.apache.thrift.protocol.TType.I64, (short)18);
 
   private static final Map<Class<? extends IScheme>, SchemeFactory> schemes = new HashMap<Class<? extends IScheme>, SchemeFactory>();
   static {
@@ -89,6 +90,7 @@ public class TabletServerStatus implements org.apache.thrift.TBase<TabletServerS
   public long flushs; // required
   public long syncs; // required
   public List<BulkImportStatus> bulkImports; // required
+  public long responseTime; // required
 
   /** The set of fields this struct contains, along with convenience methods for finding and manipulating them. */
   public enum _Fields implements org.apache.thrift.TFieldIdEnum {
@@ -105,7 +107,8 @@ public class TabletServerStatus implements org.apache.thrift.TBase<TabletServerS
     LOG_SORTS((short)14, "logSorts"),
     FLUSHS((short)15, "flushs"),
     SYNCS((short)16, "syncs"),
-    BULK_IMPORTS((short)17, "bulkImports");
+    BULK_IMPORTS((short)17, "bulkImports"),
+    RESPONSE_TIME((short)18, "responseTime");
 
     private static final Map<String, _Fields> byName = new HashMap<String, _Fields>();
 
@@ -148,6 +151,8 @@ public class TabletServerStatus implements org.apache.thrift.TBase<TabletServerS
           return SYNCS;
         case 17: // BULK_IMPORTS
           return BULK_IMPORTS;
+        case 18: // RESPONSE_TIME
+          return RESPONSE_TIME;
         default:
           return null;
       }
@@ -198,6 +203,7 @@ public class TabletServerStatus implements org.apache.thrift.TBase<TabletServerS
   private static final int __DATACACHEREQUEST_ISSET_ID = 7;
   private static final int __FLUSHS_ISSET_ID = 8;
   private static final int __SYNCS_ISSET_ID = 9;
+  private static final int __RESPONSETIME_ISSET_ID = 10;
   private short __isset_bitfield = 0;
   public static final Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> metaDataMap;
   static {
@@ -234,6 +240,8 @@ public class TabletServerStatus implements org.apache.thrift.TBase<TabletServerS
     tmpMap.put(_Fields.BULK_IMPORTS, new org.apache.thrift.meta_data.FieldMetaData("bulkImports", org.apache.thrift.TFieldRequirementType.DEFAULT, 
         new org.apache.thrift.meta_data.ListMetaData(org.apache.thrift.protocol.TType.LIST, 
             new org.apache.thrift.meta_data.StructMetaData(org.apache.thrift.protocol.TType.STRUCT, BulkImportStatus.class))));
+    tmpMap.put(_Fields.RESPONSE_TIME, new org.apache.thrift.meta_data.FieldMetaData("responseTime", org.apache.thrift.TFieldRequirementType.DEFAULT, 
+        new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.I64)));
     metaDataMap = Collections.unmodifiableMap(tmpMap);
     org.apache.thrift.meta_data.FieldMetaData.addStructMetaDataMap(TabletServerStatus.class, metaDataMap);
   }
@@ -255,7 +263,8 @@ public class TabletServerStatus implements org.apache.thrift.TBase<TabletServerS
     List<RecoveryStatus> logSorts,
     long flushs,
     long syncs,
-    List<BulkImportStatus> bulkImports)
+    List<BulkImportStatus> bulkImports,
+    long responseTime)
   {
     this();
     this.tableMap = tableMap;
@@ -282,6 +291,8 @@ public class TabletServerStatus implements org.apache.thrift.TBase<TabletServerS
     this.syncs = syncs;
     setSyncsIsSet(true);
     this.bulkImports = bulkImports;
+    this.responseTime = responseTime;
+    setResponseTimeIsSet(true);
   }
 
   /**
@@ -331,6 +342,7 @@ public class TabletServerStatus implements org.apache.thrift.TBase<TabletServerS
       }
       this.bulkImports = __this__bulkImports;
     }
+    this.responseTime = other.responseTime;
   }
 
   public TabletServerStatus deepCopy() {
@@ -363,6 +375,8 @@ public class TabletServerStatus implements org.apache.thrift.TBase<TabletServerS
     setSyncsIsSet(false);
     this.syncs = 0;
     this.bulkImports = null;
+    setResponseTimeIsSet(false);
+    this.responseTime = 0;
   }
 
   public int getTableMapSize() {
@@ -732,6 +746,29 @@ public class TabletServerStatus implements org.apache.thrift.TBase<TabletServerS
     }
   }
 
+  public long getResponseTime() {
+    return this.responseTime;
+  }
+
+  public TabletServerStatus setResponseTime(long responseTime) {
+    this.responseTime = responseTime;
+    setResponseTimeIsSet(true);
+    return this;
+  }
+
+  public void unsetResponseTime() {
+    __isset_bitfield = EncodingUtils.clearBit(__isset_bitfield, __RESPONSETIME_ISSET_ID);
+  }
+
+  /** Returns true if field responseTime is set (has been assigned a value) and false otherwise */
+  public boolean isSetResponseTime() {
+    return EncodingUtils.testBit(__isset_bitfield, __RESPONSETIME_ISSET_ID);
+  }
+
+  public void setResponseTimeIsSet(boolean value) {
+    __isset_bitfield = EncodingUtils.setBit(__isset_bitfield, __RESPONSETIME_ISSET_ID, value);
+  }
+
   public void setFieldValue(_Fields field, Object value) {
     switch (field) {
     case TABLE_MAP:
@@ -846,6 +883,14 @@ public class TabletServerStatus implements org.apache.thrift.TBase<TabletServerS
       }
       break;
 
+    case RESPONSE_TIME:
+      if (value == null) {
+        unsetResponseTime();
+      } else {
+        setResponseTime((Long)value);
+      }
+      break;
+
     }
   }
 
@@ -893,6 +938,9 @@ public class TabletServerStatus implements org.apache.thrift.TBase<TabletServerS
     case BULK_IMPORTS:
       return getBulkImports();
 
+    case RESPONSE_TIME:
+      return getResponseTime();
+
     }
     throw new IllegalStateException();
   }
@@ -932,6 +980,8 @@ public class TabletServerStatus implements org.apache.thrift.TBase<TabletServerS
       return isSetSyncs();
     case BULK_IMPORTS:
       return isSetBulkImports();
+    case RESPONSE_TIME:
+      return isSetResponseTime();
     }
     throw new IllegalStateException();
   }
@@ -1075,6 +1125,15 @@ public class TabletServerStatus implements org.apache.thrift.TBase<TabletServerS
         return false;
     }
 
+    boolean this_present_responseTime = true;
+    boolean that_present_responseTime = true;
+    if (this_present_responseTime || that_present_responseTime) {
+      if (!(this_present_responseTime && that_present_responseTime))
+        return false;
+      if (this.responseTime != that.responseTime)
+        return false;
+    }
+
     return true;
   }
 
@@ -1152,6 +1211,11 @@ public class TabletServerStatus implements org.apache.thrift.TBase<TabletServerS
     if (present_bulkImports)
       list.add(bulkImports);
 
+    boolean present_responseTime = true;
+    list.add(present_responseTime);
+    if (present_responseTime)
+      list.add(responseTime);
+
     return list.hashCode();
   }
 
@@ -1303,6 +1367,16 @@ public class TabletServerStatus implements org.apache.thrift.TBase<TabletServerS
         return lastComparison;
       }
     }
+    lastComparison = Boolean.valueOf(isSetResponseTime()).compareTo(other.isSetResponseTime());
+    if (lastComparison != 0) {
+      return lastComparison;
+    }
+    if (isSetResponseTime()) {
+      lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.responseTime, other.responseTime);
+      if (lastComparison != 0) {
+        return lastComparison;
+      }
+    }
     return 0;
   }
 
@@ -1394,6 +1468,10 @@ public class TabletServerStatus implements org.apache.thrift.TBase<TabletServerS
       sb.append(this.bulkImports);
     }
     first = false;
+    if (!first) sb.append(", ");
+    sb.append("responseTime:");
+    sb.append(this.responseTime);
+    first = false;
     sb.append(")");
     return sb.toString();
   }
@@ -1586,6 +1664,14 @@ public class TabletServerStatus implements org.apache.thrift.TBase<TabletServerS
               org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type);
             }
             break;
+          case 18: // RESPONSE_TIME
+            if (schemeField.type == org.apache.thrift.protocol.TType.I64) {
+              struct.responseTime = iprot.readI64();
+              struct.setResponseTimeIsSet(true);
+            } else { 
+              org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type);
+            }
+            break;
           default:
             org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type);
         }
@@ -1673,6 +1759,9 @@ public class TabletServerStatus implements org.apache.thrift.TBase<TabletServerS
         }
         oprot.writeFieldEnd();
       }
+      oprot.writeFieldBegin(RESPONSE_TIME_FIELD_DESC);
+      oprot.writeI64(struct.responseTime);
+      oprot.writeFieldEnd();
       oprot.writeFieldStop();
       oprot.writeStructEnd();
     }
@@ -1733,7 +1822,10 @@ public class TabletServerStatus implements org.apache.thrift.TBase<TabletServerS
       if (struct.isSetBulkImports()) {
         optionals.set(13);
       }
-      oprot.writeBitSet(optionals, 14);
+      if (struct.isSetResponseTime()) {
+        optionals.set(14);
+      }
+      oprot.writeBitSet(optionals, 15);
       if (struct.isSetTableMap()) {
         {
           oprot.writeI32(struct.tableMap.size());
@@ -1795,12 +1887,15 @@ public class TabletServerStatus implements org.apache.thrift.TBase<TabletServerS
           }
         }
       }
+      if (struct.isSetResponseTime()) {
+        oprot.writeI64(struct.responseTime);
+      }
     }
 
     @Override
     public void read(org.apache.thrift.protocol.TProtocol prot, TabletServerStatus struct) throws org.apache.thrift.TException {
       TTupleProtocol iprot = (TTupleProtocol) prot;
-      BitSet incoming = iprot.readBitSet(14);
+      BitSet incoming = iprot.readBitSet(15);
       if (incoming.get(0)) {
         {
           org.apache.thrift.protocol.TMap _map16 = new org.apache.thrift.protocol.TMap(org.apache.thrift.protocol.TType.STRING, org.apache.thrift.protocol.TType.STRUCT, iprot.readI32());
@@ -1889,6 +1984,10 @@ public class TabletServerStatus implements org.apache.thrift.TBase<TabletServerS
         }
         struct.setBulkImportsIsSet(true);
       }
+      if (incoming.get(14)) {
+        struct.responseTime = iprot.readI64();
+        struct.setResponseTimeIsSet(true);
+      }
     }
   }
 

http://git-wip-us.apache.org/repos/asf/accumulo/blob/ef78423e/core/src/main/thrift/master.thrift
----------------------------------------------------------------------
diff --git a/core/src/main/thrift/master.thrift b/core/src/main/thrift/master.thrift
index 6104fea..b959074 100644
--- a/core/src/main/thrift/master.thrift
+++ b/core/src/main/thrift/master.thrift
@@ -85,6 +85,7 @@ struct TabletServerStatus {
   15:i64 flushs
   16:i64 syncs
   17:list<BulkImportStatus> bulkImports
+  18:i64 responseTime
 }
 
 enum MasterState {

http://git-wip-us.apache.org/repos/asf/accumulo/blob/ef78423e/server/base/src/main/java/org/apache/accumulo/server/master/LiveTServerSet.java
----------------------------------------------------------------------
diff --git a/server/base/src/main/java/org/apache/accumulo/server/master/LiveTServerSet.java b/server/base/src/main/java/org/apache/accumulo/server/master/LiveTServerSet.java
index 7d1d6e1..df135d6 100644
--- a/server/base/src/main/java/org/apache/accumulo/server/master/LiveTServerSet.java
+++ b/server/base/src/main/java/org/apache/accumulo/server/master/LiveTServerSet.java
@@ -120,11 +120,17 @@ public class LiveTServerSet implements Watcher {
       if (usePooledConnection == true)
         throw new UnsupportedOperationException();
 
+      long start = System.currentTimeMillis();
+
       TTransport transport = ThriftUtil.createTransport(address, context);
 
       try {
         TabletClientService.Client client = ThriftUtil.createClient(new TabletClientService.Client.Factory(), transport);
-        return client.getTabletServerStatus(Tracer.traceInfo(), context.rpcCreds());
+        TabletServerStatus status = client.getTabletServerStatus(Tracer.traceInfo(), context.rpcCreds());
+        if (status != null) {
+          status.setResponseTime(System.currentTimeMillis() - start);
+        }
+        return status;
       } finally {
         if (transport != null)
           transport.close();

http://git-wip-us.apache.org/repos/asf/accumulo/blob/ef78423e/server/monitor/src/main/java/org/apache/accumulo/monitor/servlets/TServersServlet.java
----------------------------------------------------------------------
diff --git a/server/monitor/src/main/java/org/apache/accumulo/monitor/servlets/TServersServlet.java b/server/monitor/src/main/java/org/apache/accumulo/monitor/servlets/TServersServlet.java
index 858192b..04a6511 100644
--- a/server/monitor/src/main/java/org/apache/accumulo/monitor/servlets/TServersServlet.java
+++ b/server/monitor/src/main/java/org/apache/accumulo/monitor/servlets/TServersServlet.java
@@ -309,18 +309,28 @@ public class TServersServlet extends BasicServlet {
     }
   }
 
+  static final long SECOND = 1000;
+  static final long RESPONSE_TIME_MAX_ERR = 3 * SECOND;
+  static final long MINUTE = 60 * SECOND;
+  static final long LAST_CONTEXT_MAX_ERR = 3 * MINUTE;
+
   static void doTserverList(HttpServletRequest req, StringBuilder sb, List<TabletServerStatus> tservers, String tableId, Table tServerList) {
     int guessHighLoad = ManagementFactory.getOperatingSystemMXBean().getAvailableProcessors();
     long now = System.currentTimeMillis();
 
     double avgLastContact = 0.;
+    double avgResponseTime = 0.;
+    int count = 0;
     for (TabletServerStatus status : tservers) {
+      count++;
       avgLastContact += (now - status.lastContact);
+      avgResponseTime += status.responseTime;
     }
-    final long MINUTES = 3 * 60 * 1000;
+    avgResponseTime /= count;
     tServerList.addSortableColumn("Server", new TServerLinkType(), null);
     tServerList.addSortableColumn("Hosted&nbsp;Tablets", new NumberType<>(0, Integer.MAX_VALUE), null);
-    tServerList.addSortableColumn("Last&nbsp;Contact", new DurationType(0l, (long) Math.min(avgLastContact * 4, MINUTES)), null);
+    tServerList.addSortableColumn("Last&nbsp;Contact", new DurationType(0l, (long) Math.min(avgLastContact * 4, LAST_CONTEXT_MAX_ERR)), null);
+    tServerList.addSortableColumn("Response&nbsp;Time", new DurationType(0l, (long) Math.min(avgResponseTime * 4, RESPONSE_TIME_MAX_ERR)), null);
     tServerList.addSortableColumn("Entries", new NumberType<Long>(), "The number of key/value pairs.");
     tServerList.addSortableColumn("Ingest", new NumberType<Long>(), "The number of key/value pairs inserted. (Note that deletes are also 'inserted')");
     tServerList.addSortableColumn("Query", new NumberType<Long>(), "The number of key/value pairs returned to clients. (Not the number of scans)");
@@ -352,6 +362,7 @@ public class TServersServlet extends BasicServlet {
       row.add(status); // add for server name
       row.add(summary.tablets);
       row.add(now - status.lastContact);
+      row.add(status.responseTime);
       row.add(summary.recs);
       row.add(summary.ingestRate);
       row.add(summary.queryRate);

http://git-wip-us.apache.org/repos/asf/accumulo/blob/ef78423e/server/tserver/src/main/java/org/apache/accumulo/tserver/TabletServer.java
----------------------------------------------------------------------
diff --git a/server/tserver/src/main/java/org/apache/accumulo/tserver/TabletServer.java b/server/tserver/src/main/java/org/apache/accumulo/tserver/TabletServer.java
index 6ead6b8..9c2d3e3 100644
--- a/server/tserver/src/main/java/org/apache/accumulo/tserver/TabletServer.java
+++ b/server/tserver/src/main/java/org/apache/accumulo/tserver/TabletServer.java
@@ -2856,6 +2856,7 @@ public class TabletServer extends AccumuloServerContext implements Runnable {
   }
 
   public TabletServerStatus getStats(Map<String,MapCounter<ScanRunState>> scanCounts) {
+    long start = System.currentTimeMillis();
     TabletServerStatus result = new TabletServerStatus();
 
     Map<KeyExtent,Tablet> onlineTabletsCopy;
@@ -2943,6 +2944,7 @@ public class TabletServer extends AccumuloServerContext implements Runnable {
     result.bulkImports = new ArrayList<>();
     result.bulkImports.addAll(clientHandler.getBulkLoadStatus());
     result.bulkImports.addAll(bulkImportStatus.getBulkLoadStatus());
+    result.responseTime = System.currentTimeMillis() - start;
     return result;
   }