accumulo-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From dlmar...@apache.org
Subject accumulo git commit: Squashed commit of the following:
Date Tue, 29 Mar 2016 14:34:46 GMT
Repository: accumulo
Updated Branches:
  refs/heads/ACCUMULO-4173 [created] 594ecc3c6


Squashed commit of the following:

commit 2afa820763ece3a1299ac9e8889532fa4966acff
Author: Dave Marion <dlmarion@apache.org>
Date:   Fri Mar 25 14:36:18 2016 -0400

    Added tests where tablets were either all assigned or partially assigned

commit 9c08258b7907ad3195227d21a782ffe7545fa696
Author: Dave Marion <dlmarion@apache.org>
Date:   Fri Mar 25 14:26:57 2016 -0400

    Added test for out of bounds tablets

commit be07ba3d20e378d88c71f77366e1b3f2dd325c73
Author: Dave Marion <dlmarion@apache.org>
Date:   Fri Mar 25 13:38:35 2016 -0400

    Added more tests

commit dc842305d4fda77d2271ae8a111031bfb1eda9f7
Author: Dave Marion <dlmarion@apache.org>
Date:   Fri Mar 25 11:31:20 2016 -0400

    Initial work on Host based regex master balancer


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

Branch: refs/heads/ACCUMULO-4173
Commit: 594ecc3c6a876922b1a47301a619551e32c31e7a
Parents: 1d49030
Author: Dave Marion <dlmarion@apache.org>
Authored: Tue Mar 29 10:33:41 2016 -0400
Committer: Dave Marion <dlmarion@apache.org>
Committed: Tue Mar 29 10:33:41 2016 -0400

----------------------------------------------------------------------
 .../balancer/HostRegexTableLoadBalancer.java    | 306 +++++++++
 .../HostRegexTableLoadBalancerTest.java         | 618 +++++++++++++++++++
 2 files changed, 924 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/accumulo/blob/594ecc3c/server/base/src/main/java/org/apache/accumulo/server/master/balancer/HostRegexTableLoadBalancer.java
----------------------------------------------------------------------
diff --git a/server/base/src/main/java/org/apache/accumulo/server/master/balancer/HostRegexTableLoadBalancer.java
b/server/base/src/main/java/org/apache/accumulo/server/master/balancer/HostRegexTableLoadBalancer.java
new file mode 100644
index 0000000..50156d9
--- /dev/null
+++ b/server/base/src/main/java/org/apache/accumulo/server/master/balancer/HostRegexTableLoadBalancer.java
@@ -0,0 +1,306 @@
+/*
+ * 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.server.master.balancer;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.SortedMap;
+import java.util.TreeMap;
+import java.util.regex.Pattern;
+
+import org.apache.accumulo.core.client.admin.TableOperations;
+import org.apache.accumulo.core.conf.AccumuloConfiguration;
+import org.apache.accumulo.core.conf.Property;
+import org.apache.accumulo.core.data.impl.KeyExtent;
+import org.apache.accumulo.core.master.thrift.TabletServerStatus;
+import org.apache.accumulo.core.tabletserver.thrift.TabletStats;
+import org.apache.accumulo.server.conf.ServerConfiguration;
+import org.apache.accumulo.server.master.state.TServerInstance;
+import org.apache.accumulo.server.master.state.TabletMigration;
+import org.apache.thrift.TException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This balancer will create pools of tablet servers by grouping tablet servers that match
a regex into the same pool and calling the balancer set on the table
+ * to balance within the set of matching tablet servers. </br> Regex properties for
this balancer are specified as:</br>
+ * <b>table.custom.balancer.host.regex.&lt;tablename&gt;=&lt;regex&gt;</b></br>
Periodically (default 5m) this balancer will check to see if a tablet server is
+ * hosting tablets that it should not be according to the regex configuration. If this occurs
then the offending tablets will be reassigned. This would cover
+ * the case where the configuration is changed and the master is restarted while the tablet
servers are up. To change the out of bounds check time period, set
+ * the following property:</br> <b>table.custom.balancer.host.regex.oob.period=5m</b></br>
Periodically (default 5m) this balancer will regroup the set of
+ * current tablet servers into pools based on regexes applied to the tserver host names.
This would cover the case of tservers dying or coming online. To change
+ * the host pool check time period, set the following property: </br> <b>table.custom.balancer.host.regex.pool.check=5m</b></br>
Regex matching can be based on
+ * either the host name (default) or host ip address. To set this balancer to match the regular
expressions to the tablet server IP address, then set the
+ * following property:</br> <b>table.custom.balancer.host.regex.is.ip=true</b>
+ * 
+ */
+public class HostRegexTableLoadBalancer extends TableLoadBalancer {
+
+  private static final Logger LOG = LoggerFactory.getLogger(HostRegexTableLoadBalancer.class);
+  public static final String HOST_BALANCER_PREFIX = Property.TABLE_ARBITRARY_PROP_PREFIX.getKey()
+ "balancer.host.regex.";
+  public static final String HOST_BALANCER_OOB_CHECK = Property.TABLE_ARBITRARY_PROP_PREFIX.getKey()
+ "balancer.host.regex.oob.period";
+  private static final String HOST_BALANCER_OOB_DEFAULT = "5m";
+  public static final String HOST_BALANCER_POOL_RECHECK_KEY = Property.TABLE_ARBITRARY_PROP_PREFIX.getKey()
+ "balancer.host.regex.pool.check";
+  private static final String HOST_BALANCER_POOL_RECHECK_DEFAULT = "5m";
+  public static final String HOST_BALANCER_REGEX_USING_IPS = Property.TABLE_ARBITRARY_PROP_PREFIX.getKey()
+ "balancer.host.regex.is.ip";
+  protected static final String DEFAULT_POOL = "HostTableLoadBalancer.ALL";
+
+  protected long oobCheckMillis = AccumuloConfiguration.getTimeInMillis(HOST_BALANCER_OOB_DEFAULT);
+  protected long poolRecheckMillis = AccumuloConfiguration.getTimeInMillis(HOST_BALANCER_POOL_RECHECK_DEFAULT);
+
+  private Map<String,String> tableIdToTableName = null;
+  private Map<String,Pattern> poolNameToRegexPattern = null;
+  private long lastOOBCheck = System.currentTimeMillis();
+  private long lastPoolRecheck = 0;
+  private boolean isIpBasedRegex = false;
+  private Map<String,SortedMap<TServerInstance,TabletServerStatus>> pools = new
HashMap<String,SortedMap<TServerInstance,TabletServerStatus>>();
+
+  /**
+   * Group the set of current tservers by pool name. Tservers that don't match a regex are
put into a default ppol.
+   * 
+   * @param current
+   * @return current servers grouped by pool name, if not a match it is put into a default
pool.
+   */
+  protected synchronized Map<String,SortedMap<TServerInstance,TabletServerStatus>>
splitCurrentByRegex(SortedMap<TServerInstance,TabletServerStatus> current) {
+    if ((System.currentTimeMillis() - lastPoolRecheck) > poolRecheckMillis) {
+      Map<String,SortedMap<TServerInstance,TabletServerStatus>> newPools = new
HashMap<String,SortedMap<TServerInstance,TabletServerStatus>>();
+      for (Entry<TServerInstance,TabletServerStatus> e : current.entrySet()) {
+        String tableName = getPoolNameForHost(e.getKey().host());
+        if (!newPools.containsKey(tableName)) {
+          newPools.put(tableName, new TreeMap<TServerInstance,TabletServerStatus>());
+        }
+        newPools.get(tableName).put(e.getKey(), e.getValue());
+      }
+      // Ensure that no host is in more than one pool
+      // TODO: I'm not sure that I need to check for disjoint as the call to getPoolNameForHost
checks for more than one match
+      boolean error = false;
+      for (SortedMap<TServerInstance,TabletServerStatus> s1 : newPools.values()) {
+        for (SortedMap<TServerInstance,TabletServerStatus> s2 : newPools.values())
{
+          if (s1 == s2) {
+            continue;
+          }
+          if (!Collections.disjoint(s1.keySet(), s2.keySet())) {
+            LOG.error("Pools are not disjoint: {}, there is a problem with your regular expressions.
Putting all servers in default pool", newPools);
+            error = true;
+          }
+        }
+      }
+      if (error) {
+        // Put all servers into the default pool
+        newPools.clear();
+        newPools.put(DEFAULT_POOL, new TreeMap<TServerInstance,TabletServerStatus>());
+        for (Entry<TServerInstance,TabletServerStatus> e : current.entrySet()) {
+          newPools.get(DEFAULT_POOL).put(e.getKey(), e.getValue());
+        }
+      }
+      pools = newPools;
+      this.lastPoolRecheck = System.currentTimeMillis();
+    }
+    return pools;
+  }
+
+  /**
+   * Matches host against the regexes and returns the matching pool name
+   * 
+   * @param host
+   * @return name of pool. will return default pool if host matches more than one regex
+   */
+  protected String getPoolNameForHost(String host) {
+    String test = host;
+    String table = DEFAULT_POOL;
+    if (!isIpBasedRegex) {
+      try {
+        test = getNameFromIp(host);
+      } catch (UnknownHostException e1) {
+        LOG.error("Unable to determine host name for IP: " + host + ", setting to default
pool", e1);
+        return table;
+      }
+    }
+    for (Entry<String,Pattern> e : poolNameToRegexPattern.entrySet()) {
+      if (e.getValue().matcher(test).matches()) {
+        if (!table.equals(DEFAULT_POOL)) {
+          LOG.warn("host {} matches more than one regex, assigning to default pool", host);
+          return DEFAULT_POOL;
+        }
+        table = e.getKey();
+      }
+    }
+    return table;
+  }
+
+  protected String getNameFromIp(String hostIp) throws UnknownHostException {
+    return InetAddress.getByName(hostIp).getHostName();
+  }
+
+  /**
+   * Matches table name against pool names, returns matching pool name or DEFAULT_POOL.
+   * 
+   * @param tableName
+   * @return
+   */
+  protected String getPoolNameForTable(String tableName) {
+    if (null == tableName) {
+      return DEFAULT_POOL;
+    }
+    return poolNameToRegexPattern.containsKey(tableName) ? tableName : DEFAULT_POOL;
+  }
+
+  /**
+   * Parse configuration and extract properties
+   * 
+   * @param conf
+   */
+  protected void parseConfiguration(ServerConfiguration conf) {
+    tableIdToTableName = new HashMap<>();
+    poolNameToRegexPattern = new HashMap<>();
+    for (Entry<String,String> table : getTableOperations().tableIdMap().entrySet())
{
+      tableIdToTableName.put(table.getValue(), table.getKey());
+      Map<String,String> customProps = conf.getTableConfiguration(table.getValue()).getAllPropertiesWithPrefix(Property.TABLE_ARBITRARY_PROP_PREFIX);
+      if (null != customProps && customProps.size() > 0) {
+        for (Entry<String,String> customProp : customProps.entrySet()) {
+          String tableName = customProp.getKey().substring(HOST_BALANCER_PREFIX.length());
+          String regex = customProp.getValue();
+          poolNameToRegexPattern.put(tableName, Pattern.compile(regex));
+        }
+      }
+    }
+    String oobProperty = conf.getConfiguration().get(HOST_BALANCER_OOB_CHECK);
+    if (null != oobProperty) {
+      oobCheckMillis = AccumuloConfiguration.getTimeInMillis(oobProperty);
+    }
+    String poolRecheckProperty = conf.getConfiguration().get(HOST_BALANCER_POOL_RECHECK_KEY);
+    if (null != poolRecheckProperty) {
+      poolRecheckMillis = AccumuloConfiguration.getTimeInMillis(poolRecheckProperty);
+    }
+    String ipBased = conf.getConfiguration().get(HOST_BALANCER_REGEX_USING_IPS);
+    if (null != ipBased) {
+      isIpBasedRegex = Boolean.parseBoolean(ipBased);
+    }
+  }
+
+  public Map<String,String> getTableIdToTableName() {
+    return tableIdToTableName;
+  }
+
+  public Map<String,Pattern> getPoolNameToRegexPattern() {
+    return poolNameToRegexPattern;
+  }
+
+  public long getOobCheckMillis() {
+    return oobCheckMillis;
+  }
+
+  public long getPoolRecheckMillis() {
+    return poolRecheckMillis;
+  }
+
+  public boolean isIpBasedRegex() {
+    return isIpBasedRegex;
+  }
+
+  @Override
+  public void init(ServerConfiguration conf) {
+    super.init(conf);
+    parseConfiguration(conf);
+  }
+
+  @Override
+  public void getAssignments(SortedMap<TServerInstance,TabletServerStatus> current,
Map<KeyExtent,TServerInstance> unassigned,
+      Map<KeyExtent,TServerInstance> assignments) {
+
+    if ((System.currentTimeMillis() - this.lastOOBCheck) > this.oobCheckMillis) {
+      // Check to see if a tablet is assigned outside the bounds of the pool. If so, migrate
it.
+      for (Entry<TServerInstance,TabletServerStatus> e : current.entrySet()) {
+        String assignedPool = getPoolNameForHost(e.getKey().host());
+        for (String pool : poolNameToRegexPattern.keySet()) {
+          if (assignedPool.equals(pool) || pool.equals(DEFAULT_POOL)) {
+            continue;
+          }
+          String tid = getTableOperations().tableIdMap().get(pool);
+          try {
+            List<TabletStats> outOfBoundsTablets = getOnlineTabletsForTable(e.getKey(),
tid);
+            for (TabletStats ts : outOfBoundsTablets) {
+              LOG.info("Tablet {} is currently outside the bounds of the regex, reassigning",
ts.toString());
+              unassigned.put(new KeyExtent(ts.getExtent()), e.getKey());
+            }
+          } catch (TException e1) {
+            LOG.error("Error in OOB check getting tablets for table {} from server {}", tid,
e.getKey().host(), e);
+          }
+        }
+      }
+      this.oobCheckMillis = System.currentTimeMillis();
+    }
+
+    Map<String,SortedMap<TServerInstance,TabletServerStatus>> pools = splitCurrentByRegex(current);
+    // separate the unassigned into tables
+    Map<String,Map<KeyExtent,TServerInstance>> groupedUnassigned = new HashMap<String,Map<KeyExtent,TServerInstance>>();
+    for (Entry<KeyExtent,TServerInstance> e : unassigned.entrySet()) {
+      Map<KeyExtent,TServerInstance> tableUnassigned = groupedUnassigned.get(e.getKey().getTableId());
+      if (tableUnassigned == null) {
+        tableUnassigned = new HashMap<KeyExtent,TServerInstance>();
+        groupedUnassigned.put(e.getKey().getTableId(), tableUnassigned);
+      }
+      tableUnassigned.put(e.getKey(), e.getValue());
+    }
+    // Send a view of the current servers to the tables tablet balancer
+    for (Entry<String,Map<KeyExtent,TServerInstance>> e : groupedUnassigned.entrySet())
{
+      Map<KeyExtent,TServerInstance> newAssignments = new HashMap<KeyExtent,TServerInstance>();
+      String tableName = tableIdToTableName.get(e.getKey());
+      String poolName = getPoolNameForTable(tableName);
+      SortedMap<TServerInstance,TabletServerStatus> currentView = pools.get(poolName);
+      getBalancerForTable(e.getKey()).getAssignments(currentView, e.getValue(), newAssignments);
+      assignments.putAll(newAssignments);
+    }
+  }
+
+  @Override
+  public long balance(SortedMap<TServerInstance,TabletServerStatus> current, Set<KeyExtent>
migrations, List<TabletMigration> migrationsOut) {
+    long minBalanceTime = 5 * 1000;
+    // Iterate over the tables and balance each of them
+    TableOperations t = getTableOperations();
+    if (t == null)
+      return minBalanceTime;
+
+    if (migrations != null && migrations.size() > 0) {
+      LOG.warn("Not balancing tables due to outstanding migrations");
+      return minBalanceTime;
+    }
+
+    Map<String,SortedMap<TServerInstance,TabletServerStatus>> currentGrouped
= splitCurrentByRegex(current);
+    for (String s : t.tableIdMap().values()) {
+      String tableName = tableIdToTableName.get(s);
+      String regexTableName = getPoolNameForTable(tableName);
+      SortedMap<TServerInstance,TabletServerStatus> currentView = currentGrouped.get(regexTableName);
+      ArrayList<TabletMigration> newMigrations = new ArrayList<TabletMigration>();
+      long tableBalanceTime = getBalancerForTable(s).balance(currentView, migrations, newMigrations);
+      if (tableBalanceTime < minBalanceTime) {
+        minBalanceTime = tableBalanceTime;
+      }
+      migrationsOut.addAll(newMigrations);
+    }
+
+    return minBalanceTime;
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/accumulo/blob/594ecc3c/server/base/src/test/java/org/apache/accumulo/server/master/balancer/HostRegexTableLoadBalancerTest.java
----------------------------------------------------------------------
diff --git a/server/base/src/test/java/org/apache/accumulo/server/master/balancer/HostRegexTableLoadBalancerTest.java
b/server/base/src/test/java/org/apache/accumulo/server/master/balancer/HostRegexTableLoadBalancerTest.java
new file mode 100644
index 0000000..85ddf86
--- /dev/null
+++ b/server/base/src/test/java/org/apache/accumulo/server/master/balancer/HostRegexTableLoadBalancerTest.java
@@ -0,0 +1,618 @@
+/*
+ * 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.server.master.balancer;
+
+import java.net.UnknownHostException;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.SortedMap;
+import java.util.TreeMap;
+import java.util.regex.Pattern;
+
+import org.apache.accumulo.core.client.AccumuloException;
+import org.apache.accumulo.core.client.AccumuloSecurityException;
+import org.apache.accumulo.core.client.Connector;
+import org.apache.accumulo.core.client.Instance;
+import org.apache.accumulo.core.client.admin.TableOperations;
+import org.apache.accumulo.core.client.impl.ClientContext;
+import org.apache.accumulo.core.client.impl.TableOperationsImpl;
+import org.apache.accumulo.core.client.impl.thrift.ThriftSecurityException;
+import org.apache.accumulo.core.client.security.tokens.AuthenticationToken;
+import org.apache.accumulo.core.conf.AccumuloConfiguration;
+import org.apache.accumulo.core.conf.ConfigurationCopy;
+import org.apache.accumulo.core.conf.Property;
+import org.apache.accumulo.core.data.impl.KeyExtent;
+import org.apache.accumulo.core.data.thrift.TKeyExtent;
+import org.apache.accumulo.core.master.thrift.TabletServerStatus;
+import org.apache.accumulo.core.tabletserver.thrift.TabletStats;
+import org.apache.accumulo.fate.util.UtilWaitThread;
+import org.apache.accumulo.server.conf.ServerConfiguration;
+import org.apache.accumulo.server.conf.ServerConfigurationFactory;
+import org.apache.accumulo.server.conf.TableConfiguration;
+import org.apache.accumulo.server.master.state.TServerInstance;
+import org.apache.accumulo.server.master.state.TabletMigration;
+import org.apache.hadoop.io.Text;
+import org.apache.thrift.TException;
+import org.easymock.EasyMock;
+import org.junit.Assert;
+import org.junit.Test;
+
+import com.google.common.base.Predicate;
+
+public class HostRegexTableLoadBalancerTest extends HostRegexTableLoadBalancer {
+
+  static class TestInstance implements Instance {
+
+    @Override
+    public String getRootTabletLocation() {
+      throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public List<String> getMasterLocations() {
+      throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String getInstanceID() {
+      return "1111";
+    }
+
+    @Override
+    public String getInstanceName() {
+      return "test";
+    }
+
+    @Override
+    public String getZooKeepers() {
+      return "";
+    }
+
+    @Override
+    public int getZooKeepersSessionTimeOut() {
+      return 30;
+    }
+
+    @Override
+    public Connector getConnector(String user, byte[] pass) throws AccumuloException, AccumuloSecurityException
{
+      throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Connector getConnector(String user, ByteBuffer pass) throws AccumuloException,
AccumuloSecurityException {
+      throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Connector getConnector(String user, CharSequence pass) throws AccumuloException,
AccumuloSecurityException {
+      throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public AccumuloConfiguration getConfiguration() {
+      throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setConfiguration(AccumuloConfiguration conf) {}
+
+    @Override
+    public Connector getConnector(String principal, AuthenticationToken token) throws AccumuloException,
AccumuloSecurityException {
+      throw new UnsupportedOperationException();
+    }
+
+  }
+
+  private static class Table {
+    private String tableName;
+    private String id;
+
+    Table(String tableName, String id) {
+      this.tableName = tableName;
+      this.id = id;
+    }
+
+    public String getTableName() {
+      return tableName;
+    }
+
+    public String getId() {
+      return id;
+    }
+  }
+
+  static class TestServerConfigurationFactory extends ServerConfigurationFactory {
+
+    public TestServerConfigurationFactory(Instance instance) {
+      super(instance);
+    }
+
+    @Override
+    public synchronized AccumuloConfiguration getConfiguration() {
+      HashMap<String,String> props = new HashMap<>();
+      props.put(HostRegexTableLoadBalancer.HOST_BALANCER_OOB_CHECK, "10s");
+      props.put(HostRegexTableLoadBalancer.HOST_BALANCER_POOL_RECHECK_KEY, "30s");
+      return new ConfigurationCopy(props);
+    }
+
+    @Override
+    public TableConfiguration getTableConfiguration(String tableId) {
+      return new TableConfiguration(getInstance(), tableId, null) {
+        HashMap<String,String> tableProperties = new HashMap<>();
+        {
+          tableProperties.put(HostRegexTableLoadBalancer.HOST_BALANCER_PREFIX + FOO.getTableName(),
"r01.*");
+          tableProperties.put(HostRegexTableLoadBalancer.HOST_BALANCER_PREFIX + BAR.getTableName(),
"r02.*");
+        }
+
+        @Override
+        public String get(Property property) {
+          return tableProperties.get(property);
+        }
+
+        @Override
+        public void getProperties(Map<String,String> props, Predicate<String>
filter) {
+          for (Entry<String,String> e : tableProperties.entrySet()) {
+            if (filter.apply(e.getKey())) {
+              props.put(e.getKey(), e.getValue());
+            }
+          }
+        }
+      };
+    }
+  }
+
+  private static final Table FOO = new Table("foo", "1");
+  private static final Table BAR = new Table("bar", "2");
+  private static final Table BAZ = new Table("baz", "3");
+
+  private final TestInstance instance = new TestInstance();
+  private final TestServerConfigurationFactory factory = new TestServerConfigurationFactory(instance);
+  private final Map<String,String> servers = new HashMap<>(15);
+  private final SortedMap<TServerInstance,TabletServerStatus> allTabletServers = new
TreeMap<>();
+  private final Map<String,List<KeyExtent>> tableExtents = new HashMap<>(3);
+
+  {
+    servers.put("192.168.0.1", "r01s01");
+    servers.put("192.168.0.2", "r01s02");
+    servers.put("192.168.0.3", "r01s03");
+    servers.put("192.168.0.4", "r01s04");
+    servers.put("192.168.0.5", "r01s05");
+    servers.put("192.168.0.6", "r02s01");
+    servers.put("192.168.0.7", "r02s02");
+    servers.put("192.168.0.8", "r02s03");
+    servers.put("192.168.0.9", "r02s04");
+    servers.put("192.168.0.10", "r02s05");
+    servers.put("192.168.0.11", "r03s01");
+    servers.put("192.168.0.12", "r03s02");
+    servers.put("192.168.0.13", "r03s03");
+    servers.put("192.168.0.14", "r03s04");
+    servers.put("192.168.0.15", "r03s05");
+
+    allTabletServers.put(new TServerInstance("192.168.0.1:9997", 1), new TabletServerStatus());
+    allTabletServers.put(new TServerInstance("192.168.0.2:9997", 1), new TabletServerStatus());
+    allTabletServers.put(new TServerInstance("192.168.0.3:9997", 1), new TabletServerStatus());
+    allTabletServers.put(new TServerInstance("192.168.0.4:9997", 1), new TabletServerStatus());
+    allTabletServers.put(new TServerInstance("192.168.0.5:9997", 1), new TabletServerStatus());
+    allTabletServers.put(new TServerInstance("192.168.0.6:9997", 1), new TabletServerStatus());
+    allTabletServers.put(new TServerInstance("192.168.0.7:9997", 1), new TabletServerStatus());
+    allTabletServers.put(new TServerInstance("192.168.0.8:9997", 1), new TabletServerStatus());
+    allTabletServers.put(new TServerInstance("192.168.0.9:9997", 1), new TabletServerStatus());
+    allTabletServers.put(new TServerInstance("192.168.0.10:9997", 1), new TabletServerStatus());
+    allTabletServers.put(new TServerInstance("192.168.0.11:9997", 1), new TabletServerStatus());
+    allTabletServers.put(new TServerInstance("192.168.0.12:9997", 1), new TabletServerStatus());
+    allTabletServers.put(new TServerInstance("192.168.0.13:9997", 1), new TabletServerStatus());
+    allTabletServers.put(new TServerInstance("192.168.0.14:9997", 1), new TabletServerStatus());
+    allTabletServers.put(new TServerInstance("192.168.0.15:9997", 1), new TabletServerStatus());
+
+    tableExtents.put(FOO.getTableName(), new ArrayList<KeyExtent>());
+    tableExtents.get(FOO.getTableName()).add(new KeyExtent(FOO.getId(), new Text("1"), new
Text("0")));
+    tableExtents.get(FOO.getTableName()).add(new KeyExtent(FOO.getId(), new Text("2"), new
Text("1")));
+    tableExtents.get(FOO.getTableName()).add(new KeyExtent(FOO.getId(), new Text("3"), new
Text("2")));
+    tableExtents.get(FOO.getTableName()).add(new KeyExtent(FOO.getId(), new Text("4"), new
Text("3")));
+    tableExtents.get(FOO.getTableName()).add(new KeyExtent(FOO.getId(), new Text("5"), new
Text("4")));
+    tableExtents.put(BAR.getTableName(), new ArrayList<KeyExtent>());
+    tableExtents.get(BAR.getTableName()).add(new KeyExtent(BAR.getId(), new Text("11"), new
Text("10")));
+    tableExtents.get(BAR.getTableName()).add(new KeyExtent(BAR.getId(), new Text("12"), new
Text("11")));
+    tableExtents.get(BAR.getTableName()).add(new KeyExtent(BAR.getId(), new Text("13"), new
Text("12")));
+    tableExtents.get(BAR.getTableName()).add(new KeyExtent(BAR.getId(), new Text("14"), new
Text("13")));
+    tableExtents.get(BAR.getTableName()).add(new KeyExtent(BAR.getId(), new Text("15"), new
Text("14")));
+    tableExtents.put(BAZ.getTableName(), new ArrayList<KeyExtent>());
+    tableExtents.get(BAZ.getTableName()).add(new KeyExtent(BAZ.getId(), new Text("21"), new
Text("20")));
+    tableExtents.get(BAZ.getTableName()).add(new KeyExtent(BAZ.getId(), new Text("22"), new
Text("21")));
+    tableExtents.get(BAZ.getTableName()).add(new KeyExtent(BAZ.getId(), new Text("23"), new
Text("22")));
+    tableExtents.get(BAZ.getTableName()).add(new KeyExtent(BAZ.getId(), new Text("24"), new
Text("23")));
+    tableExtents.get(BAZ.getTableName()).add(new KeyExtent(BAZ.getId(), new Text("25"), new
Text("24")));
+  }
+
+  @Override
+  protected String getNameFromIp(String hostIp) throws UnknownHostException {
+    if (servers.containsKey(hostIp)) {
+      return servers.get(hostIp);
+    } else {
+      throw new UnknownHostException();
+    }
+  }
+
+  @Override
+  protected TableOperations getTableOperations() {
+    return new TableOperationsImpl(EasyMock.createMock(ClientContext.class)) {
+      @Override
+      public Map<String,String> tableIdMap() {
+        HashMap<String,String> tables = new HashMap<>();
+        tables.put(FOO.getTableName(), FOO.getId());
+        tables.put(BAR.getTableName(), BAR.getId());
+        tables.put(BAZ.getTableName(), BAZ.getId());
+        return tables;
+      }
+    };
+  }
+
+  @Override
+  protected TabletBalancer getBalancerForTable(String table) {
+    return new DefaultLoadBalancer();
+  }
+
+  private SortedMap<TServerInstance,TabletServerStatus> createCurrent(int numTservers)
{
+    String base = "192.168.0.";
+    TreeMap<TServerInstance,TabletServerStatus> current = new TreeMap<>();
+    for (int i = 1; i <= numTservers; i++) {
+      current.put(new TServerInstance(base + i + ":9997", 1), new TabletServerStatus());
+    }
+    return current;
+  }
+
+  @Test
+  public void testInit() {
+    init((ServerConfiguration) factory);
+    Assert.assertEquals("OOB check interval value is incorrect", 10000, this.getOobCheckMillis());
+    Assert.assertEquals("Pool check interval value is incorrect", 30000, this.getPoolRecheckMillis());
+    Assert.assertFalse(isIpBasedRegex());
+    Map<String,Pattern> patterns = this.getPoolNameToRegexPattern();
+    Assert.assertEquals(2, patterns.size());
+    Assert.assertTrue(patterns.containsKey(FOO.getTableName()));
+    Assert.assertEquals(Pattern.compile("r01.*").pattern(), patterns.get(FOO.getTableName()).pattern());
+    Assert.assertTrue(patterns.containsKey(BAR.getTableName()));
+    Assert.assertEquals(Pattern.compile("r02.*").pattern(), patterns.get(BAR.getTableName()).pattern());
+    Map<String,String> tids = this.getTableIdToTableName();
+    Assert.assertEquals(3, tids.size());
+    Assert.assertTrue(tids.containsKey(FOO.getId()));
+    Assert.assertEquals(FOO.getTableName(), tids.get(FOO.getId()));
+    Assert.assertTrue(tids.containsKey(BAR.getId()));
+    Assert.assertEquals(BAR.getTableName(), tids.get(BAR.getId()));
+    Assert.assertTrue(tids.containsKey(BAZ.getId()));
+    Assert.assertEquals(BAZ.getTableName(), tids.get(BAZ.getId()));
+    Assert.assertEquals(false, this.isIpBasedRegex());
+  }
+
+  @Test
+  public void testBalanceWithMigrations() {
+    List<TabletMigration> migrations = new ArrayList<>();
+    init((ServerConfiguration) factory);
+    long wait = this.balance(createCurrent(2), Collections.singleton(new KeyExtent()), migrations);
+    Assert.assertEquals(5000, wait);
+    Assert.assertEquals(0, migrations.size());
+  }
+
+  @Test
+  public void testSplitCurrentByRegexUsingHostname() {
+    init((ServerConfiguration) factory);
+    Map<String,SortedMap<TServerInstance,TabletServerStatus>> groups = this.splitCurrentByRegex(createCurrent(15));
+    Assert.assertEquals(3, groups.size());
+    Assert.assertTrue(groups.containsKey(FOO.getTableName()));
+    SortedMap<TServerInstance,TabletServerStatus> fooHosts = groups.get(FOO.getTableName());
+    Assert.assertEquals(5, fooHosts.size());
+    Assert.assertTrue(fooHosts.containsKey(new TServerInstance("192.168.0.1:9997", 1)));
+    Assert.assertTrue(fooHosts.containsKey(new TServerInstance("192.168.0.2:9997", 1)));
+    Assert.assertTrue(fooHosts.containsKey(new TServerInstance("192.168.0.3:9997", 1)));
+    Assert.assertTrue(fooHosts.containsKey(new TServerInstance("192.168.0.4:9997", 1)));
+    Assert.assertTrue(fooHosts.containsKey(new TServerInstance("192.168.0.5:9997", 1)));
+    Assert.assertTrue(groups.containsKey(BAR.getTableName()));
+    SortedMap<TServerInstance,TabletServerStatus> barHosts = groups.get(BAR.getTableName());
+    Assert.assertEquals(5, barHosts.size());
+    Assert.assertTrue(barHosts.containsKey(new TServerInstance("192.168.0.6:9997", 1)));
+    Assert.assertTrue(barHosts.containsKey(new TServerInstance("192.168.0.7:9997", 1)));
+    Assert.assertTrue(barHosts.containsKey(new TServerInstance("192.168.0.8:9997", 1)));
+    Assert.assertTrue(barHosts.containsKey(new TServerInstance("192.168.0.9:9997", 1)));
+    Assert.assertTrue(barHosts.containsKey(new TServerInstance("192.168.0.10:9997", 1)));
+    Assert.assertTrue(groups.containsKey(DEFAULT_POOL));
+    SortedMap<TServerInstance,TabletServerStatus> defHosts = groups.get(DEFAULT_POOL);
+    Assert.assertEquals(5, defHosts.size());
+    Assert.assertTrue(defHosts.containsKey(new TServerInstance("192.168.0.11:9997", 1)));
+    Assert.assertTrue(defHosts.containsKey(new TServerInstance("192.168.0.12:9997", 1)));
+    Assert.assertTrue(defHosts.containsKey(new TServerInstance("192.168.0.13:9997", 1)));
+    Assert.assertTrue(defHosts.containsKey(new TServerInstance("192.168.0.14:9997", 1)));
+    Assert.assertTrue(defHosts.containsKey(new TServerInstance("192.168.0.15:9997", 1)));
+  }
+
+  @Test
+  public void testSplitCurrentByRegexUsingHostnameMatchesTooMany() {
+    init((ServerConfiguration) new TestServerConfigurationFactory(instance) {
+      @Override
+      public TableConfiguration getTableConfiguration(String tableId) {
+        return new TableConfiguration(getInstance(), tableId, null) {
+          HashMap<String,String> tableProperties = new HashMap<>();
+          {
+            tableProperties.put(HostRegexTableLoadBalancer.HOST_BALANCER_PREFIX + FOO.getTableName(),
"r.*");
+            tableProperties.put(HostRegexTableLoadBalancer.HOST_BALANCER_PREFIX + BAR.getTableName(),
"r01.*|r02.*");
+          }
+
+          @Override
+          public String get(Property property) {
+            return tableProperties.get(property);
+          }
+
+          @Override
+          public void getProperties(Map<String,String> props, Predicate<String>
filter) {
+            for (Entry<String,String> e : tableProperties.entrySet()) {
+              if (filter.apply(e.getKey())) {
+                props.put(e.getKey(), e.getValue());
+              }
+            }
+          }
+        };
+      }
+    });
+    Map<String,SortedMap<TServerInstance,TabletServerStatus>> groups = this.splitCurrentByRegex(createCurrent(15));
+    Assert.assertEquals(2, groups.size());
+    Assert.assertTrue(groups.containsKey(FOO.getTableName()));
+    SortedMap<TServerInstance,TabletServerStatus> fooHosts = groups.get(FOO.getTableName());
+    Assert.assertEquals(5, fooHosts.size());
+    Assert.assertTrue(fooHosts.containsKey(new TServerInstance("192.168.0.11:9997", 1)));
+    Assert.assertTrue(fooHosts.containsKey(new TServerInstance("192.168.0.12:9997", 1)));
+    Assert.assertTrue(fooHosts.containsKey(new TServerInstance("192.168.0.13:9997", 1)));
+    Assert.assertTrue(fooHosts.containsKey(new TServerInstance("192.168.0.14:9997", 1)));
+    Assert.assertTrue(fooHosts.containsKey(new TServerInstance("192.168.0.15:9997", 1)));
+    Assert.assertTrue(groups.containsKey(DEFAULT_POOL));
+    SortedMap<TServerInstance,TabletServerStatus> defHosts = groups.get(DEFAULT_POOL);
+    Assert.assertEquals(10, defHosts.size());
+    Assert.assertTrue(defHosts.containsKey(new TServerInstance("192.168.0.1:9997", 1)));
+    Assert.assertTrue(defHosts.containsKey(new TServerInstance("192.168.0.2:9997", 1)));
+    Assert.assertTrue(defHosts.containsKey(new TServerInstance("192.168.0.3:9997", 1)));
+    Assert.assertTrue(defHosts.containsKey(new TServerInstance("192.168.0.4:9997", 1)));
+    Assert.assertTrue(defHosts.containsKey(new TServerInstance("192.168.0.5:9997", 1)));
+    Assert.assertTrue(defHosts.containsKey(new TServerInstance("192.168.0.6:9997", 1)));
+    Assert.assertTrue(defHosts.containsKey(new TServerInstance("192.168.0.7:9997", 1)));
+    Assert.assertTrue(defHosts.containsKey(new TServerInstance("192.168.0.8:9997", 1)));
+    Assert.assertTrue(defHosts.containsKey(new TServerInstance("192.168.0.9:9997", 1)));
+    Assert.assertTrue(defHosts.containsKey(new TServerInstance("192.168.0.10:9997", 1)));
+  }
+
+  @Test
+  public void testSplitCurrentByRegexUsingIP() {
+    init((ServerConfiguration) new TestServerConfigurationFactory(instance) {
+      @Override
+      public synchronized AccumuloConfiguration getConfiguration() {
+        HashMap<String,String> props = new HashMap<>();
+        props.put(HostRegexTableLoadBalancer.HOST_BALANCER_OOB_CHECK, "30s");
+        props.put(HostRegexTableLoadBalancer.HOST_BALANCER_POOL_RECHECK_KEY, "30s");
+        props.put(HostRegexTableLoadBalancer.HOST_BALANCER_REGEX_USING_IPS, "true");
+        return new ConfigurationCopy(props);
+      }
+
+      @Override
+      public TableConfiguration getTableConfiguration(String tableId) {
+        return new TableConfiguration(getInstance(), tableId, null) {
+          HashMap<String,String> tableProperties = new HashMap<>();
+          {
+            tableProperties.put(HostRegexTableLoadBalancer.HOST_BALANCER_PREFIX + FOO.getTableName(),
"192\\.168\\.0\\.[1-5]");
+            tableProperties.put(HostRegexTableLoadBalancer.HOST_BALANCER_PREFIX + BAR.getTableName(),
"192\\.168\\.0\\.[6-9]|192\\.168\\.0\\.10");
+          }
+
+          @Override
+          public String get(Property property) {
+            return tableProperties.get(property);
+          }
+
+          @Override
+          public void getProperties(Map<String,String> props, Predicate<String>
filter) {
+            for (Entry<String,String> e : tableProperties.entrySet()) {
+              if (filter.apply(e.getKey())) {
+                props.put(e.getKey(), e.getValue());
+              }
+            }
+          }
+        };
+      }
+    });
+    Assert.assertTrue(isIpBasedRegex());
+    Map<String,SortedMap<TServerInstance,TabletServerStatus>> groups = this.splitCurrentByRegex(createCurrent(15));
+    Assert.assertEquals(3, groups.size());
+    Assert.assertTrue(groups.containsKey(FOO.getTableName()));
+    SortedMap<TServerInstance,TabletServerStatus> fooHosts = groups.get(FOO.getTableName());
+    Assert.assertEquals(5, fooHosts.size());
+    Assert.assertTrue(fooHosts.containsKey(new TServerInstance("192.168.0.1:9997", 1)));
+    Assert.assertTrue(fooHosts.containsKey(new TServerInstance("192.168.0.2:9997", 1)));
+    Assert.assertTrue(fooHosts.containsKey(new TServerInstance("192.168.0.3:9997", 1)));
+    Assert.assertTrue(fooHosts.containsKey(new TServerInstance("192.168.0.4:9997", 1)));
+    Assert.assertTrue(fooHosts.containsKey(new TServerInstance("192.168.0.5:9997", 1)));
+    Assert.assertTrue(groups.containsKey(BAR.getTableName()));
+    SortedMap<TServerInstance,TabletServerStatus> barHosts = groups.get(BAR.getTableName());
+    Assert.assertEquals(5, barHosts.size());
+    Assert.assertTrue(barHosts.containsKey(new TServerInstance("192.168.0.6:9997", 1)));
+    Assert.assertTrue(barHosts.containsKey(new TServerInstance("192.168.0.7:9997", 1)));
+    Assert.assertTrue(barHosts.containsKey(new TServerInstance("192.168.0.8:9997", 1)));
+    Assert.assertTrue(barHosts.containsKey(new TServerInstance("192.168.0.9:9997", 1)));
+    Assert.assertTrue(barHosts.containsKey(new TServerInstance("192.168.0.10:9997", 1)));
+    Assert.assertTrue(groups.containsKey(DEFAULT_POOL));
+    SortedMap<TServerInstance,TabletServerStatus> defHosts = groups.get(DEFAULT_POOL);
+    Assert.assertEquals(5, defHosts.size());
+    Assert.assertTrue(defHosts.containsKey(new TServerInstance("192.168.0.11:9997", 1)));
+    Assert.assertTrue(defHosts.containsKey(new TServerInstance("192.168.0.12:9997", 1)));
+    Assert.assertTrue(defHosts.containsKey(new TServerInstance("192.168.0.13:9997", 1)));
+    Assert.assertTrue(defHosts.containsKey(new TServerInstance("192.168.0.14:9997", 1)));
+    Assert.assertTrue(defHosts.containsKey(new TServerInstance("192.168.0.15:9997", 1)));
+  }
+
+  @Test
+  public void testAllUnassigned() {
+    init((ServerConfiguration) factory);
+    Map<KeyExtent,TServerInstance> assignments = new HashMap<>();
+    Map<KeyExtent,TServerInstance> unassigned = new HashMap<>();
+    for (List<KeyExtent> extents : tableExtents.values()) {
+      for (KeyExtent ke : extents) {
+        unassigned.put(ke, null);
+      }
+    }
+    this.getAssignments(allTabletServers, unassigned, assignments);
+    Assert.assertEquals(15, assignments.size());
+    // Ensure unique tservers
+    for (Entry<KeyExtent,TServerInstance> e : assignments.entrySet()) {
+      for (Entry<KeyExtent,TServerInstance> e2 : assignments.entrySet()) {
+        if (e.getKey().equals(e2.getKey())) {
+          continue;
+        }
+        if (e.getValue().equals(e2.getValue())) {
+          Assert.fail("Assignment failure");
+        }
+      }
+    }
+    // Ensure assignments are correct
+    for (Entry<KeyExtent,TServerInstance> e : assignments.entrySet()) {
+      if (!tabletInBounds(e.getKey(), e.getValue())) {
+        Assert.fail("tablet not in bounds: " + e.getKey() + " -> " + e.getValue().host());
+      }
+    }
+  }
+
+  @Test
+  public void testAllAassigned() {
+    init((ServerConfiguration) factory);
+    Map<KeyExtent,TServerInstance> assignments = new HashMap<>();
+    Map<KeyExtent,TServerInstance> unassigned = new HashMap<>();
+    this.getAssignments(allTabletServers, unassigned, assignments);
+    Assert.assertEquals(0, assignments.size());
+  }
+
+  @Test
+  public void testPartiallyAassigned() {
+    init((ServerConfiguration) factory);
+    Map<KeyExtent,TServerInstance> assignments = new HashMap<>();
+    Map<KeyExtent,TServerInstance> unassigned = new HashMap<>();
+    int i = 0;
+    for (List<KeyExtent> extents : tableExtents.values()) {
+      for (KeyExtent ke : extents) {
+        if ((i % 2) == 0) {
+          unassigned.put(ke, null);
+        }
+        i++;
+      }
+    }
+    this.getAssignments(allTabletServers, unassigned, assignments);
+    Assert.assertEquals(unassigned.size(), assignments.size());
+    // Ensure unique tservers
+    for (Entry<KeyExtent,TServerInstance> e : assignments.entrySet()) {
+      for (Entry<KeyExtent,TServerInstance> e2 : assignments.entrySet()) {
+        if (e.getKey().equals(e2.getKey())) {
+          continue;
+        }
+        if (e.getValue().equals(e2.getValue())) {
+          Assert.fail("Assignment failure");
+        }
+      }
+    }
+    // Ensure assignments are correct
+    for (Entry<KeyExtent,TServerInstance> e : assignments.entrySet()) {
+      if (!tabletInBounds(e.getKey(), e.getValue())) {
+        Assert.fail("tablet not in bounds: " + e.getKey() + " -> " + e.getValue().host());
+      }
+    }
+  }
+
+  @Test
+  public void testOutOfBoundsTablets() {
+    init((ServerConfiguration) factory);
+    // Wait to trigger the out of bounds check which will call our version of getOnlineTabletsForTable
+    UtilWaitThread.sleep(11000);
+    Map<KeyExtent,TServerInstance> assignments = new HashMap<>();
+    Map<KeyExtent,TServerInstance> unassigned = new HashMap<>();
+    for (List<KeyExtent> extents : tableExtents.values()) {
+      for (KeyExtent ke : extents) {
+        unassigned.put(ke, null);
+      }
+    }
+    this.getAssignments(allTabletServers, unassigned, assignments);
+    Assert.assertEquals(15, assignments.size());
+    // Ensure unique tservers
+    for (Entry<KeyExtent,TServerInstance> e : assignments.entrySet()) {
+      for (Entry<KeyExtent,TServerInstance> e2 : assignments.entrySet()) {
+        if (e.getKey().equals(e2.getKey())) {
+          continue;
+        }
+        if (e.getValue().equals(e2.getValue())) {
+          Assert.fail("Assignment failure");
+        }
+      }
+    }
+    // Ensure assignments are correct
+    for (Entry<KeyExtent,TServerInstance> e : assignments.entrySet()) {
+      if (!tabletInBounds(e.getKey(), e.getValue())) {
+        Assert.fail("tablet not in bounds: " + e.getKey() + " -> " + e.getValue().host());
+      }
+    }
+  }
+
+  @Override
+  public List<TabletStats> getOnlineTabletsForTable(TServerInstance tserver, String
tableId) throws ThriftSecurityException, TException {
+    // Report incorrent information so that getAssignments will create n assignment
+    List<TabletStats> tablets = new ArrayList<>();
+    if (tableId.equals(BAR.getId()) && tserver.host().equals("192.168.0.1")) {
+      // Report that we have a bar tablet on this server
+      TKeyExtent tke = new TKeyExtent();
+      tke.setTable(BAR.getId().getBytes());
+      tke.setEndRow("11".getBytes());
+      tke.setPrevEndRow("10".getBytes());
+      TabletStats ts = new TabletStats();
+      ts.setExtent(tke);
+      tablets.add(ts);
+    } else if (tableId.equals(FOO.getId()) && tserver.host().equals("192.168.0.6"))
{
+      // Report that we have a foo tablet on this server
+      TKeyExtent tke = new TKeyExtent();
+      tke.setTable(FOO.getId().getBytes());
+      tke.setEndRow("1".getBytes());
+      tke.setPrevEndRow("0".getBytes());
+      TabletStats ts = new TabletStats();
+      ts.setExtent(tke);
+      tablets.add(ts);
+
+    }
+    return tablets;
+  }
+
+  private boolean tabletInBounds(KeyExtent ke, TServerInstance tsi) {
+    String tid = ke.getTableId();
+    String host = tsi.host();
+    if (tid.equals("1")
+        && (host.equals("192.168.0.1") || host.equals("192.168.0.2") || host.equals("192.168.0.3")
|| host.equals("192.168.0.4") || host.equals("192.168.0.5"))) {
+      return true;
+    } else if (tid.equals("2")
+        && (host.equals("192.168.0.6") || host.equals("192.168.0.7") || host.equals("192.168.0.8")
|| host.equals("192.168.0.9") || host.equals("192.168.0.10"))) {
+      return true;
+    } else if (tid.equals("3")
+        && (host.equals("192.168.0.11") || host.equals("192.168.0.12") || host.equals("192.168.0.13")
|| host.equals("192.168.0.14") || host
+            .equals("192.168.0.15"))) {
+      return true;
+    } else {
+      return false;
+    }
+  }
+
+}


Mime
View raw message