SOLR-5087, CoreAdminHandler.handleMergeAction generating NullPointerException. Thanks Patrick

git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1508476 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Erick Erickson 2013-07-30 14:51:56 +00:00
parent 4d29e7e20e
commit 460a1be8a9
4 changed files with 157 additions and 43 deletions

View File

@ -18,6 +18,7 @@
package org.apache.solr.handler.admin;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.lucene.index.DirectoryReader;
@ -295,17 +296,17 @@ public class CoreAdminHandler extends RequestHandlerBase {
}
protected void handleMergeAction(SolrQueryRequest req, SolrQueryResponse rsp) throws IOException {
protected void handleMergeAction(SolrQueryRequest req, SolrQueryResponse rsp) throws Exception {
SolrParams params = req.getParams();
String cname = params.required().get(CoreAdminParams.CORE);
SolrCore core = coreContainer.getCore(cname);
SolrQueryRequest wrappedReq = null;
SolrCore[] sourceCores = null;
RefCounted<SolrIndexSearcher>[] searchers = null;
List<SolrCore> sourceCores = Lists.newArrayList();
List<RefCounted<SolrIndexSearcher>> searchers = Lists.newArrayList();
// stores readers created from indexDir param values
DirectoryReader[] readersToBeClosed = null;
Directory[] dirsToBeReleased = null;
List<DirectoryReader> readersToBeClosed = Lists.newArrayList();
List<Directory> dirsToBeReleased = Lists.newArrayList();
if (core != null) {
try {
String[] dirNames = params.getParams(CoreAdminParams.INDEX_DIR);
@ -315,38 +316,34 @@ public class CoreAdminHandler extends RequestHandlerBase {
throw new SolrException( SolrException.ErrorCode.BAD_REQUEST,
"At least one indexDir or srcCore must be specified");
sourceCores = new SolrCore[sources.length];
for (int i = 0; i < sources.length; i++) {
String source = sources[i];
SolrCore srcCore = coreContainer.getCore(source);
if (srcCore == null)
throw new SolrException(SolrException.ErrorCode.BAD_REQUEST,
"Core: " + source + " does not exist");
sourceCores[i] = srcCore;
sourceCores.add(srcCore);
}
} else {
readersToBeClosed = new DirectoryReader[dirNames.length];
dirsToBeReleased = new Directory[dirNames.length];
DirectoryFactory dirFactory = core.getDirectoryFactory();
for (int i = 0; i < dirNames.length; i++) {
Directory dir = dirFactory.get(dirNames[i], DirContext.DEFAULT, core.getSolrConfig().indexConfig.lockType);
dirsToBeReleased[i] = dir;
dirsToBeReleased.add(dir);
// TODO: why doesn't this use the IR factory? what is going on here?
readersToBeClosed[i] = DirectoryReader.open(dir);
readersToBeClosed.add(DirectoryReader.open(dir));
}
}
DirectoryReader[] readers = null;
if (readersToBeClosed != null) {
List<DirectoryReader> readers = null;
if (readersToBeClosed.size() > 0) {
readers = readersToBeClosed;
} else {
readers = new DirectoryReader[sourceCores.length];
searchers = new RefCounted[sourceCores.length];
for (int i = 0; i < sourceCores.length; i++) {
SolrCore solrCore = sourceCores[i];
readers = Lists.newArrayList();
for (SolrCore solrCore: sourceCores) {
// record the searchers so that we can decref
searchers[i] = solrCore.getSearcher();
readers[i] = searchers[i].get().getIndexReader();
RefCounted<SolrIndexSearcher> searcher = solrCore.getSearcher();
searchers.add(searcher);
readers.add(searcher.get().getIndexReader());
}
}
@ -356,23 +353,21 @@ public class CoreAdminHandler extends RequestHandlerBase {
UpdateRequestProcessor processor =
processorChain.createProcessor(wrappedReq, rsp);
processor.processMergeIndexes(new MergeIndexesCommand(readers, req));
} catch (Exception e) {
// log and rethrow so that if the finally fails we don't lose the original problem
log.error("ERROR executing merge:", e);
throw e;
} finally {
if (searchers != null) {
for (RefCounted<SolrIndexSearcher> searcher : searchers) {
if (searcher != null) searcher.decref();
}
for (RefCounted<SolrIndexSearcher> searcher : searchers) {
if (searcher != null) searcher.decref();
}
if (sourceCores != null) {
for (SolrCore solrCore : sourceCores) {
if (solrCore != null) solrCore.close();
}
for (SolrCore solrCore : sourceCores) {
if (solrCore != null) solrCore.close();
}
if (readersToBeClosed != null) IOUtils.closeWhileHandlingException(readersToBeClosed);
if (dirsToBeReleased != null) {
for (Directory dir : dirsToBeReleased) {
DirectoryFactory dirFactory = core.getDirectoryFactory();
dirFactory.release(dir);
}
IOUtils.closeWhileHandlingException(readersToBeClosed);
for (Directory dir : dirsToBeReleased) {
DirectoryFactory dirFactory = core.getDirectoryFactory();
dirFactory.release(dir);
}
if (wrappedReq != null) wrappedReq.close();
core.close();

View File

@ -31,6 +31,7 @@ import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicLong;
import org.apache.lucene.document.Document;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.Term;
@ -432,11 +433,11 @@ public class DirectUpdateHandler2 extends UpdateHandler implements SolrCoreState
log.info("start " + cmd);
IndexReader[] readers = cmd.readers;
if (readers != null && readers.length > 0) {
List<DirectoryReader> readers = cmd.readers;
if (readers != null && readers.size() > 0) {
RefCounted<IndexWriter> iw = solrCoreState.getIndexWriter(core);
try {
iw.get().addIndexes(readers);
iw.get().addIndexes(readers.toArray(new IndexReader[readers.size()]));
} finally {
iw.decref();
}

View File

@ -17,9 +17,14 @@
package org.apache.solr.update;
import com.google.common.base.Function;
import com.google.common.base.Joiner;
import com.google.common.collect.Iterables;
import org.apache.lucene.index.DirectoryReader;
import org.apache.solr.request.SolrQueryRequest;
import java.util.List;
/**
* A merge indexes command encapsulated in an object.
*
@ -27,9 +32,9 @@ import org.apache.solr.request.SolrQueryRequest;
*
*/
public class MergeIndexesCommand extends UpdateCommand {
public DirectoryReader[] readers;
public List<DirectoryReader> readers;
public MergeIndexesCommand(DirectoryReader[] readers, SolrQueryRequest req) {
public MergeIndexesCommand(List<DirectoryReader> readers, SolrQueryRequest req) {
super(req);
this.readers = readers;
}
@ -42,12 +47,13 @@ public class MergeIndexesCommand extends UpdateCommand {
@Override
public String toString() {
StringBuilder sb = new StringBuilder(super.toString());
if (readers != null && readers.length > 0) {
sb.append(readers[0].directory());
for (int i = 1; i < readers.length; i++) {
sb.append(",").append(readers[i].directory());
Joiner joiner = Joiner.on(",");
Iterable<String> directories = Iterables.transform(readers, new Function<DirectoryReader, String>() {
public String apply(DirectoryReader reader) {
return reader.directory().toString();
}
}
});
joiner.skipNulls().join(sb, directories);
sb.append('}');
return sb.toString();
}

View File

@ -0,0 +1,112 @@
package org.apache.solr.handler.admin;
/*
* 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.
*/
import com.carrotsearch.randomizedtesting.rules.SystemPropertiesRestoreRule;
import org.apache.commons.io.FileUtils;
import org.apache.lucene.store.Directory;
import org.apache.solr.SolrTestCaseJ4;
import org.apache.solr.common.params.CoreAdminParams;
import org.apache.solr.core.CoreContainer;
import org.apache.solr.core.MockFSDirectoryFactory;
import org.apache.solr.core.SolrCore;
import org.apache.solr.response.SolrQueryResponse;
import org.junit.BeforeClass;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.RuleChain;
import org.junit.rules.TestRule;
import java.io.File;
import java.io.IOException;
import java.util.Map;
public class CoreMergeIndexesAdminHandlerTest extends SolrTestCaseJ4 {
@BeforeClass
public static void beforeClass() throws Exception {
useFactory(FailingDirectoryFactory.class.getName());
initCore("solrconfig.xml", "schema.xml");
}
@Rule
public TestRule solrTestRules = RuleChain.outerRule(new SystemPropertiesRestoreRule());
private static String FAILING_MSG = "Creating a directory using FailingDirectoryFactoryException always fails";
public static class FailingDirectoryFactory extends MockFSDirectoryFactory {
public class FailingDirectoryFactoryException extends RuntimeException {
public FailingDirectoryFactoryException() {
super(FAILING_MSG);
}
}
public boolean fail = false;
@Override
public Directory create(String path, DirContext dirContext) throws IOException {
if (fail) {
throw new FailingDirectoryFactoryException();
} else {
return super.create(path, dirContext);
}
}
}
@Test
public void testMergeIndexesCoreAdminHandler() throws Exception {
final File workDir = new File(TEMP_DIR, this.getClass().getName());
if (workDir.exists()) {
FileUtils.deleteDirectory(workDir);
}
assertTrue("Failed to mkdirs workDir", workDir.mkdirs());
final CoreContainer cores = h.getCoreContainer();
final CoreAdminHandler admin = new CoreAdminHandler(cores);
SolrCore core = cores.getCore("collection1");
try {
FailingDirectoryFactory dirFactory = (FailingDirectoryFactory)core.getDirectoryFactory();
try {
dirFactory.fail = true;
ignoreException(FAILING_MSG);
SolrQueryResponse resp = new SolrQueryResponse();
admin.handleRequestBody
(req(CoreAdminParams.ACTION,
CoreAdminParams.CoreAdminAction.MERGEINDEXES.toString(),
CoreAdminParams.CORE, "collection1",
CoreAdminParams.INDEX_DIR, workDir.getAbsolutePath()),
resp);
fail("exception expected");
} catch (FailingDirectoryFactory.FailingDirectoryFactoryException e) {
// expected if error handling properly
} finally {
unIgnoreException(FAILING_MSG);
}
dirFactory.fail = false;
} finally {
core.close();
}
// cleanup
FileUtils.deleteDirectory(workDir);
}
}