| /* |
| * 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.Random; |
| 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 { |
| |
| Random random = random(); |
| |
| for (int i = 0; i < atLeast(random, 2); i++) { |
| |
| int asyncId = taskNum.incrementAndGet(); |
| |
| |
| 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 { |
| if (random.nextBoolean()) { |
| requestMetrics(true); |
| } else { |
| requestCoreStatus(); |
| } |
| |
| isCompleted = checkReloadComlpetion(asyncId); |
| } while (!isCompleted); |
| requestMetrics(false); |
| } |
| } |
| |
| 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<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); |
| return isCompleted; |
| } |
| |
| private void requestMetrics(boolean softFail) throws Exception { |
| SolrQueryResponse rsp = new SolrQueryResponse(); |
| String registry = "solr.core." + h.coreName; |
| String key = "SEARCHER.searcher.indexVersion"; |
| boolean found = false; |
| int count = 10; |
| while (!found && count-- > 0) { |
| h.getCoreContainer().getRequestHandler("/admin/metrics").handleRequest( |
| req("prefix", "SEARCHER", "registry", registry, "compact", "true"), rsp); |
| |
| @SuppressWarnings({"rawtypes"}) |
| NamedList values = rsp.getValues(); |
| // this is not guaranteed to exist right away after core reload - there's a |
| // small window between core load and before searcher metrics are registered |
| // so we may have to check a few times, and then fail softly if reload is not complete yet |
| @SuppressWarnings({"rawtypes"}) |
| NamedList metrics = (NamedList)values.get("metrics"); |
| if (metrics == null) { |
| if (softFail) { |
| return; |
| } else { |
| fail("missing 'metrics' element in handler's output: " + values.asMap(5).toString()); |
| } |
| } |
| metrics = (NamedList)metrics.get(registry); |
| if (metrics.get(key) != null) { |
| found = true; |
| assertTrue(metrics.get(key) instanceof Long); |
| break; |
| } else { |
| Thread.sleep(500); |
| } |
| } |
| if (softFail && !found) { |
| return; |
| } |
| assertTrue("Key " + key + " not found in registry " + registry, found); |
| } |
| |
| } |