You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by yo...@apache.org on 2017/03/07 03:19:10 UTC

lucene-solr:branch_6x: SOLR-10205: BlockCache - use 4 reserved blocks, don't use executor in caffeine, call cleanUp

Repository: lucene-solr
Updated Branches:
  refs/heads/branch_6x 4b1a16361 -> f2da342c4


SOLR-10205: BlockCache - use 4 reserved blocks, don't use executor in caffeine, call cleanUp


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

Branch: refs/heads/branch_6x
Commit: f2da342c47f8588996c7a68433a4e11131e46ee2
Parents: 4b1a163
Author: yonik <yo...@apache.org>
Authored: Mon Mar 6 22:13:29 2017 -0500
Committer: yonik <yo...@apache.org>
Committed: Mon Mar 6 22:15:58 2017 -0500

----------------------------------------------------------------------
 solr/CHANGES.txt                                 |  4 ++++
 .../apache/solr/store/blockcache/BlockCache.java | 19 +++++++++++++++++--
 2 files changed, 21 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/f2da342c/solr/CHANGES.txt
----------------------------------------------------------------------
diff --git a/solr/CHANGES.txt b/solr/CHANGES.txt
index 4a2fa95..3d59cfe 100644
--- a/solr/CHANGES.txt
+++ b/solr/CHANGES.txt
@@ -166,6 +166,10 @@ Optimizations
 * SOLR-10143: PointFields will create IndexOrDocValuesQuery when a field is both, indexed=true and docValues=true
   (Tom�s Fern�ndez L�bbe)
 
+* SOLR-10205: Change the HDFS BlockCache to reduce store failures and increase hit ratio. Highly concurrent
+  artificial random queries over random indexes showed performance increases of 5% to 68%, with common values
+  in the teens. (yonik)
+
 Other Changes
 ----------------------
 * SOLR-9980: Expose configVersion in core admin status (Jessica Cheng Mallet via Tom�s Fern�ndez L�bbe)

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/f2da342c/solr/core/src/java/org/apache/solr/store/blockcache/BlockCache.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/store/blockcache/BlockCache.java b/solr/core/src/java/org/apache/solr/store/blockcache/BlockCache.java
index 9deef6c..dfc1329 100644
--- a/solr/core/src/java/org/apache/solr/store/blockcache/BlockCache.java
+++ b/solr/core/src/java/org/apache/solr/store/blockcache/BlockCache.java
@@ -39,7 +39,8 @@ public class BlockCache {
   private final AtomicInteger[] lockCounters;
   private final int blockSize;
   private final int numberOfBlocksPerBank;
-  private final int maxEntries;
+  private final int maxBlocks;  // total number of underlying memory blocks allocated
+  private final int maxEntries;  // Target max size for the map.  A few less than maxBlocks due to reserved blocks.  Concurrent maps (like Caffeine) will often temporarily exceed this.
   private final Metrics metrics;
   private final List<OnRelease> onReleases = new CopyOnWriteArrayList<>();
 
@@ -65,7 +66,10 @@ public class BlockCache {
     banks = new ByteBuffer[numberOfBanks];
     locks = new BlockLocks[numberOfBanks];
     lockCounters = new AtomicInteger[numberOfBanks];
-    maxEntries = (numberOfBlocksPerBank * numberOfBanks) - 1;
+    maxBlocks = numberOfBlocksPerBank * numberOfBanks;
+
+    // Reserve 4 blocks for new entries.  This was originally 1, but contributed to many store failures (see SOLR-10205)
+    maxEntries = maxBlocks - (maxBlocks > 4 ? 4 : 1);
     for (int i = 0; i < numberOfBanks; i++) {
       if (directAllocation) {
         banks[i] = ByteBuffer.allocateDirect(numberOfBlocksPerBank * blockSize);
@@ -81,6 +85,7 @@ public class BlockCache {
     cache = Caffeine.newBuilder()
         .removalListener(listener)
         .maximumSize(maxEntries)
+        .executor(Runnable::run)  // Use the current thread for evictions instead of a separate executor.  This helps avoid store fails when cache.estimatedSize >= maxBlocks
         .build();
     this.blockSize = blockSize;
   }
@@ -205,6 +210,16 @@ public class BlockCache {
     // This is a tight loop that will try and find a location to
     // place the block before giving up
     for (int j = 0; j < 10; j++) {
+
+      // If we've been through the loop once already and haven't found a spot, it's because:
+      // 1) a simple race.. another thread stole the open spot(s) we tried to grab
+      // 2) there are currently no free spots because the the underlying map hasn't evicted enough entries yet
+      //
+      // Try to help case #2 by explicitly forcing a cleanup if there are no free blocks
+      if (j>0 && cache.estimatedSize() >= maxBlocks) {
+        cache.cleanUp();
+      }
+
       OUTER: for (int bankId = 0; bankId < banks.length; bankId++) {
         AtomicInteger bitSetCounter = lockCounters[bankId];
         BlockLocks bitSet = locks[bankId];