You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by mk...@apache.org on 2016/09/23 04:55:44 UTC
lucene-solr:master: SOLR-9330: Fix AlreadyClosedException on
admin/mbeans?stats=true
Repository: lucene-solr
Updated Branches:
refs/heads/master bede7aefa -> b50b9106f
SOLR-9330: Fix AlreadyClosedException on admin/mbeans?stats=true
Project: http://git-wip-us.apache.org/repos/asf/lucene-solr/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucene-solr/commit/b50b9106
Tree: http://git-wip-us.apache.org/repos/asf/lucene-solr/tree/b50b9106
Diff: http://git-wip-us.apache.org/repos/asf/lucene-solr/diff/b50b9106
Branch: refs/heads/master
Commit: b50b9106f821915ced14a3efc1e09c265d648fa8
Parents: bede7ae
Author: Mikhail Khludnev <mk...@apache.org>
Authored: Tue Sep 20 14:59:00 2016 +0300
Committer: Mikhail Khludnev <mk...@apache.org>
Committed: Fri Sep 23 07:48:19 2016 +0300
----------------------------------------------------------------------
solr/CHANGES.txt | 1 +
.../src/java/org/apache/solr/core/SolrCore.java | 1 -
.../apache/solr/search/SolrIndexSearcher.java | 20 +++-
.../solr/handler/admin/StatsReloadRaceTest.java | 99 ++++++++++++++++++++
4 files changed, 116 insertions(+), 5 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/b50b9106/solr/CHANGES.txt
----------------------------------------------------------------------
diff --git a/solr/CHANGES.txt b/solr/CHANGES.txt
index 1e513c8..5013e83 100644
--- a/solr/CHANGES.txt
+++ b/solr/CHANGES.txt
@@ -117,6 +117,7 @@ Bug Fixes
* SOLR-9542: Kerberos delegation tokens requires Jackson library (Ishan Chattopadhyaya via noble)
+* SOLR-9330: Fix AlreadyClosedException on admin/mbeans?stats=true (Mikhail Khludnev)
Optimizations
----------------------
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/b50b9106/solr/core/src/java/org/apache/solr/core/SolrCore.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/core/SolrCore.java b/solr/core/src/java/org/apache/solr/core/SolrCore.java
index 75d394a..e56653a 100644
--- a/solr/core/src/java/org/apache/solr/core/SolrCore.java
+++ b/solr/core/src/java/org/apache/solr/core/SolrCore.java
@@ -2077,7 +2077,6 @@ public final class SolrCore implements SolrInfoMBean, Closeable {
if (_searcher != null) {
_searcher.decref(); // dec refcount for this._searcher
_searcher = null; // isClosed() does check this
- infoRegistry.remove("currentSearcher");
}
}
}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/b50b9106/solr/core/src/java/org/apache/solr/search/SolrIndexSearcher.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/search/SolrIndexSearcher.java b/solr/core/src/java/org/apache/solr/search/SolrIndexSearcher.java
index 000d957..93572b5 100644
--- a/solr/core/src/java/org/apache/solr/search/SolrIndexSearcher.java
+++ b/solr/core/src/java/org/apache/solr/search/SolrIndexSearcher.java
@@ -96,6 +96,7 @@ public class SolrIndexSearcher extends IndexSearcher implements Closeable, SolrI
private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
public static final String STATS_SOURCE = "org.apache.solr.stats_source";
+ public static final String STATISTICS_KEY = "searcher";
// These should *only* be used for debugging or monitoring purposes
public static final AtomicLong numOpens = new AtomicLong();
public static final AtomicLong numCloses = new AtomicLong();
@@ -153,6 +154,8 @@ public class SolrIndexSearcher extends IndexSearcher implements Closeable, SolrI
private final Map<Long, IndexFingerprint> maxVersionFingerprintCache = new ConcurrentHashMap<>();
+ private final NamedList<Object> readerStats;
+
private static DirectoryReader getReader(SolrCore core, SolrIndexConfig config, DirectoryFactory directoryFactory,
String path) throws IOException {
final Directory dir = directoryFactory.get(path, DirContext.DEFAULT, config.lockType);
@@ -338,6 +341,7 @@ public class SolrIndexSearcher extends IndexSearcher implements Closeable, SolrI
// We already have our own filter cache
setQueryCache(null);
+ readerStats = snapStatistics(reader);
// do this at the end since an exception in the constructor means we won't close
numOpens.incrementAndGet();
}
@@ -423,7 +427,7 @@ public class SolrIndexSearcher extends IndexSearcher implements Closeable, SolrI
public void register() {
final Map<String,SolrInfoMBean> infoRegistry = core.getInfoRegistry();
// register self
- infoRegistry.put("searcher", this);
+ infoRegistry.put(STATISTICS_KEY, this);
infoRegistry.put(name, this);
for (SolrCache cache : cacheList) {
cache.setState(SolrCache.State.LIVE);
@@ -2449,15 +2453,23 @@ public class SolrIndexSearcher extends IndexSearcher implements Closeable, SolrI
final NamedList<Object> lst = new SimpleOrderedMap<>();
lst.add("searcherName", name);
lst.add("caching", cachingEnabled);
+
+ lst.addAll(readerStats);
+
+ lst.add("openedAt", openTime);
+ if (registerTime != null) lst.add("registeredAt", registerTime);
+ lst.add("warmupTime", warmupTime);
+ return lst;
+ }
+
+ static private NamedList<Object> snapStatistics(DirectoryReader reader) {
+ final NamedList<Object> lst = new SimpleOrderedMap<>();
lst.add("numDocs", reader.numDocs());
lst.add("maxDoc", reader.maxDoc());
lst.add("deletedDocs", reader.maxDoc() - reader.numDocs());
lst.add("reader", reader.toString());
lst.add("readerDir", reader.directory());
lst.add("indexVersion", reader.getVersion());
- lst.add("openedAt", openTime);
- if (registerTime != null) lst.add("registeredAt", registerTime);
- lst.add("warmupTime", warmupTime);
return lst;
}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/b50b9106/solr/core/src/test/org/apache/solr/handler/admin/StatsReloadRaceTest.java
----------------------------------------------------------------------
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
new file mode 100644
index 0000000..619e7d5
--- /dev/null
+++ b/solr/core/src/test/org/apache/solr/handler/admin/StatsReloadRaceTest.java
@@ -0,0 +1,99 @@
+/*
+ * 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.solr.handler.admin;
+
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.apache.solr.SolrTestCaseJ4;
+import org.apache.solr.common.params.CommonParams;
+import org.apache.solr.common.params.CoreAdminParams;
+import org.apache.solr.common.params.CoreAdminParams.CoreAdminAction;
+import org.apache.solr.common.util.NamedList;
+import org.apache.solr.response.SolrQueryResponse;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class StatsReloadRaceTest extends SolrTestCaseJ4 {
+
+ // to support many times repeating
+ static AtomicInteger taskNum = new AtomicInteger();
+
+ @BeforeClass
+ public static void beforeTests() throws Exception {
+ initCore("solrconfig.xml", "schema.xml");
+
+ XmlDoc docs = new XmlDoc();
+ for (int i = 0; i < atLeast(10); i++) {
+ docs.xml += doc("id", "" + i,
+ "name_s", "" + i);
+ }
+ assertU(add(docs));
+ assertU(commit());
+ }
+
+ @Test
+ public void testParallelReloadAndStats() throws Exception {
+
+ for (int i = 0; i < atLeast(2); i++) {
+
+ int asyncId = taskNum.incrementAndGet();
+
+ SolrQueryResponse rsp = new SolrQueryResponse();
+ h.getCoreContainer().getMultiCoreHandler().handleRequest(req(
+ CommonParams.QT, "/admin/cores",
+ CoreAdminParams.ACTION,
+ CoreAdminParams.CoreAdminAction.RELOAD.toString(),
+ CoreAdminParams.CORE, DEFAULT_TEST_CORENAME,
+ "async", "" + asyncId), new SolrQueryResponse());
+
+ boolean isCompleted;
+ do {
+ String stats = h.query(req(
+ CommonParams.QT, "/admin/mbeans",
+ "stats", "true"));
+
+ NamedList<NamedList<Object>> actualStats = SolrInfoMBeanHandler.fromXML(stats).get("CORE");
+
+ for (Map.Entry<String, NamedList<Object>> tuple : actualStats) {
+ if (tuple.getKey().contains("earcher")) { // catches "searcher" and "Searcher@345345 blah"
+ NamedList<Object> searcherStats = tuple.getValue();
+ @SuppressWarnings("unchecked")
+ NamedList<Object> statsList = (NamedList<Object>)searcherStats.get("stats");
+ assertEquals("expect to have exactly one indexVersion at "+statsList, 1, statsList.getAll("indexVersion").size());
+ assertTrue(statsList.get("indexVersion") instanceof Long);
+ }
+ }
+
+ h.getCoreContainer().getMultiCoreHandler().handleRequest(req(
+ CoreAdminParams.ACTION,
+ CoreAdminParams.CoreAdminAction.REQUESTSTATUS.toString(),
+ CoreAdminParams.REQUESTID, "" + asyncId), rsp);
+
+ @SuppressWarnings("unchecked")
+ List<Object> 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);
+ } while (!isCompleted);
+ }
+ }
+
+}