SOLR-11687: SolrCore.getNewIndexDir falsely returns {dataDir}/index on any IOException reading index.properties

This commit is contained in:
Erick 2017-12-04 09:56:58 -08:00
parent bdaf1baa80
commit 929ce7ca30
2 changed files with 70 additions and 48 deletions

View File

@ -159,6 +159,9 @@ Bug Fixes
* SOLR-11616: Snapshot the segments more robustly such that segments created during a backup does does not fail the
operation (Varun Thacker)
* SOLR-11687: SolrCore.getNewIndexDir falsely returns {dataDir}/index on any IOException reading index.properties
(Nikolay Martynov, Erick Erickson)
Optimizations
----------------------
* SOLR-11285: Refactor autoscaling framework to avoid direct references to Zookeeper and Solr

View File

@ -78,6 +78,7 @@ import org.apache.solr.cloud.CloudDescriptor;
import org.apache.solr.cloud.RecoveryStrategy;
import org.apache.solr.cloud.ZkSolrResourceLoader;
import org.apache.solr.common.SolrException;
import org.apache.solr.common.SolrException.ErrorCode;
import org.apache.solr.common.cloud.ClusterState;
import org.apache.solr.common.cloud.DocCollection;
import org.apache.solr.common.cloud.Slice;
@ -337,42 +338,28 @@ public final class SolrCore implements SolrInfoBean, SolrMetricProducer, Closeab
/**
* Returns the indexdir as given in index.properties. If index.properties exists in dataDir and
* there is a property <i>index</i> available and it points to a valid directory
* in dataDir that is returned Else dataDir/index is returned. Only called for creating new indexSearchers
* in dataDir that is returned. Else dataDir/index is returned. Only called for creating new indexSearchers
* and indexwriters. Use the getIndexDir() method to know the active index directory
*
* @return the indexdir as given in index.properties
*
* @throws SolrException if for any reason the a reasonable index directory cannot be determined.
*/
public String getNewIndexDir() {
String result = dataDir + "index/";
Properties p = new Properties();
Directory dir = null;
try {
dir = getDirectoryFactory().get(getDataDir(), DirContext.META_DATA, getSolrConfig().indexConfig.lockType);
IndexInput input;
try {
input = dir.openInput(IndexFetcher.INDEX_PROPERTIES, IOContext.DEFAULT);
} catch (FileNotFoundException | NoSuchFileException e) {
input = null;
}
if (input != null) {
final InputStream is = new PropertiesInputStream(input);
try {
p.load(new InputStreamReader(is, StandardCharsets.UTF_8));
String s = p.getProperty("index");
if (s != null && s.trim().length() > 0) {
result = dataDir + s;
}
} catch (Exception e) {
log.error("Unable to load " + IndexFetcher.INDEX_PROPERTIES, e);
} finally {
IOUtils.closeQuietly(is);
}
String result = getIndexPropertyFromPropFile(dir);
if (!result.equals(lastNewIndexDir)) {
log.debug("New index directory detected: old=" + lastNewIndexDir + " new=" + result);
}
lastNewIndexDir = result;
return result;
} catch (IOException e) {
SolrException.log(log, "", e);
// See SOLR-11687. It is inadvisable to assume we can do the right thing for any but a small
// number of exceptions that ware caught and swallowed in getIndexProperty.
throw new SolrException(ErrorCode.SERVER_ERROR, "Error in getNewIndexDir, exception: ", e);
} finally {
if (dir != null) {
try {
@ -382,12 +369,44 @@ public final class SolrCore implements SolrInfoBean, SolrMetricProducer, Closeab
}
}
}
if (!result.equals(lastNewIndexDir)) {
log.debug("New index directory detected: old="+lastNewIndexDir + " new=" + result);
}
lastNewIndexDir = result;
return result;
}
// This is guaranteed to return a string or throw an exception.
//
// NOTE: Not finding the index.properties file is normal.
//
// We return dataDir/index if there is an index.properties file with no value for "index"
// See SOLR-11687
//
private String getIndexPropertyFromPropFile(Directory dir) throws IOException {
IndexInput input;
try {
input = dir.openInput(IndexFetcher.INDEX_PROPERTIES, IOContext.DEFAULT);
} catch (FileNotFoundException | NoSuchFileException e) {
// Swallow this error, dataDir/index is the right thing to return
// if there is no index.properties file
// All other exceptions are will propagate to caller.
return dataDir + "index/";
}
final InputStream is = new PropertiesInputStream(input); // c'tor just assigns a variable here, no exception thrown.
try {
Properties p = new Properties();
p.load(new InputStreamReader(is, StandardCharsets.UTF_8));
String s = p.getProperty("index");
if (s != null && s.trim().length() > 0) {
return dataDir + s.trim();
}
// We'll return dataDir/index/ if the properties file has an "index" property with
// no associated value or does not have an index property at all.
return dataDir + "index/";
} finally {
IOUtils.closeQuietly(is);
}
}
private String lastNewIndexDir; // for debugging purposes only... access not synchronized, but that's ok
@ -785,7 +804,7 @@ public final class SolrCore implements SolrInfoBean, SolrMetricProducer, Closeab
throw inner;
}
throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, "Error Instantiating " + msg + ", " + className + " failed to instantiate " + cast.getName(), e);
throw new SolrException(ErrorCode.SERVER_ERROR, "Error Instantiating " + msg + ", " + className + " failed to instantiate " + cast.getName(), e);
}
}
@ -803,7 +822,7 @@ public final class SolrCore implements SolrInfoBean, SolrMetricProducer, Closeab
return UpdateHandler.class.cast(con.newInstance(this, updateHandler));
}
}
throw new SolrException(SolrException.ErrorCode.SERVER_ERROR,"Error Instantiating "+msg+", "+className+ " could not find proper constructor for " + UpdateHandler.class.getName());
throw new SolrException(ErrorCode.SERVER_ERROR,"Error Instantiating "+msg+", "+className+ " could not find proper constructor for " + UpdateHandler.class.getName());
} catch (SolrException e) {
throw e;
} catch (Exception e) {
@ -814,7 +833,7 @@ public final class SolrCore implements SolrInfoBean, SolrMetricProducer, Closeab
throw inner;
}
throw new SolrException(SolrException.ErrorCode.SERVER_ERROR,"Error Instantiating "+msg+", "+className+ " failed to instantiate " + UpdateHandler.class.getName(), e);
throw new SolrException(ErrorCode.SERVER_ERROR,"Error Instantiating "+msg+", "+className+ " failed to instantiate " + UpdateHandler.class.getName(), e);
}
}
@ -986,7 +1005,7 @@ public final class SolrCore implements SolrInfoBean, SolrMetricProducer, Closeab
log.error("Error while closing", t);
}
throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, e.getMessage(), e);
throw new SolrException(ErrorCode.SERVER_ERROR, e.getMessage(), e);
} finally {
// allow firstSearcher events to fire and make sure it is released
latch.countDown();
@ -1188,7 +1207,7 @@ public final class SolrCore implements SolrInfoBean, SolrMetricProducer, Closeab
try {
VersionInfo.getAndCheckVersionField(schema);
} catch (SolrException e) {
throw new SolrException(SolrException.ErrorCode.SERVER_ERROR,
throw new SolrException(ErrorCode.SERVER_ERROR,
"Schema will not work with SolrCloud mode: " +
e.getMessage(), e);
}
@ -1227,7 +1246,7 @@ public final class SolrCore implements SolrInfoBean, SolrMetricProducer, Closeab
dataDir = directoryFactory.getDataHome(coreDescriptor);
}
} catch (IOException e) {
throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, e);
throw new SolrException(ErrorCode.SERVER_ERROR, e);
}
}
}
@ -1302,7 +1321,7 @@ public final class SolrCore implements SolrInfoBean, SolrMetricProducer, Closeab
p.store(os, IndexFetcher.INDEX_PROPERTIES);
dir.sync(Collections.singleton(tmpFileName));
} catch (Exception e) {
throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, "Unable to write " + IndexFetcher.INDEX_PROPERTIES, e);
throw new SolrException(ErrorCode.SERVER_ERROR, "Unable to write " + IndexFetcher.INDEX_PROPERTIES, e);
} finally {
IOUtils.closeQuietly(os);
}
@ -1330,7 +1349,7 @@ public final class SolrCore implements SolrInfoBean, SolrMetricProducer, Closeab
Thread.sleep(milliSleep);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new SolrException(SolrException.ErrorCode.SERVER_ERROR,
throw new SolrException(ErrorCode.SERVER_ERROR,
"Caught InterruptedException whilst waiting for core " + getName() + " to close: "
+ e.getMessage(), e);
}
@ -1360,12 +1379,12 @@ public final class SolrCore implements SolrInfoBean, SolrMetricProducer, Closeab
if (null != ft.getPostingsFormat()) {
String msg = "FieldType '" + ft.getTypeName() + "' is configured with a postings format, but the codec does not support it: " + factory.getClass();
log.error(msg);
throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, msg);
throw new SolrException(ErrorCode.SERVER_ERROR, msg);
}
if (null != ft.getDocValuesFormat()) {
String msg = "FieldType '" + ft.getTypeName() + "' is configured with a docValues format, but the codec does not support it: " + factory.getClass();
log.error(msg);
throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, msg);
throw new SolrException(ErrorCode.SERVER_ERROR, msg);
}
}
}
@ -1428,7 +1447,7 @@ public final class SolrCore implements SolrInfoBean, SolrMetricProducer, Closeab
{
UpdateRequestProcessorChain chain = updateProcessorChains.get( name );
if( chain == null ) {
throw new SolrException( SolrException.ErrorCode.BAD_REQUEST,
throw new SolrException( ErrorCode.BAD_REQUEST,
"unknown UpdateRequestProcessorChain: "+name );
}
return chain;
@ -1947,7 +1966,7 @@ public final class SolrCore implements SolrInfoBean, SolrMetricProducer, Closeab
*/
public RefCounted<SolrIndexSearcher> openNewSearcher(boolean updateHandlerReopens, boolean realtime) {
if (isClosed()) { // catch some errors quicker
throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, "openNewSearcher called on closed core");
throw new SolrException(ErrorCode.SERVER_ERROR, "openNewSearcher called on closed core");
}
SolrIndexSearcher tmp;
@ -2060,7 +2079,7 @@ public final class SolrCore implements SolrInfoBean, SolrMetricProducer, Closeab
if (isClosed()) {
newSearcher.decref(); // once for caller since we're not returning it
newSearcher.decref(); // once for ourselves since it won't be "replaced"
throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, "openNewSearcher called on closed core");
throw new SolrException(ErrorCode.SERVER_ERROR, "openNewSearcher called on closed core");
}
if (realtimeSearcher != null) {
@ -2073,7 +2092,7 @@ public final class SolrCore implements SolrInfoBean, SolrMetricProducer, Closeab
return newSearcher;
} catch (Exception e) {
throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, "Error opening new searcher", e);
throw new SolrException(ErrorCode.SERVER_ERROR, "Error opening new searcher", e);
}
finally {
openSearcherLock.unlock();
@ -2321,7 +2340,7 @@ public final class SolrCore implements SolrInfoBean, SolrMetricProducer, Closeab
} catch (Exception e) {
if (e instanceof SolrException) throw (SolrException)e;
throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, e);
throw new SolrException(ErrorCode.SERVER_ERROR, e);
} finally {
timerContext.close();
@ -2466,7 +2485,7 @@ public final class SolrCore implements SolrInfoBean, SolrMetricProducer, Closeab
if (log.isWarnEnabled()) log.warn(logid + msg + ":" + req);
throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, msg);
throw new SolrException(ErrorCode.BAD_REQUEST, msg);
}
preDecorateResponse(req, rsp);
@ -2552,7 +2571,7 @@ public final class SolrCore implements SolrInfoBean, SolrMetricProducer, Closeab
if( ep != null ) {
EchoParamStyle echoParams = EchoParamStyle.get( ep );
if( echoParams == null ) {
throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "Invalid value '" + ep + "' for " + CommonParams.HEADER_ECHO_PARAMS
throw new SolrException(ErrorCode.BAD_REQUEST, "Invalid value '" + ep + "' for " + CommonParams.HEADER_ECHO_PARAMS
+ " parameter, use '" + EchoParamStyle.EXPLICIT + "' or '" + EchoParamStyle.ALL + "'" );
}
if( echoParams == EchoParamStyle.EXPLICIT ) {
@ -2674,7 +2693,7 @@ public final class SolrCore implements SolrInfoBean, SolrMetricProducer, Closeab
result.put(e.getKey(), (T) o);
} catch (Exception exp) {
//should never happen
throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, "Unable to instantiate class", exp);
throw new SolrException(ErrorCode.SERVER_ERROR, "Unable to instantiate class", exp);
}
}
return result;