mirror of https://github.com/apache/lucene.git
SOLR-4910, improvements to persisting solr.xml and misc other fixes, see CHANGES.txt
git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1493618 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
c362eeb2af
commit
05eb306423
|
@ -141,6 +141,21 @@ Bug Fixes
|
|||
|
||||
* SOLR-4925 : Collection create throws NPE when 'numShards' param is missing (Noble Paul)
|
||||
|
||||
* SOLR-4910: persisting solr.xml is broken. More stringent testing of persistence fixed
|
||||
up a number of issues and several bugs with persistence. Among them are
|
||||
> don't persisting implicit properties
|
||||
> should persist zkHost in the <solr> tag (user's list)
|
||||
> reloading a core that has transient="true" returned an error. reload should load
|
||||
a transient core if it's not yet loaded.
|
||||
> No longer persisting loadOnStartup or transient core properties if they were not
|
||||
specified in the original solr.xml
|
||||
> Testing flushed out the fact that you couldn't swap a core marked transient=true
|
||||
loadOnStartup=false because it hadn't been loaded yet.
|
||||
> SOLR-4862, CREATE fails to persist schema, config, and dataDir
|
||||
> SOLR-4363, not persisting coreLoadThreads in <solr> tag
|
||||
> SOLR-3900, logWatcher properties not persisted
|
||||
> SOLR-4852, cores defined as loadOnStartup=true, transient=false can't be searched
|
||||
|
||||
Other Changes
|
||||
----------------------
|
||||
|
||||
|
|
|
@ -61,7 +61,7 @@ public class ConfigSolrXml extends ConfigSolr {
|
|||
|
||||
// Do sanity checks - we don't want to find old style config
|
||||
failIfFound("solr/@coreLoadThreads");
|
||||
failIfFound("solr/@persist");
|
||||
failIfFound("solr/@persistent");
|
||||
failIfFound("solr/@sharedLib");
|
||||
failIfFound("solr/@zkHost");
|
||||
|
||||
|
|
|
@ -138,9 +138,9 @@ public class ConfigSolrXmlOld extends ConfigSolr {
|
|||
propMap.put(CfgProp.SOLR_SHARDHANDLERFACTORY_NAME,
|
||||
config.getVal("solr/shardHandlerFactory/@name", false));
|
||||
propMap.put(CfgProp.SOLR_SHARDHANDLERFACTORY_CONNTIMEOUT,
|
||||
config.getVal("solr/shardHandlerFactory/int[@connTimeout]", false));
|
||||
config.getVal("solr/shardHandlerFactory/int[@name='connTimeout']", false));
|
||||
propMap.put(CfgProp.SOLR_SHARDHANDLERFACTORY_SOCKETTIMEOUT,
|
||||
config.getVal("solr/shardHandlerFactory/int[@socketTimeout]", false));
|
||||
config.getVal("solr/shardHandlerFactory/int[@name='socketTimeout']", false));
|
||||
|
||||
// These have no counterpart in 5.0, asking, for any of these in Solr 5.0
|
||||
// will result in an error being
|
||||
|
|
|
@ -114,6 +114,8 @@ public class CoreContainer
|
|||
protected Integer zkClientTimeout;
|
||||
protected String solrHome;
|
||||
protected String defaultCoreName = null;
|
||||
protected int distribUpdateConnTimeout = 0;
|
||||
protected int distribUpdateSoTimeout = 0;
|
||||
|
||||
protected ZkContainer zkSys = new ZkContainer();
|
||||
|
||||
|
@ -298,8 +300,8 @@ public class CoreContainer
|
|||
shareSchema = cfg.getBool(ConfigSolr.CfgProp.SOLR_SHARESCHEMA, DEFAULT_SHARE_SCHEMA);
|
||||
zkClientTimeout = cfg.getInt(ConfigSolr.CfgProp.SOLR_ZKCLIENTTIMEOUT, DEFAULT_ZK_CLIENT_TIMEOUT);
|
||||
|
||||
int distribUpdateConnTimeout = cfg.getInt(ConfigSolr.CfgProp.SOLR_DISTRIBUPDATECONNTIMEOUT, 0);
|
||||
int distribUpdateSoTimeout = cfg.getInt(ConfigSolr.CfgProp.SOLR_DISTRIBUPDATESOTIMEOUT, 0);
|
||||
distribUpdateConnTimeout = cfg.getInt(ConfigSolr.CfgProp.SOLR_DISTRIBUPDATECONNTIMEOUT, 0);
|
||||
distribUpdateSoTimeout = cfg.getInt(ConfigSolr.CfgProp.SOLR_DISTRIBUPDATESOTIMEOUT, 0);
|
||||
|
||||
// Note: initZooKeeper will apply hardcoded default if cloud mode
|
||||
String hostPort = cfg.get(ConfigSolr.CfgProp.SOLR_HOSTPORT, null);
|
||||
|
@ -415,7 +417,13 @@ public class CoreContainer
|
|||
p.setTransient(("true".equalsIgnoreCase(opt) || "on"
|
||||
.equalsIgnoreCase(opt)) ? true : false);
|
||||
}
|
||||
|
||||
|
||||
if (p.isTransient() || ! p.isLoadOnStartup()) {
|
||||
// Store it away for later use. includes non-transient but not
|
||||
// loaded at startup cores.
|
||||
solrCores.putDynamicDescriptor(rawName, p);
|
||||
}
|
||||
|
||||
if (p.isLoadOnStartup()) { // The normal case
|
||||
|
||||
Callable<SolrCore> task = new Callable<SolrCore>() {
|
||||
|
@ -449,10 +457,6 @@ public class CoreContainer
|
|||
};
|
||||
pending.add(completionService.submit(task));
|
||||
|
||||
} else {
|
||||
// Store it away for later use. includes non-transient but not
|
||||
// loaded at startup cores.
|
||||
solrCores.putDynamicDescriptor(rawName, p);
|
||||
}
|
||||
} catch (Throwable ex) {
|
||||
SolrException.log(log, null, ex);
|
||||
|
@ -840,7 +844,7 @@ public class CoreContainer
|
|||
try {
|
||||
name = checkDefault(name);
|
||||
|
||||
SolrCore core = solrCores.getCore(name);
|
||||
SolrCore core = solrCores.getCoreFromAnyList(name);
|
||||
if (core == null)
|
||||
throw new SolrException( SolrException.ErrorCode.BAD_REQUEST, "No such core: " + name );
|
||||
|
||||
|
@ -1109,43 +1113,77 @@ public class CoreContainer
|
|||
|
||||
log.info("Persisting cores config to " + (file == null ? configFile : file));
|
||||
|
||||
|
||||
// <solr attrib="value">
|
||||
Map<String,String> rootSolrAttribs = new HashMap<String,String>();
|
||||
if (libDir != null) rootSolrAttribs.put("sharedLib", libDir);
|
||||
rootSolrAttribs.put("persistent", Boolean.toString(isPersistent()));
|
||||
|
||||
|
||||
addAttrib(rootSolrAttribs, ConfigSolr.CfgProp.SOLR_SHAREDLIB, "sharedLib", this.libDir);
|
||||
addAttrib(rootSolrAttribs, ConfigSolr.CfgProp.SOLR_PERSISTENT, "persistent", Boolean.toString(isPersistent()));
|
||||
addAttrib(rootSolrAttribs, ConfigSolr.CfgProp.SOLR_CORELOADTHREADS, "coreLoadThreads",
|
||||
Integer.toString(this.coreLoadThreads), Integer.toString(CORE_LOAD_THREADS));
|
||||
addAttrib(rootSolrAttribs, ConfigSolr.CfgProp.SOLR_ZKHOST, "zkHost", this.zkHost);
|
||||
|
||||
// <solr attrib="value"> <cores attrib="value">
|
||||
Map<String,String> coresAttribs = new HashMap<String,String>();
|
||||
addCoresAttrib(coresAttribs, ConfigSolr.CfgProp.SOLR_ADMINPATH, "adminPath", this.adminPath, null);
|
||||
addCoresAttrib(coresAttribs, ConfigSolr.CfgProp.SOLR_ADMINHANDLER, "adminHandler", this.adminHandler, null);
|
||||
addCoresAttrib(coresAttribs, ConfigSolr.CfgProp.SOLR_SHARESCHEMA,"shareSchema",
|
||||
addAttrib(coresAttribs, ConfigSolr.CfgProp.SOLR_ADMINPATH, "adminPath", this.adminPath);
|
||||
addAttrib(coresAttribs, ConfigSolr.CfgProp.SOLR_ADMINHANDLER, "adminHandler", this.adminHandler);
|
||||
addAttrib(coresAttribs, ConfigSolr.CfgProp.SOLR_SHARESCHEMA, "shareSchema",
|
||||
Boolean.toString(this.shareSchema),
|
||||
Boolean.toString(DEFAULT_SHARE_SCHEMA));
|
||||
addCoresAttrib(coresAttribs, ConfigSolr.CfgProp.SOLR_HOST, "host", zkSys.getHost(), null);
|
||||
addAttrib(coresAttribs, ConfigSolr.CfgProp.SOLR_HOST, "host", zkSys.getHost());
|
||||
|
||||
if (! (null == defaultCoreName || defaultCoreName.equals("")) ) {
|
||||
coresAttribs.put("defaultCoreName", defaultCoreName);
|
||||
}
|
||||
|
||||
addCoresAttrib(coresAttribs, ConfigSolr.CfgProp.SOLR_HOSTPORT, "hostPort",zkSys.getHostPort(), null);
|
||||
addCoresAttrib(coresAttribs, ConfigSolr.CfgProp.SOLR_ZKCLIENTTIMEOUT, "zkClientTimeout",
|
||||
addAttrib(coresAttribs, ConfigSolr.CfgProp.SOLR_HOSTPORT, "hostPort", zkSys.getHostPort());
|
||||
addAttrib(coresAttribs, ConfigSolr.CfgProp.SOLR_ZKCLIENTTIMEOUT, "zkClientTimeout",
|
||||
intToString(this.zkClientTimeout),
|
||||
Integer.toString(DEFAULT_ZK_CLIENT_TIMEOUT));
|
||||
addCoresAttrib(coresAttribs, ConfigSolr.CfgProp.SOLR_HOSTCONTEXT, "hostContext",
|
||||
zkSys.getHostContext(), null);
|
||||
addCoresAttrib(coresAttribs, ConfigSolr.CfgProp.SOLR_LEADERVOTEWAIT, "leaderVoteWait",
|
||||
addAttrib(coresAttribs, ConfigSolr.CfgProp.SOLR_HOSTCONTEXT, "hostContext",
|
||||
zkSys.getHostContext());
|
||||
addAttrib(coresAttribs, ConfigSolr.CfgProp.SOLR_LEADERVOTEWAIT, "leaderVoteWait",
|
||||
zkSys.getLeaderVoteWait(), LEADER_VOTE_WAIT);
|
||||
addCoresAttrib(coresAttribs, ConfigSolr.CfgProp.SOLR_CORELOADTHREADS, "coreLoadThreads",
|
||||
Integer.toString(this.coreLoadThreads), Integer.toString(CORE_LOAD_THREADS));
|
||||
if (transientCacheSize != Integer.MAX_VALUE) { // This test
|
||||
// is a consequence of testing. I really hate it.
|
||||
addCoresAttrib(coresAttribs, ConfigSolr.CfgProp.SOLR_TRANSIENTCACHESIZE, "transientCacheSize",
|
||||
addAttrib(coresAttribs, ConfigSolr.CfgProp.SOLR_TRANSIENTCACHESIZE, "transientCacheSize",
|
||||
Integer.toString(this.transientCacheSize), Integer.toString(Integer.MAX_VALUE));
|
||||
}
|
||||
addAttrib(coresAttribs, ConfigSolr.CfgProp.SOLR_DISTRIBUPDATECONNTIMEOUT, "distribUpdateConnTimeout",
|
||||
Integer.toString(this.distribUpdateConnTimeout));
|
||||
addAttrib(coresAttribs, ConfigSolr.CfgProp.SOLR_DISTRIBUPDATESOTIMEOUT, "distribUpdateSoTimeout",
|
||||
Integer.toString(this.distribUpdateSoTimeout));
|
||||
addAttrib(coresAttribs, ConfigSolr.CfgProp.SOLR_MANAGEMENTPATH, "managementPath",
|
||||
this.managementPath);
|
||||
|
||||
// don't forget the logging stuff
|
||||
Map<String, String> loggingAttribs = new HashMap<String, String>();
|
||||
addAttrib(loggingAttribs, ConfigSolr.CfgProp.SOLR_LOGGING_CLASS, "class",
|
||||
cfg.get(ConfigSolr.CfgProp.SOLR_LOGGING_CLASS, null));
|
||||
addAttrib(loggingAttribs, ConfigSolr.CfgProp.SOLR_LOGGING_ENABLED, "enabled",
|
||||
cfg.get(ConfigSolr.CfgProp.SOLR_LOGGING_ENABLED, null));
|
||||
|
||||
Map<String, String> watcherAttribs = new HashMap<String, String>();
|
||||
addAttrib(watcherAttribs, ConfigSolr.CfgProp.SOLR_LOGGING_WATCHER_SIZE, "size",
|
||||
cfg.get(ConfigSolr.CfgProp.SOLR_LOGGING_WATCHER_SIZE, null));
|
||||
addAttrib(watcherAttribs, ConfigSolr.CfgProp.SOLR_LOGGING_WATCHER_THRESHOLD, "threshold",
|
||||
cfg.get(ConfigSolr.CfgProp.SOLR_LOGGING_WATCHER_THRESHOLD, null));
|
||||
|
||||
|
||||
Map<String, String> shardHandlerAttrib = new HashMap<String, String>();
|
||||
addAttrib(shardHandlerAttrib, ConfigSolr.CfgProp.SOLR_SHARDHANDLERFACTORY_CLASS, "class",
|
||||
cfg.get(ConfigSolr.CfgProp.SOLR_SHARDHANDLERFACTORY_CLASS, null));
|
||||
addAttrib(shardHandlerAttrib, ConfigSolr.CfgProp.SOLR_SHARDHANDLERFACTORY_NAME, "name",
|
||||
cfg.get(ConfigSolr.CfgProp.SOLR_SHARDHANDLERFACTORY_NAME, null));
|
||||
|
||||
Map<String, String> shardHandlerProps = new HashMap<String, String>();
|
||||
addAttrib(shardHandlerProps, ConfigSolr.CfgProp.SOLR_SHARDHANDLERFACTORY_CONNTIMEOUT, "connTimeout",
|
||||
cfg.get(ConfigSolr.CfgProp.SOLR_SHARDHANDLERFACTORY_CONNTIMEOUT, null));
|
||||
addAttrib(shardHandlerProps, ConfigSolr.CfgProp.SOLR_SHARDHANDLERFACTORY_SOCKETTIMEOUT, "socketTimeout",
|
||||
cfg.get(ConfigSolr.CfgProp.SOLR_SHARDHANDLERFACTORY_SOCKETTIMEOUT, null));
|
||||
|
||||
try {
|
||||
solrCores.persistCores(origCfg, containerProperties, rootSolrAttribs, coresAttribs, file, configFile, loader);
|
||||
solrCores.persistCores(origCfg, containerProperties, rootSolrAttribs,coresAttribs,
|
||||
loggingAttribs, watcherAttribs, shardHandlerAttrib, shardHandlerProps, file, loader);
|
||||
} catch (XPathExpressionException e) {
|
||||
throw new SolrException(ErrorCode.SERVER_ERROR, null, e);
|
||||
}
|
||||
|
@ -1156,26 +1194,31 @@ public class CoreContainer
|
|||
return Integer.toString(integer);
|
||||
}
|
||||
|
||||
private void addCoresAttrib(Map<String,String> coresAttribs, ConfigSolr.CfgProp prop,
|
||||
String attribName, String attribValue, String defaultValue) {
|
||||
private void addAttrib(Map<String, String> attribs, ConfigSolr.CfgProp prop,
|
||||
String attribName, String attribValue) {
|
||||
addAttrib(attribs, prop, attribName, attribValue, null);
|
||||
}
|
||||
|
||||
private void addAttrib(Map<String, String> attribs, ConfigSolr.CfgProp prop,
|
||||
String attribName, String attribValue, String defaultValue) {
|
||||
if (cfg == null) {
|
||||
coresAttribs.put(attribName, attribValue);
|
||||
attribs.put(attribName, attribValue);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (attribValue != null) {
|
||||
String origValue = cfg.getOrigProp(prop, null);
|
||||
|
||||
|
||||
if (origValue == null && defaultValue != null && attribValue.equals(defaultValue)) return;
|
||||
|
||||
if (attribValue.equals(PropertiesUtil.substituteProperty(origValue, loader.getCoreProperties()))) {
|
||||
coresAttribs.put(attribName, origValue);
|
||||
attribs.put(attribName, origValue);
|
||||
} else {
|
||||
coresAttribs.put(attribName, attribValue);
|
||||
attribs.put(attribName, attribValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void preRegisterInZk(final CoreDescriptor p) {
|
||||
try {
|
||||
zkSys.getZkController().preRegister(p);
|
||||
|
@ -1194,7 +1237,7 @@ public class CoreContainer
|
|||
public String getSolrHome() {
|
||||
return solrHome;
|
||||
}
|
||||
|
||||
|
||||
public boolean isZooKeeperAware() {
|
||||
return zkSys.getZkController() != null;
|
||||
}
|
||||
|
|
|
@ -65,6 +65,9 @@ public class CoreDescriptor {
|
|||
// them individually.
|
||||
private Properties coreProperties = new Properties();
|
||||
|
||||
//TODO: 5.0 remove this, this is solely a hack for persistence.
|
||||
private Properties createdProperties = new Properties();
|
||||
|
||||
private boolean loadedImplicit = false;
|
||||
|
||||
private final CoreContainer coreContainer;
|
||||
|
@ -280,6 +283,14 @@ public class CoreDescriptor {
|
|||
}
|
||||
}
|
||||
|
||||
public void addCreatedProperty(String key, String value) {
|
||||
createdProperties.put(key, value);
|
||||
}
|
||||
|
||||
public final Properties getCreatedProperties() {
|
||||
return createdProperties;
|
||||
}
|
||||
|
||||
public CloudDescriptor getCloudDescriptor() {
|
||||
return cloudDesc;
|
||||
}
|
||||
|
|
|
@ -35,6 +35,7 @@ import javax.xml.xpath.XPathExpressionException;
|
|||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.solr.cloud.CloudDescriptor;
|
||||
import org.apache.solr.common.SolrException;
|
||||
import org.apache.solr.common.params.CoreAdminParams;
|
||||
import org.apache.solr.core.SolrXMLSerializer.SolrCoreXMLDef;
|
||||
import org.apache.solr.util.DOMUtil;
|
||||
import org.w3c.dom.Node;
|
||||
|
@ -246,10 +247,18 @@ class SolrCores {
|
|||
synchronized (modifyLock) {
|
||||
SolrCore c0 = cores.get(n0);
|
||||
SolrCore c1 = cores.get(n1);
|
||||
if (c0 == null)
|
||||
throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "No such core: " + n0);
|
||||
if (c1 == null)
|
||||
throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "No such core: " + n1);
|
||||
if (c0 == null) { // Might be an unloaded transient core
|
||||
c0 = container.getCore(n0);
|
||||
if (c0 == null) {
|
||||
throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "No such core: " + n0);
|
||||
}
|
||||
}
|
||||
if (c1 == null) { // Might be an unloaded transient core
|
||||
c1 = container.getCore(n1);
|
||||
if (c1 == null) {
|
||||
throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "No such core: " + n1);
|
||||
}
|
||||
}
|
||||
cores.put(n0, c1);
|
||||
cores.put(n1, c0);
|
||||
|
||||
|
@ -351,15 +360,17 @@ class SolrCores {
|
|||
return coreToOrigName.get(solrCore);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void persistCores(Config cfg, Properties containerProperties,
|
||||
Map<String,String> rootSolrAttribs, Map<String,String> coresAttribs,
|
||||
File file, File configFile, SolrResourceLoader loader) throws XPathExpressionException {
|
||||
Map<String, String> loggingAttribs, Map<String,String> watcherAttribs,
|
||||
Map<String, String> shardHandlerAttrib, Map<String,String> shardHandlerProps,
|
||||
File file, SolrResourceLoader loader) throws XPathExpressionException {
|
||||
|
||||
|
||||
|
||||
List<SolrXMLSerializer.SolrCoreXMLDef> solrCoreXMLDefs = new ArrayList<SolrXMLSerializer.SolrCoreXMLDef>();
|
||||
synchronized (modifyLock) {
|
||||
|
||||
|
||||
persistCores(cfg, cores, loader, solrCoreXMLDefs);
|
||||
persistCores(cfg, transientCores, loader, solrCoreXMLDefs);
|
||||
// add back all the cores that aren't loaded, either in cores or transient
|
||||
|
@ -384,9 +395,13 @@ class SolrCores {
|
|||
solrXMLDef.containerProperties = containerProperties;
|
||||
solrXMLDef.solrAttribs = rootSolrAttribs;
|
||||
solrXMLDef.coresAttribs = coresAttribs;
|
||||
solrXMLDef.loggingAttribs = loggingAttribs;
|
||||
solrXMLDef.watcherAttribs = watcherAttribs;
|
||||
solrXMLDef.shardHandlerAttribs = shardHandlerAttrib;
|
||||
solrXMLDef.shardHandlerProps = shardHandlerProps;
|
||||
SOLR_XML_SERIALIZER.persistFile(file, solrXMLDef);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
// Wait here until any pending operations (load, unload or reload) are completed on this core.
|
||||
protected SolrCore waitAddPendingCoreOps(String name) {
|
||||
|
@ -442,95 +457,155 @@ class SolrCores {
|
|||
addCoreToPersistList(cfg, loader, solrCore.getCoreDescriptor(), getCoreToOrigName(solrCore), solrCoreXMLDefs);
|
||||
}
|
||||
}
|
||||
|
||||
private void addCoreProperty(Map<String,String> coreAttribs, SolrResourceLoader loader, Node node, String name,
|
||||
|
||||
private void addCoreProperty(Map<String,String> propMap, SolrResourceLoader loader, Node node, String name,
|
||||
String value) {
|
||||
addCoreProperty(propMap, loader, node, name, value, null);
|
||||
}
|
||||
|
||||
private void addCoreProperty(Map<String,String> propMap, SolrResourceLoader loader, Node node, String name,
|
||||
String value, String defaultValue) {
|
||||
|
||||
|
||||
if (node == null) {
|
||||
coreAttribs.put(name, value);
|
||||
propMap.put(name, value);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (node != null) {
|
||||
String rawAttribValue = DOMUtil.getAttr(node, name, null);
|
||||
|
||||
if (rawAttribValue == null) {
|
||||
return; // It was never in the original definition.
|
||||
}
|
||||
|
||||
if (value == null) {
|
||||
coreAttribs.put(name, rawAttribValue);
|
||||
propMap.put(name, rawAttribValue);
|
||||
return;
|
||||
}
|
||||
if (rawAttribValue == null && defaultValue != null && value.equals(defaultValue)) {
|
||||
|
||||
// There are some _really stupid_ additions/subtractions of the slash that we should look out for. I'm (EOE)
|
||||
// ashamed of this but it fixes some things and we're throwing persistence away anyway (although
|
||||
// maybe not for core.properties files).
|
||||
String defComp = regularizeAttr(defaultValue);
|
||||
|
||||
if (defComp != null && regularizeAttr(value).equals(defComp)) {
|
||||
return;
|
||||
}
|
||||
if (rawAttribValue != null && value.equals(DOMUtil.substituteProperty(rawAttribValue, loader.getCoreProperties()))){
|
||||
coreAttribs.put(name, rawAttribValue);
|
||||
String rawComp = regularizeAttr(rawAttribValue);
|
||||
if (rawComp != null && regularizeAttr(value).equals(
|
||||
regularizeAttr(DOMUtil.substituteProperty(rawAttribValue, loader.getCoreProperties())))) {
|
||||
propMap.put(name, rawAttribValue);
|
||||
} else {
|
||||
coreAttribs.put(name, value);
|
||||
propMap.put(name, value);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected String regularizeAttr(String path) {
|
||||
if (path == null)
|
||||
return null;
|
||||
path = path.replace('/', File.separatorChar);
|
||||
path = path.replace('\\', File.separatorChar);
|
||||
if (path.endsWith(File.separator)) {
|
||||
path = path.substring(0, path.length() - 1);
|
||||
}
|
||||
return path;
|
||||
}
|
||||
protected void addCoreToPersistList(Config cfg, SolrResourceLoader loader,
|
||||
CoreDescriptor dcore, String origCoreName,
|
||||
List<SolrCoreXMLDef> solrCoreXMLDefs) throws XPathExpressionException {
|
||||
|
||||
String coreName = dcore.getProperty(CoreDescriptor.CORE_NAME);
|
||||
|
||||
|
||||
Map<String,String> coreAttribs = new HashMap<String,String>();
|
||||
Properties newProps = new Properties();
|
||||
|
||||
CloudDescriptor cd = dcore.getCloudDescriptor();
|
||||
String collection = null;
|
||||
if (cd != null) collection = cd.getCollectionName();
|
||||
// This is simple, just take anything sent in and saved away in at core creation and write it out.
|
||||
if (dcore.getCreatedProperties().size() > 0) {
|
||||
for (String key : dcore.getCreatedProperties().stringPropertyNames()) {
|
||||
if (CoreAdminParams.ACTION.toString().equals(key)) continue; // Don't persist the "action" verb
|
||||
if (key.indexOf(CoreAdminParams.PROPERTY_PREFIX) == 0) {
|
||||
newProps.put(key.substring(CoreAdminParams.PROPERTY_PREFIX.length()), dcore.getCreatedProperties().getProperty(key));
|
||||
} else {
|
||||
coreAttribs.put(key, dcore.getCreatedProperties().getProperty(key));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
if (origCoreName == null) {
|
||||
origCoreName = coreName;
|
||||
String coreName = dcore.getProperty(CoreDescriptor.CORE_NAME);
|
||||
|
||||
CloudDescriptor cd = dcore.getCloudDescriptor();
|
||||
String collection = null;
|
||||
if (cd != null) collection = cd.getCollectionName();
|
||||
|
||||
if (origCoreName == null) {
|
||||
origCoreName = coreName;
|
||||
}
|
||||
|
||||
Node node = null;
|
||||
if (cfg != null) {
|
||||
node = cfg.getNode("/solr/cores/core[@name='" + origCoreName + "']",
|
||||
false);
|
||||
}
|
||||
|
||||
coreAttribs.put(CoreDescriptor.CORE_NAME, coreName);
|
||||
|
||||
addCoreProperty(coreAttribs, loader, node, CoreDescriptor.CORE_INSTDIR, dcore.getRawInstanceDir(), null);
|
||||
|
||||
addCoreProperty(coreAttribs, loader, node, CoreDescriptor.CORE_COLLECTION,
|
||||
StringUtils.isNotBlank(collection) ? collection : dcore.getName());
|
||||
|
||||
addCoreProperty(coreAttribs, loader, node, CoreDescriptor.CORE_DATADIR,
|
||||
dcore.getDataDir());
|
||||
addCoreProperty(coreAttribs, loader, node, CoreDescriptor.CORE_ULOGDIR,
|
||||
dcore.getUlogDir());
|
||||
addCoreProperty(coreAttribs, loader, node, CoreDescriptor.CORE_TRANSIENT,
|
||||
Boolean.toString(dcore.isTransient()));
|
||||
addCoreProperty(coreAttribs, loader, node, CoreDescriptor.CORE_LOADONSTARTUP,
|
||||
Boolean.toString(dcore.isLoadOnStartup()));
|
||||
addCoreProperty(coreAttribs, loader, node, CoreDescriptor.CORE_CONFIG,
|
||||
dcore.getConfigName());
|
||||
addCoreProperty(coreAttribs, loader, node, CoreDescriptor.CORE_SCHEMA,
|
||||
dcore.getSchemaName());
|
||||
|
||||
addCoreProperty(coreAttribs, loader, node, CoreDescriptor.CORE_COLLECTION,
|
||||
collection, dcore.getName());
|
||||
|
||||
String shard = null;
|
||||
String roles = null;
|
||||
String node_name = null;
|
||||
if (cd != null) {
|
||||
shard = cd.getShardId();
|
||||
roles = cd.getRoles();
|
||||
node_name = cd.getCoreNodeName();
|
||||
}
|
||||
addCoreProperty(coreAttribs, loader, node, CoreDescriptor.CORE_SHARD,
|
||||
shard);
|
||||
|
||||
addCoreProperty(coreAttribs, loader, node, CoreDescriptor.CORE_ROLES,
|
||||
roles);
|
||||
|
||||
addCoreProperty(coreAttribs, loader, node, CoreDescriptor.CORE_NODE_NAME,
|
||||
node_name);
|
||||
|
||||
|
||||
for (Object key : dcore.getCoreProperties().keySet()) {
|
||||
|
||||
if (cfg != null) {
|
||||
Node propNode = cfg.getNode("/solr/cores/core[@name='" + origCoreName + "']/property[@name='" + key + "']",
|
||||
false);
|
||||
|
||||
if (propNode != null) { // This means it was in the original DOM element, so just copy it.
|
||||
newProps.put(DOMUtil.getAttr(propNode, "name", null), DOMUtil.getAttr(propNode, "value", null));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Properties properties = dcore.getCoreProperties();
|
||||
Node node = null;
|
||||
if (cfg != null) {
|
||||
node = cfg.getNode("/solr/cores/core[@name='" + origCoreName + "']",
|
||||
false);
|
||||
}
|
||||
|
||||
coreAttribs.put(CoreDescriptor.CORE_NAME, coreName);
|
||||
|
||||
addCoreProperty(coreAttribs, loader, node, CoreDescriptor.CORE_INSTDIR, dcore.getRawInstanceDir(), null);
|
||||
|
||||
coreAttribs.put(CoreDescriptor.CORE_COLLECTION,
|
||||
StringUtils.isNotBlank(collection) ? collection : dcore.getName());
|
||||
|
||||
addCoreProperty(coreAttribs, loader, node, CoreDescriptor.CORE_DATADIR, dcore.getDataDir(), null);
|
||||
addCoreProperty(coreAttribs, loader, node, CoreDescriptor.CORE_ULOGDIR, dcore.getUlogDir(), null);
|
||||
addCoreProperty(coreAttribs, loader, node, CoreDescriptor.CORE_TRANSIENT, Boolean.toString(dcore.isTransient()), null);
|
||||
addCoreProperty(coreAttribs, loader, node, CoreDescriptor.CORE_LOADONSTARTUP, Boolean.toString(dcore.isLoadOnStartup()), null);
|
||||
|
||||
addCoreProperty(coreAttribs, loader, node, CoreDescriptor.CORE_COLLECTION,
|
||||
collection, dcore.getName());
|
||||
|
||||
String shard = null;
|
||||
String roles = null;
|
||||
if (cd != null) {
|
||||
shard = cd.getShardId();
|
||||
roles = cd.getRoles();
|
||||
}
|
||||
addCoreProperty(coreAttribs, loader, node, CoreDescriptor.CORE_SHARD,
|
||||
shard, null);
|
||||
|
||||
addCoreProperty(coreAttribs, loader, node, CoreDescriptor.CORE_ROLES,
|
||||
roles, null);
|
||||
|
||||
coreAttribs.put(CoreDescriptor.CORE_LOADONSTARTUP,
|
||||
Boolean.toString(dcore.isLoadOnStartup()));
|
||||
coreAttribs.put(CoreDescriptor.CORE_TRANSIENT,
|
||||
Boolean.toString(dcore.isTransient()));
|
||||
|
||||
|
||||
SolrXMLSerializer.SolrCoreXMLDef solrCoreXMLDef = new SolrXMLSerializer.SolrCoreXMLDef();
|
||||
solrCoreXMLDef.coreAttribs = coreAttribs;
|
||||
solrCoreXMLDef.coreProperties = properties;
|
||||
solrCoreXMLDef.coreProperties = newProps;
|
||||
solrCoreXMLDefs.add(solrCoreXMLDef);
|
||||
|
||||
}
|
||||
|
||||
protected Object getModifyLock() {
|
||||
|
|
|
@ -62,6 +62,41 @@ public class SolrXMLSerializer {
|
|||
if (containerProperties != null && !containerProperties.isEmpty()) {
|
||||
writeProperties(w, containerProperties, " ");
|
||||
}
|
||||
|
||||
// Output logging section if any
|
||||
if (solrXMLDef.loggingAttribs.size() > 0 || solrXMLDef.watcherAttribs.size() > 0) {
|
||||
w.write(INDENT + "<logging");
|
||||
for (Map.Entry<String, String> ent : solrXMLDef.loggingAttribs.entrySet()) {
|
||||
writeAttribute(w, ent.getKey(), ent.getValue());
|
||||
}
|
||||
w.write(">\n");
|
||||
|
||||
if (solrXMLDef.watcherAttribs.size() > 0) {
|
||||
w.write(INDENT + INDENT + "<watcher");
|
||||
for (Map.Entry<String, String> ent : solrXMLDef.watcherAttribs.entrySet()) {
|
||||
writeAttribute(w, ent.getKey(), ent.getValue());
|
||||
}
|
||||
w.write("/>\n");
|
||||
}
|
||||
w.write(INDENT + "</logging>\n");
|
||||
}
|
||||
|
||||
// Output shard handler section if any
|
||||
if (solrXMLDef.shardHandlerAttribs.size() > 0 || solrXMLDef.shardHandlerProps.size() > 0) {
|
||||
w.write(INDENT + "<shardHandlerFactory");
|
||||
for (Map.Entry<String, String> ent : solrXMLDef.shardHandlerAttribs.entrySet()) {
|
||||
writeAttribute(w, ent.getKey(), ent.getValue());
|
||||
}
|
||||
w.write(">\n");
|
||||
if (solrXMLDef.shardHandlerProps.size() > 0) {
|
||||
for (Map.Entry<String, String> ent : solrXMLDef.shardHandlerProps.entrySet()) {
|
||||
w.write(INDENT + INDENT + "<int name=\"" + ent.getKey() + "\"" + ">" + ent.getValue() + "</int>\n");
|
||||
}
|
||||
}
|
||||
w.write(INDENT + "</shardHandlerFactory>\n");
|
||||
}
|
||||
|
||||
|
||||
w.write(INDENT + "<cores");
|
||||
Map<String,String> coresAttribs = solrXMLDef.coresAttribs;
|
||||
Set<String> coreAttribKeys = coresAttribs.keySet();
|
||||
|
@ -198,6 +233,10 @@ public class SolrXMLSerializer {
|
|||
Properties containerProperties;
|
||||
Map<String,String> solrAttribs;
|
||||
Map<String,String> coresAttribs;
|
||||
Map<String, String> loggingAttribs;
|
||||
Map<String, String> watcherAttribs;
|
||||
Map<String, String> shardHandlerAttribs;
|
||||
Map<String, String> shardHandlerProps;
|
||||
List<SolrCoreXMLDef> coresDefs;
|
||||
}
|
||||
|
||||
|
|
|
@ -498,10 +498,12 @@ public class CoreAdminHandler extends RequestHandlerBase {
|
|||
Iterator<String> parameterNamesIterator = params.getParameterNamesIterator();
|
||||
while (parameterNamesIterator.hasNext()) {
|
||||
String parameterName = parameterNamesIterator.next();
|
||||
String parameterValue = params.get(parameterName);
|
||||
dcore.addCreatedProperty(parameterName, parameterValue); // Need this junk for silly persistence
|
||||
|
||||
if(parameterName.startsWith(CoreAdminParams.PROPERTY_PREFIX)) {
|
||||
String parameterValue = params.get(parameterName);
|
||||
String propertyName = parameterName.substring(CoreAdminParams.PROPERTY_PREFIX.length()); // skip prefix
|
||||
coreProperties.put(propertyName, parameterValue);
|
||||
String propertyName = parameterName.substring(CoreAdminParams.PROPERTY_PREFIX.length()); // skip prefix
|
||||
coreProperties.put(propertyName, parameterValue);
|
||||
}
|
||||
}
|
||||
dcore.setCoreProperties(coreProperties);
|
||||
|
|
|
@ -392,22 +392,4 @@ public class TestCoreContainer extends SolrTestCaseJ4 {
|
|||
" <cores adminPath=\"/admin/cores\" transientCacheSize=\"32\" >\n" +
|
||||
" </cores>\n" +
|
||||
"</solr>";
|
||||
|
||||
private static final String SOLR_XML_SAME_NAME ="<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n" +
|
||||
"<solr persistent=\"false\">\n" +
|
||||
" <cores adminPath=\"/admin/cores\" transientCacheSize=\"32\" >\n" +
|
||||
" <core name=\"core1\" instanceDir=\"core1\" dataDir=\"core1\"/> \n" +
|
||||
" <core name=\"core1\" instanceDir=\"core2\" dataDir=\"core2\"/> \n " +
|
||||
" </cores>\n" +
|
||||
"</solr>";
|
||||
|
||||
private static final String SOLR_XML_SAME_DATADIR ="<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n" +
|
||||
"<solr persistent=\"false\">\n" +
|
||||
" <cores adminPath=\"/admin/cores\" transientCacheSize=\"32\" >\n" +
|
||||
" <core name=\"core2\" instanceDir=\"core2\" dataDir=\"../samedatadir\" schema=\"schema-tiny.xml\" config=\"solrconfig-minimal.xml\" /> \n" +
|
||||
" <core name=\"core1\" instanceDir=\"core2\" dataDir=\"../samedatadir\" schema=\"schema-tiny.xml\" config=\"solrconfig-minimal.xml\" /> \n " +
|
||||
" </cores>\n" +
|
||||
"</solr>";
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -143,6 +143,11 @@ public class TestSolrXMLSerializer extends LuceneTestCase {
|
|||
solrXMLDef.containerProperties = containerProperties ;
|
||||
solrXMLDef.solrAttribs = rootSolrAttribs;
|
||||
solrXMLDef.coresAttribs = coresAttribs;
|
||||
solrXMLDef.loggingAttribs = new HashMap<String, String>();
|
||||
solrXMLDef.shardHandlerProps = new HashMap<String, String>();
|
||||
solrXMLDef.shardHandlerAttribs = new HashMap<String, String>();
|
||||
solrXMLDef.loggingAttribs = new HashMap<String, String>();
|
||||
solrXMLDef.watcherAttribs = new HashMap<String, String>();
|
||||
return solrXMLDef;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,510 @@
|
|||
/*
|
||||
* 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.core;
|
||||
|
||||
import com.carrotsearch.randomizedtesting.rules.SystemPropertiesRestoreRule;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.lucene.util.IOUtils;
|
||||
import org.apache.solr.SolrTestCaseJ4;
|
||||
import org.apache.solr.common.params.CoreAdminParams;
|
||||
import org.apache.solr.handler.admin.CoreAdminHandler;
|
||||
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 org.w3c.dom.Document;
|
||||
import org.w3c.dom.NamedNodeMap;
|
||||
import org.w3c.dom.Node;
|
||||
import org.w3c.dom.NodeList;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class TestSolrXmlPersistence extends SolrTestCaseJ4 {
|
||||
|
||||
private final File solrHomeDirectory = new File(TEMP_DIR, this.getClass().getName());
|
||||
|
||||
@BeforeClass
|
||||
public static void beforeClass() throws Exception {
|
||||
initCore("solrconfig-minimal.xml", "schema-tiny.xml");
|
||||
}
|
||||
|
||||
@Rule
|
||||
public TestRule solrTestRules =
|
||||
RuleChain.outerRule(new SystemPropertiesRestoreRule());
|
||||
|
||||
|
||||
private CoreContainer init(String solrXmlString, String... subDirs) throws Exception {
|
||||
if (solrHomeDirectory.exists()) {
|
||||
FileUtils.deleteDirectory(solrHomeDirectory);
|
||||
}
|
||||
|
||||
for (String s : subDirs) {
|
||||
copyMinConf(new File(solrHomeDirectory, s));
|
||||
}
|
||||
|
||||
File solrXml = new File(solrHomeDirectory, "solr.xml");
|
||||
FileUtils.write(solrXml, solrXmlString, IOUtils.CHARSET_UTF_8.toString());
|
||||
final CoreContainer cores = new CoreContainer(solrHomeDirectory.getAbsolutePath());
|
||||
cores.load(solrHomeDirectory.getAbsolutePath(), solrXml);
|
||||
|
||||
cores.setPersistent(false);
|
||||
return cores;
|
||||
}
|
||||
|
||||
|
||||
// take a solr.xml with system vars in <solr>, <cores> and <core> and <core/properties> tags that have system
|
||||
// variables defined. Insure that after persisting solr.xml, they're all still there as ${} syntax.
|
||||
// Also insure that nothing extra crept in.
|
||||
@Test
|
||||
public void testSystemVars() throws Exception {
|
||||
//Set these system props in order to insure that we don't write out the values rather than the ${} syntax.
|
||||
System.setProperty("solr.zkclienttimeout", "93");
|
||||
System.setProperty("solrconfig", "solrconfig-minimal.xml");
|
||||
System.setProperty("schema", "schema-tiny.xml");
|
||||
System.setProperty("zkHostSet", "localhost:9983");
|
||||
|
||||
CoreContainer cc = init(SOLR_XML_LOTS_SYSVARS, "SystemVars1", "SystemVars2");
|
||||
try {
|
||||
|
||||
// This seems odd, but it's just a little self check to see if the comparison strings are being created correctly
|
||||
origMatchesPersist(cc, new File(solrHomeDirectory, "solr_copy.xml"));
|
||||
|
||||
// Is everything in the persisted file identical to the original?
|
||||
final File persistXml = new File(solrHomeDirectory, "sysvars.solr.xml");
|
||||
// Side effect here is that the new file is persisted and available later.
|
||||
origMatchesPersist(cc, persistXml);
|
||||
|
||||
// Is everything in the original contained in the persisted one?
|
||||
assertXmlFile(persistXml, getAllNodes(new File(solrHomeDirectory, "solr.xml")));
|
||||
|
||||
} finally {
|
||||
cc.shutdown();
|
||||
if (solrHomeDirectory.exists()) {
|
||||
FileUtils.deleteDirectory(solrHomeDirectory);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReload() throws Exception {
|
||||
// Whether the core is transient or not can make a difference.
|
||||
doReloadTest("SystemVars2");
|
||||
doReloadTest("SystemVars1");
|
||||
|
||||
}
|
||||
|
||||
private void doReloadTest(String which) throws Exception {
|
||||
|
||||
CoreContainer cc = init(SOLR_XML_LOTS_SYSVARS, "SystemVars1", "SystemVars2");
|
||||
try {
|
||||
final CoreAdminHandler admin = new CoreAdminHandler(cc);
|
||||
SolrQueryResponse resp = new SolrQueryResponse();
|
||||
admin.handleRequestBody
|
||||
(req(CoreAdminParams.ACTION,
|
||||
CoreAdminParams.CoreAdminAction.RELOAD.toString(),
|
||||
CoreAdminParams.CORE, which),
|
||||
resp);
|
||||
assertNull("Exception on reload", resp.getException());
|
||||
|
||||
origMatchesPersist(cc, new File(solrHomeDirectory, "reload1.solr.xml"));
|
||||
|
||||
} finally {
|
||||
cc.shutdown();
|
||||
if (solrHomeDirectory.exists()) {
|
||||
FileUtils.deleteDirectory(solrHomeDirectory);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRename() throws Exception {
|
||||
doTestRename("SystemVars1");
|
||||
doTestRename("SystemVars2");
|
||||
}
|
||||
|
||||
private void doTestRename(String which) throws Exception {
|
||||
CoreContainer cc = init(SOLR_XML_LOTS_SYSVARS, "SystemVars1", "SystemVars2");
|
||||
try {
|
||||
final CoreAdminHandler admin = new CoreAdminHandler(cc);
|
||||
SolrQueryResponse resp = new SolrQueryResponse();
|
||||
admin.handleRequestBody
|
||||
(req(CoreAdminParams.ACTION,
|
||||
CoreAdminParams.CoreAdminAction.RENAME.toString(),
|
||||
CoreAdminParams.CORE, which,
|
||||
CoreAdminParams.OTHER, "RenamedCore"),
|
||||
resp);
|
||||
assertNull("Exception on rename", resp.getException());
|
||||
|
||||
File persistXml = new File(solrHomeDirectory, "rename.solr.xml");
|
||||
File origXml = new File(solrHomeDirectory, "solr.xml");
|
||||
|
||||
// OK, Assure that if I change everything that has been renamed with the original value for the core, it matches
|
||||
// the old list
|
||||
cc.persistFile(persistXml);
|
||||
String[] persistList = getAllNodes(persistXml);
|
||||
String[] expressions = new String[persistList.length];
|
||||
|
||||
for (int idx = 0; idx < persistList.length; ++idx) {
|
||||
expressions[idx] = persistList[idx].replaceAll("RenamedCore", which);
|
||||
}
|
||||
|
||||
assertXmlFile(origXml, expressions);
|
||||
|
||||
// Now the other way, If I replace the original name in the original XML file with "RenamedCore", does it match
|
||||
// what was persisted?
|
||||
persistList = getAllNodes(origXml);
|
||||
for (int idx = 0; idx < persistList.length; ++idx) {
|
||||
// /solr/cores/core[@name='SystemVars1' and @collection='${collection:collection1}']
|
||||
expressions[idx] = persistList[idx].replace("@name='" + which + "'", "@name='RenamedCore'");
|
||||
}
|
||||
|
||||
assertXmlFile(persistXml, expressions);
|
||||
} finally {
|
||||
cc.shutdown();
|
||||
if (solrHomeDirectory.exists()) {
|
||||
FileUtils.deleteDirectory(solrHomeDirectory);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSwap() throws Exception {
|
||||
doTestSwap("SystemVars1", "SystemVars2");
|
||||
doTestSwap("SystemVars2", "SystemVars1");
|
||||
}
|
||||
|
||||
private void doTestSwap(String from, String to) throws Exception {
|
||||
CoreContainer cc = init(SOLR_XML_LOTS_SYSVARS, "SystemVars1", "SystemVars2");
|
||||
try {
|
||||
final CoreAdminHandler admin = new CoreAdminHandler(cc);
|
||||
SolrQueryResponse resp = new SolrQueryResponse();
|
||||
admin.handleRequestBody
|
||||
(req(CoreAdminParams.ACTION,
|
||||
CoreAdminParams.CoreAdminAction.SWAP.toString(),
|
||||
CoreAdminParams.CORE, from,
|
||||
CoreAdminParams.OTHER, to),
|
||||
resp);
|
||||
assertNull("Exception on swap", resp.getException());
|
||||
|
||||
File persistXml = new File(solrHomeDirectory, "rename.solr.xml");
|
||||
File origXml = new File(solrHomeDirectory, "solr.xml");
|
||||
|
||||
cc.persistFile(persistXml);
|
||||
String[] persistList = getAllNodes(persistXml);
|
||||
String[] expressions = new String[persistList.length];
|
||||
|
||||
// Now manually change the names back and it should match exactly to the original XML.
|
||||
for (int idx = 0; idx < persistList.length; ++idx) {
|
||||
String fromName = "@name='" + from + "'";
|
||||
String toName = "@name='" + to + "'";
|
||||
if (persistList[idx].contains(fromName)) {
|
||||
expressions[idx] = persistList[idx].replace(fromName, toName);
|
||||
} else {
|
||||
expressions[idx] = persistList[idx].replace(toName, fromName);
|
||||
}
|
||||
}
|
||||
|
||||
assertXmlFile(origXml, expressions);
|
||||
|
||||
} finally {
|
||||
cc.shutdown();
|
||||
if (solrHomeDirectory.exists()) {
|
||||
FileUtils.deleteDirectory(solrHomeDirectory);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnloadCreate() throws Exception {
|
||||
doTestUnloadCreate("SystemVars1");
|
||||
doTestUnloadCreate("SystemVars2");
|
||||
}
|
||||
|
||||
private void doTestUnloadCreate(String which) throws Exception {
|
||||
CoreContainer cc = init(SOLR_XML_LOTS_SYSVARS, "SystemVars1", "SystemVars2");
|
||||
try {
|
||||
final CoreAdminHandler admin = new CoreAdminHandler(cc);
|
||||
|
||||
SolrQueryResponse resp = new SolrQueryResponse();
|
||||
admin.handleRequestBody
|
||||
(req(CoreAdminParams.ACTION,
|
||||
CoreAdminParams.CoreAdminAction.UNLOAD.toString(),
|
||||
CoreAdminParams.CORE, which),
|
||||
resp);
|
||||
assertNull("Exception on unload", resp.getException());
|
||||
|
||||
origMatchesPersist(cc, new File(solrHomeDirectory, "unloadcreate1.solr.xml"));
|
||||
|
||||
String instPath = new File(solrHomeDirectory, which).getAbsolutePath();
|
||||
admin.handleRequestBody
|
||||
(req(CoreAdminParams.ACTION,
|
||||
CoreAdminParams.CoreAdminAction.CREATE.toString(),
|
||||
CoreAdminParams.INSTANCE_DIR, instPath,
|
||||
CoreAdminParams.CONFIG, "solrconfig-minimal.xml",
|
||||
CoreAdminParams.SCHEMA, "schema-tiny.xml",
|
||||
CoreAdminParams.NAME, which),
|
||||
resp);
|
||||
assertNull("Exception on create", resp.getException());
|
||||
|
||||
File persistXml = new File(solrHomeDirectory, "rename.solr.xml");
|
||||
File origXml = new File(solrHomeDirectory, "solr.xml");
|
||||
|
||||
cc.persistFile(persistXml);
|
||||
String[] persistList = getAllNodes(persistXml);
|
||||
String[] expressions = new String[persistList.length];
|
||||
|
||||
// Now manually change the names back and it should match exactly to the original XML.
|
||||
for (int idx = 0; idx < persistList.length; ++idx) {
|
||||
String name = "@name='" + which + "'";
|
||||
|
||||
if (persistList[idx].contains(name)) {
|
||||
if (persistList[idx].contains("@schema='schema-tiny.xml'")) {
|
||||
expressions[idx] = persistList[idx].replace("schema-tiny.xml", "${schema:schema-tiny.xml}");
|
||||
} else if (persistList[idx].contains("@config='solrconfig-minimal.xml'")) {
|
||||
expressions[idx] = persistList[idx].replace("solrconfig-minimal.xml", "${solrconfig:solrconfig-minimal.xml}");
|
||||
} else if (persistList[idx].contains("@instanceDir=")) {
|
||||
expressions[idx] = persistList[idx].replaceFirst("instanceDir\\='.*?'", "instanceDir='" + which + "'");
|
||||
} else {
|
||||
expressions[idx] = persistList[idx];
|
||||
}
|
||||
} else {
|
||||
expressions[idx] = persistList[idx];
|
||||
}
|
||||
}
|
||||
|
||||
assertXmlFile(origXml, expressions);
|
||||
|
||||
|
||||
} finally {
|
||||
cc.shutdown();
|
||||
if (solrHomeDirectory.exists()) {
|
||||
FileUtils.deleteDirectory(solrHomeDirectory);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void origMatchesPersist(CoreContainer cc, File persistXml) throws IOException, SAXException, ParserConfigurationException {
|
||||
cc.persistFile(persistXml);
|
||||
// Is everything that's in the original file persisted?
|
||||
String[] expressions = getAllNodes(persistXml);
|
||||
assertXmlFile(new File(solrHomeDirectory, "solr.xml"), expressions);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreatePersistCore() throws Exception {
|
||||
// Template for creating a core.
|
||||
CoreContainer cc = init(SOLR_XML_LOTS_SYSVARS, "SystemVars1", "SystemVars2", "props1", "props2");
|
||||
try {
|
||||
final CoreAdminHandler admin = new CoreAdminHandler(cc);
|
||||
// create a new core (using CoreAdminHandler) w/ properties
|
||||
String instPath1 = new File(solrHomeDirectory, "props1").getAbsolutePath();
|
||||
SolrQueryResponse resp = new SolrQueryResponse();
|
||||
admin.handleRequestBody
|
||||
(req(CoreAdminParams.ACTION,
|
||||
CoreAdminParams.CoreAdminAction.CREATE.toString(),
|
||||
CoreAdminParams.INSTANCE_DIR, instPath1,
|
||||
CoreAdminParams.NAME, "props1",
|
||||
CoreAdminParams.TRANSIENT, "true",
|
||||
CoreAdminParams.LOAD_ON_STARTUP, "true",
|
||||
CoreAdminParams.PROPERTY_PREFIX + "prefix1", "valuep1",
|
||||
CoreAdminParams.PROPERTY_PREFIX + "prefix2", "valueP2",
|
||||
CoreAdminParams.CONFIG, "solrconfig-minimal.xml",
|
||||
CoreAdminParams.SCHEMA, "schema-tiny.xml"),
|
||||
resp);
|
||||
assertNull("Exception on create", resp.getException());
|
||||
|
||||
String instPath2 = new File(solrHomeDirectory, "props2").getAbsolutePath();
|
||||
admin.handleRequestBody
|
||||
(req(CoreAdminParams.ACTION,
|
||||
CoreAdminParams.CoreAdminAction.CREATE.toString(),
|
||||
CoreAdminParams.INSTANCE_DIR, instPath2,
|
||||
CoreAdminParams.NAME, "props2",
|
||||
CoreAdminParams.PROPERTY_PREFIX + "prefix2_1", "valuep2_1",
|
||||
CoreAdminParams.PROPERTY_PREFIX + "prefix2_2", "valueP2_2",
|
||||
CoreAdminParams.CONFIG, "solrconfig-minimal.xml",
|
||||
CoreAdminParams.DATA_DIR, "./dataDirTest",
|
||||
CoreAdminParams.SCHEMA, "schema-tiny.xml"),
|
||||
resp);
|
||||
assertNull("Exception on create", resp.getException());
|
||||
|
||||
// Everything that was in the original XML file should be in the persisted one.
|
||||
final File persistXml = new File(solrHomeDirectory, "persist_create_core.solr.xml");
|
||||
cc.persistFile(persistXml);
|
||||
String[] expressions = getAllNodes(new File(solrHomeDirectory, "solr.xml"));
|
||||
assertXmlFile(persistXml, expressions);
|
||||
|
||||
|
||||
// And the params for the new core should be in the persisted file.
|
||||
assertXmlFile
|
||||
(persistXml
|
||||
, "/solr/cores/core[@name='props1']/property[@name='prefix1' and @value='valuep1']"
|
||||
, "/solr/cores/core[@name='props1']/property[@name='prefix2' and @value='valueP2']"
|
||||
, "/solr/cores/core[@name='props1' and @config='solrconfig-minimal.xml']"
|
||||
, "/solr/cores/core[@name='props1' and @schema='schema-tiny.xml']"
|
||||
, "/solr/cores/core[@name='props1' and @transient='true']"
|
||||
, "/solr/cores/core[@name='props1' and @loadOnStartup='true']"
|
||||
, "/solr/cores/core[@name='props2']/property[@name='prefix2_1' and @value='valuep2_1']"
|
||||
, "/solr/cores/core[@name='props2']/property[@name='prefix2_2' and @value='valueP2_2']"
|
||||
, "/solr/cores/core[@name='props2' and @config='solrconfig-minimal.xml']"
|
||||
, "/solr/cores/core[@name='props2' and @schema='schema-tiny.xml']"
|
||||
, "/solr/cores/core[@name='props2' and not(@loadOnStartup)]"
|
||||
, "/solr/cores/core[@name='props2' and not(@transient)]"
|
||||
, "/solr/cores/core[@name='props2' and @dataDir='./dataDirTest']"
|
||||
);
|
||||
|
||||
} finally {
|
||||
cc.shutdown();
|
||||
if (solrHomeDirectory.exists()) {
|
||||
FileUtils.deleteDirectory(solrHomeDirectory);
|
||||
}
|
||||
|
||||
}
|
||||
// / insure that after you create a core and persist solr.xml the created core has
|
||||
// all expected and no extraneous values, both attribs and <property> tags.
|
||||
// How to create this core with sysprops?
|
||||
}
|
||||
|
||||
private String[] getAllNodes(File xmlFile) throws ParserConfigurationException, IOException, SAXException {
|
||||
List<String> expressions = new ArrayList<String>(); // XPATH and value for all elements in the indicated XML
|
||||
DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory
|
||||
.newInstance();
|
||||
DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder();
|
||||
Document document = docBuilder.parse(xmlFile);
|
||||
|
||||
Node root = document.getDocumentElement();
|
||||
gatherNodes(root, expressions, "");
|
||||
return expressions.toArray(new String[expressions.size()]);
|
||||
}
|
||||
|
||||
|
||||
// Note this is pretty specialized for a solr.xml file because working with the DOM is such a pain.
|
||||
|
||||
private static List<String> qualified = new ArrayList<String>() {{
|
||||
add("core");
|
||||
add("property");
|
||||
add("int");
|
||||
add("str");
|
||||
add("long");
|
||||
add("property");
|
||||
}};
|
||||
|
||||
private static List<String> addText = new ArrayList<String>() {{
|
||||
add("int");
|
||||
add("str");
|
||||
add("long");
|
||||
}};
|
||||
|
||||
// path is the path to parent node
|
||||
|
||||
private void gatherNodes(Node node, List<String> expressions, String path) {
|
||||
|
||||
String nodeName = node.getNodeName();
|
||||
String thisPath = path + "/" + nodeName;
|
||||
//Parent[@id='1']/Children/child[@name]
|
||||
// Add in the xpaths for verification of any attributes.
|
||||
NamedNodeMap attrs = node.getAttributes();
|
||||
String qualifier = "";
|
||||
if (attrs.getLength() > 0) {
|
||||
// Assemble the prefix for qualifying all of the attributes with the same name
|
||||
if (qualified.contains(nodeName)) {
|
||||
qualifier = "@name='" + node.getAttributes().getNamedItem("name").getTextContent() + "'";
|
||||
}
|
||||
|
||||
for (int idx = 0; idx < attrs.getLength(); ++idx) {
|
||||
|
||||
Node attr = attrs.item(idx);
|
||||
if (StringUtils.isNotBlank(qualifier) && "name".equals(attr.getNodeName())) {
|
||||
continue; // Already added "name" attribute in qualifier string.
|
||||
}
|
||||
if (StringUtils.isNotBlank(qualifier)) {
|
||||
// Create [@name="stuff" and @attrib="value"] fragment
|
||||
expressions.add(thisPath +
|
||||
"[" + qualifier + " and @" + attr.getNodeName() + "='" + attr.getTextContent() + "']");
|
||||
|
||||
} else {
|
||||
// Create [@attrib="value"] fragment
|
||||
expressions.add(thisPath +
|
||||
"[" + qualifier + " @" + attr.getNodeName() + "='" + attr.getTextContent() + "']");
|
||||
}
|
||||
}
|
||||
}
|
||||
// Now add the text for special nodes
|
||||
// a[normalize-space(text())='somesite']
|
||||
if (addText.contains(nodeName)) {
|
||||
expressions.add(thisPath + "[" + qualifier + " and text()='" + node.getTextContent() + "']");
|
||||
}
|
||||
// Now collect all the child element nodes.
|
||||
NodeList nodeList = node.getChildNodes();
|
||||
for (int i = 0; i < nodeList.getLength(); i++) {
|
||||
|
||||
Node currentNode = nodeList.item(i);
|
||||
if (currentNode.getNodeType() == Node.ELEMENT_NODE) {
|
||||
if (StringUtils.isNotBlank(qualifier)) {
|
||||
gatherNodes(currentNode, expressions, thisPath + "[" + qualifier + "]");
|
||||
} else {
|
||||
gatherNodes(currentNode, expressions, thisPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static String SOLR_XML_LOTS_SYSVARS =
|
||||
"<solr persistent=\"${solr.xml.persist:false}\" coreLoadThreads=\"12\" sharedLib=\"${something:.}\" >\n" +
|
||||
" <logging class=\"${logclass:log4j.class}\" enabled=\"{logenable:true}\">\n" +
|
||||
" <watcher size=\"{watchSize:13}\" threshold=\"${logThresh:54}\" />\n" +
|
||||
" </logging>\n" +
|
||||
" <shardHandlerFactory name=\"${shhandler:shardHandlerFactory}\" class=\"${handlefac:HttpShardHandlerFactory}\">\n" +
|
||||
" <int name=\"socketTimeout\">${socketTimeout:120000}</int> \n" +
|
||||
" <int name=\"connTimeout\">${connTimeout:15000}</int> \n" +
|
||||
" </shardHandlerFactory> \n" +
|
||||
" <cores adminPath=\"/admin/cores\" defaultCoreName=\"SystemVars1\" host=\"127.0.0.1\" \n" +
|
||||
" hostPort=\"${hostPort:8983}\" hostContext=\"${hostContext:solr}\" \n" +
|
||||
" zkClientTimeout=\"${solr.zkclienttimeout:30000}\" \n" +
|
||||
" shareSchema=\"${shareSchema:false}\" distribUpdateConnTimeout=\"${distribUpdateConnTimeout:15000}\" \n" +
|
||||
" distribUpdateSoTimeout=\"${distribUpdateSoTimeout:120000}\" \n" +
|
||||
" leaderVoteWait=\"${leadVoteWait:32}\" managementPath=\"${manpath:/var/lib/path}\" transientCacheSize=\"${tranSize:128}\"> \n" +
|
||||
" <core name=\"SystemVars1\" instanceDir=\"SystemVars1\" shard=\"${shard:32}\" \n" +
|
||||
" collection=\"${collection:collection1}\" config=\"${solrconfig:solrconfig-minimal.xml}\" \n" +
|
||||
" schema=\"${schema:schema-tiny.xml}\" ulogDir=\"${ulog:./}\" roles=\"${myrole:boss}\" \n" +
|
||||
" dataDir=\"${data:./}\" loadOnStartup=\"${onStart:true}\" transient=\"${tran:true}\" \n" +
|
||||
" coreNodeName=\"${coreNode:utterlyridiculous}\" \n" +
|
||||
" >\n" +
|
||||
" </core>\n" +
|
||||
" <core name=\"SystemVars2\" instanceDir=\"SystemVars2\" shard=\"${shard:32}\" \n" +
|
||||
" collection=\"${collection:collection2}\" config=\"${solrconfig:solrconfig-minimal.xml}\" \n" +
|
||||
" coreNodeName=\"${coreNodeName:}\" schema=\"${schema:schema-tiny.xml}\">\n" +
|
||||
" <property name=\"collection\" value=\"{collection:collection2}\"/>\n" +
|
||||
" <property name=\"schema\" value=\"${schema:schema-tiny.xml}\"/>\n" +
|
||||
" <property name=\"coreNodeName\" value=\"EricksCore\"/>\n" +
|
||||
" </core>\n" +
|
||||
" </cores>\n" +
|
||||
"</solr>";
|
||||
|
||||
|
||||
}
|
|
@ -244,7 +244,7 @@ public class TestSolrProperties extends AbstractEmbeddedSolrServerTestCase {
|
|||
fis = new FileInputStream(new File(tempDir, SOLR_PERSIST_XML));
|
||||
try {
|
||||
Document document = builder.parse(fis);
|
||||
assertTrue(exists("/solr/cores/core[@name='collection1' and (@instanceDir='./' or @instanceDir='.\\')]", document));
|
||||
assertTrue(exists("/solr/cores/core[@name='collection1' and @instanceDir='.']", document));
|
||||
} finally {
|
||||
fis.close();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue