From fa1ee56fd39e2c297890d2363699f7bccf7c883c Mon Sep 17 00:00:00 2001 From: Mikhail Khludnev Date: Thu, 22 Dec 2016 08:17:20 +0300 Subject: [PATCH] SOLR-9699: fixing exception on core status during concurrent reload --- solr/CHANGES.txt | 2 + .../handler/admin/LukeRequestHandler.java | 18 +++- .../handler/admin/StatsReloadRaceTest.java | 84 ++++++++++++------- 3 files changed, 75 insertions(+), 29 deletions(-) diff --git a/solr/CHANGES.txt b/solr/CHANGES.txt index 576b6f14210..df2fdc041e1 100644 --- a/solr/CHANGES.txt +++ b/solr/CHANGES.txt @@ -207,6 +207,8 @@ Bug Fixes * SOLR-9760: Windows script doesn't need write permission (Alex Crome by Mikhail Khludnev) +* SOLR-9699,SOLR-4668: fix exception from core status in parallel with core reload (Mikhail Khludnev) + Other Changes ---------------------- diff --git a/solr/core/src/java/org/apache/solr/handler/admin/LukeRequestHandler.java b/solr/core/src/java/org/apache/solr/handler/admin/LukeRequestHandler.java index d0dd15252dd..d7dedf1a46d 100644 --- a/solr/core/src/java/org/apache/solr/handler/admin/LukeRequestHandler.java +++ b/solr/core/src/java/org/apache/solr/handler/admin/LukeRequestHandler.java @@ -58,6 +58,7 @@ import org.apache.lucene.index.Terms; import org.apache.lucene.index.TermsEnum; import org.apache.lucene.search.DocIdSetIterator; import org.apache.lucene.search.similarities.Similarity; +import org.apache.lucene.store.AlreadyClosedException; import org.apache.lucene.store.Directory; import org.apache.lucene.util.Bits; import org.apache.lucene.util.BytesRef; @@ -577,7 +578,7 @@ public class LukeRequestHandler extends RequestHandlerBase indexInfo.add("version", reader.getVersion()); // TODO? Is this different then: IndexReader.getCurrentVersion( dir )? indexInfo.add("segmentCount", reader.leaves().size()); - indexInfo.add("current", reader.isCurrent() ); + indexInfo.add("current", closeSafe( reader::isCurrent)); indexInfo.add("hasDeletions", reader.hasDeletions() ); indexInfo.add("directory", dir ); IndexCommit indexCommit = reader.getIndexCommit(); @@ -593,6 +594,21 @@ public class LukeRequestHandler extends RequestHandlerBase return indexInfo; } + @FunctionalInterface + interface IOSupplier { + boolean get() throws IOException; + } + + private static Object closeSafe(IOSupplier isCurrent) { + try { + return isCurrent.get(); + }catch(AlreadyClosedException | IOException exception) { + } + return false; + } + + + private static long getFileLength(Directory dir, String filename) { try { return dir.fileLength(filename); diff --git a/solr/core/src/test/org/apache/solr/handler/admin/StatsReloadRaceTest.java b/solr/core/src/test/org/apache/solr/handler/admin/StatsReloadRaceTest.java index 619e7d51e83..7bf493923e5 100644 --- a/solr/core/src/test/org/apache/solr/handler/admin/StatsReloadRaceTest.java +++ b/solr/core/src/test/org/apache/solr/handler/admin/StatsReloadRaceTest.java @@ -18,6 +18,7 @@ package org.apache.solr.handler.admin; import java.util.List; import java.util.Map; +import java.util.Random; import java.util.concurrent.atomic.AtomicInteger; import org.apache.solr.SolrTestCaseJ4; @@ -50,11 +51,13 @@ public class StatsReloadRaceTest extends SolrTestCaseJ4 { @Test public void testParallelReloadAndStats() throws Exception { - for (int i = 0; i < atLeast(2); i++) { + Random random = random(); + + for (int i = 0; i < atLeast(random, 2); i++) { int asyncId = taskNum.incrementAndGet(); - SolrQueryResponse rsp = new SolrQueryResponse(); + h.getCoreContainer().getMultiCoreHandler().handleRequest(req( CommonParams.QT, "/admin/cores", CoreAdminParams.ACTION, @@ -64,36 +67,61 @@ public class StatsReloadRaceTest extends SolrTestCaseJ4 { boolean isCompleted; do { - String stats = h.query(req( - CommonParams.QT, "/admin/mbeans", - "stats", "true")); - - NamedList> actualStats = SolrInfoMBeanHandler.fromXML(stats).get("CORE"); - - for (Map.Entry> tuple : actualStats) { - if (tuple.getKey().contains("earcher")) { // catches "searcher" and "Searcher@345345 blah" - NamedList searcherStats = tuple.getValue(); - @SuppressWarnings("unchecked") - NamedList statsList = (NamedList)searcherStats.get("stats"); - assertEquals("expect to have exactly one indexVersion at "+statsList, 1, statsList.getAll("indexVersion").size()); - assertTrue(statsList.get("indexVersion") instanceof Long); - } + if (random.nextBoolean()) { + requestMbeans(); + } else { + requestCoreStatus(); } - h.getCoreContainer().getMultiCoreHandler().handleRequest(req( - CoreAdminParams.ACTION, - CoreAdminParams.CoreAdminAction.REQUESTSTATUS.toString(), - CoreAdminParams.REQUESTID, "" + asyncId), rsp); - - @SuppressWarnings("unchecked") - List statusLog = rsp.getValues().getAll(CoreAdminAction.STATUS.name()); - - assertFalse("expect status check w/o error, got:" + statusLog, - statusLog.contains(CoreAdminHandler.FAILED)); - - isCompleted = statusLog.contains(CoreAdminHandler.COMPLETED); + isCompleted = checkReloadComlpetion(asyncId); } while (!isCompleted); } } + private void requestCoreStatus() throws Exception { + SolrQueryResponse rsp = new SolrQueryResponse(); + h.getCoreContainer().getMultiCoreHandler().handleRequest(req( + CoreAdminParams.ACTION, + CoreAdminParams.CoreAdminAction.STATUS.toString(), + "core", DEFAULT_TEST_CORENAME), rsp); + assertNull(""+rsp.getException(),rsp.getException()); + + } + + private boolean checkReloadComlpetion(int asyncId) { + boolean isCompleted; + SolrQueryResponse rsp = new SolrQueryResponse(); + h.getCoreContainer().getMultiCoreHandler().handleRequest(req( + CoreAdminParams.ACTION, + CoreAdminParams.CoreAdminAction.REQUESTSTATUS.toString(), + CoreAdminParams.REQUESTID, "" + asyncId), rsp); + + @SuppressWarnings("unchecked") + List statusLog = rsp.getValues().getAll(CoreAdminAction.STATUS.name()); + + assertFalse("expect status check w/o error, got:" + statusLog, + statusLog.contains(CoreAdminHandler.FAILED)); + + isCompleted = statusLog.contains(CoreAdminHandler.COMPLETED); + return isCompleted; + } + + private void requestMbeans() throws Exception { + String stats = h.query(req( + CommonParams.QT, "/admin/mbeans", + "stats", "true")); + + NamedList> actualStats = SolrInfoMBeanHandler.fromXML(stats).get("CORE"); + + for (Map.Entry> tuple : actualStats) { + if (tuple.getKey().contains("earcher")) { // catches "searcher" and "Searcher@345345 blah" + NamedList searcherStats = tuple.getValue(); + @SuppressWarnings("unchecked") + NamedList statsList = (NamedList)searcherStats.get("stats"); + assertEquals("expect to have exactly one indexVersion at "+statsList, 1, statsList.getAll("indexVersion").size()); + assertTrue(statsList.get("indexVersion") instanceof Long); + } + } + } + }