You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@phoenix.apache.org by st...@apache.org on 2020/05/19 06:54:45 UTC

[phoenix-queryserver] branch master updated: PHOENIX-5826 Remove guava from queryserver

This is an automated email from the ASF dual-hosted git repository.

stoty pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/phoenix-queryserver.git


The following commit(s) were added to refs/heads/master by this push:
     new baa8132  PHOENIX-5826 Remove guava from queryserver
baa8132 is described below

commit baa8132675eeaab7a573cdba0b856761b8cb5d64
Author: Istvan Toth <st...@apache.org>
AuthorDate: Thu May 14 16:34:01 2020 +0200

    PHOENIX-5826 Remove guava from queryserver
    
    Closes #33
---
 load-balancer/pom.xml                              |   4 -
 .../phoenix/end2end/LoadBalancerEnd2EndIT.java     |   2 +-
 .../service/LoadBalanceZookeeperConfImpl.java      |   5 +-
 .../phoenix/loadbalancer/service/LoadBalancer.java |  21 +-
 .../queryserver/register/ZookeeperRegistry.java    |   2 +-
 pom.xml                                            |   8 +-
 queryserver-it/pom.xml                             |   5 -
 .../phoenix/end2end/QueryServerEnvironment.java    |  10 +-
 .../phoenix/end2end/QueryServerTestUtil.java       |   4 +-
 .../end2end/SecureQueryServerPhoenixDBIT.java      |  10 +-
 queryserver-orchestrator/pom.xml                   |   4 -
 .../tool/ParameterizedPhoenixCanaryToolIT.java     |   5 +-
 .../orchestrator/TestExecutorClient.java           |   3 +-
 .../queryserver/orchestrator/ToolWrapper.java      |   3 +-
 .../org/apache/phoenix/tool/PhoenixCanaryTool.java |  41 ++-
 queryserver/pom.xml                                |   4 +-
 .../service/LoadBalanceZookeeperConf.java          |   2 +-
 .../queryserver/server/PhoenixMetaFactoryImpl.java |  17 +-
 .../phoenix/queryserver/server/QueryServer.java    |  81 +++---
 .../java/org/apache/phoenix/util/HostAndPort.java  | 287 +++++++++++++++++++++
 .../org/apache/phoenix/util/InstanceResolver.java  |   4 +-
 .../org/apache/phoenix/util/SimpleLRUCache.java    |  96 +++++++
 .../queryserver/util/SimpleLRUCacheTest.java       |  58 +++++
 23 files changed, 551 insertions(+), 125 deletions(-)

diff --git a/load-balancer/pom.xml b/load-balancer/pom.xml
index c0e01dc..70e072a 100644
--- a/load-balancer/pom.xml
+++ b/load-balancer/pom.xml
@@ -120,10 +120,6 @@
       <groupId>org.slf4j</groupId>
       <artifactId>slf4j-api</artifactId>
     </dependency>
-    <dependency>
-      <groupId>com.google.guava</groupId>
-      <artifactId>guava</artifactId>
-    </dependency>
 
     <!-- for tests -->
     <dependency>
diff --git a/load-balancer/src/it/java/org/apache/phoenix/end2end/LoadBalancerEnd2EndIT.java b/load-balancer/src/it/java/org/apache/phoenix/end2end/LoadBalancerEnd2EndIT.java
index 448c28f..16471a7 100644
--- a/load-balancer/src/it/java/org/apache/phoenix/end2end/LoadBalancerEnd2EndIT.java
+++ b/load-balancer/src/it/java/org/apache/phoenix/end2end/LoadBalancerEnd2EndIT.java
@@ -18,7 +18,6 @@
  */
 package org.apache.phoenix.end2end;
 
-import com.google.common.net.HostAndPort;
 import org.apache.curator.CuratorZookeeperClient;
 import org.apache.curator.framework.CuratorFramework;
 import org.apache.curator.framework.CuratorFrameworkFactory;
@@ -30,6 +29,7 @@ import org.apache.phoenix.loadbalancer.service.LoadBalanceZookeeperConf;
 import org.apache.phoenix.loadbalancer.service.LoadBalanceZookeeperConfImpl;
 import org.apache.phoenix.queryserver.register.Registry;
 import org.apache.phoenix.queryserver.register.ZookeeperRegistry;
+import org.apache.phoenix.util.HostAndPort;
 import org.apache.zookeeper.KeeperException;
 import org.junit.*;
 import org.slf4j.Logger;
diff --git a/load-balancer/src/main/java/org/apache/phoenix/loadbalancer/service/LoadBalanceZookeeperConfImpl.java b/load-balancer/src/main/java/org/apache/phoenix/loadbalancer/service/LoadBalanceZookeeperConfImpl.java
index 17294cb..4aacc08 100644
--- a/load-balancer/src/main/java/org/apache/phoenix/loadbalancer/service/LoadBalanceZookeeperConfImpl.java
+++ b/load-balancer/src/main/java/org/apache/phoenix/loadbalancer/service/LoadBalanceZookeeperConfImpl.java
@@ -19,13 +19,12 @@
 
 package org.apache.phoenix.loadbalancer.service;
 
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.net.HostAndPort;
 import org.apache.hadoop.conf.Configuration;
 import org.apache.hadoop.hbase.HBaseConfiguration;
 import org.apache.hadoop.hbase.zookeeper.ZKConfig;
 import org.apache.phoenix.queryserver.QueryServerOptions;
 import org.apache.phoenix.queryserver.QueryServerProperties;
+import org.apache.phoenix.util.HostAndPort;
 import org.apache.zookeeper.ZooDefs;
 import org.apache.zookeeper.data.ACL;
 import org.apache.zookeeper.data.Id;
@@ -47,7 +46,7 @@ public class LoadBalanceZookeeperConfImpl implements LoadBalanceZookeeperConf {
             this.configuration = configuration;
         }
 
-        @VisibleForTesting
+        //@VisibleForTesting
         public void setConfiguration(Configuration configuration) {
             this.configuration = configuration;
         }
diff --git a/load-balancer/src/main/java/org/apache/phoenix/loadbalancer/service/LoadBalancer.java b/load-balancer/src/main/java/org/apache/phoenix/loadbalancer/service/LoadBalancer.java
index 9bcf2d4..4cfd1a4 100644
--- a/load-balancer/src/main/java/org/apache/phoenix/loadbalancer/service/LoadBalancer.java
+++ b/load-balancer/src/main/java/org/apache/phoenix/loadbalancer/service/LoadBalancer.java
@@ -18,9 +18,6 @@
  */
 package org.apache.phoenix.loadbalancer.service;
 
-import com.google.common.base.Preconditions;
-import com.google.common.collect.Lists;
-import com.google.common.net.HostAndPort;
 import org.apache.curator.framework.CuratorFramework;
 import org.apache.curator.framework.CuratorFrameworkFactory;
 import org.apache.curator.framework.api.UnhandledErrorListener;
@@ -30,6 +27,7 @@ import org.apache.curator.framework.state.ConnectionStateListener;
 import org.apache.curator.retry.ExponentialBackoffRetry;
 import org.apache.curator.utils.CloseableUtils;
 import org.apache.hadoop.hbase.HBaseConfiguration;
+import org.apache.phoenix.util.HostAndPort;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -54,7 +52,7 @@ public class LoadBalancer {
     private static final LoadBalancer loadBalancer = new LoadBalancer();
     private ConnectionStateListener connectionStateListener = null;
     private UnhandledErrorListener unhandledErrorListener = null;
-    private List<Closeable> closeAbles = Lists.newArrayList();
+    private List<Closeable> closeAbles = new ArrayList<>();
 
     private LoadBalancer()  {
         try  {
@@ -87,11 +85,11 @@ public class LoadBalancer {
 
     /**
      * It returns the location of Phoenix Query Server
-     * in form of Guava <a href="https://google.github.io/guava/releases/19.0/api/docs/com/google/common/net/HostAndPort.html">HostAndPort</a>
+     * in form of a HostAndPort (copied from Guava)
      * from the cache. The client should catch Exception incase
      * the method is unable to fetch PQS location due to network failure or
      * in-correct configuration issues.
-     * @return - return Guava HostAndPort. See <a href="http://google.com">http://google.com</a>
+     * @return - return HostAndPort
      * @throws Exception
      */
     public HostAndPort getSingleServiceLocation()  throws Exception{
@@ -103,7 +101,7 @@ public class LoadBalancer {
 
     /**
      * return locations of all Phoenix Query Servers
-     * in the form of a List of PQS servers  <a href="https://google.github.io/guava/releases/19.0/api/docs/com/google/common/net/HostAndPort.html">HostAndPort</a>
+     * in the form of a List of PQS servers
      * @return - HostAndPort
      * @throws Exception
      */
@@ -112,9 +110,12 @@ public class LoadBalancer {
     }
 
     private List<HostAndPort> conductSanityCheckAndReturn() throws Exception{
-        Preconditions.checkNotNull(curaFramework
-                ," curator framework in not initialized ");
-        Preconditions.checkNotNull(cache," cache value is not initialized");
+        if (curaFramework == null) {
+            throw new NullPointerException(String.valueOf(" curator framework in not initialized "));
+        }
+        if (cache == null) {
+            throw new NullPointerException(String.valueOf(" cache value is not initialized"));
+        }
         boolean connected = curaFramework.getZookeeperClient().isConnected();
         if (!connected) {
             String message = " Zookeeper seems to be down. The data is stale ";
diff --git a/load-balancer/src/main/java/org/apache/phoenix/queryserver/register/ZookeeperRegistry.java b/load-balancer/src/main/java/org/apache/phoenix/queryserver/register/ZookeeperRegistry.java
index 7159e14..974be31 100644
--- a/load-balancer/src/main/java/org/apache/phoenix/queryserver/register/ZookeeperRegistry.java
+++ b/load-balancer/src/main/java/org/apache/phoenix/queryserver/register/ZookeeperRegistry.java
@@ -19,12 +19,12 @@
 package org.apache.phoenix.queryserver.register;
 
 
-import com.google.common.net.HostAndPort;
 import org.apache.curator.framework.CuratorFramework;
 import org.apache.curator.framework.CuratorFrameworkFactory;
 import org.apache.curator.retry.ExponentialBackoffRetry;
 import org.apache.curator.utils.CloseableUtils;
 import org.apache.phoenix.loadbalancer.service.LoadBalanceZookeeperConf;
+import org.apache.phoenix.util.HostAndPort;
 import org.apache.zookeeper.CreateMode;
 import org.apache.zookeeper.data.Stat;
 import org.slf4j.Logger;
diff --git a/pom.xml b/pom.xml
index 94258a1..274f522 100644
--- a/pom.xml
+++ b/pom.xml
@@ -79,7 +79,6 @@
         <curator.version>2.12.0</curator.version>
 
         <gson.version>2.2.4</gson.version>
-        <guava.version>13.0.1</guava.version>
         <jetty.version>9.4.27.v20200227</jetty.version>
         <commons-io.version>2.5</commons-io.version>
         <commons-collections.version>3.2.2</commons-collections.version>
@@ -87,6 +86,7 @@
         <slf4j.version>1.7.30</slf4j.version>
         <avatica.version>1.16.0</avatica.version>
         <servlet.api.version>3.1.0</servlet.api.version>
+        <jsr305.version>3.0.0</jsr305.version>
 
         <!-- Test Dependency versions -->
         <mockito-all.version>1.8.5</mockito-all.version>
@@ -409,9 +409,9 @@
               <version>${gson.version}</version>
             </dependency>
             <dependency>
-              <groupId>com.google.guava</groupId>
-              <artifactId>guava</artifactId>
-              <version>${guava.version}</version>
+              <groupId>com.google.code.findbugs</groupId>
+              <artifactId>jsr305</artifactId>
+              <version>${jsr305.version}</version>
             </dependency>
             <dependency>
               <groupId>org.eclipse.jetty</groupId>
diff --git a/queryserver-it/pom.xml b/queryserver-it/pom.xml
index fac2c54..e660c71 100644
--- a/queryserver-it/pom.xml
+++ b/queryserver-it/pom.xml
@@ -208,10 +208,5 @@
       <type>test-jar</type>
       <scope>test</scope>
      </dependency>
-     <dependency>
-       <groupId>com.google.guava</groupId>
-       <artifactId>guava</artifactId>
-       <scope>test</scope>
-     </dependency>
   </dependencies>
 </project>
diff --git a/queryserver-it/src/it/java/org/apache/phoenix/end2end/QueryServerEnvironment.java b/queryserver-it/src/it/java/org/apache/phoenix/end2end/QueryServerEnvironment.java
index 17c8856..0d1c55f 100644
--- a/queryserver-it/src/it/java/org/apache/phoenix/end2end/QueryServerEnvironment.java
+++ b/queryserver-it/src/it/java/org/apache/phoenix/end2end/QueryServerEnvironment.java
@@ -18,6 +18,7 @@ import java.io.IOException;
 import java.lang.reflect.Field;
 import java.net.InetAddress;
 import java.security.PrivilegedAction;
+import java.util.AbstractMap;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
@@ -48,9 +49,6 @@ import org.apache.phoenix.util.ThinClientUtil;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.google.common.base.Preconditions;
-import com.google.common.collect.Maps;
-
 /**
  * Due to this bug https://bugzilla.redhat.com/show_bug.cgi?id=668830 We need to use
  * `localhost.localdomain` as host name when running these tests on Jenkins (Centos) but for Mac OS
@@ -151,8 +149,10 @@ public class QueryServerEnvironment {
     }
 
     public Map.Entry<String, File> getUser(int offset) {
-        Preconditions.checkArgument(offset > 0 && offset <= NUM_CREATED_USERS);
-        return Maps.immutableEntry("user" + offset, USER_KEYTAB_FILES.get(offset - 1));
+        if (!(offset > 0 && offset <= NUM_CREATED_USERS)) {
+          throw new IllegalArgumentException();
+        }
+        return new AbstractMap.SimpleImmutableEntry<String, File>("user" + offset, USER_KEYTAB_FILES.get(offset - 1));
     }
 
     /**
diff --git a/queryserver-it/src/it/java/org/apache/phoenix/end2end/QueryServerTestUtil.java b/queryserver-it/src/it/java/org/apache/phoenix/end2end/QueryServerTestUtil.java
index e599c26..92977a0 100644
--- a/queryserver-it/src/it/java/org/apache/phoenix/end2end/QueryServerTestUtil.java
+++ b/queryserver-it/src/it/java/org/apache/phoenix/end2end/QueryServerTestUtil.java
@@ -37,8 +37,6 @@ import org.apache.phoenix.util.ThinClientUtil;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.google.common.base.Strings;
-
 public class QueryServerTestUtil {
     private static final Logger LOG = LoggerFactory.getLogger(QueryServerTestUtil.class);
 
@@ -101,7 +99,7 @@ public class QueryServerTestUtil {
     public void startQueryServer() throws Exception {
         setupQueryServerConfiguration(conf);
         executor = Executors.newSingleThreadExecutor();
-        if (!Strings.isNullOrEmpty(principal) && null != keytab) {
+        if (principal != null && !principal.isEmpty() && null != keytab) {
             // Get the PQS ident for PQS to use
             final UserGroupInformation ugi = UserGroupInformation
                     .loginUserFromKeytabAndReturnUGI(principal, keytab.getAbsolutePath());
diff --git a/queryserver-it/src/it/java/org/apache/phoenix/end2end/SecureQueryServerPhoenixDBIT.java b/queryserver-it/src/it/java/org/apache/phoenix/end2end/SecureQueryServerPhoenixDBIT.java
index b054105..495e5db 100644
--- a/queryserver-it/src/it/java/org/apache/phoenix/end2end/SecureQueryServerPhoenixDBIT.java
+++ b/queryserver-it/src/it/java/org/apache/phoenix/end2end/SecureQueryServerPhoenixDBIT.java
@@ -31,6 +31,7 @@ import java.io.Writer;
 import java.lang.reflect.Field;
 import java.nio.file.Paths;
 import java.security.PrivilegedAction;
+import java.util.AbstractMap;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
@@ -71,9 +72,6 @@ import org.junit.experimental.categories.Category;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.google.common.base.Preconditions;
-import com.google.common.collect.Maps;
-
 /**
  * This integration test stands up a secured PQS and runs Python code against it. See supporting
  * files in phoenix-queryserver/src/it/bin.
@@ -134,8 +132,10 @@ public class SecureQueryServerPhoenixDBIT {
     }
 
     private static Entry<String,File> getUser(int offset) {
-        Preconditions.checkArgument(offset > 0 && offset <= NUM_CREATED_USERS);
-        return Maps.immutableEntry("user" + offset, USER_KEYTAB_FILES.get(offset - 1));
+        if (!(offset > 0 && offset <= NUM_CREATED_USERS)) {
+          throw new IllegalArgumentException();
+        }
+        return new AbstractMap.SimpleImmutableEntry<String,File>("user" + offset, USER_KEYTAB_FILES.get(offset - 1));
     }
 
     /**
diff --git a/queryserver-orchestrator/pom.xml b/queryserver-orchestrator/pom.xml
index 852b010..5a3dbff 100644
--- a/queryserver-orchestrator/pom.xml
+++ b/queryserver-orchestrator/pom.xml
@@ -87,10 +87,6 @@
             <artifactId>hadoop-common</artifactId>
         </dependency>
         <dependency>
-            <groupId>com.google.guava</groupId>
-            <artifactId>guava</artifactId>
-        </dependency>
-        <dependency>
             <groupId>com.google.code.gson</groupId>
             <artifactId>gson</artifactId>
         </dependency>
diff --git a/queryserver-orchestrator/src/it/java/org/apache/phoenix/tool/ParameterizedPhoenixCanaryToolIT.java b/queryserver-orchestrator/src/it/java/org/apache/phoenix/tool/ParameterizedPhoenixCanaryToolIT.java
index 815cf67..7b7c02d 100644
--- a/queryserver-orchestrator/src/it/java/org/apache/phoenix/tool/ParameterizedPhoenixCanaryToolIT.java
+++ b/queryserver-orchestrator/src/it/java/org/apache/phoenix/tool/ParameterizedPhoenixCanaryToolIT.java
@@ -17,7 +17,6 @@
 */
 package org.apache.phoenix.tool;
 
-import com.google.common.collect.Maps;
 import com.google.gson.Gson;
 
 import org.apache.phoenix.end2end.NeedsOwnMiniClusterTest;
@@ -65,8 +64,8 @@ public class ParameterizedPhoenixCanaryToolIT extends BaseTest {
 	private static final String fileOutSink
 			= "org.apache.phoenix.tool.PhoenixCanaryTool$FileOutSink";
 
-	private static Map<String, String> serverProps = Maps.newHashMapWithExpectedSize(2);
-	private static Map<String, String> clientProps = Maps.newHashMapWithExpectedSize(2);
+	private static Map<String, String> serverProps = new HashMap<>(2);
+	private static Map<String, String> clientProps = new HashMap<>(2);
 	private static String connString = "";
 	private static Properties canaryProp = new Properties();
 	private static Connection connection = null;
diff --git a/queryserver-orchestrator/src/main/java/org/apache/phoenix/queryserver/orchestrator/TestExecutorClient.java b/queryserver-orchestrator/src/main/java/org/apache/phoenix/queryserver/orchestrator/TestExecutorClient.java
index d252ed2..22a8682 100644
--- a/queryserver-orchestrator/src/main/java/org/apache/phoenix/queryserver/orchestrator/TestExecutorClient.java
+++ b/queryserver-orchestrator/src/main/java/org/apache/phoenix/queryserver/orchestrator/TestExecutorClient.java
@@ -18,7 +18,6 @@
  */
 package org.apache.phoenix.queryserver.orchestrator;
 
-import com.google.common.annotations.VisibleForTesting;
 import org.apache.curator.framework.CuratorFramework;
 import org.apache.curator.framework.recipes.leader.CancelLeadershipException;
 import org.apache.curator.framework.recipes.leader.LeaderSelector;
@@ -110,7 +109,7 @@ public class TestExecutorClient extends LeaderSelectorListenerAdapter implements
         }
     }
 
-    @VisibleForTesting
+    //@VisibleForTesting
     public void executeQueryServerCanaryTool() {
         List<String> cmd = new ArrayList<>();
         for (Map.Entry<String, String> entry : params.entrySet()) {
diff --git a/queryserver-orchestrator/src/main/java/org/apache/phoenix/queryserver/orchestrator/ToolWrapper.java b/queryserver-orchestrator/src/main/java/org/apache/phoenix/queryserver/orchestrator/ToolWrapper.java
index 62e00a4..01f9dfc 100644
--- a/queryserver-orchestrator/src/main/java/org/apache/phoenix/queryserver/orchestrator/ToolWrapper.java
+++ b/queryserver-orchestrator/src/main/java/org/apache/phoenix/queryserver/orchestrator/ToolWrapper.java
@@ -18,7 +18,6 @@
  */
 package org.apache.phoenix.queryserver.orchestrator;
 
-import com.google.common.base.Joiner;
 import org.apache.phoenix.tool.PhoenixCanaryTool;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -37,7 +36,7 @@ public class ToolWrapper {
             LOGGER.error("Bad argument list passed to executeMain. Skipping QueryServerCanaryTool.");
             return;
         }
-        LOGGER.info("Passing args to QueryServerCanaryTool: " + Joiner.on(",").join(args));
+        LOGGER.info("Passing args to QueryServerCanaryTool: " + String.join(",",args));
         PhoenixCanaryTool.main(args);
     }
 }
diff --git a/queryserver-orchestrator/src/main/java/org/apache/phoenix/tool/PhoenixCanaryTool.java b/queryserver-orchestrator/src/main/java/org/apache/phoenix/tool/PhoenixCanaryTool.java
index a008799..5d346f4 100644
--- a/queryserver-orchestrator/src/main/java/org/apache/phoenix/tool/PhoenixCanaryTool.java
+++ b/queryserver-orchestrator/src/main/java/org/apache/phoenix/tool/PhoenixCanaryTool.java
@@ -17,15 +17,13 @@
  */
 package org.apache.phoenix.tool;
 
-import com.google.common.base.Throwables;
-import com.google.common.io.Files;
-import com.google.common.util.concurrent.SimpleTimeLimiter;
 import com.google.gson.Gson;
 import com.google.gson.GsonBuilder;
 import net.sourceforge.argparse4j.ArgumentParsers;
 import net.sourceforge.argparse4j.inf.ArgumentParser;
 import net.sourceforge.argparse4j.inf.ArgumentParserException;
 import net.sourceforge.argparse4j.inf.Namespace;
+
 import org.apache.hadoop.conf.Configured;
 import org.apache.hadoop.hbase.util.Bytes;
 import org.apache.hadoop.hbase.util.RetryCounter;
@@ -35,7 +33,10 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import java.io.File;
+import java.io.FileOutputStream;
 import java.io.InputStream;
+import java.io.PrintWriter;
+import java.io.StringWriter;
 import java.sql.Connection;
 import java.sql.DriverManager;
 import java.sql.PreparedStatement;
@@ -48,7 +49,11 @@ import java.util.Date;
 import java.util.List;
 import java.util.Properties;
 import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
 import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
 
 /**
  * A Canary Tool to perform synthetic tests for Phoenix
@@ -99,7 +104,7 @@ public class PhoenixCanaryTool extends Configured implements Tool {
                 result.setMessage("Test " + result.getTestName() + " successful");
             } catch (Exception e) {
                 result.setSuccessful(false);
-                result.setMessage(Throwables.getStackTraceAsString(e));
+                result.setMessage(getStackTrace(e));
             } finally {
                 onExit();
             }
@@ -226,7 +231,9 @@ public class PhoenixCanaryTool extends Configured implements Tool {
             String fileName = logfileName + "-" + new SimpleDateFormat("yyyy.MM.dd.HH" + ".mm" +
                     ".ss").format(new Date()) + ".log";
             File file = new File(dir, fileName);
-            Files.write(Bytes.toBytes(resultJson), file);
+            try (FileOutputStream fos = new FileOutputStream(file)) {
+                fos.write(Bytes.toBytes(resultJson));
+            }
         }
 
         @Override
@@ -330,9 +337,8 @@ public class PhoenixCanaryTool extends Configured implements Tool {
                 LOGGER.error("Failed to get connection after multiple retries; the connection is null");
             }
 
-            SimpleTimeLimiter limiter = new SimpleTimeLimiter();
-
-            limiter.callWithTimeout(new Callable<Void>() {
+            ExecutorService executor = Executors.newFixedThreadPool(1);
+            Future<Void> future = executor.submit(new Callable<Void>() {
 
                 public Void call() {
 
@@ -347,16 +353,22 @@ public class PhoenixCanaryTool extends Configured implements Tool {
                     return null;
 
                 }
-            }, timeoutVal, TimeUnit.SECONDS, true);
+            });
 
+            try {
+                future.get(timeoutVal, TimeUnit.SECONDS);
+            } catch (InterruptedException|TimeoutException e) {
+                future.cancel(true);
+                throw e;
+            }
             long estimatedTime = System.currentTimeMillis() - startTime;
 
             appInfo.setExecutionTime(estimatedTime);
             appInfo.setSuccessful(true);
 
         } catch (Exception e) {
-            LOGGER.error(Throwables.getStackTraceAsString(e));
-            appInfo.setMessage(Throwables.getStackTraceAsString(e));
+            LOGGER.error("error running tests", e);
+            appInfo.setMessage(getStackTrace(e));
             appInfo.setSuccessful(false);
 
         } finally {
@@ -368,6 +380,13 @@ public class PhoenixCanaryTool extends Configured implements Tool {
         return 0;
     }
 
+    private static String getStackTrace(Throwable t) {
+        StringWriter sw = new StringWriter();
+        PrintWriter pw = new PrintWriter(sw);
+        t.printStackTrace(pw);
+        return sw.toString();
+    }
+
     private Connection getConnectionWithRetry(String connectionURL) {
         Connection connection=null;
         try{
diff --git a/queryserver/pom.xml b/queryserver/pom.xml
index ba0d2c3..b0e7024 100644
--- a/queryserver/pom.xml
+++ b/queryserver/pom.xml
@@ -214,8 +214,8 @@
       <artifactId>commons-collections</artifactId>
     </dependency>
     <dependency>
-      <groupId>com.google.guava</groupId>
-      <artifactId>guava</artifactId>
+      <groupId>com.google.code.findbugs</groupId>
+      <artifactId>jsr305</artifactId>
     </dependency>
 
     <!-- for tests -->
diff --git a/queryserver/src/main/java/org/apache/phoenix/loadbalancer/service/LoadBalanceZookeeperConf.java b/queryserver/src/main/java/org/apache/phoenix/loadbalancer/service/LoadBalanceZookeeperConf.java
index afce5be..383c20a 100644
--- a/queryserver/src/main/java/org/apache/phoenix/loadbalancer/service/LoadBalanceZookeeperConf.java
+++ b/queryserver/src/main/java/org/apache/phoenix/loadbalancer/service/LoadBalanceZookeeperConf.java
@@ -18,7 +18,7 @@
  */
 package org.apache.phoenix.loadbalancer.service;
 
-import com.google.common.net.HostAndPort;
+import org.apache.phoenix.util.HostAndPort;
 import org.apache.zookeeper.data.ACL;
 
 import java.util.List;
diff --git a/queryserver/src/main/java/org/apache/phoenix/queryserver/server/PhoenixMetaFactoryImpl.java b/queryserver/src/main/java/org/apache/phoenix/queryserver/server/PhoenixMetaFactoryImpl.java
index 88c577f..bc41a77 100644
--- a/queryserver/src/main/java/org/apache/phoenix/queryserver/server/PhoenixMetaFactoryImpl.java
+++ b/queryserver/src/main/java/org/apache/phoenix/queryserver/server/PhoenixMetaFactoryImpl.java
@@ -31,8 +31,6 @@ import org.apache.hadoop.hbase.HConstants;
 import org.apache.phoenix.queryserver.QueryServerOptions;
 import org.apache.phoenix.queryserver.QueryServerProperties;
 
-import com.google.common.base.Preconditions;
-
 /**
  * Bridge between Phoenix and Avatica.
  */
@@ -51,7 +49,10 @@ public class PhoenixMetaFactoryImpl extends Configured implements PhoenixMetaFac
 
   @Override
   public Meta create(List<String> args) {
-    Configuration conf = Preconditions.checkNotNull(getConf(), "Configuration must not be null.");
+    Configuration conf = getConf();
+    if (conf == null) {
+      throw new NullPointerException(String.valueOf("Configuration must not be null."));
+    }
     Properties info = new Properties();
     info.putAll(conf.getValByRegex("avatica.*"));
     try {
@@ -110,7 +111,9 @@ public class PhoenixMetaFactoryImpl extends Configured implements PhoenixMetaFac
 
   private int getInt(String key, int defaultValue, Properties props, Configuration conf) {
     if (conf == null) {
-      Preconditions.checkNotNull(props);
+      if (props == null) {
+        throw new NullPointerException();
+      }
       return Integer.parseInt(props.getProperty(key, String.valueOf(defaultValue)));
     }
     return conf.getInt(key, defaultValue);
@@ -118,8 +121,10 @@ public class PhoenixMetaFactoryImpl extends Configured implements PhoenixMetaFac
 
   private String getString(String key, String defaultValue, Properties props, Configuration conf) {
       if (conf == null) {
-          Preconditions.checkNotNull(props);
-          return props.getProperty(key, defaultValue);
+        if (props == null) {
+          throw new NullPointerException();
+        }
+        return props.getProperty(key, defaultValue);
       }
       return conf.get(key, defaultValue);
   }
diff --git a/queryserver/src/main/java/org/apache/phoenix/queryserver/server/QueryServer.java b/queryserver/src/main/java/org/apache/phoenix/queryserver/server/QueryServer.java
index 1b29415..b50a44f 100644
--- a/queryserver/src/main/java/org/apache/phoenix/queryserver/server/QueryServer.java
+++ b/queryserver/src/main/java/org/apache/phoenix/queryserver/server/QueryServer.java
@@ -17,12 +17,6 @@
  */
 package org.apache.phoenix.queryserver.server;
 
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Preconditions;
-import com.google.common.cache.CacheBuilder;
-import com.google.common.cache.CacheLoader;
-import com.google.common.cache.LoadingCache;
-
 import org.apache.calcite.avatica.Meta;
 import org.apache.calcite.avatica.remote.Driver;
 import org.apache.calcite.avatica.remote.LocalService;
@@ -53,6 +47,7 @@ import org.apache.phoenix.queryserver.QueryServerOptions;
 import org.apache.phoenix.queryserver.QueryServerProperties;
 import org.apache.phoenix.queryserver.register.Registry;
 import org.apache.phoenix.util.InstanceResolver;
+import org.apache.phoenix.util.SimpleLRUCache;
 import org.eclipse.jetty.server.Server;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -156,7 +151,7 @@ public final class QueryServer extends Configured implements Tool, Runnable {
   /**
    * @return the port number this instance is bound to, or {@code -1} if the server is not running.
    */
-  @VisibleForTesting
+  //@VisibleForTesting
   public int getPort() {
     if (server == null) return -1;
     return server.getPort();
@@ -165,7 +160,7 @@ public final class QueryServer extends Configured implements Tool, Runnable {
   /**
    * @return the return code from running as a {@link Tool}.
    */
-  @VisibleForTesting
+  //@VisibleForTesting
   public int getRetCode() {
     return retCode;
   }
@@ -173,7 +168,7 @@ public final class QueryServer extends Configured implements Tool, Runnable {
   /**
    * @return the throwable from an unsuccessful run, or null otherwise.
    */
-  @VisibleForTesting
+  //@VisibleForTesting
   public Throwable getThrowable() {
     return t;
   }
@@ -295,7 +290,7 @@ public final class QueryServer extends Configured implements Tool, Runnable {
     }
 }
 
-@VisibleForTesting
+  //@VisibleForTesting
   void configureClientAuthentication(final HttpServer.Builder builder, boolean disableSpnego, UserGroupInformation ugi) throws IOException {
 
     // Enable SPNEGO for client authentication unless it's explicitly disabled
@@ -305,7 +300,7 @@ public final class QueryServer extends Configured implements Tool, Runnable {
     configureCallBack(builder, ugi);
   }
 
-  @VisibleForTesting
+  //@VisibleForTesting
   void configureSpnegoAuthentication(HttpServer.Builder builder, UserGroupInformation ugi) throws IOException {
     String keytabPath = getConf().get(QueryServerProperties.QUERY_SERVER_KEYTAB_FILENAME_ATTRIB);
     File keytab = new File(keytabPath);
@@ -350,7 +345,7 @@ public final class QueryServer extends Configured implements Tool, Runnable {
     return SecurityUtil.getServerPrincipal(httpPrincipal, hostname);
   }
 
-  @VisibleForTesting
+  //@VisibleForTesting
   UserGroupInformation getUserGroupInformation() throws IOException {
     UserGroupInformation ugi = UserGroupInformation.getCurrentUser();
     LOG.debug("Current user is " + ugi);
@@ -361,7 +356,7 @@ public final class QueryServer extends Configured implements Tool, Runnable {
     return ugi;
   }
 
-  @VisibleForTesting
+  //@VisibleForTesting
   void configureCallBack(HttpServer.Builder<Server> builder, UserGroupInformation ugi) {
     builder.withImpersonation(new PhoenixDoAsCallback(ugi, getConf()));
   }
@@ -386,9 +381,14 @@ public final class QueryServer extends Configured implements Tool, Runnable {
     boolean success = true ;
     try {
       LoadBalanceZookeeperConf loadBalanceConfiguration = getLoadBalanceConfiguration();
-      Preconditions.checkNotNull(loadBalanceConfiguration);
+      if (loadBalanceConfiguration == null) {
+        throw new NullPointerException();
+      }
       this.registry = getRegistry();
-      Preconditions.checkNotNull(registry);
+
+      if (registry == null) {
+        throw new NullPointerException();
+      }
       String zkConnectString = loadBalanceConfiguration.getZkConnectString();
       this.registry.registerServer(loadBalanceConfiguration, getPort(), zkConnectString, hostName);
     } catch(Throwable ex){
@@ -464,7 +464,7 @@ public final class QueryServer extends Configured implements Tool, Runnable {
   }
 
   // add remoteUserExtractor to builder if enabled
-  @VisibleForTesting
+  //@VisibleForTesting
   public void setRemoteUserExtractorIfNecessary(HttpServer.Builder builder, Configuration conf) {
     if (conf.getBoolean(QueryServerProperties.QUERY_SERVER_WITH_REMOTEUSEREXTRACTOR_ATTRIB,
             QueryServerOptions.DEFAULT_QUERY_SERVER_WITH_REMOTEUSEREXTRACTOR)) {
@@ -472,7 +472,7 @@ public final class QueryServer extends Configured implements Tool, Runnable {
     }
   }
 
-  @VisibleForTesting
+  //@VisibleForTesting
   public void enableServerCustomizersIfNecessary(HttpServer.Builder<Server> builder,
                                                  Configuration conf, AvaticaServerConfiguration avaticaServerConfiguration) {
     // Always try to enable the "provided" ServerCustomizers. The expectation is that the Factory implementation
@@ -483,7 +483,7 @@ public final class QueryServer extends Configured implements Tool, Runnable {
     }
   }
 
-  @VisibleForTesting
+  //@VisibleForTesting
   public AvaticaServerConfiguration enableCustomAuth(HttpServer.Builder<Server> builder,
                                                      Configuration conf, UserGroupInformation ugi) {
     AvaticaServerConfiguration avaticaServerConfiguration = createAvaticaServerConfig(conf, ugi);
@@ -500,21 +500,21 @@ public final class QueryServer extends Configured implements Tool, Runnable {
   private static final AvaticaServerConfigurationFactory DEFAULT_SERVER_CONFIG =
     new AvaticaServerConfigurationFactory.AvaticaServerConfigurationFactoryImpl();
 
-  @VisibleForTesting
+  //@VisibleForTesting
   RemoteUserExtractor createRemoteUserExtractor(Configuration conf) {
     RemoteUserExtractorFactory factory =
         InstanceResolver.getSingleton(RemoteUserExtractorFactory.class, DEFAULT_USER_EXTRACTOR);
     return factory.createRemoteUserExtractor(conf);
   }
 
-  @VisibleForTesting
+  //@VisibleForTesting
   List<ServerCustomizer<Server>> createServerCustomizers(Configuration conf, AvaticaServerConfiguration avaticaServerConfiguration) {
     ServerCustomizersFactory factory =
       InstanceResolver.getSingleton(ServerCustomizersFactory.class, DEFAULT_SERVER_CUSTOMIZERS);
     return factory.createServerCustomizers(conf, avaticaServerConfiguration);
   }
 
-  @VisibleForTesting
+  //@VisibleForTesting
   AvaticaServerConfiguration createAvaticaServerConfig(Configuration conf, UserGroupInformation ugi) {
     AvaticaServerConfigurationFactory factory =
             InstanceResolver.getSingleton(AvaticaServerConfigurationFactory.class, DEFAULT_SERVER_CONFIG);
@@ -566,18 +566,15 @@ public final class QueryServer extends Configured implements Tool, Runnable {
    */
   public static class PhoenixDoAsCallback implements DoAsRemoteUserCallback {
     private final UserGroupInformation serverUgi;
-    private final LoadingCache<String,UserGroupInformation> ugiCache;
+    private final SimpleLRUCache<String,UserGroupInformation> ugiCache;
 
     public PhoenixDoAsCallback(UserGroupInformation serverUgi, Configuration conf) {
       this.serverUgi = Objects.requireNonNull(serverUgi);
-      this.ugiCache = CacheBuilder.newBuilder()
-          .initialCapacity(conf.getInt(QueryServerProperties.QUERY_SERVER_UGI_CACHE_INITIAL_SIZE,
-                  QueryServerOptions.DEFAULT_QUERY_SERVER_UGI_CACHE_INITIAL_SIZE))
-          .concurrencyLevel(conf.getInt(QueryServerProperties.QUERY_SERVER_UGI_CACHE_CONCURRENCY,
-                  QueryServerOptions.DEFAULT_QUERY_SERVER_UGI_CACHE_CONCURRENCY))
-          .maximumSize(conf.getLong(QueryServerProperties.QUERY_SERVER_UGI_CACHE_MAX_SIZE,
-                  QueryServerOptions.DEFAULT_QUERY_SERVER_UGI_CACHE_MAX_SIZE))
-          .build(new UgiCacheLoader(this.serverUgi));
+      this.ugiCache = new SimpleLRUCache<String,UserGroupInformation>(
+              conf.getLong(QueryServerProperties.QUERY_SERVER_UGI_CACHE_MAX_SIZE,
+                  QueryServerOptions.DEFAULT_QUERY_SERVER_UGI_CACHE_MAX_SIZE),
+              conf.getInt(QueryServerProperties.QUERY_SERVER_UGI_CACHE_CONCURRENCY,
+                  QueryServerOptions.DEFAULT_QUERY_SERVER_UGI_CACHE_CONCURRENCY));
     }
 
     @Override
@@ -600,37 +597,21 @@ public final class QueryServer extends Configured implements Tool, Runnable {
       });
     }
 
-      @VisibleForTesting
+      //@VisibleForTesting
       UserGroupInformation createProxyUser(String remoteUserName) throws ExecutionException {
           // PHOENIX-3164 UGI's hashCode and equals methods rely on reference checks, not
           // value-based checks. We need to make sure we return the same UGI instance for a remote
           // user, otherwise downstream code in Phoenix and HBase may not treat two of the same
           // calls from one user as equivalent.
-          return ugiCache.get(remoteUserName);
+          return ugiCache.computeIfAbsent(remoteUserName, f -> UserGroupInformation.createProxyUser(f, serverUgi));
       }
 
-      @VisibleForTesting
-      LoadingCache<String,UserGroupInformation> getCache() {
+      //@VisibleForTesting
+      SimpleLRUCache<String,UserGroupInformation> getCache() {
           return ugiCache;
       }
   }
 
-  /**
-   * CacheLoader implementation which creates a "proxy" UGI instance for the given user name.
-   */
-  static class UgiCacheLoader extends CacheLoader<String,UserGroupInformation> {
-      private final UserGroupInformation serverUgi;
-
-      public UgiCacheLoader(UserGroupInformation serverUgi) {
-          this.serverUgi = Objects.requireNonNull(serverUgi);
-      }
-
-      @Override
-      public UserGroupInformation load(String remoteUserName) throws Exception {
-          return UserGroupInformation.createProxyUser(remoteUserName, serverUgi);
-      }
-  }
-
   public static void main(String[] argv) throws Exception {
     int ret = ToolRunner.run(HBaseConfiguration.create(), new QueryServer(), argv);
     System.exit(ret);
diff --git a/queryserver/src/main/java/org/apache/phoenix/util/HostAndPort.java b/queryserver/src/main/java/org/apache/phoenix/util/HostAndPort.java
new file mode 100644
index 0000000..e01a005
--- /dev/null
+++ b/queryserver/src/main/java/org/apache/phoenix/util/HostAndPort.java
@@ -0,0 +1,287 @@
+/*
+ * Copyright (C) 2011 The Guava Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.phoenix.util;
+
+import java.io.Serializable;
+import java.util.Objects;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import javax.annotation.concurrent.Immutable;
+
+/**
+ * This class has been copied from Guava 13.0.1, and modified so that it works without the rest
+ * of Guava.
+ *
+ * An immutable representation of a host and port.
+ *
+ * <p>Example usage:
+ * <pre>
+ * HostAndPort hp = HostAndPort.fromString("[2001:db8::1]")
+ *     .withDefaultPort(80)
+ *     .requireBracketsForIPv6();
+ * hp.getHostText();  // returns "2001:db8::1"
+ * hp.getPort();      // returns 80
+ * hp.toString();     // returns "[2001:db8::1]:80"
+ * </pre>
+ *
+ * <p>Here are some examples of recognized formats:
+ * <ul>
+ *   <li>example.com
+ *   <li>example.com:80
+ *   <li>192.0.2.1
+ *   <li>192.0.2.1:80
+ *   <li>[2001:db8::1]     - {@link #getHostText()} omits brackets
+ *   <li>[2001:db8::1]:80  - {@link #getHostText()} omits brackets
+ *   <li>2001:db8::1       - Use {@link #requireBracketsForIPv6()} to prohibit this
+ * </ul>
+ *
+ * <p>Note that this is not an exhaustive list, because these methods are only
+ * concerned with brackets, colons, and port numbers.  Full validation of the
+ * host field (if desired) is the caller's responsibility.
+ *
+ * @author Paul Marks
+ * @since 10.0
+ */
+@Immutable
+public final class HostAndPort implements Serializable {
+  /** Magic value indicating the absence of a port number. */
+  private static final int NO_PORT = -1;
+
+  /** Hostname, IPv4/IPv6 literal, or unvalidated nonsense. */
+  private final String host;
+
+  /** Validated port number in the range [0..65535], or NO_PORT */
+  private final int port;
+
+  /** True if the parsed host has colons, but no surrounding brackets. */
+  private final boolean hasBracketlessColons;
+
+  private HostAndPort(String host, int port, boolean hasBracketlessColons) {
+    this.host = host;
+    this.port = port;
+    this.hasBracketlessColons = hasBracketlessColons;
+  }
+
+  /**
+   * Returns the portion of this {@code HostAndPort} instance that should
+   * represent the hostname or IPv4/IPv6 literal.
+   *
+   * A successful parse does not imply any degree of sanity in this field.
+   * For additional validation, see the HostSpecifier class.
+   */
+  public String getHostText() {
+    return host;
+  }
+
+  /** Return true if this instance has a defined port. */
+  public boolean hasPort() {
+    return port >= 0;
+  }
+
+  /**
+   * Get the current port number, failing if no port is defined.
+   *
+   * @return a validated port number, in the range [0..65535]
+   * @throws IllegalStateException if no port is defined.  You can use
+   *         {@link #withDefaultPort(int)} to prevent this from occurring.
+   */
+  public int getPort() {
+    if (!hasPort()) {
+      throw new IllegalStateException();
+    }
+    return port;
+  }
+
+  /**
+   * Returns the current port number, with a default if no port is defined.
+   */
+  public int getPortOrDefault(int defaultPort) {
+    return hasPort() ? port : defaultPort;
+  }
+
+  /**
+   * Build a HostAndPort instance from separate host and port values.
+   *
+   * <p>Note: Non-bracketed IPv6 literals are allowed.
+   * Use {@link #requireBracketsForIPv6()} to prohibit these.
+   *
+   * @param host the host string to parse.  Must not contain a port number.
+   * @param port a port number from [0..65535]
+   * @return if parsing was successful, a populated HostAndPort object.
+   * @throws IllegalArgumentException if {@code host} contains a port number,
+   *     or {@code port} is out of range.
+   */
+  public static HostAndPort fromParts(String host, int port) {
+    if (!isValidPort(port)) {
+      throw new IllegalArgumentException();
+    }
+    HostAndPort parsedHost = fromString(host);
+    if (parsedHost.hasPort()) {
+      throw new IllegalArgumentException();
+    }
+    return new HostAndPort(parsedHost.host, port, parsedHost.hasBracketlessColons);
+  }
+
+  private static final Pattern BRACKET_PATTERN = Pattern.compile("^\\[(.*:.*)\\](?::(\\d*))?$");
+
+  /**
+   * Split a freeform string into a host and port, without strict validation.
+   *
+   * Note that the host-only formats will leave the port field undefined.  You
+   * can use {@link #withDefaultPort(int)} to patch in a default value.
+   *
+   * @param hostPortString the input string to parse.
+   * @return if parsing was successful, a populated HostAndPort object.
+   * @throws IllegalArgumentException if nothing meaningful could be parsed.
+   */
+  public static HostAndPort fromString(String hostPortString) {
+    if(hostPortString == null) {
+        throw new NullPointerException();
+    }
+    String host;
+    String portString = null;
+    boolean hasBracketlessColons = false;
+
+    if (hostPortString.startsWith("[")) {
+      // Parse a bracketed host, typically an IPv6 literal.
+      Matcher matcher = BRACKET_PATTERN.matcher(hostPortString);
+      if (!matcher.matches()) {
+        throw new IllegalArgumentException(
+          String.format("Invalid bracketed host/port: %s", hostPortString));
+      }
+      host = matcher.group(1);
+      portString = matcher.group(2);  // could be null
+    } else {
+      int colonPos = hostPortString.indexOf(':');
+      if (colonPos >= 0 && hostPortString.indexOf(':', colonPos + 1) == -1) {
+        // Exactly 1 colon.  Split into host:port.
+        host = hostPortString.substring(0, colonPos);
+        portString = hostPortString.substring(colonPos + 1);
+      } else {
+        // 0 or 2+ colons.  Bare hostname or IPv6 literal.
+        host = hostPortString;
+        hasBracketlessColons = (colonPos >= 0);
+      }
+    }
+
+    int port = NO_PORT;
+    if (portString != null) {
+      // Try to parse the whole port string as a number.
+      // JDK7 accepts leading plus signs. We don't want to.
+      if (!!portString.startsWith("+")) {
+        throw new IllegalArgumentException(
+          String.format("Unparseable port number: %s", hostPortString));
+      }
+      try {
+        port = Integer.parseInt(portString);
+      } catch (NumberFormatException e) {
+        throw new IllegalArgumentException("Unparseable port number: " + hostPortString);
+      }
+      if (!isValidPort(port)) {
+        throw new IllegalArgumentException(
+          String.format("Port number out of range: %s", hostPortString));
+      }
+    }
+
+    return new HostAndPort(host, port, hasBracketlessColons);
+  }
+
+  /**
+   * Provide a default port if the parsed string contained only a host.
+   *
+   * You can chain this after {@link #fromString(String)} to include a port in
+   * case the port was omitted from the input string.  If a port was already
+   * provided, then this method is a no-op.
+   *
+   * @param defaultPort a port number, from [0..65535]
+   * @return a HostAndPort instance, guaranteed to have a defined port.
+   */
+  public HostAndPort withDefaultPort(int defaultPort) {
+    if (!isValidPort(defaultPort)) {
+      throw new IllegalArgumentException();
+    }
+    if (hasPort() || port == defaultPort) {
+      return this;
+    }
+    return new HostAndPort(host, defaultPort, hasBracketlessColons);
+  }
+
+  /**
+   * Generate an error if the host might be a non-bracketed IPv6 literal.
+   *
+   * <p>URI formatting requires that IPv6 literals be surrounded by brackets,
+   * like "[2001:db8::1]".  Chain this call after {@link #fromString(String)}
+   * to increase the strictness of the parser, and disallow IPv6 literals
+   * that don't contain these brackets.
+   *
+   * <p>Note that this parser identifies IPv6 literals solely based on the
+   * presence of a colon.  To perform actual validation of IP addresses, see
+   * the InetAddresses#forString(String) method.
+   *
+   * @return {@code this}, to enable chaining of calls.
+   * @throws IllegalArgumentException if bracketless IPv6 is detected.
+   */
+  public HostAndPort requireBracketsForIPv6() {
+    if (hasBracketlessColons) {
+      throw new IllegalArgumentException(
+        String.format("Possible bracketless IPv6 literal: %s", host));
+    }
+    return this;
+  }
+
+  @Override
+  public boolean equals(Object other) {
+    if (this == other) {
+      return true;
+    }
+    if (other instanceof HostAndPort) {
+      HostAndPort that = (HostAndPort) other;
+      return Objects.equals(this.host, that.host)
+          && this.port == that.port
+          && this.hasBracketlessColons == that.hasBracketlessColons;
+    }
+    return false;
+  }
+
+  @Override
+  public int hashCode() {
+    return Objects.hash(host, port, hasBracketlessColons);
+  }
+
+  /** Rebuild the host:port string, including brackets if necessary. */
+  @Override
+  public String toString() {
+    StringBuilder builder = new StringBuilder(host.length() + 7);
+    if (host.indexOf(':') >= 0) {
+      builder.append('[').append(host).append(']');
+    } else {
+      builder.append(host);
+    }
+    if (hasPort()) {
+      builder.append(':').append(port);
+    }
+    return builder.toString();
+  }
+
+  /** Return true for valid port numbers. */
+  private static boolean isValidPort(int port) {
+    return port >= 0 && port <= 65535;
+  }
+
+  private static final long serialVersionUID = 0;
+}
diff --git a/queryserver/src/main/java/org/apache/phoenix/util/InstanceResolver.java b/queryserver/src/main/java/org/apache/phoenix/util/InstanceResolver.java
index 4757e46..8a84a92 100644
--- a/queryserver/src/main/java/org/apache/phoenix/util/InstanceResolver.java
+++ b/queryserver/src/main/java/org/apache/phoenix/util/InstanceResolver.java
@@ -19,8 +19,6 @@ package org.apache.phoenix.util;
 
 import org.apache.commons.collections.IteratorUtils;
 
-import com.google.common.annotations.VisibleForTesting;
-
 import java.util.Iterator;
 import java.util.List;
 import java.util.ServiceLoader;
@@ -88,7 +86,7 @@ public class InstanceResolver {
         return defaultInstance;
     }
 
-    @VisibleForTesting
+    //@VisibleForTesting
     public static void clearSingletons() {
         RESOLVED_SINGLETONS.clear();
     }
diff --git a/queryserver/src/main/java/org/apache/phoenix/util/SimpleLRUCache.java b/queryserver/src/main/java/org/apache/phoenix/util/SimpleLRUCache.java
new file mode 100644
index 0000000..97e47f3
--- /dev/null
+++ b/queryserver/src/main/java/org/apache/phoenix/util/SimpleLRUCache.java
@@ -0,0 +1,96 @@
+/*
+ * 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.phoenix.util;
+
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.TreeSet;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * Minimal Cache implementation based on ConcurrentHashMap.
+ *
+ * The maxSize logic will only work if all access is via the the computeIfAbsent() method.
+ *
+ */
+public class SimpleLRUCache <K extends Comparable, V> extends ConcurrentHashMap<K,V> {
+
+    protected static final Logger LOG = LoggerFactory.getLogger(SimpleLRUCache.class);
+
+    int maxSize;
+    int triggerSize;
+
+    private ConcurrentHashMap<K, AtomicLong> accessed =
+            new ConcurrentHashMap<>();
+
+    public SimpleLRUCache (long maxSize, int concurrencyLevel) {
+        super((int)(maxSize * 1.1), (float)0.75, concurrencyLevel);
+        this.maxSize = (int)maxSize;
+        this.triggerSize = (int)(maxSize * 1.1)+1 ;
+    }
+
+    @Override
+    public V computeIfAbsent(K key, Function<? super K,? extends V> mappingFunction) {
+        V value = super.computeIfAbsent(key, mappingFunction);
+        if (value != null) {
+            accessed.put(key, new AtomicLong(System.currentTimeMillis()));
+            if (this.size() > triggerSize) {
+                evict();
+            }
+        }
+        return value;
+    }
+
+    private void evict() {
+        synchronized(this) {
+            int currentSize = this.size();
+            if (currentSize <= triggerSize) {
+                return;
+            }
+            LOG.warn("UGI Cache capacity exceeded, you may want to increase its size");
+            TreeSet<Entry<K, AtomicLong>> sortedByLRU = new TreeSet<>(
+                    new Comparator<Entry<K, AtomicLong>>() {
+                        @Override
+                        public int compare(Entry<K, AtomicLong> o1, Entry<K, AtomicLong> o2) {
+                            int keyResult =
+                                    Long.compare(o2.getValue().get(), o1.getValue().get());
+                            if(keyResult == 0) {
+                                return o2.getKey().compareTo(o1.getKey());
+                            } else {
+                                return keyResult;
+                            }
+                        }
+                    });
+            sortedByLRU.addAll(accessed.entrySet());
+            Entry<Object, AtomicLong>[] toRetain =
+                    Arrays.copyOfRange(sortedByLRU.toArray(new Entry[currentSize]), 0, maxSize);
+            java.util.List<Object> retainList =
+                    Arrays.stream(toRetain).map( f -> f.getKey()).collect(Collectors.toList());
+            this.keySet().retainAll(retainList);
+            accessed.keySet().retainAll(this.keySet());
+        }
+    }
+
+}
diff --git a/queryserver/src/test/java/org/apache/phoenix/queryserver/util/SimpleLRUCacheTest.java b/queryserver/src/test/java/org/apache/phoenix/queryserver/util/SimpleLRUCacheTest.java
new file mode 100644
index 0000000..e1e6d88
--- /dev/null
+++ b/queryserver/src/test/java/org/apache/phoenix/queryserver/util/SimpleLRUCacheTest.java
@@ -0,0 +1,58 @@
+/*
+ * 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.phoenix.queryserver.util;
+
+import static org.junit.Assert.assertTrue;
+
+import org.apache.phoenix.util.SimpleLRUCache;
+import org.junit.Test;
+
+public class SimpleLRUCacheTest {
+
+    @Test
+    public void testCache() throws InterruptedException {
+        SimpleLRUCache<String, String> cache = new SimpleLRUCache<>(10, 1);
+
+        String zero = access(cache, "0");
+        //Make sure we actually cache objects
+        assertTrue(zero  == access(cache, "0"));
+
+        for(int c=1; c<9; c++) {
+            access(cache, Integer.toString(c));
+            Thread.sleep(5);
+        }
+
+        //Access these to make sure that they don't get evicted.
+        String one = access(cache, "1");
+        String two = access(cache, "2");
+
+        for(int c=10; c<13; c++) {
+            access(cache, Integer.toString(c));
+            Thread.sleep(5);
+        }
+
+        assertTrue(one == access(cache, one));
+        assertTrue(two == access(cache, two));
+
+        assertTrue(cache.size() <= 12);
+    }
+
+    private String access(SimpleLRUCache<String, String> cache, String key) {
+        return cache.computeIfAbsent(key, k -> new String(key));
+    }
+}