incubator-blur-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From amccu...@apache.org
Subject [2/2] git commit: Adding thrift request caching, this should help with performance where the same requests are being made over and over.
Date Thu, 26 Feb 2015 16:09:17 GMT
Adding thrift request caching, this should help with performance where the same requests are being made over and over.


Project: http://git-wip-us.apache.org/repos/asf/incubator-blur/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-blur/commit/06c929b9
Tree: http://git-wip-us.apache.org/repos/asf/incubator-blur/tree/06c929b9
Diff: http://git-wip-us.apache.org/repos/asf/incubator-blur/diff/06c929b9

Branch: refs/heads/master
Commit: 06c929b966cb3d4217a6d5a9b1bdfffc04e8d75a
Parents: 56bb87b
Author: Aaron McCurry <amccurry@gmail.com>
Authored: Thu Feb 26 11:09:10 2015 -0500
Committer: Aaron McCurry <amccurry@gmail.com>
Committed: Thu Feb 26 11:09:10 2015 -0500

----------------------------------------------------------------------
 .../AbstractDistributedIndexServer.java         |   4 +
 .../indexserver/DistributedIndexServer.java     |  17 +-
 .../manager/indexserver/LocalIndexServer.java   |   2 +-
 .../apache/blur/manager/writer/BlurIndex.java   |   4 +-
 .../blur/manager/writer/BlurIndexReadOnly.java  |   2 +-
 .../manager/writer/BlurIndexSimpleWriter.java   |  11 +-
 .../org/apache/blur/server/TableContext.java    |   9 +-
 .../apache/blur/server/cache/ThriftCache.java   | 128 +++++
 .../blur/server/cache/ThriftCacheKey.java       | 110 ++++
 .../blur/server/cache/ThriftCacheServer.java    | 133 +++++
 .../blur/server/cache/ThriftCacheValue.java     |  78 +++
 .../blur/thrift/ThriftBlurControllerServer.java |   4 +
 .../blur/thrift/ThriftBlurShardServer.java      |  23 +-
 .../blur/command/ShardCommandManagerTest.java   |   2 +-
 .../writer/BlurIndexSimpleWriterTest.java       |   3 +-
 .../blur/manager/writer/IndexImporterTest.java  |   2 +-
 .../blur/server/cache/ThriftCacheKeyTest.java   | 135 +++++
 .../server/cache/ThriftCacheServerTest.java     | 531 +++++++++++++++++++
 .../blur/server/cache/ThriftCacheTest.java      |  80 +++
 .../blur/server/cache/ThriftCacheValueTest.java |  43 ++
 .../apache/blur/metrics/MetricsConstants.java   |   2 +
 .../org/apache/blur/utils/BlurConstants.java    |   2 +
 .../src/main/resources/blur-default.properties  |   6 +
 23 files changed, 1311 insertions(+), 20 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/06c929b9/blur-core/src/main/java/org/apache/blur/manager/indexserver/AbstractDistributedIndexServer.java
----------------------------------------------------------------------
diff --git a/blur-core/src/main/java/org/apache/blur/manager/indexserver/AbstractDistributedIndexServer.java b/blur-core/src/main/java/org/apache/blur/manager/indexserver/AbstractDistributedIndexServer.java
index d1e7500..50bb8db 100644
--- a/blur-core/src/main/java/org/apache/blur/manager/indexserver/AbstractDistributedIndexServer.java
+++ b/blur-core/src/main/java/org/apache/blur/manager/indexserver/AbstractDistributedIndexServer.java
@@ -20,6 +20,7 @@ import static org.apache.blur.metrics.MetricsConstants.BLUR;
 import static org.apache.blur.metrics.MetricsConstants.INDEX_COUNT;
 import static org.apache.blur.metrics.MetricsConstants.INDEX_MEMORY_USAGE;
 import static org.apache.blur.metrics.MetricsConstants.ORG_APACHE_BLUR;
+import static org.apache.blur.metrics.MetricsConstants.RECORD_COUNT;
 import static org.apache.blur.metrics.MetricsConstants.SEGMENT_COUNT;
 import static org.apache.blur.metrics.MetricsConstants.TABLE_COUNT;
 
@@ -48,6 +49,7 @@ public abstract class AbstractDistributedIndexServer extends AbstractIndexServer
   protected final AtomicLong _indexCount = new AtomicLong();
   protected final AtomicLong _segmentCount = new AtomicLong();
   protected final AtomicLong _indexMemoryUsage = new AtomicLong();
+  protected final AtomicLong _recordCount = new AtomicLong();
 
   public AbstractDistributedIndexServer(ClusterStatus clusterStatus, Configuration configuration, String nodeName,
       String cluster) {
@@ -59,11 +61,13 @@ public abstract class AbstractDistributedIndexServer extends AbstractIndexServer
     MetricName indexCount = new MetricName(ORG_APACHE_BLUR, BLUR, INDEX_COUNT, _cluster);
     MetricName segmentCount = new MetricName(ORG_APACHE_BLUR, BLUR, SEGMENT_COUNT, _cluster);
     MetricName indexMemoryUsage = new MetricName(ORG_APACHE_BLUR, BLUR, INDEX_MEMORY_USAGE, _cluster);
+    MetricName recordCount = new MetricName(ORG_APACHE_BLUR, BLUR, RECORD_COUNT, _cluster);
 
     Metrics.newGauge(tableCount, new AtomicLongGauge(_tableCount));
     Metrics.newGauge(indexCount, new AtomicLongGauge(_indexCount));
     Metrics.newGauge(segmentCount, new AtomicLongGauge(_segmentCount));
     Metrics.newGauge(indexMemoryUsage, new AtomicLongGauge(_indexMemoryUsage));
+    Metrics.newGauge(recordCount, new AtomicLongGauge(_recordCount));
   }
 
   @Override

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/06c929b9/blur-core/src/main/java/org/apache/blur/manager/indexserver/DistributedIndexServer.java
----------------------------------------------------------------------
diff --git a/blur-core/src/main/java/org/apache/blur/manager/indexserver/DistributedIndexServer.java b/blur-core/src/main/java/org/apache/blur/manager/indexserver/DistributedIndexServer.java
index 324090f..efeb051 100644
--- a/blur-core/src/main/java/org/apache/blur/manager/indexserver/DistributedIndexServer.java
+++ b/blur-core/src/main/java/org/apache/blur/manager/indexserver/DistributedIndexServer.java
@@ -49,6 +49,7 @@ import org.apache.blur.manager.writer.BlurIndexReadOnly;
 import org.apache.blur.manager.writer.SharedMergeScheduler;
 import org.apache.blur.server.ShardContext;
 import org.apache.blur.server.TableContext;
+import org.apache.blur.server.cache.ThriftCache;
 import org.apache.blur.store.BlockCacheDirectoryFactory;
 import org.apache.blur.store.hdfs.BlurLockFactory;
 import org.apache.blur.store.hdfs.HdfsDirectory;
@@ -117,13 +118,15 @@ public class DistributedIndexServer extends AbstractDistributedIndexServer {
   private final Timer _hdfsKeyValueTimer;
   private final Timer _indexImporterTimer;
   private final Timer _indexBulkTimer;
+  private final ThriftCache _thriftCache;
 
   public DistributedIndexServer(Configuration configuration, ZooKeeper zookeeper, ClusterStatus clusterStatus,
       BlurFilterCache filterCache, BlockCacheDirectoryFactory blockCacheDirectoryFactory,
       DistributedLayoutFactory distributedLayoutFactory, String cluster, String nodeName, long safeModeDelay,
       int shardOpenerThreadCount, int maxMergeThreads, int internalSearchThreads,
       int minimumNumberOfNodesBeforeExitingSafeMode, Timer hdfsKeyValueTimer, Timer indexImporterTimer,
-      long smallMergeThreshold, Timer indexBulkTimer) throws KeeperException, InterruptedException {
+      long smallMergeThreshold, Timer indexBulkTimer, ThriftCache thriftCache) throws KeeperException,
+      InterruptedException {
     super(clusterStatus, configuration, nodeName, cluster);
     _indexImporterTimer = indexImporterTimer;
     _indexBulkTimer = indexBulkTimer;
@@ -138,6 +141,7 @@ public class DistributedIndexServer extends AbstractDistributedIndexServer {
     _internalSearchThreads = internalSearchThreads;
     _blockCacheDirectoryFactory = blockCacheDirectoryFactory;
     _distributedLayoutFactory = distributedLayoutFactory;
+    _thriftCache = thriftCache;
 
     _closer.register(_shardStateManager);
 
@@ -380,12 +384,13 @@ public class DistributedIndexServer extends AbstractDistributedIndexServer {
       long indexCount = 0;
       AtomicLong segmentCount = new AtomicLong();
       AtomicLong indexMemoryUsage = new AtomicLong();
+      AtomicLong recordCount = new AtomicLong();
       for (String table : tableList) {
         try {
           Map<String, BlurIndex> indexes = getIndexes(table);
           int count = indexes.size();
           indexCount += count;
-          updateMetrics(indexes, segmentCount, indexMemoryUsage);
+          updateMetrics(indexes, segmentCount, indexMemoryUsage, recordCount);
           LOG.debug("Table [{0}] has [{1}] number of shards online in this node.", table, count);
         } catch (IOException e) {
           LOG.error("Unknown error trying to warm table [{0}]", e, table);
@@ -394,14 +399,16 @@ public class DistributedIndexServer extends AbstractDistributedIndexServer {
       _indexCount.set(indexCount);
       _segmentCount.set(segmentCount.get());
       _indexMemoryUsage.set(indexMemoryUsage.get());
+      _recordCount.set(recordCount.get());
     }
   }
 
-  private void updateMetrics(Map<String, BlurIndex> indexes, AtomicLong segmentCount, AtomicLong indexMemoryUsage)
-      throws IOException {
+  private void updateMetrics(Map<String, BlurIndex> indexes, AtomicLong segmentCount, AtomicLong indexMemoryUsage,
+      AtomicLong recordCount) throws IOException {
     for (BlurIndex index : indexes.values()) {
       indexMemoryUsage.addAndGet(index.getIndexMemoryUsage());
       segmentCount.addAndGet(index.getSegmentCount());
+      recordCount.addAndGet(index.getRecordCount());
     }
   }
 
@@ -522,7 +529,7 @@ public class DistributedIndexServer extends AbstractDistributedIndexServer {
     }
 
     BlurIndex index = tableContext.newInstanceBlurIndex(shardContext, directory, _mergeScheduler, _searchExecutor,
-        _indexCloser, _indexImporterTimer, _indexBulkTimer);
+        _indexCloser, _indexImporterTimer, _indexBulkTimer, _thriftCache);
 
     if (_clusterStatus.isReadOnly(true, _cluster, table)) {
       index = new BlurIndexReadOnly(index);

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/06c929b9/blur-core/src/main/java/org/apache/blur/manager/indexserver/LocalIndexServer.java
----------------------------------------------------------------------
diff --git a/blur-core/src/main/java/org/apache/blur/manager/indexserver/LocalIndexServer.java b/blur-core/src/main/java/org/apache/blur/manager/indexserver/LocalIndexServer.java
index a8cbb23..ba7987b 100644
--- a/blur-core/src/main/java/org/apache/blur/manager/indexserver/LocalIndexServer.java
+++ b/blur-core/src/main/java/org/apache/blur/manager/indexserver/LocalIndexServer.java
@@ -168,7 +168,7 @@ public class LocalIndexServer extends AbstractIndexServer {
   private BlurIndex openIndex(String table, String shard, Directory dir) throws CorruptIndexException, IOException {
     ShardContext shardContext = ShardContext.create(_tableContext, shard);
     BlurIndexSimpleWriter index = new BlurIndexSimpleWriter(shardContext, dir, _mergeScheduler, _searchExecutor,
-        _indexCloser, _timer, _bulkTimer);
+        _indexCloser, _timer, _bulkTimer, null);
     return index;
   }
 

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/06c929b9/blur-core/src/main/java/org/apache/blur/manager/writer/BlurIndex.java
----------------------------------------------------------------------
diff --git a/blur-core/src/main/java/org/apache/blur/manager/writer/BlurIndex.java b/blur-core/src/main/java/org/apache/blur/manager/writer/BlurIndex.java
index dd92fc7..cf1865f 100644
--- a/blur-core/src/main/java/org/apache/blur/manager/writer/BlurIndex.java
+++ b/blur-core/src/main/java/org/apache/blur/manager/writer/BlurIndex.java
@@ -25,6 +25,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
 
 import org.apache.blur.lucene.search.IndexSearcherCloseable;
 import org.apache.blur.server.ShardContext;
+import org.apache.blur.server.cache.ThriftCache;
 import org.apache.blur.thrift.generated.RowMutation;
 import org.apache.blur.utils.BlurUtil;
 import org.apache.lucene.index.IndexReader;
@@ -41,7 +42,8 @@ public abstract class BlurIndex {
   protected ShardContext _shardContext;
 
   public BlurIndex(ShardContext shardContext, Directory directory, SharedMergeScheduler mergeScheduler,
-      ExecutorService searchExecutor, BlurIndexCloser indexCloser, Timer indexImporterTimer, Timer bulkIndexingTimer) throws IOException {
+      ExecutorService searchExecutor, BlurIndexCloser indexCloser, Timer indexImporterTimer, Timer bulkIndexingTimer,
+      ThriftCache thriftCache) throws IOException {
     _shardContext = shardContext;
   }
 

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/06c929b9/blur-core/src/main/java/org/apache/blur/manager/writer/BlurIndexReadOnly.java
----------------------------------------------------------------------
diff --git a/blur-core/src/main/java/org/apache/blur/manager/writer/BlurIndexReadOnly.java b/blur-core/src/main/java/org/apache/blur/manager/writer/BlurIndexReadOnly.java
index 4145a3d..aca14c9 100644
--- a/blur-core/src/main/java/org/apache/blur/manager/writer/BlurIndexReadOnly.java
+++ b/blur-core/src/main/java/org/apache/blur/manager/writer/BlurIndexReadOnly.java
@@ -28,7 +28,7 @@ public class BlurIndexReadOnly extends BlurIndex {
   private final BlurIndex _blurIndex;
 
   public BlurIndexReadOnly(BlurIndex blurIndex) throws IOException {
-    super(null, null, null, null, null, null, null);
+    super(null, null, null, null, null, null, null, null);
     _blurIndex = blurIndex;
   }
 

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/06c929b9/blur-core/src/main/java/org/apache/blur/manager/writer/BlurIndexSimpleWriter.java
----------------------------------------------------------------------
diff --git a/blur-core/src/main/java/org/apache/blur/manager/writer/BlurIndexSimpleWriter.java b/blur-core/src/main/java/org/apache/blur/manager/writer/BlurIndexSimpleWriter.java
index 3536f20..0bbcd54 100644
--- a/blur-core/src/main/java/org/apache/blur/manager/writer/BlurIndexSimpleWriter.java
+++ b/blur-core/src/main/java/org/apache/blur/manager/writer/BlurIndexSimpleWriter.java
@@ -60,6 +60,7 @@ import org.apache.blur.server.IndexSearcherCloseableBase;
 import org.apache.blur.server.IndexSearcherCloseableSecureBase;
 import org.apache.blur.server.ShardContext;
 import org.apache.blur.server.TableContext;
+import org.apache.blur.server.cache.ThriftCache;
 import org.apache.blur.thrift.generated.BlurException;
 import org.apache.blur.thrift.generated.RowMutation;
 import org.apache.blur.thrift.generated.TableDescriptor;
@@ -135,6 +136,7 @@ public class BlurIndexSimpleWriter extends BlurIndex {
   private final Splitter _commaSplitter;
   private final Timer _bulkIndexingTimer;
   private final TimerTask _watchForIdleBulkWriters;
+  private final ThriftCache _thriftCache;
 
   private Thread _optimizeThread;
   private Thread _writerOpener;
@@ -142,8 +144,10 @@ public class BlurIndexSimpleWriter extends BlurIndex {
 
   public BlurIndexSimpleWriter(ShardContext shardContext, Directory directory, SharedMergeScheduler mergeScheduler,
       final ExecutorService searchExecutor, BlurIndexCloser indexCloser, Timer indexImporterTimer,
-      Timer bulkIndexingTimer) throws IOException {
-    super(shardContext, directory, mergeScheduler, searchExecutor, indexCloser, indexImporterTimer, bulkIndexingTimer);
+      Timer bulkIndexingTimer, ThriftCache thriftCache) throws IOException {
+    super(shardContext, directory, mergeScheduler, searchExecutor, indexCloser, indexImporterTimer, bulkIndexingTimer,
+        thriftCache);
+    _thriftCache = thriftCache;
     _commaSplitter = Splitter.on(',');
     _bulkWriters = new ConcurrentHashMap<String, BlurIndexSimpleWriter.BulkEntry>();
     _indexImporterTimer = indexImporterTimer;
@@ -515,6 +519,9 @@ public class BlurIndexSimpleWriter extends BlurIndex {
       indexAction.doPostRollback(writer);
       throw new IOException("Unknown error during mutation", e);
     } finally {
+      if (_thriftCache != null) {
+        _thriftCache.clearTable(_tableContext.getTable());
+      }
       if (indexSearcher != null) {
         indexSearcher.close();
       }

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/06c929b9/blur-core/src/main/java/org/apache/blur/server/TableContext.java
----------------------------------------------------------------------
diff --git a/blur-core/src/main/java/org/apache/blur/server/TableContext.java b/blur-core/src/main/java/org/apache/blur/server/TableContext.java
index d30955c..7f98a77 100644
--- a/blur-core/src/main/java/org/apache/blur/server/TableContext.java
+++ b/blur-core/src/main/java/org/apache/blur/server/TableContext.java
@@ -57,6 +57,7 @@ import org.apache.blur.manager.writer.BlurIndexCloser;
 import org.apache.blur.manager.writer.BlurIndexSimpleWriter;
 //import org.apache.blur.manager.writer.BlurNRTIndex;
 import org.apache.blur.manager.writer.SharedMergeScheduler;
+import org.apache.blur.server.cache.ThriftCache;
 import org.apache.blur.store.hdfs.HdfsDirectory;
 import org.apache.blur.thrift.generated.Blur.Iface;
 import org.apache.blur.thrift.generated.ScoreType;
@@ -358,8 +359,8 @@ public class TableContext implements Cloneable {
 
   @SuppressWarnings("unchecked")
   public BlurIndex newInstanceBlurIndex(ShardContext shardContext, Directory dir, SharedMergeScheduler mergeScheduler,
-      ExecutorService searchExecutor, BlurIndexCloser indexCloser, Timer indexImporterTimer, Timer bulkTimer)
-      throws IOException {
+      ExecutorService searchExecutor, BlurIndexCloser indexCloser, Timer indexImporterTimer, Timer bulkTimer,
+      ThriftCache thriftCache) throws IOException {
 
     String className = _blurConfiguration.get(BLUR_SHARD_BLURINDEX_CLASS, BlurIndexSimpleWriter.class.getName());
 
@@ -372,7 +373,7 @@ public class TableContext implements Cloneable {
     Constructor<? extends BlurIndex> constructor = findConstructor(clazz);
     try {
       return constructor.newInstance(shardContext, dir, mergeScheduler, searchExecutor, indexCloser,
-          indexImporterTimer, bulkTimer);
+          indexImporterTimer, bulkTimer, thriftCache);
     } catch (InstantiationException e) {
       throw new IOException(e);
     } catch (IllegalAccessException e) {
@@ -387,7 +388,7 @@ public class TableContext implements Cloneable {
   private Constructor<? extends BlurIndex> findConstructor(Class<? extends BlurIndex> clazz) throws IOException {
     try {
       return clazz.getConstructor(new Class[] { ShardContext.class, Directory.class, SharedMergeScheduler.class,
-          ExecutorService.class, BlurIndexCloser.class, Timer.class, Timer.class });
+          ExecutorService.class, BlurIndexCloser.class, Timer.class, Timer.class, ThriftCache.class });
     } catch (NoSuchMethodException e) {
       throw new IOException(e);
     } catch (SecurityException e) {

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/06c929b9/blur-core/src/main/java/org/apache/blur/server/cache/ThriftCache.java
----------------------------------------------------------------------
diff --git a/blur-core/src/main/java/org/apache/blur/server/cache/ThriftCache.java b/blur-core/src/main/java/org/apache/blur/server/cache/ThriftCache.java
new file mode 100644
index 0000000..f3940fb
--- /dev/null
+++ b/blur-core/src/main/java/org/apache/blur/server/cache/ThriftCache.java
@@ -0,0 +1,128 @@
+/**
+ * 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.blur.server.cache;
+
+import static org.apache.blur.metrics.MetricsConstants.EVICTION;
+import static org.apache.blur.metrics.MetricsConstants.HIT;
+import static org.apache.blur.metrics.MetricsConstants.MISS;
+import static org.apache.blur.metrics.MetricsConstants.ORG_APACHE_BLUR;
+import static org.apache.blur.metrics.MetricsConstants.THRIFT_CACHE;
+
+import java.util.Iterator;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.blur.log.Log;
+import org.apache.blur.log.LogFactory;
+import org.apache.blur.thirdparty.thrift_0_9_0.TBase;
+import org.apache.blur.thrift.generated.BlurException;
+import org.apache.blur.user.User;
+import org.apache.blur.user.UserContext;
+
+import com.googlecode.concurrentlinkedhashmap.ConcurrentLinkedHashMap;
+import com.googlecode.concurrentlinkedhashmap.EvictionListener;
+import com.googlecode.concurrentlinkedhashmap.Weigher;
+import com.yammer.metrics.Metrics;
+import com.yammer.metrics.core.Meter;
+import com.yammer.metrics.core.MetricName;
+
+public class ThriftCache {
+
+  private static final Log LOG = LogFactory.getLog(ThriftCache.class);
+
+  private final ConcurrentLinkedHashMap<ThriftCacheKey<?>, ThriftCacheValue<?>> _cacheMap;
+  private final Meter _hits;
+  private final Meter _misses;
+  private final Meter _evictions;
+
+  public ThriftCache(long totalNumberOfBytes) {
+    _hits = Metrics.newMeter(new MetricName(ORG_APACHE_BLUR, THRIFT_CACHE, HIT), HIT, TimeUnit.SECONDS);
+    _misses = Metrics.newMeter(new MetricName(ORG_APACHE_BLUR, THRIFT_CACHE, MISS), MISS, TimeUnit.SECONDS);
+    _evictions = Metrics.newMeter(new MetricName(ORG_APACHE_BLUR, THRIFT_CACHE, EVICTION), EVICTION, TimeUnit.SECONDS);
+    _cacheMap = new ConcurrentLinkedHashMap.Builder<ThriftCacheKey<?>, ThriftCacheValue<?>>()
+        .weigher(new Weigher<ThriftCacheValue<?>>() {
+          @Override
+          public int weightOf(ThriftCacheValue<?> value) {
+            return value.size();
+          }
+        }).listener(new EvictionListener<ThriftCacheKey<?>, ThriftCacheValue<?>>() {
+          @Override
+          public void onEviction(ThriftCacheKey<?> key, ThriftCacheValue<?> value) {
+            _evictions.mark();
+          }
+        }).maximumWeightedCapacity(totalNumberOfBytes).build();
+  }
+
+  public <K extends TBase<?, ?>, V extends TBase<?, ?>> V put(ThriftCacheKey<K> key, V t) throws BlurException {
+    _cacheMap.put(key, new ThriftCacheValue<V>(t));
+    return t;
+  }
+
+  @SuppressWarnings("unchecked")
+  public <K extends TBase<?, ?>, V extends TBase<?, ?>> V get(ThriftCacheKey<K> key, Class<V> clazz)
+      throws BlurException {
+    ThriftCacheValue<V> value = (ThriftCacheValue<V>) _cacheMap.get(key);
+    if (value == null) {
+      LOG.debug("Cache Miss for [{0}]", key);
+      _misses.mark();
+      return null;
+    }
+    LOG.debug("Cache Hit for [{0}]", key);
+    _hits.mark();
+    return value.getValue(clazz);
+  }
+
+  public <K extends TBase<?, ?>> ThriftCacheKey<K> getKey(String table, K tkey, Class<K> clazz) {
+    User user = UserContext.getUser();
+    return new ThriftCacheKey<K>(user, table, tkey, clazz);
+  }
+
+  public void clear() {
+    LOG.info("Clearing all cache.");
+    _cacheMap.clear();
+  }
+
+  public void clearTable(String table) {
+    LOG.info("Clearing cache for table [{0}]", table);
+    Set<Entry<ThriftCacheKey<?>, ThriftCacheValue<?>>> entrySet = _cacheMap.entrySet();
+    Iterator<Entry<ThriftCacheKey<?>, ThriftCacheValue<?>>> iterator = entrySet.iterator();
+    while (iterator.hasNext()) {
+      Entry<ThriftCacheKey<?>, ThriftCacheValue<?>> entry = iterator.next();
+      if (entry.getKey().getTable().equals(table)) {
+        iterator.remove();
+      }
+    }
+  }
+
+  public long size() {
+    return _cacheMap.weightedSize();
+  }
+
+  public Meter getHits() {
+    return _hits;
+  }
+
+  public Meter getMisses() {
+    return _misses;
+  }
+
+  public Meter getEvictions() {
+    return _evictions;
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/06c929b9/blur-core/src/main/java/org/apache/blur/server/cache/ThriftCacheKey.java
----------------------------------------------------------------------
diff --git a/blur-core/src/main/java/org/apache/blur/server/cache/ThriftCacheKey.java b/blur-core/src/main/java/org/apache/blur/server/cache/ThriftCacheKey.java
new file mode 100644
index 0000000..790533b
--- /dev/null
+++ b/blur-core/src/main/java/org/apache/blur/server/cache/ThriftCacheKey.java
@@ -0,0 +1,110 @@
+/**
+ * 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.blur.server.cache;
+
+import java.util.Map;
+import java.util.TreeMap;
+
+import org.apache.blur.thirdparty.thrift_0_9_0.TBase;
+import org.apache.blur.user.User;
+
+public class ThriftCacheKey<T extends TBase<?, ?>> {
+
+  private final String _username;
+  private final Map<String, String> _attributes;
+  private final String _table;
+  private final T _t;
+  private final String _clazz;
+
+  public ThriftCacheKey(User user, String table, T t, Class<T> clazz) {
+    _clazz = clazz.getName();
+    if (user != null) {
+      _username = user.getUsername();
+      Map<String, String> attributes = user.getAttributes();
+      if (attributes == null) {
+        _attributes = attributes;
+      } else {
+        _attributes = new TreeMap<String, String>(user.getAttributes());
+      }
+    } else {
+      _username = null;
+      _attributes = null;
+    }
+    _table = table;
+    _t = t;
+  }
+
+  public String getTable() {
+    return _table;
+  }
+
+  @Override
+  public int hashCode() {
+    final int prime = 31;
+    int result = 1;
+    result = prime * result + ((_attributes == null) ? 0 : _attributes.hashCode());
+    result = prime * result + ((_clazz == null) ? 0 : _clazz.hashCode());
+    result = prime * result + ((_t == null) ? 0 : _t.hashCode());
+    result = prime * result + ((_table == null) ? 0 : _table.hashCode());
+    result = prime * result + ((_username == null) ? 0 : _username.hashCode());
+    return result;
+  }
+
+  @Override
+  public boolean equals(Object obj) {
+    if (this == obj)
+      return true;
+    if (obj == null)
+      return false;
+    if (getClass() != obj.getClass())
+      return false;
+    ThriftCacheKey<?> other = (ThriftCacheKey<?>) obj;
+    if (_attributes == null) {
+      if (other._attributes != null)
+        return false;
+    } else if (!_attributes.equals(other._attributes))
+      return false;
+    if (_clazz == null) {
+      if (other._clazz != null)
+        return false;
+    } else if (!_clazz.equals(other._clazz))
+      return false;
+    if (_t == null) {
+      if (other._t != null)
+        return false;
+    } else if (!_t.equals(other._t))
+      return false;
+    if (_table == null) {
+      if (other._table != null)
+        return false;
+    } else if (!_table.equals(other._table))
+      return false;
+    if (_username == null) {
+      if (other._username != null)
+        return false;
+    } else if (!_username.equals(other._username))
+      return false;
+    return true;
+  }
+
+  @Override
+  public String toString() {
+    return "ThriftCacheKey [_username=" + _username + ", _attributes=" + _attributes + ", _table=" + _table + ", _t="
+        + _t + ", _clazz=" + _clazz + "]";
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/06c929b9/blur-core/src/main/java/org/apache/blur/server/cache/ThriftCacheServer.java
----------------------------------------------------------------------
diff --git a/blur-core/src/main/java/org/apache/blur/server/cache/ThriftCacheServer.java b/blur-core/src/main/java/org/apache/blur/server/cache/ThriftCacheServer.java
new file mode 100644
index 0000000..dbd395f
--- /dev/null
+++ b/blur-core/src/main/java/org/apache/blur/server/cache/ThriftCacheServer.java
@@ -0,0 +1,133 @@
+/**
+ * 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.blur.server.cache;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+
+import org.apache.blur.BlurConfiguration;
+import org.apache.blur.server.FilteredBlurServer;
+import org.apache.blur.thirdparty.thrift_0_9_0.TException;
+import org.apache.blur.thrift.generated.Blur.Iface;
+import org.apache.blur.thrift.generated.BlurException;
+import org.apache.blur.thrift.generated.BlurQuery;
+import org.apache.blur.thrift.generated.BlurResults;
+import org.apache.blur.thrift.generated.FetchResult;
+import org.apache.blur.thrift.generated.Selector;
+import org.apache.blur.thrift.generated.TableStats;
+
+public class ThriftCacheServer extends FilteredBlurServer {
+
+  private final ThriftCache _thriftCache;
+
+  public ThriftCacheServer(BlurConfiguration configuration, Iface iface, ThriftCache thriftCache) {
+    super(configuration, iface, true);
+    _thriftCache = thriftCache;
+  }
+
+  @Override
+  public TableStats tableStats(String table) throws BlurException, TException {
+    ThriftCacheKey<TableStats> key = _thriftCache.getKey(table, null, TableStats.class);
+    TableStats results = _thriftCache.get(key, TableStats.class);
+    if (results != null) {
+      return results;
+    }
+    return _thriftCache.put(key, super.tableStats(table));
+  }
+
+  @Override
+  public BlurResults query(String table, BlurQuery blurQuery) throws BlurException, TException {
+    boolean useCacheIfPresent = blurQuery.isUseCacheIfPresent();
+    boolean cacheResult = blurQuery.isCacheResult();
+    BlurQuery copy = new BlurQuery(blurQuery);
+    // These are the fields that play no part in the actual results returned.
+    // So we are going to normalize the values so that we can reuse the cache
+    // results.
+    copy.useCacheIfPresent = false;
+    copy.maxQueryTime = 0;
+    copy.uuid = null;
+    copy.userContext = null;
+    copy.cacheResult = false;
+    copy.startTime = 0;
+    ThriftCacheKey<BlurQuery> key = _thriftCache.getKey(table, copy, BlurQuery.class);
+    BlurResults results = _thriftCache.get(key, BlurResults.class);
+    if (results != null && useCacheIfPresent) {
+      return results;
+    }
+    BlurResults blurResults = super.query(table, blurQuery);
+    if (cacheResult) {
+      return _thriftCache.put(key, blurResults);  
+    }
+    return blurResults;
+  }
+
+  @Override
+  public FetchResult fetchRow(String table, Selector selector) throws BlurException, TException {
+    Selector copy = new Selector(selector);
+    ThriftCacheKey<Selector> key = _thriftCache.getKey(table, copy, Selector.class);
+    FetchResult results = _thriftCache.get(key, FetchResult.class);
+    if (results != null) {
+      return results;
+    }
+    return _thriftCache.put(key, super.fetchRow(table, selector));
+  }
+
+  @Override
+  public List<FetchResult> fetchRowBatch(String table, List<Selector> selectors) throws BlurException, TException {
+    Map<Integer, FetchResult> resultMap = new TreeMap<Integer, FetchResult>();
+
+    // Maps cache miss request list index to original request list.
+    Map<Integer, Integer> requestMapping = new HashMap<Integer, Integer>();
+    List<Selector> selectorRequest = new ArrayList<Selector>();
+
+    // Gather hits that are already in cache.
+    for (int i = 0; i < selectors.size(); i++) {
+      Selector selector = selectors.get(i);
+      Selector copy = new Selector(selector);
+      ThriftCacheKey<Selector> key = _thriftCache.getKey(table, copy, Selector.class);
+      FetchResult fetchResult = _thriftCache.get(key, FetchResult.class);
+      if (fetchResult != null) {
+        resultMap.put(i, fetchResult);
+      } else {
+        int index = selectorRequest.size();
+        requestMapping.put(index, i);
+        selectorRequest.add(selector);
+      }
+    }
+
+    if (selectorRequest.size() != 0) {
+      List<FetchResult> missingResults = super.fetchRowBatch(table, selectorRequest);
+      for (int i = 0; i < missingResults.size(); i++) {
+        Selector selector = selectorRequest.get(i);
+        FetchResult fetchResult = missingResults.get(i);
+        ThriftCacheKey<Selector> key = _thriftCache.getKey(table, new Selector(selector), Selector.class);
+        _thriftCache.put(key, fetchResult);
+        int originalIndex = requestMapping.get(i);
+        resultMap.put(originalIndex, fetchResult);
+      }
+    }
+    return toList(resultMap);
+  }
+
+  private List<FetchResult> toList(Map<Integer, FetchResult> resultMap) {
+    return new ArrayList<FetchResult>(resultMap.values());
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/06c929b9/blur-core/src/main/java/org/apache/blur/server/cache/ThriftCacheValue.java
----------------------------------------------------------------------
diff --git a/blur-core/src/main/java/org/apache/blur/server/cache/ThriftCacheValue.java b/blur-core/src/main/java/org/apache/blur/server/cache/ThriftCacheValue.java
new file mode 100644
index 0000000..7d259f4
--- /dev/null
+++ b/blur-core/src/main/java/org/apache/blur/server/cache/ThriftCacheValue.java
@@ -0,0 +1,78 @@
+/**
+ * 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.blur.server.cache;
+
+import org.apache.blur.thirdparty.thrift_0_9_0.TBase;
+import org.apache.blur.thirdparty.thrift_0_9_0.TException;
+import org.apache.blur.thirdparty.thrift_0_9_0.protocol.TCompactProtocol;
+import org.apache.blur.thirdparty.thrift_0_9_0.transport.TMemoryBuffer;
+import org.apache.blur.thirdparty.thrift_0_9_0.transport.TMemoryInputTransport;
+import org.apache.blur.thrift.BException;
+import org.apache.blur.thrift.generated.BlurException;
+
+public class ThriftCacheValue<T extends TBase<?, ?>> {
+
+  private final byte[] _data;
+
+  public ThriftCacheValue(T t) throws BlurException {
+    if (t == null) {
+      _data = null;
+    } else {
+      TMemoryBuffer transport = new TMemoryBuffer(1024);
+      try {
+        t.write(new TCompactProtocol(transport));
+      } catch (TException e) {
+        throw new BException("Unknown error while trying to read from cache.", e);
+      }
+      _data = trim(transport.getArray(), transport.length());
+    }
+  }
+
+  private byte[] trim(byte[] bs, int len) {
+    if (bs.length == len) {
+      return bs;
+    }
+    byte[] buf = new byte[len];
+    System.arraycopy(bs, 0, buf, 0, len);
+    return buf;
+  }
+
+  public int size() {
+    if (_data == null) {
+      // Cache weight has to have a weight of at least 1.
+      return 1;
+    }
+    return _data.length;
+  }
+
+  public T getValue(Class<T> clazz) throws BlurException {
+    if (_data == null) {
+      return null;
+    }
+    try {
+      T t = clazz.newInstance();
+      t.read(new TCompactProtocol(new TMemoryInputTransport(_data)));
+      return t;
+    } catch (InstantiationException e) {
+      throw new BException("Unknown error while trying to read from cache.", e);
+    } catch (IllegalAccessException e) {
+      throw new BException("Unknown error while trying to read from cache.", e);
+    } catch (TException e) {
+      throw new BException("Unknown error while trying to read from cache.", e);
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/06c929b9/blur-core/src/main/java/org/apache/blur/thrift/ThriftBlurControllerServer.java
----------------------------------------------------------------------
diff --git a/blur-core/src/main/java/org/apache/blur/thrift/ThriftBlurControllerServer.java b/blur-core/src/main/java/org/apache/blur/thrift/ThriftBlurControllerServer.java
index 1e328ef..3279d0c 100644
--- a/blur-core/src/main/java/org/apache/blur/thrift/ThriftBlurControllerServer.java
+++ b/blur-core/src/main/java/org/apache/blur/thrift/ThriftBlurControllerServer.java
@@ -38,6 +38,7 @@ import static org.apache.blur.utils.BlurConstants.BLUR_CONTROLLER_SHARD_CONNECTI
 import static org.apache.blur.utils.BlurConstants.BLUR_CONTROLLER_THRIFT_ACCEPT_QUEUE_SIZE_PER_THREAD;
 import static org.apache.blur.utils.BlurConstants.BLUR_CONTROLLER_THRIFT_MAX_READ_BUFFER_BYTES;
 import static org.apache.blur.utils.BlurConstants.BLUR_CONTROLLER_THRIFT_SELECTOR_THREADS;
+import static org.apache.blur.utils.BlurConstants.BLUR_GC_BACK_PRESSURE_HEAP_RATIO;
 import static org.apache.blur.utils.BlurConstants.BLUR_GUI_CONTROLLER_PORT;
 import static org.apache.blur.utils.BlurConstants.BLUR_HTTP_STATUS_RUNNING_PORT;
 import static org.apache.blur.utils.BlurConstants.BLUR_MAX_RECORDS_PER_ROW_FETCH_REQUEST;
@@ -76,6 +77,7 @@ import org.apache.blur.thrift.generated.Blur.Iface;
 import org.apache.blur.trace.Trace;
 import org.apache.blur.trace.TraceStorage;
 import org.apache.blur.utils.BlurUtil;
+import org.apache.blur.utils.GCWatcher;
 import org.apache.blur.utils.MemoryReporter;
 import org.apache.blur.zookeeper.ZkUtils;
 import org.apache.hadoop.conf.Configuration;
@@ -96,6 +98,8 @@ public class ThriftBlurControllerServer extends ThriftServer {
       ReporterSetup.setupReporters(configuration);
       MemoryReporter.enable();
       setupJvmMetrics();
+      double ratio = configuration.getDouble(BLUR_GC_BACK_PRESSURE_HEAP_RATIO, 0.75);
+      GCWatcher.init(ratio);
       ThriftServer server = createServer(serverIndex, configuration);
       server.start();
     } catch (Throwable t) {

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/06c929b9/blur-core/src/main/java/org/apache/blur/thrift/ThriftBlurShardServer.java
----------------------------------------------------------------------
diff --git a/blur-core/src/main/java/org/apache/blur/thrift/ThriftBlurShardServer.java b/blur-core/src/main/java/org/apache/blur/thrift/ThriftBlurShardServer.java
index b504f5d..4df1656 100644
--- a/blur-core/src/main/java/org/apache/blur/thrift/ThriftBlurShardServer.java
+++ b/blur-core/src/main/java/org/apache/blur/thrift/ThriftBlurShardServer.java
@@ -20,6 +20,7 @@ import static org.apache.blur.utils.BlurConstants.BLUR_CLUSTER;
 import static org.apache.blur.utils.BlurConstants.BLUR_CLUSTER_NAME;
 import static org.apache.blur.utils.BlurConstants.BLUR_COMMAND_LIB_PATH;
 import static org.apache.blur.utils.BlurConstants.BLUR_CONTROLLER_REMOTE_FETCH_COUNT;
+import static org.apache.blur.utils.BlurConstants.BLUR_GC_BACK_PRESSURE_HEAP_RATIO;
 import static org.apache.blur.utils.BlurConstants.BLUR_GUI_SHARD_PORT;
 import static org.apache.blur.utils.BlurConstants.BLUR_HTTP_STATUS_RUNNING_PORT;
 import static org.apache.blur.utils.BlurConstants.BLUR_INDEXMANAGER_FACET_THREAD_COUNT;
@@ -41,6 +42,7 @@ import static org.apache.blur.utils.BlurConstants.BLUR_SHARD_HOSTNAME;
 import static org.apache.blur.utils.BlurConstants.BLUR_SHARD_INTERNAL_SEARCH_THREAD_COUNT;
 import static org.apache.blur.utils.BlurConstants.BLUR_SHARD_MERGE_THREAD_COUNT;
 import static org.apache.blur.utils.BlurConstants.BLUR_SHARD_OPENER_THREAD_COUNT;
+import static org.apache.blur.utils.BlurConstants.BLUR_SHARD_REQUEST_CACHE_SIZE;
 import static org.apache.blur.utils.BlurConstants.BLUR_SHARD_SAFEMODEDELAY;
 import static org.apache.blur.utils.BlurConstants.BLUR_SHARD_SERVER_MINIMUM_BEFORE_SAFEMODE_EXIT;
 import static org.apache.blur.utils.BlurConstants.BLUR_SHARD_SERVER_THRIFT_THREAD_COUNT;
@@ -77,6 +79,7 @@ import org.apache.blur.manager.BlurFilterCache;
 import org.apache.blur.manager.BlurQueryChecker;
 import org.apache.blur.manager.DefaultBlurFilterCache;
 import org.apache.blur.manager.IndexManager;
+import org.apache.blur.manager.clusterstatus.ClusterStatus.Action;
 import org.apache.blur.manager.clusterstatus.ZookeeperClusterStatus;
 import org.apache.blur.manager.indexserver.BlurServerShutDown;
 import org.apache.blur.manager.indexserver.BlurServerShutDown.BlurShutdown;
@@ -90,6 +93,8 @@ import org.apache.blur.server.ServerSecurityFilterFactory;
 import org.apache.blur.server.ServerSecurityUtil;
 import org.apache.blur.server.ShardServerEventHandler;
 import org.apache.blur.server.TableContext;
+import org.apache.blur.server.cache.ThriftCache;
+import org.apache.blur.server.cache.ThriftCacheServer;
 import org.apache.blur.store.BlockCacheDirectoryFactory;
 import org.apache.blur.store.BlockCacheDirectoryFactoryV1;
 import org.apache.blur.store.BlockCacheDirectoryFactoryV2;
@@ -130,7 +135,8 @@ public class ThriftBlurShardServer extends ThriftServer {
       MemoryReporter.enable();
       setupJvmMetrics();
       // make this configurable
-      GCWatcher.init(0.75);
+      double ratio = configuration.getDouble(BLUR_GC_BACK_PRESSURE_HEAP_RATIO, 0.75);
+      GCWatcher.init(ratio);
       ThriftServer server = createServer(serverIndex, configuration);
       server.start();
     } catch (Throwable t) {
@@ -202,6 +208,9 @@ public class ThriftBlurShardServer extends ThriftServer {
     DistributedLayoutFactory distributedLayoutFactory = DistributedLayoutFactoryImpl.getDistributedLayoutFactory(
         configuration, cluster, zooKeeper);
 
+    long requestCacheSize = configuration.getLong(BLUR_SHARD_REQUEST_CACHE_SIZE, 10000000);
+    final ThriftCache thriftCache = new ThriftCache(requestCacheSize);
+
     long safeModeDelay = configuration.getLong(BLUR_SHARD_SAFEMODEDELAY, 60000);
     int shardOpenerThreadCount = configuration.getInt(BLUR_SHARD_OPENER_THREAD_COUNT, 16);
     int maxMergeThreads = configuration.getInt(BLUR_SHARD_MERGE_THREAD_COUNT, 3);
@@ -215,7 +224,7 @@ public class ThriftBlurShardServer extends ThriftServer {
     final DistributedIndexServer indexServer = new DistributedIndexServer(config, zooKeeper, clusterStatus,
         filterCache, blockCacheDirectoryFactory, distributedLayoutFactory, cluster, nodeName, safeModeDelay,
         shardOpenerThreadCount, maxMergeThreads, internalSearchThreads, minimumNumberOfNodesBeforeExitingSafeMode,
-        hdfsKeyValueTimer, indexImporterTimer, smallMergeThreshold, indexBulkTimer);
+        hdfsKeyValueTimer, indexImporterTimer, smallMergeThreshold, indexBulkTimer, thriftCache);
 
     BooleanQuery.setMaxClauseCount(configuration.getInt(BLUR_MAX_CLAUSE_COUNT, 1024));
 
@@ -256,6 +265,13 @@ public class ThriftBlurShardServer extends ThriftServer {
     final ShardCommandManager commandManager = new ShardCommandManager(indexServer, tmpPath, commandPath,
         numberOfShardWorkerCommandThreads, numberOfShardDriverCommandThreads, Connection.DEFAULT_TIMEOUT, config);
 
+    clusterStatus.registerActionOnTableStateChange(new Action() {
+      @Override
+      public void action() {
+        thriftCache.clear();
+      }
+    });
+
     final BlurShardServer shardServer = new BlurShardServer();
     shardServer.setCommandManager(commandManager);
     shardServer.setIndexServer(indexServer);
@@ -274,7 +290,8 @@ public class ThriftBlurShardServer extends ThriftServer {
     List<ServerSecurityFilter> serverSecurity = getServerSecurityList(configuration,
         ServerSecurityFilterFactory.ServerType.SHARD);
 
-    Iface iface = BlurUtil.wrapFilteredBlurServer(configuration, shardServer, true);
+    Iface iface = new ThriftCacheServer(configuration, shardServer, thriftCache);
+    iface = BlurUtil.wrapFilteredBlurServer(configuration, iface, true);
     iface = ServerSecurityUtil.applySecurity(iface, serverSecurity, true);
     iface = BlurUtil.recordMethodCallsAndAverageTimes(iface, Iface.class, false);
     iface = BlurUtil.runWithUser(iface, false);

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/06c929b9/blur-core/src/test/java/org/apache/blur/command/ShardCommandManagerTest.java
----------------------------------------------------------------------
diff --git a/blur-core/src/test/java/org/apache/blur/command/ShardCommandManagerTest.java b/blur-core/src/test/java/org/apache/blur/command/ShardCommandManagerTest.java
index 445b9a8..ef41c4b 100644
--- a/blur-core/src/test/java/org/apache/blur/command/ShardCommandManagerTest.java
+++ b/blur-core/src/test/java/org/apache/blur/command/ShardCommandManagerTest.java
@@ -366,7 +366,7 @@ public class ShardCommandManagerTest {
 
   protected BlurIndex getNullBlurIndex(String shard) throws IOException {
     ShardContext shardContext = ShardContext.create(getTableContextFactory().getTableContext("test"), shard);
-    return new BlurIndex(shardContext, null, null, null, null, null, null) {
+    return new BlurIndex(shardContext, null, null, null, null, null, null, null) {
 
       @Override
       public void removeSnapshot(String name) throws IOException {

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/06c929b9/blur-core/src/test/java/org/apache/blur/manager/writer/BlurIndexSimpleWriterTest.java
----------------------------------------------------------------------
diff --git a/blur-core/src/test/java/org/apache/blur/manager/writer/BlurIndexSimpleWriterTest.java b/blur-core/src/test/java/org/apache/blur/manager/writer/BlurIndexSimpleWriterTest.java
index 8921917..f807053 100644
--- a/blur-core/src/test/java/org/apache/blur/manager/writer/BlurIndexSimpleWriterTest.java
+++ b/blur-core/src/test/java/org/apache/blur/manager/writer/BlurIndexSimpleWriterTest.java
@@ -127,7 +127,8 @@ public class BlurIndexSimpleWriterTest {
     // FSDirectory directory = FSDirectory.open(path);
 
     ShardContext shardContext = ShardContext.create(tableContext, "test-shard-" + uuid);
-    _writer = new BlurIndexSimpleWriter(shardContext, directory, _mergeScheduler, _service, _closer, _timer, _bulkTimer);
+    _writer = new BlurIndexSimpleWriter(shardContext, directory, _mergeScheduler, _service, _closer, _timer,
+        _bulkTimer, null);
   }
 
   @After

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/06c929b9/blur-core/src/test/java/org/apache/blur/manager/writer/IndexImporterTest.java
----------------------------------------------------------------------
diff --git a/blur-core/src/test/java/org/apache/blur/manager/writer/IndexImporterTest.java b/blur-core/src/test/java/org/apache/blur/manager/writer/IndexImporterTest.java
index b0e25e7..1cf1e5a 100644
--- a/blur-core/src/test/java/org/apache/blur/manager/writer/IndexImporterTest.java
+++ b/blur-core/src/test/java/org/apache/blur/manager/writer/IndexImporterTest.java
@@ -125,7 +125,7 @@ public class IndexImporterTest {
   }
 
   private BlurIndex getBlurIndex(ShardContext shardContext, final Directory mainDirectory) throws IOException {
-    return new BlurIndex(shardContext, mainDirectory, null, null, null, null, null) {
+    return new BlurIndex(shardContext, mainDirectory, null, null, null, null, null, null) {
 
       @Override
       public void removeSnapshot(String name) throws IOException {

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/06c929b9/blur-core/src/test/java/org/apache/blur/server/cache/ThriftCacheKeyTest.java
----------------------------------------------------------------------
diff --git a/blur-core/src/test/java/org/apache/blur/server/cache/ThriftCacheKeyTest.java b/blur-core/src/test/java/org/apache/blur/server/cache/ThriftCacheKeyTest.java
new file mode 100644
index 0000000..0ca81a6
--- /dev/null
+++ b/blur-core/src/test/java/org/apache/blur/server/cache/ThriftCacheKeyTest.java
@@ -0,0 +1,135 @@
+/**
+ * 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.blur.server.cache;
+
+import static org.junit.Assert.*;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.blur.thrift.generated.BlurQuery;
+import org.apache.blur.user.User;
+import org.junit.Test;
+
+public class ThriftCacheKeyTest {
+
+  @Test
+  public void test1() {
+    User user = null;
+    String table = "t";
+    BlurQuery bq1 = new BlurQuery();
+    BlurQuery bq2 = new BlurQuery();
+    ThriftCacheKey<BlurQuery> key1 = new ThriftCacheKey<BlurQuery>(user, table, bq1, BlurQuery.class);
+    ThriftCacheKey<BlurQuery> key2 = new ThriftCacheKey<BlurQuery>(user, table, bq2, BlurQuery.class);
+
+    assertEquals(key1, key2);
+    assertEquals(key1.hashCode(), key2.hashCode());
+  }
+
+  @Test
+  public void test2() {
+    User user = null;
+    String table = "t";
+    ThriftCacheKey<BlurQuery> key1 = new ThriftCacheKey<BlurQuery>(user, table, null, BlurQuery.class);
+    ThriftCacheKey<BlurQuery> key2 = new ThriftCacheKey<BlurQuery>(user, table, null, BlurQuery.class);
+
+    assertEquals(key1, key2);
+    assertEquals(key1.hashCode(), key2.hashCode());
+  }
+
+  @Test
+  public void test3() {
+    User user = new User("test", null);
+    String table = "t";
+    BlurQuery bq1 = new BlurQuery();
+    BlurQuery bq2 = new BlurQuery();
+    ThriftCacheKey<BlurQuery> key1 = new ThriftCacheKey<BlurQuery>(user, table, bq1, BlurQuery.class);
+    ThriftCacheKey<BlurQuery> key2 = new ThriftCacheKey<BlurQuery>(user, table, bq2, BlurQuery.class);
+
+    assertEquals(key1, key2);
+    assertEquals(key1.hashCode(), key2.hashCode());
+  }
+
+  @Test
+  public void test4() {
+    User user = new User("test", map("a", "b"));
+    String table = "t";
+    BlurQuery bq1 = new BlurQuery();
+    BlurQuery bq2 = new BlurQuery();
+    ThriftCacheKey<BlurQuery> key1 = new ThriftCacheKey<BlurQuery>(user, table, bq1, BlurQuery.class);
+    ThriftCacheKey<BlurQuery> key2 = new ThriftCacheKey<BlurQuery>(user, table, bq2, BlurQuery.class);
+
+    assertEquals(key1, key2);
+    assertEquals(key1.hashCode(), key2.hashCode());
+  }
+
+  @Test
+  public void test5() {
+    User user1 = new User("test1", null);
+    User user2 = new User("test2", null);
+    String table = "t";
+    BlurQuery bq1 = new BlurQuery();
+    BlurQuery bq2 = new BlurQuery();
+    ThriftCacheKey<BlurQuery> key1 = new ThriftCacheKey<BlurQuery>(user1, table, bq1, BlurQuery.class);
+    ThriftCacheKey<BlurQuery> key2 = new ThriftCacheKey<BlurQuery>(user2, table, bq2, BlurQuery.class);
+
+    assertFalse(key1.equals(key2));
+    assertFalse(key1.hashCode() == key2.hashCode());
+  }
+
+  @Test
+  public void test6() {
+    User user1 = new User("test1", map("a", "b"));
+    User user2 = new User("test1", map("a", "c"));
+    String table = "t";
+    BlurQuery bq1 = new BlurQuery();
+    BlurQuery bq2 = new BlurQuery();
+    ThriftCacheKey<BlurQuery> key1 = new ThriftCacheKey<BlurQuery>(user1, table, bq1, BlurQuery.class);
+    ThriftCacheKey<BlurQuery> key2 = new ThriftCacheKey<BlurQuery>(user2, table, bq2, BlurQuery.class);
+
+    assertFalse(key1.equals(key2));
+    assertFalse(key1.hashCode() == key2.hashCode());
+  }
+
+  @Test
+  public void test7() {
+    User user1 = new User("test1", map("a", "b"));
+    User user2 = new User("test2", map("a", "b"));
+    String table = "t";
+    BlurQuery bq1 = new BlurQuery();
+    BlurQuery bq2 = new BlurQuery();
+    ThriftCacheKey<BlurQuery> key1 = new ThriftCacheKey<BlurQuery>(user1, table, bq1, BlurQuery.class);
+    ThriftCacheKey<BlurQuery> key2 = new ThriftCacheKey<BlurQuery>(user2, table, bq2, BlurQuery.class);
+
+    assertFalse(key1.equals(key2));
+    assertFalse(key1.hashCode() == key2.hashCode());
+  }
+
+  private Map<String, String> map(String... s) {
+    if (s == null) {
+      return null;
+    }
+    if (s.length % 2 != 0) {
+      throw new RuntimeException("Can only take pairs.");
+    }
+    Map<String, String> map = new HashMap<String, String>();
+    for (int i = 1; i < s.length; i += 2) {
+      map.put(s[i - 1], s[i]);
+    }
+    return map;
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/06c929b9/blur-core/src/test/java/org/apache/blur/server/cache/ThriftCacheServerTest.java
----------------------------------------------------------------------
diff --git a/blur-core/src/test/java/org/apache/blur/server/cache/ThriftCacheServerTest.java b/blur-core/src/test/java/org/apache/blur/server/cache/ThriftCacheServerTest.java
new file mode 100644
index 0000000..6f9b20d
--- /dev/null
+++ b/blur-core/src/test/java/org/apache/blur/server/cache/ThriftCacheServerTest.java
@@ -0,0 +1,531 @@
+/**
+ * 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.blur.server.cache;
+
+import static org.junit.Assert.*;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.blur.BlurConfiguration;
+import org.apache.blur.thirdparty.thrift_0_9_0.TException;
+import org.apache.blur.thrift.generated.Arguments;
+import org.apache.blur.thrift.generated.Blur.Iface;
+import org.apache.blur.thrift.generated.BlurException;
+import org.apache.blur.thrift.generated.BlurQuery;
+import org.apache.blur.thrift.generated.BlurQueryStatus;
+import org.apache.blur.thrift.generated.BlurResults;
+import org.apache.blur.thrift.generated.ColumnDefinition;
+import org.apache.blur.thrift.generated.CommandDescriptor;
+import org.apache.blur.thrift.generated.CommandStatus;
+import org.apache.blur.thrift.generated.CommandStatusState;
+import org.apache.blur.thrift.generated.FetchResult;
+import org.apache.blur.thrift.generated.Level;
+import org.apache.blur.thrift.generated.Metric;
+import org.apache.blur.thrift.generated.Query;
+import org.apache.blur.thrift.generated.Response;
+import org.apache.blur.thrift.generated.RowMutation;
+import org.apache.blur.thrift.generated.Schema;
+import org.apache.blur.thrift.generated.Selector;
+import org.apache.blur.thrift.generated.ShardState;
+import org.apache.blur.thrift.generated.TableDescriptor;
+import org.apache.blur.thrift.generated.TableStats;
+import org.apache.blur.thrift.generated.TimeoutException;
+import org.apache.blur.thrift.generated.User;
+import org.junit.Before;
+import org.junit.Test;
+
+import com.yammer.metrics.core.Meter;
+
+public class ThriftCacheServerTest {
+
+  private BlurConfiguration _configuration;
+  private ThriftCache _thriftCache;
+  private ThriftCacheServer _thriftCacheServer;
+  private String _table;
+
+  @Before
+  public void setup() throws IOException {
+    _configuration = new BlurConfiguration();
+    _thriftCache = new ThriftCache(10000);
+    _thriftCacheServer = new ThriftCacheServer(_configuration, getMock(), _thriftCache);
+    _table = "t";
+  }
+
+  @Test
+  public void testQuery() throws IOException, BlurException, TException {
+    _thriftCache.clear();
+    Meter misses = _thriftCache.getMisses();
+    long currentMisses = misses.count();
+    Meter hits = _thriftCache.getHits();
+    long currentHits = misses.count();
+
+    assertEquals(0 + currentMisses, misses.count());
+    assertEquals(0 + currentHits, hits.count());
+
+    BlurQuery blurQuery1 = new BlurQuery();
+    blurQuery1.setUserContext("user1");
+    BlurResults blurResults1 = _thriftCacheServer.query(_table, blurQuery1);
+
+    assertEquals(1 + currentMisses, misses.count());
+    assertEquals(0 + currentHits, hits.count());
+
+    BlurQuery blurQuery2 = new BlurQuery();
+    blurQuery1.setUserContext("user2");
+    BlurResults blurResults2 = _thriftCacheServer.query(_table, blurQuery2);
+
+    assertEquals(1 + currentMisses, misses.count());
+    assertEquals(1 + currentHits, hits.count());
+
+    assertFalse(blurResults1 == blurResults2);
+    assertEquals(blurResults1, blurResults2);
+  }
+
+  @Test
+  public void testTableStats() throws IOException, BlurException, TException {
+    _thriftCache.clear();
+    Meter misses = _thriftCache.getMisses();
+    long currentMisses = misses.count();
+    Meter hits = _thriftCache.getHits();
+    long currentHits = misses.count();
+
+    assertEquals(0 + currentMisses, misses.count());
+    assertEquals(0 + currentHits, hits.count());
+
+    TableStats tableStats1 = _thriftCacheServer.tableStats(_table);
+
+    assertEquals(1 + currentMisses, misses.count());
+    assertEquals(0 + currentHits, hits.count());
+
+    TableStats tableStats2 = _thriftCacheServer.tableStats(_table);
+
+    assertEquals(1 + currentMisses, misses.count());
+    assertEquals(1 + currentHits, hits.count());
+
+    assertFalse(tableStats1 == tableStats2);
+    assertEquals(tableStats1, tableStats2);
+  }
+
+  @Test
+  public void testFetchRow() throws BlurException, TException {
+    _thriftCache.clear();
+    Meter misses = _thriftCache.getMisses();
+    long currentMisses = misses.count();
+    Meter hits = _thriftCache.getHits();
+    long currentHits = misses.count();
+
+    assertEquals(0 + currentMisses, misses.count());
+    assertEquals(0 + currentHits, hits.count());
+
+    Selector selector1 = new Selector();
+    selector1.setLocationId("1");
+    FetchResult fetchRow1 = _thriftCacheServer.fetchRow(_table, selector1);
+
+    assertEquals(1 + currentMisses, misses.count());
+    assertEquals(0 + currentHits, hits.count());
+
+    Selector selector2 = new Selector();
+    selector2.setLocationId("1");
+    FetchResult fetchRow2 = _thriftCacheServer.fetchRow(_table, selector2);
+
+    assertEquals(1 + currentMisses, misses.count());
+    assertEquals(1 + currentHits, hits.count());
+
+    assertFalse(fetchRow1 == fetchRow2);
+    assertEquals(fetchRow1, fetchRow2);
+  }
+
+  @Test
+  public void testFetchRowBatch1() throws BlurException, TException {
+    _thriftCache.clear();
+    Meter misses = _thriftCache.getMisses();
+    long currentMisses = misses.count();
+    Meter hits = _thriftCache.getHits();
+    long currentHits = misses.count();
+
+    assertEquals(0 + currentMisses, misses.count());
+    assertEquals(0 + currentHits, hits.count());
+
+    Selector selector1 = new Selector();
+    selector1.setLocationId("1");
+    List<FetchResult> fetchRowBatch1 = _thriftCacheServer.fetchRowBatch(_table, Arrays.asList(selector1));
+
+    assertEquals(1 + currentMisses, misses.count());
+    assertEquals(0 + currentHits, hits.count());
+
+    Selector selector2 = new Selector();
+    selector2.setLocationId("1");
+    List<FetchResult> fetchRowBatch2 = _thriftCacheServer.fetchRowBatch(_table, Arrays.asList(selector2));
+
+    assertEquals(1 + currentMisses, misses.count());
+    assertEquals(1 + currentHits, hits.count());
+
+    assertFalse(fetchRowBatch1 == fetchRowBatch2);
+    assertEquals(fetchRowBatch1, fetchRowBatch2);
+  }
+
+  @Test
+  public void testFetchRowBatch2() throws BlurException, TException {
+    _thriftCache.clear();
+    Meter misses = _thriftCache.getMisses();
+    long currentMisses = misses.count();
+    Meter hits = _thriftCache.getHits();
+    long currentHits = misses.count();
+
+    assertEquals(0 + currentMisses, misses.count());
+    assertEquals(0 + currentHits, hits.count());
+
+    Selector selector1 = new Selector();
+    selector1.setLocationId("1");
+    List<FetchResult> fetchRowBatch1 = _thriftCacheServer.fetchRowBatch(_table, Arrays.asList(selector1));
+
+    assertEquals(1 + currentMisses, misses.count());
+    assertEquals(0 + currentHits, hits.count());
+
+    Selector selector2 = new Selector();
+    selector2.setLocationId("1");
+    List<FetchResult> fetchRowBatch2 = _thriftCacheServer.fetchRowBatch(_table, Arrays.asList(selector2));
+
+    assertEquals(1 + currentMisses, misses.count());
+    assertEquals(1 + currentHits, hits.count());
+
+    assertFalse(fetchRowBatch1 == fetchRowBatch2);
+    assertEquals(fetchRowBatch1, fetchRowBatch2);
+
+    Selector selector3 = new Selector();
+    selector3.setLocationId("2");
+    List<FetchResult> fetchRowBatch3 = _thriftCacheServer.fetchRowBatch(_table, Arrays.asList(selector1, selector3));
+
+    // one miss for the non cached selector
+    assertEquals(2 + currentMisses, misses.count());
+    // one hit for the cached selector
+    assertEquals(2 + currentHits, hits.count());
+
+    Selector selector4 = new Selector();
+    selector4.setLocationId("2");
+    List<FetchResult> fetchRowBatch4 = _thriftCacheServer.fetchRowBatch(_table, Arrays.asList(selector2, selector4));
+
+    assertEquals(2 + currentMisses, misses.count());
+    // two hits for the cached selectors
+    assertEquals(4 + currentHits, hits.count());
+
+    assertFalse(fetchRowBatch3 == fetchRowBatch4);
+    assertEquals(fetchRowBatch3, fetchRowBatch4);
+
+  }
+
+  private Iface getMock() {
+    return new Iface() {
+
+      @Override
+      public List<String> traceRequestList(String traceId) throws BlurException, TException {
+        throw new RuntimeException("Not implemented.");
+      }
+
+      @Override
+      public String traceRequestFetch(String traceId, String requestId) throws BlurException, TException {
+        throw new RuntimeException("Not implemented.");
+      }
+
+      @Override
+      public void traceRemove(String traceId) throws BlurException, TException {
+        throw new RuntimeException("Not implemented.");
+      }
+
+      @Override
+      public List<String> traceList() throws BlurException, TException {
+        throw new RuntimeException("Not implemented.");
+      }
+
+      @Override
+      public List<String> terms(String table, String columnFamily, String columnName, String startWith, short size)
+          throws BlurException, TException {
+        throw new RuntimeException("Not implemented.");
+      }
+
+      @Override
+      public TableStats tableStats(String table) throws BlurException, TException {
+        return new TableStats();
+      }
+
+      @Override
+      public List<String> tableListByCluster(String cluster) throws BlurException, TException {
+        throw new RuntimeException("Not implemented.");
+      }
+
+      @Override
+      public List<String> tableList() throws BlurException, TException {
+        throw new RuntimeException("Not implemented.");
+      }
+
+      @Override
+      public void startTrace(String traceId, String requestId) throws TException {
+        throw new RuntimeException("Not implemented.");
+      }
+
+      @Override
+      public List<String> shardServerList(String cluster) throws BlurException, TException {
+        throw new RuntimeException("Not implemented.");
+      }
+
+      @Override
+      public Map<String, Map<String, ShardState>> shardServerLayoutState(String table) throws BlurException, TException {
+        throw new RuntimeException("Not implemented.");
+      }
+
+      @Override
+      public Map<String, String> shardServerLayout(String table) throws BlurException, TException {
+        throw new RuntimeException("Not implemented.");
+      }
+
+      @Override
+      public List<String> shardClusterList() throws BlurException, TException {
+        throw new RuntimeException("Not implemented.");
+      }
+
+      @Override
+      public void setUser(User user) throws TException {
+        throw new RuntimeException("Not implemented.");
+      }
+
+      @Override
+      public Schema schema(String table) throws BlurException, TException {
+        throw new RuntimeException("Not implemented.");
+      }
+
+      @Override
+      public void resetLogging() throws BlurException, TException {
+        throw new RuntimeException("Not implemented.");
+      }
+
+      @Override
+      public void removeTable(String table, boolean deleteIndexFiles) throws BlurException, TException {
+        throw new RuntimeException("Not implemented.");
+      }
+
+      @Override
+      public void removeSnapshot(String table, String name) throws BlurException, TException {
+        throw new RuntimeException("Not implemented.");
+      }
+
+      @Override
+      public void refresh() throws TException {
+        throw new RuntimeException("Not implemented.");
+      }
+
+      @Override
+      public long recordFrequency(String table, String columnFamily, String columnName, String value)
+          throws BlurException, TException {
+        throw new RuntimeException("Not implemented.");
+      }
+
+      @Override
+      public Response reconnect(long instanceExecutionId) throws BlurException, TimeoutException, TException {
+        throw new RuntimeException("Not implemented.");
+      }
+
+      @Override
+      public List<String> queryStatusIdList(String table) throws BlurException, TException {
+        throw new RuntimeException("Not implemented.");
+      }
+
+      @Override
+      public BlurQueryStatus queryStatusById(String table, String uuid) throws BlurException, TException {
+        throw new RuntimeException("Not implemented.");
+      }
+
+      @Override
+      public BlurResults query(String table, BlurQuery blurQuery) throws BlurException, TException {
+        BlurResults blurResults = new BlurResults();
+        return blurResults;
+      }
+
+      @Override
+      public void ping() throws TException {
+        throw new RuntimeException("Not implemented.");
+      }
+
+      @Override
+      public String parseQuery(String table, Query query) throws BlurException, TException {
+        throw new RuntimeException("Not implemented.");
+      }
+
+      @Override
+      public void optimize(String table, int numberOfSegmentsPerShard) throws BlurException, TException {
+        throw new RuntimeException("Not implemented.");
+      }
+
+      @Override
+      public void mutateBatch(List<RowMutation> mutations) throws BlurException, TException {
+        throw new RuntimeException("Not implemented.");
+      }
+
+      @Override
+      public void mutate(RowMutation mutation) throws BlurException, TException {
+        throw new RuntimeException("Not implemented.");
+      }
+
+      @Override
+      public Map<String, Metric> metrics(Set<String> metrics) throws BlurException, TException {
+        throw new RuntimeException("Not implemented.");
+      }
+
+      @Override
+      public void logging(String classNameOrLoggerName, Level level) throws BlurException, TException {
+        throw new RuntimeException("Not implemented.");
+      }
+
+      @Override
+      public void loadData(String table, String location) throws BlurException, TException {
+        throw new RuntimeException("Not implemented.");
+      }
+
+      @Override
+      public Map<String, List<String>> listSnapshots(String table) throws BlurException, TException {
+        throw new RuntimeException("Not implemented.");
+      }
+
+      @Override
+      public List<CommandDescriptor> listInstalledCommands() throws BlurException, TException {
+        throw new RuntimeException("Not implemented.");
+      }
+
+      @Override
+      public boolean isInSafeMode(String cluster) throws BlurException, TException {
+        throw new RuntimeException("Not implemented.");
+      }
+
+      @Override
+      public List<FetchResult> fetchRowBatch(String table, List<Selector> selectors) throws BlurException, TException {
+        List<FetchResult> list = new ArrayList<FetchResult>();
+        for (Selector selector : selectors) {
+          list.add(fetchRow(table, selector));
+        }
+        return list;
+      }
+
+      @Override
+      public FetchResult fetchRow(String table, Selector selector) throws BlurException, TException {
+        FetchResult fetchResult = new FetchResult();
+        return fetchResult;
+      }
+
+      @Override
+      public Response execute(String commandName, Arguments arguments) throws BlurException, TimeoutException,
+          TException {
+        throw new RuntimeException("Not implemented.");
+      }
+
+      @Override
+      public void enqueueMutateBatch(List<RowMutation> mutations) throws BlurException, TException {
+        throw new RuntimeException("Not implemented.");
+      }
+
+      @Override
+      public void enqueueMutate(RowMutation mutation) throws BlurException, TException {
+        throw new RuntimeException("Not implemented.");
+      }
+
+      @Override
+      public void enableTable(String table) throws BlurException, TException {
+        throw new RuntimeException("Not implemented.");
+      }
+
+      @Override
+      public void disableTable(String table) throws BlurException, TException {
+        throw new RuntimeException("Not implemented.");
+      }
+
+      @Override
+      public TableDescriptor describe(String table) throws BlurException, TException {
+        throw new RuntimeException("Not implemented.");
+      }
+
+      @Override
+      public void createTable(TableDescriptor tableDescriptor) throws BlurException, TException {
+        throw new RuntimeException("Not implemented.");
+      }
+
+      @Override
+      public void createSnapshot(String table, String name) throws BlurException, TException {
+        throw new RuntimeException("Not implemented.");
+      }
+
+      @Override
+      public List<String> controllerServerList() throws BlurException, TException {
+        throw new RuntimeException("Not implemented.");
+      }
+
+      @Override
+      public Map<String, String> configuration() throws BlurException, TException {
+        throw new RuntimeException("Not implemented.");
+      }
+
+      @Override
+      public List<String> commandStatusList(int startingAt, short fetch, CommandStatusState state)
+          throws BlurException, TException {
+        throw new RuntimeException("Not implemented.");
+      }
+
+      @Override
+      public CommandStatus commandStatus(String commandExecutionId) throws BlurException, TException {
+        throw new RuntimeException("Not implemented.");
+      }
+
+      @Override
+      public void commandCancel(String commandExecutionId) throws BlurException, TException {
+        throw new RuntimeException("Not implemented.");
+      }
+
+      @Override
+      public void cancelQuery(String table, String uuid) throws BlurException, TException {
+        throw new RuntimeException("Not implemented.");
+      }
+
+      @Override
+      public void bulkMutateStart(String bulkId) throws BlurException, TException {
+        throw new RuntimeException("Not implemented.");
+      }
+
+      @Override
+      public void bulkMutateFinish(String bulkId, boolean apply, boolean blockUntilComplete) throws BlurException,
+          TException {
+        throw new RuntimeException("Not implemented.");
+      }
+
+      @Override
+      public void bulkMutateAddMultiple(String bulkId, List<RowMutation> rowMutations) throws BlurException, TException {
+        throw new RuntimeException("Not implemented.");
+      }
+
+      @Override
+      public void bulkMutateAdd(String bulkId, RowMutation rowMutation) throws BlurException, TException {
+        throw new RuntimeException("Not implemented.");
+      }
+
+      @Override
+      public boolean addColumnDefinition(String table, ColumnDefinition columnDefinition) throws BlurException,
+          TException {
+        throw new RuntimeException("Not implemented.");
+      }
+    };
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/06c929b9/blur-core/src/test/java/org/apache/blur/server/cache/ThriftCacheTest.java
----------------------------------------------------------------------
diff --git a/blur-core/src/test/java/org/apache/blur/server/cache/ThriftCacheTest.java b/blur-core/src/test/java/org/apache/blur/server/cache/ThriftCacheTest.java
new file mode 100644
index 0000000..da96ba5
--- /dev/null
+++ b/blur-core/src/test/java/org/apache/blur/server/cache/ThriftCacheTest.java
@@ -0,0 +1,80 @@
+/**
+ * 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.blur.server.cache;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import org.apache.blur.thrift.generated.BlurException;
+import org.apache.blur.thrift.generated.BlurQuery;
+import org.apache.blur.thrift.generated.BlurResults;
+import org.apache.blur.thrift.generated.TableStats;
+import org.junit.Test;
+
+public class ThriftCacheTest {
+
+  @Test
+  public void test1() throws BlurException {
+    ThriftCache thriftCache = new ThriftCache(10000);
+    BlurQuery blurQuery = new BlurQuery();
+    ThriftCacheKey<?> key = thriftCache.getKey("t", blurQuery, BlurQuery.class);
+    assertNull(thriftCache.get(key, BlurResults.class));
+    BlurResults value = new BlurResults();
+    // assert same instance
+    assertTrue(value == thriftCache.put(key, value));
+    BlurResults blurResults = thriftCache.get(key, BlurResults.class);
+    assertFalse(value == blurResults);
+    assertEquals(value, blurResults);
+  }
+
+  @Test
+  public void test2() throws BlurException {
+    ThriftCache thriftCache = new ThriftCache(10000);
+    ThriftCacheKey<?> key = thriftCache.getKey("t", null, TableStats.class);
+    assertNull(thriftCache.get(key, TableStats.class));
+    TableStats value = new TableStats();
+    // assert same instance
+    assertTrue(value == thriftCache.put(key, value));
+    TableStats tableStats = thriftCache.get(key, TableStats.class);
+    assertFalse(value == tableStats);
+    assertEquals(value, tableStats);
+  }
+
+  @Test
+  public void test3() throws BlurException {
+    int maxSize = 100;
+    ThriftCache thriftCache = new ThriftCache(maxSize);
+    for (int i = 0; i < 1000000; i++) {
+      BlurQuery blurQuery = new BlurQuery();
+      // just make keys different
+      blurQuery.fetch = i;
+      ThriftCacheKey<?> key = thriftCache.getKey("t", blurQuery, BlurQuery.class);
+      assertNull(thriftCache.get(key, BlurResults.class));
+      BlurResults value = new BlurResults();
+      // assert same instance
+      assertTrue(value == thriftCache.put(key, value));
+      BlurResults blurResults = thriftCache.get(key, BlurResults.class);
+      assertFalse(value == blurResults);
+      assertEquals(value, blurResults);
+    }
+    long size = thriftCache.size();
+    assertTrue(size <= maxSize);
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/06c929b9/blur-core/src/test/java/org/apache/blur/server/cache/ThriftCacheValueTest.java
----------------------------------------------------------------------
diff --git a/blur-core/src/test/java/org/apache/blur/server/cache/ThriftCacheValueTest.java b/blur-core/src/test/java/org/apache/blur/server/cache/ThriftCacheValueTest.java
new file mode 100644
index 0000000..937903c
--- /dev/null
+++ b/blur-core/src/test/java/org/apache/blur/server/cache/ThriftCacheValueTest.java
@@ -0,0 +1,43 @@
+/**
+ * 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.blur.server.cache;
+
+import static org.junit.Assert.*;
+
+import org.apache.blur.thrift.generated.BlurException;
+import org.apache.blur.thrift.generated.BlurResults;
+import org.junit.Test;
+
+public class ThriftCacheValueTest {
+
+  @Test
+  public void test1() throws BlurException {
+    ThriftCacheValue<BlurResults> thriftCacheValue = new ThriftCacheValue<BlurResults>(null);
+    BlurResults results = thriftCacheValue.getValue(BlurResults.class);
+    assertNull(results);
+  }
+
+  @Test
+  public void test2() throws BlurException {
+    BlurResults blurResults = new BlurResults();
+    ThriftCacheValue<BlurResults> thriftCacheValue = new ThriftCacheValue<BlurResults>(blurResults);
+    BlurResults results = thriftCacheValue.getValue(BlurResults.class);
+    assertNotNull(results);
+    assertEquals(blurResults, results);
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/06c929b9/blur-util/src/main/java/org/apache/blur/metrics/MetricsConstants.java
----------------------------------------------------------------------
diff --git a/blur-util/src/main/java/org/apache/blur/metrics/MetricsConstants.java b/blur-util/src/main/java/org/apache/blur/metrics/MetricsConstants.java
index e0609c2..da6f874 100644
--- a/blur-util/src/main/java/org/apache/blur/metrics/MetricsConstants.java
+++ b/blur-util/src/main/java/org/apache/blur/metrics/MetricsConstants.java
@@ -45,6 +45,7 @@ public class MetricsConstants {
   public static final String REMOVAL = "Removal";
   public static final String MISS = "Miss";
   public static final String CACHE = "Cache";
+  public static final String THRIFT_CACHE = "ThriftCache";
   public static final String HDFS_KV = "HDFS-KV";
   public static final String DEEP_PAGING_CACHE = "DeepPagingCache";
   public static final String CACHE_POOL = "CachePool";
@@ -55,6 +56,7 @@ public class MetricsConstants {
   public static final String TABLE_COUNT = "Table Count";
   public static final String FILES_IN_QUEUE_TO_BE_DELETED = "Files in Queue to be Deleted";
   public static final String INDEX_MEMORY_USAGE = "Index Memory Usage";
+  public static final String RECORD_COUNT = "Record Count";
   public static final String SEGMENT_COUNT = "Segment Count";
   public static final String INDEX_COUNT = "Index Count";
   public static final String INTERNAL_SEARCH = "internal search";

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/06c929b9/blur-util/src/main/java/org/apache/blur/utils/BlurConstants.java
----------------------------------------------------------------------
diff --git a/blur-util/src/main/java/org/apache/blur/utils/BlurConstants.java b/blur-util/src/main/java/org/apache/blur/utils/BlurConstants.java
index e14895d..0cae234 100644
--- a/blur-util/src/main/java/org/apache/blur/utils/BlurConstants.java
+++ b/blur-util/src/main/java/org/apache/blur/utils/BlurConstants.java
@@ -110,6 +110,8 @@ public class BlurConstants {
   public static final String BLUR_SHARD_BLURINDEX_CLASS = "blur.shard.blurindex.class";
   public static final String BLUR_SHARD_SERVER_MINIMUM_BEFORE_SAFEMODE_EXIT = "blur.shard.server.minimum.before.safemode.exit";
   public static final String BLUR_SHARD_SMALL_MERGE_THRESHOLD = "blur.shard.small.merge.threshold";
+  public static final String BLUR_SHARD_REQUEST_CACHE_SIZE = "blur.shard.request.cache.size";
+  public static final String BLUR_GC_BACK_PRESSURE_HEAP_RATIO = "blur.gc.back.pressure.heap.ratio";
 
   public static final String BLUR_FIELDTYPE = "blur.fieldtype.";
 

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/06c929b9/blur-util/src/main/resources/blur-default.properties
----------------------------------------------------------------------
diff --git a/blur-util/src/main/resources/blur-default.properties b/blur-util/src/main/resources/blur-default.properties
index db313dc..82ac9a1 100644
--- a/blur-util/src/main/resources/blur-default.properties
+++ b/blur-util/src/main/resources/blur-default.properties
@@ -67,6 +67,9 @@ blur.metrics.reporters=
 # Thrift max frame size
 blur.thrift.max.frame.size=16384000
 
+# The GC back pressure heap ratio, if the heap size after a GC isn't below the ratio size the GC watcher will take action to relieve pressure. 
+blur.gc.back.pressure.heap.ratio=0.75
+
 # The command lib path where the controller and shard server processes will poll for new commands to enable.
 blur.command.lib.path=
 
@@ -252,6 +255,9 @@ blur.shard.deep.paging.cache.size=1000
 # Defines the blur layout factor class to use for managing how shards are layed out across the cluster.
 blur.shard.distributed.layout.factory.class=
 
+# Sets the request cache size in bytes.
+blur.shard.request.cache.size=10000000
+
 ### Controller Server Configuration
 
 # Sets the hostname for the controller, if blank the hostname is automatically detected


Mime
View raw message