Skip to content

Commit 764aff6

Browse files
kotman12Matthew Biscocho
authored andcommitted
SOLR-17863: fix per segment fingerprint cache race (#3477)
Fix race condition in SolrCore's fingerprint cache which caused leader election to hang
1 parent 3157010 commit 764aff6

File tree

3 files changed

+19
-23
lines changed

3 files changed

+19
-23
lines changed

solr/CHANGES.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ Bug Fixes
2828
* SOLR-17789: When Solr forwards/proxies requests to another node that can service the request, it needs to pass authorization headers.
2929
(Timo Crabbé)
3030

31+
* SOLR-17863: Fix race condition in SolrCore's fingerprint cache which caused leader election to hang. (Luke Kot-Zaniewski, Matthew Biscocho)
32+
3133
Dependency Upgrades
3234
---------------------
3335
(No changes)

solr/core/src/java/org/apache/solr/core/SolrCore.java

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121

2222
import com.codahale.metrics.Counter;
2323
import com.codahale.metrics.Timer;
24+
import com.github.benmanes.caffeine.cache.Cache;
25+
import com.github.benmanes.caffeine.cache.Caffeine;
2426
import java.io.Closeable;
2527
import java.io.File;
2628
import java.io.FileNotFoundException;
@@ -55,7 +57,6 @@
5557
import java.util.Spliterator;
5658
import java.util.Spliterators;
5759
import java.util.UUID;
58-
import java.util.WeakHashMap;
5960
import java.util.concurrent.Callable;
6061
import java.util.concurrent.ConcurrentHashMap;
6162
import java.util.concurrent.CopyOnWriteArrayList;
@@ -246,6 +247,8 @@ public class SolrCore implements SolrInfoBean, Closeable {
246247
private IndexReaderFactory indexReaderFactory;
247248
private final Codec codec;
248249
private final ConfigSet configSet;
250+
private final Cache<IndexReader.CacheKey, IndexFingerprint> perSegmentFingerprintCache =
251+
Caffeine.newBuilder().weakKeys().build();
249252
// singleton listener for all packages used in schema
250253

251254
private final CircuitBreakerRegistry circuitBreakerRegistry;
@@ -276,9 +279,6 @@ public Date getStartTimeStamp() {
276279
return startTime;
277280
}
278281

279-
private final Map<IndexReader.CacheKey, IndexFingerprint> perSegmentFingerprintCache =
280-
new WeakHashMap<>();
281-
282282
public long getStartNanoTime() {
283283
return startNanoTime;
284284
}
@@ -2146,7 +2146,7 @@ public IndexFingerprint getIndexFingerprint(
21462146
}
21472147

21482148
IndexFingerprint f = null;
2149-
f = perSegmentFingerprintCache.get(cacheHelper.getKey());
2149+
f = perSegmentFingerprintCache.getIfPresent(cacheHelper.getKey());
21502150
// fingerprint is either not cached or if we want fingerprint only up to a version less than
21512151
// maxVersionEncountered in the segment, or documents were deleted from segment for which
21522152
// fingerprint was cached
@@ -2186,8 +2186,8 @@ public IndexFingerprint getIndexFingerprint(
21862186
}
21872187
if (log.isDebugEnabled()) {
21882188
log.debug(
2189-
"Cache Size: {}, Segments Size:{}",
2190-
perSegmentFingerprintCache.size(),
2189+
"Approximate perSegmentFingerprintCache Size: {}, Segments Size:{}",
2190+
perSegmentFingerprintCache.estimatedSize(),
21912191
searcher.getTopReaderContext().leaves().size());
21922192
}
21932193
return f;

solr/core/src/test/org/apache/solr/update/SolrIndexFingerprintTest.java

Lines changed: 10 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
package org.apache.solr.update;
1818

1919
import java.io.IOException;
20+
import java.util.stream.IntStream;
2021
import org.apache.lucene.index.FilterLeafReader;
2122
import org.apache.lucene.index.LeafReader;
2223
import org.apache.solr.SolrTestCaseJ4;
@@ -28,29 +29,22 @@ public class SolrIndexFingerprintTest extends SolrTestCaseJ4 {
2829

2930
@BeforeClass
3031
public static void beforeTests() throws Exception {
31-
initCore("solrconfig.xml", "schema.xml");
32+
initCore("solrconfig-nomergepolicyfactory.xml", "schema.xml");
3233
}
3334

3435
@Test
3536
public void testSequentialVsParallelFingerprint() throws Exception {
3637
long maxVersion = Long.MAX_VALUE;
3738
SolrCore core = h.getCore();
3839

39-
// Create a set of 3 segments
40-
assertU(adoc("id", "101"));
41-
assertU(adoc("id", "102"));
42-
assertU(adoc("id", "103"));
43-
assertU(commit());
44-
45-
assertU(adoc("id", "104"));
46-
assertU(adoc("id", "105"));
47-
assertU(adoc("id", "106"));
48-
assertU(commit());
49-
50-
assertU(adoc("id", "107"));
51-
assertU(adoc("id", "108"));
52-
assertU(adoc("id", "109"));
53-
assertU(commit());
40+
int numDocs = RANDOM_MULTIPLIER == 1 ? 3 : 500;
41+
// Create a set of many segments (to catch race conditions, i.e. SOLR-17863)
42+
IntStream.range(0, numDocs)
43+
.forEach(
44+
i -> {
45+
assertU(adoc("id", "" + i));
46+
assertU(commit());
47+
});
5448

5549
try (var searcher = core.getSearcher().get()) {
5650
// Compute fingerprint sequentially to compare with parallel computation

0 commit comments

Comments
 (0)