SOLR-4914: Factor out core discovery and persistence logic

git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1502276 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Alan Woodward 2013-07-11 16:35:01 +00:00
parent aade0000a6
commit 5a42052fba
36 changed files with 1531 additions and 1858 deletions

View File

@ -64,6 +64,11 @@ Upgrading from Solr 4.4.0
Detailed Change List Detailed Change List
---------------------- ----------------------
Other Changes
----------------------
* SOLR-4914: Factor out core list persistence and discovery into a
new CoresLocator interface. (Alan Woodward)
================== 4.4.0 ================== ================== 4.4.0 ==================

View File

@ -0,0 +1,9 @@
# Logging level
log4j.rootLogger=INFO, CONSOLE
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.Target=System.err
log4j.appender.CONSOLE.layout=org.apache.solr.util.SolrLogLayout
log4j.appender.CONSOLE.layout.ConversionPattern=%-5p - %d{yyyy-MM-dd HH:mm:ss.SSS}; %C; %m\n
log4j.logger.org.apache.zookeeper=WARN

View File

@ -17,11 +17,16 @@ package org.apache.solr.cloud;
* limitations under the License. * limitations under the License.
*/ */
import org.apache.solr.common.cloud.ZkStateReader;
import org.apache.solr.common.cloud.Slice; import org.apache.solr.common.cloud.Slice;
import org.apache.solr.common.cloud.ZkStateReader;
import org.apache.solr.common.params.SolrParams; import org.apache.solr.common.params.SolrParams;
import org.apache.solr.core.CoreDescriptor;
import org.apache.solr.util.PropertiesUtil;
import java.util.Properties;
public class CloudDescriptor { public class CloudDescriptor {
private String shardId; private String shardId;
private String collectionName; private String collectionName;
private SolrParams params; private SolrParams params;
@ -37,6 +42,21 @@ public class CloudDescriptor {
volatile boolean isLeader = false; volatile boolean isLeader = false;
volatile String lastPublished = ZkStateReader.ACTIVE; volatile String lastPublished = ZkStateReader.ACTIVE;
public static final String SHARD_STATE = "shardState";
public static final String NUM_SHARDS = "numShards";
public static final String SHARD_RANGE = "shardRange";
public CloudDescriptor(String coreName, Properties props) {
this.shardId = props.getProperty(CoreDescriptor.CORE_SHARD, null);
// If no collection name is specified, we default to the core name
this.collectionName = props.getProperty(CoreDescriptor.CORE_COLLECTION, coreName);
this.roles = props.getProperty(CoreDescriptor.CORE_ROLES, null);
this.nodeName = props.getProperty(CoreDescriptor.CORE_NODE_NAME);
this.shardState = props.getProperty(CloudDescriptor.SHARD_STATE, Slice.ACTIVE);
this.numShards = PropertiesUtil.toInteger(props.getProperty(CloudDescriptor.NUM_SHARDS), null);
this.shardRange = props.getProperty(CloudDescriptor.SHARD_RANGE, null);
}
public String getLastPublished() { public String getLastPublished() {
return lastPublished; return lastPublished;
} }

View File

@ -10,13 +10,11 @@ import org.apache.commons.cli.ParseException;
import org.apache.commons.cli.PosixParser; import org.apache.commons.cli.PosixParser;
import org.apache.solr.common.cloud.OnReconnect; import org.apache.solr.common.cloud.OnReconnect;
import org.apache.solr.common.cloud.SolrZkClient; import org.apache.solr.common.cloud.SolrZkClient;
import org.apache.solr.core.ConfigSolr; import org.apache.solr.core.CoreContainer;
import org.apache.solr.core.SolrResourceLoader;
import org.apache.zookeeper.CreateMode; import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.KeeperException; import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.ZooDefs; import org.apache.zookeeper.ZooDefs;
import org.apache.zookeeper.data.ACL; import org.apache.zookeeper.data.ACL;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException; import org.xml.sax.SAXException;
import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.ParserConfigurationException;
@ -173,17 +171,18 @@ public class ZkCLI {
+ " is required for " + BOOTSTRAP); + " is required for " + BOOTSTRAP);
System.exit(1); System.exit(1);
} }
SolrResourceLoader loader = new SolrResourceLoader(solrHome);
solrHome = loader.getInstanceDir();
ConfigSolr cfg = ConfigSolr.fromSolrHome(loader, solrHome); CoreContainer cc = new CoreContainer(solrHome);
if(!ZkController.checkChrootPath(zkServerAddress, true)) { if(!ZkController.checkChrootPath(zkServerAddress, true)) {
System.out.println("A chroot was specified in zkHost but the znode doesn't exist. "); System.out.println("A chroot was specified in zkHost but the znode doesn't exist. ");
System.exit(1); System.exit(1);
} }
ZkController.bootstrapConf(zkClient, cfg, solrHome); ZkController.bootstrapConf(zkClient, cc, solrHome);
// No need to shutdown the CoreContainer, as it wasn't started
// up in the first place...
} else if (line.getOptionValue(CMD).equals(UPCONFIG)) { } else if (line.getOptionValue(CMD).equals(UPCONFIG)) {
if (!line.hasOption(CONFDIR) || !line.hasOption(CONFNAME)) { if (!line.hasOption(CONFDIR) || !line.hasOption(CONFNAME)) {

View File

@ -18,6 +18,7 @@ package org.apache.solr.cloud;
*/ */
import org.apache.commons.io.FileUtils; import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.solr.client.solrj.impl.HttpSolrServer; import org.apache.solr.client.solrj.impl.HttpSolrServer;
import org.apache.solr.client.solrj.request.CoreAdminRequest.WaitForState; import org.apache.solr.client.solrj.request.CoreAdminRequest.WaitForState;
import org.apache.solr.common.SolrException; import org.apache.solr.common.SolrException;
@ -36,14 +37,12 @@ import org.apache.solr.common.cloud.ZkNodeProps;
import org.apache.solr.common.cloud.ZkStateReader; import org.apache.solr.common.cloud.ZkStateReader;
import org.apache.solr.common.cloud.ZooKeeperException; import org.apache.solr.common.cloud.ZooKeeperException;
import org.apache.solr.common.params.SolrParams; import org.apache.solr.common.params.SolrParams;
import org.apache.solr.core.ConfigSolr;
import org.apache.solr.core.CoreContainer; import org.apache.solr.core.CoreContainer;
import org.apache.solr.core.CoreDescriptor; import org.apache.solr.core.CoreDescriptor;
import org.apache.solr.core.SolrCore; import org.apache.solr.core.SolrCore;
import org.apache.solr.handler.component.ShardHandler; import org.apache.solr.handler.component.ShardHandler;
import org.apache.solr.update.UpdateLog; import org.apache.solr.update.UpdateLog;
import org.apache.solr.update.UpdateShardHandler; import org.apache.solr.update.UpdateShardHandler;
import org.apache.solr.util.PropertiesUtil;
import org.apache.zookeeper.CreateMode; import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.KeeperException; import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.KeeperException.NoNodeException; import org.apache.zookeeper.KeeperException.NoNodeException;
@ -1493,27 +1492,22 @@ public final class ZkController {
/** /**
* If in SolrCloud mode, upload config sets for each SolrCore in solr.xml. * If in SolrCloud mode, upload config sets for each SolrCore in solr.xml.
*/ */
public static void bootstrapConf(SolrZkClient zkClient, ConfigSolr cfg, String solrHome) throws IOException, public static void bootstrapConf(SolrZkClient zkClient, CoreContainer cc, String solrHome) throws IOException,
KeeperException, InterruptedException { KeeperException, InterruptedException {
List<String> allCoreNames = cfg.getAllCoreNames(); //List<String> allCoreNames = cfg.getAllCoreNames();
List<CoreDescriptor> cds = cc.getCoresLocator().discover(cc);
log.info("bootstraping config for " + allCoreNames.size() + " cores into ZooKeeper using solr.xml from " + solrHome); log.info("bootstrapping config for " + cds.size() + " cores into ZooKeeper using solr.xml from " + solrHome);
for (String coreName : allCoreNames) { for (CoreDescriptor cd : cds) {
String rawName = PropertiesUtil.substituteProperty(cfg.getProperty(coreName, "name", null), new Properties()); String coreName = cd.getName();
String instanceDir = cfg.getProperty(coreName, "instanceDir", null); String confName = cd.getCollectionName();
File idir = new File(instanceDir); if (StringUtils.isEmpty(confName))
System.out.println("idir:" + idir); confName = coreName;
if (!idir.isAbsolute()) { String instanceDir = cd.getInstanceDir();
idir = new File(solrHome, instanceDir); File udir = new File(instanceDir, "conf");
} log.info("Uploading directory " + udir + " with name " + confName + " for SolrCore " + coreName);
String confName = PropertiesUtil.substituteProperty(cfg.getProperty(coreName, "collection", null), new Properties());
if (confName == null) {
confName = rawName;
}
File udir = new File(idir, "conf");
log.info("Uploading directory " + udir + " with name " + confName + " for SolrCore " + rawName);
ZkController.uploadConfigDir(zkClient, udir, confName); ZkController.uploadConfigDir(zkClient, udir, confName);
} }
} }

View File

@ -18,6 +18,7 @@ package org.apache.solr.core;
*/ */
import com.google.common.base.Charsets; import com.google.common.base.Charsets;
import com.google.common.io.ByteStreams;
import org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
import org.apache.solr.common.SolrException; import org.apache.solr.common.SolrException;
import org.apache.solr.util.DOMUtil; import org.apache.solr.util.DOMUtil;
@ -32,11 +33,11 @@ import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants; import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException; import javax.xml.xpath.XPathExpressionException;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File; import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.InputStream; import java.io.InputStream;
import java.util.HashMap; import java.util.HashMap;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Properties; import java.util.Properties;
@ -59,7 +60,10 @@ public abstract class ConfigSolr {
else { else {
inputStream = new FileInputStream(configFile); inputStream = new FileInputStream(configFile);
} }
return fromInputStream(loader, inputStream); ByteArrayOutputStream baos = new ByteArrayOutputStream();
ByteStreams.copy(inputStream, baos);
String originalXml = IOUtils.toString(new ByteArrayInputStream(baos.toByteArray()), "UTF-8");
return fromInputStream(loader, new ByteArrayInputStream(baos.toByteArray()), configFile, originalXml);
} }
catch (Exception e) { catch (Exception e) {
throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, throw new SolrException(SolrException.ErrorCode.SERVER_ERROR,
@ -70,15 +74,14 @@ public abstract class ConfigSolr {
} }
} }
public static ConfigSolr fromString(SolrResourceLoader loader, String xml) { public static ConfigSolr fromString(String xml) {
return fromInputStream(loader, new ByteArrayInputStream(xml.getBytes(Charsets.UTF_8))); return fromInputStream(null, new ByteArrayInputStream(xml.getBytes(Charsets.UTF_8)), null, xml);
} }
public static ConfigSolr fromInputStream(SolrResourceLoader loader, InputStream is) { public static ConfigSolr fromInputStream(SolrResourceLoader loader, InputStream is, File file, String originalXml) {
try { try {
Config config = new Config(loader, null, new InputSource(is), null, false); Config config = new Config(loader, null, new InputSource(is), null, false);
//config.substituteProperties(); return fromConfig(config, file, originalXml);
return fromConfig(config);
} }
catch (Exception e) { catch (Exception e) {
throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, e); throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, e);
@ -89,12 +92,14 @@ public abstract class ConfigSolr {
return fromFile(loader, new File(solrHome, SOLR_XML_FILE)); return fromFile(loader, new File(solrHome, SOLR_XML_FILE));
} }
public static ConfigSolr fromConfig(Config config) { public static ConfigSolr fromConfig(Config config, File file, String originalXml) {
boolean oldStyle = (config.getNode("solr/cores", false) != null); boolean oldStyle = (config.getNode("solr/cores", false) != null);
return oldStyle ? new ConfigSolrXmlOld(config) return oldStyle ? new ConfigSolrXmlOld(config, file, originalXml)
: new ConfigSolrXml(config, null); : new ConfigSolrXml(config);
} }
public abstract CoresLocator getCoresLocator();
public PluginInfo getShardHandlerFactoryPluginInfo() { public PluginInfo getShardHandlerFactoryPluginInfo() {
Node node = config.getNode(getShardHandlerFactoryConfigPath(), false); Node node = config.getNode(getShardHandlerFactoryConfigPath(), false);
@ -171,12 +176,6 @@ public abstract class ConfigSolr {
return (val == null) ? def : val; return (val == null) ? def : val;
} }
// For saving the original property, ${} syntax and all.
public String getOrigProp(CfgProp prop, String def) {
String val = propMap.get(prop);
return (val == null) ? def : val;
}
public Properties getSolrProperties(String path) { public Properties getSolrProperties(String path) {
try { try {
return readProperties(((NodeList) config.evaluate( return readProperties(((NodeList) config.evaluate(
@ -200,15 +199,5 @@ public abstract class ConfigSolr {
return properties; return properties;
} }
public abstract void substituteProperties();
public abstract List<String> getAllCoreNames();
public abstract String getProperty(String coreName, String property, String defaultVal);
public abstract Properties readCoreProperties(String coreName);
public abstract Map<String, String> readCoreAttributes(String coreName);
} }

View File

@ -17,40 +17,32 @@ package org.apache.solr.core;
* limitations under the License. * limitations under the License.
*/ */
import org.apache.commons.io.IOUtils;
import org.apache.solr.common.SolrException; import org.apache.solr.common.SolrException;
import org.apache.solr.util.PropertiesUtil; import org.apache.solr.util.PropertiesUtil;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
/** /**
* *
*/ */
public class ConfigSolrXml extends ConfigSolr { public class ConfigSolrXml extends ConfigSolr {
protected static Logger log = LoggerFactory.getLogger(ConfigSolrXml.class); protected static Logger log = LoggerFactory.getLogger(ConfigSolrXml.class);
private SolrCoreDiscoverer solrCoreDiscoverer = new SolrCoreDiscoverer(); private final CoresLocator coresLocator;
private final Map<String, CoreDescriptor> coreDescriptorMap;
public ConfigSolrXml(Config config, CoreContainer container) { public ConfigSolrXml(Config config) {
super(config); super(config);
try { try {
checkForIllegalConfig(); checkForIllegalConfig();
fillPropMap(); fillPropMap();
config.substituteProperties(); config.substituteProperties();
String coreRoot = get(CfgProp.SOLR_COREROOTDIRECTORY, (container == null ? config.getResourceLoader().getInstanceDir() : container.getSolrHome())); log.info("Config-defined core root directory: {}", get(CfgProp.SOLR_COREROOTDIRECTORY, ""));
coreDescriptorMap = solrCoreDiscoverer.discover(container, new File(coreRoot)); String coreRoot = get(CfgProp.SOLR_COREROOTDIRECTORY, config.getResourceLoader().getInstanceDir());
coresLocator = new CorePropertiesLocator(coreRoot);
} }
catch (IOException e) { catch (IOException e) {
throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, e); throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, e);
@ -133,68 +125,14 @@ public class ConfigSolrXml extends ConfigSolr {
propMap.put(CfgProp.SOLR_LOGGING_WATCHER_THRESHOLD, doSub("solr/logging/watcher/int[@name='threshold']")); propMap.put(CfgProp.SOLR_LOGGING_WATCHER_THRESHOLD, doSub("solr/logging/watcher/int[@name='threshold']"));
} }
@Override
public Map<String,String> readCoreAttributes(String coreName) {
Map<String,String> attrs = new HashMap<String,String>();
return attrs; // this is a no-op.... intentionally
}
@Override
public List<String> getAllCoreNames() {
List<String> ret = new ArrayList<String>(coreDescriptorMap.keySet());
return ret;
}
@Override
public String getProperty(String coreName, String property, String defaultVal) {
CoreDescriptor cd = coreDescriptorMap.get(coreName);
if (cd == null) return defaultVal;
return cd.getProperty(property, defaultVal);
}
@Override
public Properties readCoreProperties(String coreName) {
CoreDescriptor cd = coreDescriptorMap.get(coreName);
if (cd == null) return null;
return new Properties(cd.getCoreProperties());
}
static Properties getCoreProperties(String instanceDir, CoreDescriptor dcore) {
String file = dcore.getPropertiesName();
if (file == null) file = "conf" + File.separator + "solrcore.properties";
File corePropsFile = new File(file);
if (!corePropsFile.isAbsolute()) {
corePropsFile = new File(instanceDir, file);
}
Properties p = dcore.getCoreProperties();
if (corePropsFile.exists() && corePropsFile.isFile()) {
p = new Properties(dcore.getCoreProperties());
InputStream is = null;
try {
is = new FileInputStream(corePropsFile);
p.load(is);
} catch (IOException e) {
log.warn("Error loading properties ", e);
} finally {
IOUtils.closeQuietly(is);
}
}
return p;
}
@Override @Override
protected String getShardHandlerFactoryConfigPath() { protected String getShardHandlerFactoryConfigPath() {
return "solr/shardHandlerFactory"; return "solr/shardHandlerFactory";
} }
@Override @Override
public void substituteProperties() { public CoresLocator getCoresLocator() {
config.substituteProperties(); return coresLocator;
} }
} }

View File

@ -22,7 +22,6 @@ import org.apache.solr.util.DOMUtil;
import org.apache.solr.util.PropertiesUtil; import org.apache.solr.util.PropertiesUtil;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node; import org.w3c.dom.Node;
import org.w3c.dom.NodeList; import org.w3c.dom.NodeList;
@ -44,28 +43,38 @@ import java.util.Set;
* *
*/ */
public class ConfigSolrXmlOld extends ConfigSolr { public class ConfigSolrXmlOld extends ConfigSolr {
protected static Logger log = LoggerFactory.getLogger(ConfigSolrXmlOld.class); protected static Logger log = LoggerFactory.getLogger(ConfigSolrXmlOld.class);
private NodeList coreNodes = null; private NodeList coreNodes = null;
private final CoresLocator persistor;
@Override @Override
protected String getShardHandlerFactoryConfigPath() { protected String getShardHandlerFactoryConfigPath() {
return "solr/cores/shardHandlerFactory"; return "solr/cores/shardHandlerFactory";
} }
public ConfigSolrXmlOld(Config config) { public ConfigSolrXmlOld(Config config, File configFile, String originalXML) {
super(config); super(config);
try { try {
checkForIllegalConfig(); checkForIllegalConfig();
fillPropMap(); fillPropMap();
config.substituteProperties(); config.substituteProperties();
initCoreList(); initCoreList();
this.persistor = isPersistent() ? new SolrXMLCoresLocator(configFile, originalXML, this)
: new SolrXMLCoresLocator.NonPersistingLocator(configFile, originalXML, this);
} }
catch (IOException e) { catch (IOException e) {
throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, e); throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, e);
} }
} }
@Override
public CoresLocator getCoresLocator() {
return this.persistor;
}
private void checkForIllegalConfig() throws IOException { private void checkForIllegalConfig() throws IOException {
// Do sanity checks - we don't want to find new style // Do sanity checks - we don't want to find new style
// config // config
@ -101,6 +110,10 @@ public class ConfigSolrXmlOld extends ConfigSolr {
} }
} }
public boolean isPersistent() {
return config.getBool("solr/@persistent", false);
}
private void fillPropMap() { private void fillPropMap() {
propMap.put(CfgProp.SOLR_CORELOADTHREADS, propMap.put(CfgProp.SOLR_CORELOADTHREADS,
@ -208,34 +221,6 @@ public class ConfigSolrXmlOld extends ConfigSolr {
} }
@Override
public Map<String, String> readCoreAttributes(String coreName) {
Map<String, String> attrs = new HashMap<String, String>();
synchronized (coreNodes) {
for (int idx = 0; idx < coreNodes.getLength(); ++idx) {
Node node = coreNodes.item(idx);
if (coreName.equals(DOMUtil.getAttr(node, CoreDescriptor.CORE_NAME, null))) {
NamedNodeMap attributes = node.getAttributes();
for (int i = 0; i < attributes.getLength(); i++) {
Node attribute = attributes.item(i);
String val = PropertiesUtil.substituteProperty(attribute.getNodeValue(), null);
if (CoreDescriptor.CORE_DATADIR.equals(attribute.getNodeName()) ||
CoreDescriptor.CORE_INSTDIR.equals(attribute.getNodeName())) {
if (val.indexOf('$') == -1) {
val = (val != null && !val.endsWith("/")) ? val + '/' : val;
}
}
attrs.put(attribute.getNodeName(), val);
}
return attrs;
}
}
}
return attrs;
}
@Override
public List<String> getAllCoreNames() { public List<String> getAllCoreNames() {
List<String> ret = new ArrayList<String>(); List<String> ret = new ArrayList<String>();
@ -249,7 +234,6 @@ public class ConfigSolrXmlOld extends ConfigSolr {
return ret; return ret;
} }
@Override
public String getProperty(String coreName, String property, String defaultVal) { public String getProperty(String coreName, String property, String defaultVal) {
synchronized (coreNodes) { synchronized (coreNodes) {
@ -257,7 +241,9 @@ public class ConfigSolrXmlOld extends ConfigSolr {
Node node = coreNodes.item(idx); Node node = coreNodes.item(idx);
if (coreName.equals(DOMUtil.getAttr(node, CoreDescriptor.CORE_NAME, if (coreName.equals(DOMUtil.getAttr(node, CoreDescriptor.CORE_NAME,
null))) { null))) {
String propVal = DOMUtil.getAttr(node, property, defaultVal); String propVal = DOMUtil.getAttr(node, property);
if (propVal == null)
propVal = defaultVal;
return PropertiesUtil.substituteProperty(propVal, null); return PropertiesUtil.substituteProperty(propVal, null);
} }
} }
@ -266,24 +252,20 @@ public class ConfigSolrXmlOld extends ConfigSolr {
} }
@Override public Properties getCoreProperties(String coreName) {
public Properties readCoreProperties(String coreName) {
synchronized (coreNodes) { synchronized (coreNodes) {
for (int idx = 0; idx < coreNodes.getLength(); ++idx) { for (int idx = 0; idx < coreNodes.getLength(); idx++) {
Node node = coreNodes.item(idx); Node node = coreNodes.item(idx);
if (coreName.equals(DOMUtil.getAttr(node, CoreDescriptor.CORE_NAME, if (coreName.equals(DOMUtil.getAttr(node, CoreDescriptor.CORE_NAME, null))) {
null))) {
try { try {
return readProperties(node); return readProperties(node);
} catch (XPathExpressionException e) { } catch (XPathExpressionException e) {
return null; SolrException.log(log, e);
} }
} }
} }
} }
return new Properties();
return null;
} }
public static final String DEF_SOLR_XML = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n" public static final String DEF_SOLR_XML = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n"
@ -298,9 +280,4 @@ public class ConfigSolrXmlOld extends ConfigSolr {
+ "\" shard=\"${shard:}\" collection=\"${collection:collection1}\" instanceDir=\"collection1\" />\n" + "\" shard=\"${shard:}\" collection=\"${collection:collection1}\" instanceDir=\"collection1\" />\n"
+ " </cores>\n" + "</solr>"; + " </cores>\n" + "</solr>";
@Override
public void substituteProperties() {
config.substituteProperties();
}
} }

View File

@ -17,6 +17,7 @@
package org.apache.solr.core; package org.apache.solr.core;
import com.google.common.collect.Maps;
import org.apache.solr.cloud.ZkController; import org.apache.solr.cloud.ZkController;
import org.apache.solr.cloud.ZkSolrResourceLoader; import org.apache.solr.cloud.ZkSolrResourceLoader;
import org.apache.solr.common.SolrException; import org.apache.solr.common.SolrException;
@ -33,18 +34,15 @@ import org.apache.solr.schema.IndexSchema;
import org.apache.solr.schema.IndexSchemaFactory; import org.apache.solr.schema.IndexSchemaFactory;
import org.apache.solr.util.DefaultSolrThreadFactory; import org.apache.solr.util.DefaultSolrThreadFactory;
import org.apache.solr.util.FileUtils; import org.apache.solr.util.FileUtils;
import org.apache.solr.util.PropertiesUtil;
import org.apache.zookeeper.KeeperException; import org.apache.zookeeper.KeeperException;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import javax.xml.xpath.XPathExpressionException;
import java.io.File; import java.io.File;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.Date; import java.util.Date;
import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
@ -116,8 +114,11 @@ public class CoreContainer
protected final ConfigSolr cfg; protected final ConfigSolr cfg;
protected final SolrResourceLoader loader; protected final SolrResourceLoader loader;
protected final String solrHome; protected final String solrHome;
private InfoHandler infoHandler; private InfoHandler infoHandler;
protected final CoresLocator coresLocator;
{ {
log.info("New CoreContainer " + System.identityHashCode(this)); log.info("New CoreContainer " + System.identityHashCode(this));
} }
@ -152,8 +153,9 @@ public class CoreContainer
} }
/** /**
* Create a new CoreContainer using the given SolrResourceLoader and * Create a new CoreContainer using the given SolrResourceLoader,
* configuration. The container's cores are not loaded. * configuration and CoresLocator. The container's cores are
* not loaded.
* @param loader the SolrResourceLoader * @param loader the SolrResourceLoader
* @param config a ConfigSolr representation of this container's configuration * @param config a ConfigSolr representation of this container's configuration
* @see #load() * @see #load()
@ -162,6 +164,14 @@ public class CoreContainer
this.loader = checkNotNull(loader); this.loader = checkNotNull(loader);
this.solrHome = loader.getInstanceDir(); this.solrHome = loader.getInstanceDir();
this.cfg = checkNotNull(config); this.cfg = checkNotNull(config);
this.coresLocator = config.getCoresLocator();
}
public CoreContainer(SolrResourceLoader loader, ConfigSolr config, CoresLocator locator) {
this.loader = checkNotNull(loader);
this.solrHome = loader.getInstanceDir();
this.cfg = checkNotNull(config);
this.coresLocator = locator;
} }
/** /**
@ -280,81 +290,20 @@ public class CoreContainer
coreLoadExecutor); coreLoadExecutor);
Set<Future<SolrCore>> pending = new HashSet<Future<SolrCore>>(); Set<Future<SolrCore>> pending = new HashSet<Future<SolrCore>>();
List<String> allCores = cfg.getAllCoreNames(); List<CoreDescriptor> cds = coresLocator.discover(this);
checkForDuplicateCoreNames(cds);
for (String oneCoreName : allCores) { for (final CoreDescriptor cd : cds) {
final String name = cd.getName();
try { try {
String rawName = cfg.getProperty(oneCoreName, CoreDescriptor.CORE_NAME, null);
if (null == rawName) { if (cd.isTransient() || ! cd.isLoadOnStartup()) {
throw new SolrException(SolrException.ErrorCode.SERVER_ERROR,
"Each core in solr.xml must have a 'name'");
}
final String name = rawName;
final CoreDescriptor p = new CoreDescriptor(this, name,
cfg.getProperty(oneCoreName, CoreDescriptor.CORE_INSTDIR, null));
// deal with optional settings
String opt = cfg.getProperty(oneCoreName, CoreDescriptor.CORE_CONFIG, null);
if (opt != null) {
p.setConfigName(opt);
}
opt = cfg.getProperty(oneCoreName, CoreDescriptor.CORE_SCHEMA, null);
if (opt != null) {
p.setSchemaName(opt);
}
if (zkSys.getZkController() != null) {
opt = cfg.getProperty(oneCoreName, CoreDescriptor.CORE_SHARD, null);
if (opt != null && opt.length() > 0) {
p.getCloudDescriptor().setShardId(opt);
}
opt = cfg.getProperty(oneCoreName, CoreDescriptor.CORE_COLLECTION, null);
if (opt != null) {
p.getCloudDescriptor().setCollectionName(opt);
}
opt = cfg.getProperty(oneCoreName, CoreDescriptor.CORE_ROLES, null);
if (opt != null) {
p.getCloudDescriptor().setRoles(opt);
}
opt = cfg.getProperty(oneCoreName, CoreDescriptor.CORE_NODE_NAME, null);
if (opt != null && opt.length() > 0) {
p.getCloudDescriptor().setCoreNodeName(opt);
}
}
opt = cfg.getProperty(oneCoreName, CoreDescriptor.CORE_PROPERTIES, null);
if (opt != null) {
p.setPropertiesName(opt);
}
opt = cfg.getProperty(oneCoreName, CoreDescriptor.CORE_DATADIR, null);
if (opt != null) {
p.setDataDir(opt);
}
p.setCoreProperties(cfg.readCoreProperties(oneCoreName));
opt = cfg.getProperty(oneCoreName, CoreDescriptor.CORE_LOADONSTARTUP, null);
if (opt != null) {
p.setLoadOnStartup(("true".equalsIgnoreCase(opt) || "on"
.equalsIgnoreCase(opt)) ? true : false);
}
opt = cfg.getProperty(oneCoreName, CoreDescriptor.CORE_TRANSIENT, null);
if (opt != null) {
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 // Store it away for later use. includes non-transient but not
// loaded at startup cores. // loaded at startup cores.
solrCores.putDynamicDescriptor(rawName, p); solrCores.putDynamicDescriptor(name, cd);
} }
if (cd.isLoadOnStartup()) { // The normal case
if (p.isLoadOnStartup()) { // The normal case
Callable<SolrCore> task = new Callable<SolrCore>() { Callable<SolrCore> task = new Callable<SolrCore>() {
@Override @Override
@ -362,14 +311,14 @@ public class CoreContainer
SolrCore c = null; SolrCore c = null;
try { try {
if (zkSys.getZkController() != null) { if (zkSys.getZkController() != null) {
preRegisterInZk(p); preRegisterInZk(cd);
} }
c = create(p); c = create(cd);
registerCore(p.isTransient(), name, c, false); registerCore(cd.isTransient(), name, c, false);
} catch (Throwable t) { } catch (Throwable t) {
if (isZooKeeperAware()) { if (isZooKeeperAware()) {
try { try {
zkSys.zkController.unregister(name, p); zkSys.zkController.unregister(name, cd);
} catch (InterruptedException e) { } catch (InterruptedException e) {
Thread.currentThread().interrupt(); Thread.currentThread().interrupt();
SolrException.log(log, null, e); SolrException.log(log, null, e);
@ -427,6 +376,18 @@ public class CoreContainer
} }
} }
private static void checkForDuplicateCoreNames(List<CoreDescriptor> cds) {
Map<String, String> addedCores = Maps.newHashMap();
for (CoreDescriptor cd : cds) {
final String name = cd.getName();
if (addedCores.containsKey(name))
throw new SolrException(ErrorCode.SERVER_ERROR,
String.format(Locale.ROOT, "Found multiple cores with the name [%s], with instancedirs [%s] and [%s]",
name, addedCores.get(name), cd.getInstanceDir()));
addedCores.put(name, cd.getInstanceDir());
}
}
private volatile boolean isShutDown = false; private volatile boolean isShutDown = false;
public boolean isShutDown() { public boolean isShutDown() {
@ -521,6 +482,10 @@ public class CoreContainer
} }
} }
public CoresLocator getCoresLocator() {
return coresLocator;
}
protected SolrCore registerCore(boolean isTransientCore, String name, SolrCore core, boolean returnPrevNotClosed) { protected SolrCore registerCore(boolean isTransientCore, String name, SolrCore core, boolean returnPrevNotClosed) {
if( core == null ) { if( core == null ) {
throw new RuntimeException( "Can not register a null core." ); throw new RuntimeException( "Can not register a null core." );
@ -548,7 +513,6 @@ public class CoreContainer
*/ */
core.setName(name); core.setName(name);
core.getCoreDescriptor().putProperty(CoreDescriptor.CORE_NAME, name);
synchronized (coreInitFailures) { synchronized (coreInitFailures) {
coreInitFailures.remove(name); coreInitFailures.remove(name);
@ -587,7 +551,7 @@ public class CoreContainer
SolrResourceLoader solrLoader = null; SolrResourceLoader solrLoader = null;
SolrConfig config = null; SolrConfig config = null;
solrLoader = new SolrResourceLoader(instanceDir, loader.getClassLoader(), ConfigSolrXml.getCoreProperties(instanceDir, dcore)); solrLoader = new SolrResourceLoader(instanceDir, loader.getClassLoader(), dcore.getCoreProperties());
try { try {
config = new SolrConfig(solrLoader, dcore.getConfigName(), null); config = new SolrConfig(solrLoader, dcore.getConfigName(), null);
} catch (Exception e) { } catch (Exception e) {
@ -609,11 +573,11 @@ public class CoreContainer
schemaFile.lastModified())); schemaFile.lastModified()));
schema = indexSchemaCache.get(key); schema = indexSchemaCache.get(key);
if (schema == null) { if (schema == null) {
log.info("creating new schema object for core: " + dcore.getProperty(CoreDescriptor.CORE_NAME)); log.info("creating new schema object for core: " + dcore.getName());
schema = IndexSchemaFactory.buildIndexSchema(dcore.getSchemaName(), config); schema = IndexSchemaFactory.buildIndexSchema(dcore.getSchemaName(), config);
indexSchemaCache.put(key, schema); indexSchemaCache.put(key, schema);
} else { } else {
log.info("re-using schema object for core: " + dcore.getProperty(CoreDescriptor.CORE_NAME)); log.info("re-using schema object for core: " + dcore.getName());
} }
} }
} }
@ -752,7 +716,8 @@ public class CoreContainer
cd.getName(), instanceDir.getAbsolutePath()); cd.getName(), instanceDir.getAbsolutePath());
SolrResourceLoader solrLoader; SolrResourceLoader solrLoader;
if(zkSys.getZkController() == null) { if(zkSys.getZkController() == null) {
solrLoader = new SolrResourceLoader(instanceDir.getAbsolutePath(), loader.getClassLoader(), ConfigSolrXml.getCoreProperties(instanceDir.getAbsolutePath(), cd)); solrLoader = new SolrResourceLoader(instanceDir.getAbsolutePath(), loader.getClassLoader(),
cd.getCoreProperties());
} else { } else {
try { try {
String collection = cd.getCloudDescriptor().getCollectionName(); String collection = cd.getCloudDescriptor().getCollectionName();
@ -765,7 +730,7 @@ public class CoreContainer
"Could not find config name for collection:" + collection); "Could not find config name for collection:" + collection);
} }
solrLoader = new ZkSolrResourceLoader(instanceDir.getAbsolutePath(), zkConfigName, loader.getClassLoader(), solrLoader = new ZkSolrResourceLoader(instanceDir.getAbsolutePath(), zkConfigName, loader.getClassLoader(),
ConfigSolrXml.getCoreProperties(instanceDir.getAbsolutePath(), cd), zkSys.getZkController()); cd.getCoreProperties(), zkSys.getZkController());
} catch (KeeperException e) { } catch (KeeperException e) {
log.error("", e); log.error("", e);
throw new ZooKeeperException(SolrException.ErrorCode.SERVER_ERROR, throw new ZooKeeperException(SolrException.ErrorCode.SERVER_ERROR,
@ -808,15 +773,18 @@ public class CoreContainer
n1 = checkDefault(n1); n1 = checkDefault(n1);
solrCores.swap(n0, n1); solrCores.swap(n0, n1);
coresLocator.persist(this, solrCores.getCoreDescriptor(n0), solrCores.getCoreDescriptor(n1));
log.info("swapped: "+n0 + " with " + n1); log.info("swapped: "+n0 + " with " + n1);
} }
/** Removes and returns registered core w/o decrementing it's reference count */ /** Removes and returns registered core w/o decrementing it's reference count */
public SolrCore remove( String name ) { public SolrCore remove( String name ) {
name = checkDefault(name); name = checkDefault(name);
CoreDescriptor cd = solrCores.getCoreDescriptor(name);
return solrCores.remove(name, true); SolrCore removed = solrCores.remove(name, true);
coresLocator.delete(this, cd);
return removed;
} }
public void rename(String name, String toName) { public void rename(String name, String toName) {
@ -825,7 +793,8 @@ public class CoreContainer
if (core != null) { if (core != null) {
registerCore(false, toName, core, false); registerCore(false, toName, core, false);
name = checkDefault(name); name = checkDefault(name);
solrCores.remove(name, false); SolrCore old = solrCores.remove(name, false);
coresLocator.rename(this, old.getCoreDescriptor(), core.getCoreDescriptor());
} }
} finally { } finally {
if (core != null) { if (core != null) {
@ -833,6 +802,24 @@ public class CoreContainer
} }
} }
} }
/**
* Get the CoreDescriptors for all cores managed by this container
* @return a List of CoreDescriptors
*/
public List<CoreDescriptor> getCoreDescriptors() {
return solrCores.getCoreDescriptors();
}
public CoreDescriptor getCoreDescriptor(String coreName) {
// TODO make this less hideous!
for (CoreDescriptor cd : getCoreDescriptors()) {
if (cd.getName().equals(coreName))
return cd;
}
return null;
}
/** /**
* Gets a core by name and increase its refcount. * Gets a core by name and increase its refcount.
* *
@ -972,10 +959,6 @@ public class CoreContainer
logging = v; logging = v;
} }
public File getConfigFile() {
return new File(solrHome, ConfigSolr.SOLR_XML_FILE);
}
/** /**
* Determines whether the core is already loaded or not but does NOT load the core * Determines whether the core is already loaded or not but does NOT load the core
* *
@ -984,12 +967,6 @@ public class CoreContainer
return solrCores.isLoaded(name); return solrCores.isLoaded(name);
} }
/** Persists the cores config file in cores.xml. */
@Deprecated
public void persist() {
persistFile(getConfigFile());
}
/** /**
* Gets a solr core descriptor for a core that is not loaded. Note that if the caller calls this on a * Gets a solr core descriptor for a core that is not loaded. Note that if the caller calls this on a
* loaded core, the unloaded descriptor will be returned. * loaded core, the unloaded descriptor will be returned.
@ -1001,126 +978,6 @@ public class CoreContainer
return solrCores.getUnloadedCoreDescriptor(cname); return solrCores.getUnloadedCoreDescriptor(cname);
} }
/** Persists the cores config file in a user provided file. */
@Deprecated
public void persistFile(File file) {
assert file != null;
// only the old solrxml persists
if (cfg != null && !(cfg instanceof ConfigSolrXmlOld)) return;
log.info("Persisting cores config to " + (file == null ? getConfigFile() : file));
// <solr attrib="value">
Map<String,String> rootSolrAttribs = new HashMap<String,String>();
addAttrib(rootSolrAttribs, ConfigSolr.CfgProp.SOLR_SHAREDLIB, "sharedLib", this.libDir);
addAttrib(rootSolrAttribs, ConfigSolr.CfgProp.SOLR_PERSISTENT, "persistent",
Boolean.toString(isPersistent()), "false");
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>();
addAttrib(coresAttribs, ConfigSolr.CfgProp.SOLR_ADMINPATH, "adminPath", this.adminPath, this.getAdminPath());
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));
addAttrib(coresAttribs, ConfigSolr.CfgProp.SOLR_HOST, "host", zkSys.getHost());
if (! (null == defaultCoreName || defaultCoreName.equals("")) ) {
coresAttribs.put("defaultCoreName", defaultCoreName);
}
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));
addAttrib(coresAttribs, ConfigSolr.CfgProp.SOLR_HOSTCONTEXT, "hostContext",
zkSys.getHostContext());
addAttrib(coresAttribs, ConfigSolr.CfgProp.SOLR_LEADERVOTEWAIT, "leaderVoteWait",
zkSys.getLeaderVoteWait(), LEADER_VOTE_WAIT);
addAttrib(coresAttribs, ConfigSolr.CfgProp.SOLR_GENERICCORENODENAMES, "genericCoreNodeNames",
Boolean.toString(zkSys.getGenericCoreNodeNames()), "false");
if (transientCacheSize != Integer.MAX_VALUE) { // This test
// is a consequence of testing. I really hate it.
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), Integer.toString(this.distribUpdateConnTimeout));
addAttrib(coresAttribs, ConfigSolr.CfgProp.SOLR_DISTRIBUPDATESOTIMEOUT, "distribUpdateSoTimeout",
Integer.toString(this.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(cfg.config.getOriginalConfig(), containerProperties, rootSolrAttribs,coresAttribs,
loggingAttribs, watcherAttribs, cfg.getUnsubsititutedShardHandlerFactoryPluginNode(), file, loader);
} catch (XPathExpressionException e) {
throw new SolrException(ErrorCode.SERVER_ERROR, null, e);
}
}
private String intToString(Integer integer) {
if (integer == null) return null;
return Integer.toString(integer);
}
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) {
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()))) {
attribs.put(attribName, origValue);
} else {
attribs.put(attribName, attribValue);
}
}
}
public void preRegisterInZk(final CoreDescriptor p) { public void preRegisterInZk(final CoreDescriptor p) {
zkSys.getZkController().preRegister(p); zkSys.getZkController().preRegister(p);
} }

View File

@ -17,12 +17,20 @@
package org.apache.solr.core; package org.apache.solr.core;
import java.util.Properties; import com.google.common.collect.ImmutableList;
import java.io.File; import com.google.common.collect.ImmutableMap;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.apache.solr.cloud.CloudDescriptor; import org.apache.solr.cloud.CloudDescriptor;
import org.apache.solr.core.ConfigSolr.CfgProp; import org.apache.solr.common.SolrException;
import org.apache.solr.util.PropertiesUtil;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Locale;
import java.util.Properties;
import static com.google.common.base.Preconditions.checkNotNull;
/** /**
* A Solr core descriptor * A Solr core descriptor
@ -34,7 +42,8 @@ public class CoreDescriptor {
// Properties file name constants // Properties file name constants
public static final String CORE_NAME = "name"; public static final String CORE_NAME = "name";
public static final String CORE_CONFIG = "config"; public static final String CORE_CONFIG = "config";
public static final String CORE_INSTDIR = "instanceDir"; // should probably be removed after 4x public static final String CORE_INSTDIR = "instanceDir";
public static final String CORE_ABS_INSTDIR = "absoluteInstDir";
public static final String CORE_DATADIR = "dataDir"; public static final String CORE_DATADIR = "dataDir";
public static final String CORE_ULOGDIR = "ulogDir"; public static final String CORE_ULOGDIR = "ulogDir";
public static final String CORE_SCHEMA = "schema"; public static final String CORE_SCHEMA = "schema";
@ -46,153 +55,207 @@ public class CoreDescriptor {
public static final String CORE_TRANSIENT = "transient"; public static final String CORE_TRANSIENT = "transient";
public static final String CORE_NODE_NAME = "coreNodeName"; public static final String CORE_NODE_NAME = "coreNodeName";
public static final String[] standardPropNames = { public static final String DEFAULT_EXTERNAL_PROPERTIES_FILE = "conf" + File.separator + "solrcore.properties";
/**
* Get the standard properties in persistable form
* @return the standard core properties in persistable form
*/
public Properties getPersistableStandardProperties() {
return originalCoreProperties;
}
/**
* Get user-defined core properties in persistable form
* @return user-defined core properties in persistable form
*/
public Properties getPersistableUserProperties() {
return originalExtraProperties;
}
private static ImmutableMap<String, String> defaultProperties = ImmutableMap.of(
CORE_CONFIG, "solrconfig.xml",
CORE_SCHEMA, "schema.xml",
CORE_DATADIR, "data" + File.separator,
CORE_TRANSIENT, "false",
CORE_LOADONSTARTUP, "true"
);
private static ImmutableList<String> requiredProperties = ImmutableList.of(
CORE_NAME, CORE_INSTDIR, CORE_ABS_INSTDIR
);
public static ImmutableList<String> standardPropNames = ImmutableList.of(
CORE_NAME, CORE_NAME,
CORE_CONFIG, CORE_CONFIG,
CORE_INSTDIR, CORE_INSTDIR,
CORE_DATADIR, CORE_DATADIR,
CORE_ULOGDIR, CORE_ULOGDIR,
CORE_SCHEMA, CORE_SCHEMA,
CORE_PROPERTIES,
CORE_LOADONSTARTUP,
CORE_TRANSIENT,
// cloud props
CORE_SHARD, CORE_SHARD,
CORE_COLLECTION, CORE_COLLECTION,
CORE_ROLES, CORE_ROLES,
CORE_PROPERTIES, CORE_NODE_NAME,
CORE_LOADONSTARTUP, CloudDescriptor.NUM_SHARDS,
CORE_TRANSIENT CloudDescriptor.SHARD_STATE
}; );
// As part of moving away from solr.xml (see SOLR-4196), it's _much_ easier to keep these as properties than set
// them individually.
private Properties coreProperties = new Properties();
//TODO: 5.0 remove this, this is solely a hack for persistence. And perhaps creating cores in discovery mode?
private Properties createdProperties = new Properties();
private boolean loadedImplicit = false;
private final CoreContainer coreContainer; private final CoreContainer coreContainer;
private CloudDescriptor cloudDesc; private final CloudDescriptor cloudDesc;
private CoreDescriptor(CoreContainer cont) { /** The original standard core properties, before substitution */
// Just a place to put initialization since it's a pain to add to the descriptor in every c'tor. protected final Properties originalCoreProperties = new Properties();
this.coreContainer = cont;
coreProperties.put(CORE_LOADONSTARTUP, "true");
coreProperties.put(CORE_TRANSIENT, "false");
} /** The original extra core properties, before substitution */
protected final Properties originalExtraProperties = new Properties();
public CoreDescriptor(CoreContainer container, String name, String instanceDir) { /** The properties for this core, as available through getProperty() */
this(container); protected final Properties coreProperties = new Properties();
doInit(name, instanceDir);
}
/**
* Create a new CoreDescriptor.
* @param container the CoreDescriptor's container
* @param name the CoreDescriptor's name
* @param instanceDir a String containing the instanceDir
* @param coreProps a Properties object of the properties for this core
*/
public CoreDescriptor(CoreContainer container, String name, String instanceDir,
Properties coreProps) {
public CoreDescriptor(CoreDescriptor descr) { this.coreContainer = container;
this(descr.coreContainer);
coreProperties.put(CORE_INSTDIR, descr.getInstanceDir()); originalCoreProperties.setProperty(CORE_NAME, name);
coreProperties.put(CORE_CONFIG, descr.getConfigName()); originalCoreProperties.setProperty(CORE_INSTDIR, instanceDir);
coreProperties.put(CORE_SCHEMA, descr.getSchemaName());
coreProperties.put(CORE_NAME, descr.getName()); Properties containerProperties = container.getContainerProperties();
coreProperties.put(CORE_DATADIR, descr.getDataDir()); name = PropertiesUtil.substituteProperty(checkPropertyIsNotEmpty(name, CORE_NAME),
containerProperties);
instanceDir = PropertiesUtil.substituteProperty(checkPropertyIsNotEmpty(instanceDir, CORE_INSTDIR),
containerProperties);
coreProperties.putAll(defaultProperties);
coreProperties.put(CORE_NAME, name);
coreProperties.put(CORE_INSTDIR, instanceDir);
coreProperties.put(CORE_ABS_INSTDIR, convertToAbsolute(instanceDir, container.getSolrHome()));
for (String propname : coreProps.stringPropertyNames()) {
String propvalue = coreProps.getProperty(propname);
if (isUserDefinedProperty(propname))
originalExtraProperties.put(propname, propvalue);
else
originalCoreProperties.put(propname, propvalue);
if (!requiredProperties.contains(propname)) // Required props are already dealt with
coreProperties.setProperty(propname,
PropertiesUtil.substituteProperty(propvalue, containerProperties));
}
loadExtraProperties();
// TODO maybe make this a CloudCoreDescriptor subclass?
if (container.isZooKeeperAware()) {
cloudDesc = new CloudDescriptor(name, coreProperties);
}
else {
cloudDesc = null;
}
} }
/** /**
* CoreDescriptor - create a core descriptor given default properties from a core.properties file. This will be * Load properties specified in an external properties file.
* used in the "solr.xml-less (See SOLR-4196) world where there are no &lt;core&gt; &lt;/core&gt; tags at all, thus much
* of the initialization that used to be done when reading solr.xml needs to be done here instead, particularly
* setting any defaults (e.g. schema.xml, directories, whatever).
* *
* @param container - the CoreContainer that holds all the information about our cores, loaded, lazy etc. * The file to load can be specified in a {@code properties} property on
* @param propsIn - A properties structure "core.properties" found while walking the file tree to discover cores. * the original Properties object used to create this CoreDescriptor. If
* Any properties set in this param will overwrite the any defaults. * this has not been set, then we look for {@code conf/solrcore.properties}
* underneath the instance dir.
*
* File paths are taken as read from the core's instance directory
* if they are not absolute.
*/ */
public CoreDescriptor(CoreContainer container, Properties propsIn) { protected void loadExtraProperties() {
this(container); String filename = coreProperties.getProperty(CORE_PROPERTIES, DEFAULT_EXTERNAL_PROPERTIES_FILE);
File propertiesFile = resolvePaths(filename);
// Set some default, normalize a directory or two if (propertiesFile.exists()) {
doInit(propsIn.getProperty(CORE_NAME), propsIn.getProperty(CORE_INSTDIR)); try {
Properties externalProps = new Properties();
coreProperties.putAll(propsIn); externalProps.load(new FileInputStream(propertiesFile));
} coreProperties.putAll(externalProps);
}
private void doInit(String name, String instanceDir) { catch (IOException e) {
if (name == null) { String message = String.format(Locale.ROOT, "Could not load properties from %s: %s:",
throw new RuntimeException("Core needs a name"); propertiesFile.getAbsoluteFile(), e.toString());
throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, message);
}
} }
}
coreProperties.put(CORE_NAME, name); protected File resolvePaths(String filepath) {
File file = new File(filepath);
if (file.isAbsolute())
return file;
return new File(getInstanceDir(), filepath);
}
if(coreContainer != null && coreContainer.getZkController() != null) { /**
this.cloudDesc = new CloudDescriptor(); * Is this property a Solr-standard property, or is it an extra property
// cloud collection defaults to core name * defined per-core by the user?
cloudDesc.setCollectionName(name); * @param propName the Property name
* @return @{code true} if this property is user-defined
*/
protected static boolean isUserDefinedProperty(String propName) {
return !standardPropNames.contains(propName);
}
public static String checkPropertyIsNotEmpty(String value, String propName) {
if (StringUtils.isEmpty(value)) {
String message = String.format(Locale.ROOT, "Cannot create core with empty %s value", propName);
throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, message);
} }
return value;
if (instanceDir == null) {
throw new NullPointerException("Missing required \'instanceDir\'");
}
instanceDir = SolrResourceLoader.normalizeDir(instanceDir);
coreProperties.put(CORE_INSTDIR, instanceDir);
coreProperties.put(CORE_CONFIG, getDefaultConfigName());
coreProperties.put(CORE_SCHEMA, getDefaultSchemaName());
} }
public Properties initImplicitProperties() { /**
* Create a new CoreDescriptor with a given name and instancedir
Properties implicitProperties = new Properties(); * @param container the CoreDescriptor's container
if (coreContainer != null && coreContainer.getContainerProperties() != null){ * @param name the CoreDescriptor's name
implicitProperties.putAll(coreContainer.getContainerProperties()); * @param instanceDir the CoreDescriptor's instancedir
} */
implicitProperties.setProperty("solr.core.name", getName()); public CoreDescriptor(CoreContainer container, String name, String instanceDir) {
implicitProperties.setProperty("solr.core.instanceDir", getInstanceDir()); this(container, name, instanceDir, new Properties());
implicitProperties.setProperty("solr.core.dataDir", getDataDir());
implicitProperties.setProperty("solr.core.configName", getConfigName());
implicitProperties.setProperty("solr.core.schemaName", getSchemaName());
return implicitProperties;
} }
/**@return the default config name. */ /**
public String getDefaultConfigName() { * Create a new CoreDescriptor using the properties of an existing one
return "solrconfig.xml"; * @param coreName the new CoreDescriptor's name
} * @param other the CoreDescriptor to copy
*/
/**@return the default schema name. */ public CoreDescriptor(String coreName, CoreDescriptor other) {
public String getDefaultSchemaName() { this.coreContainer = other.coreContainer;
return "schema.xml"; this.originalExtraProperties.putAll(other.originalExtraProperties);
} this.originalCoreProperties.putAll(other.originalCoreProperties);
this.coreProperties.putAll(other.coreProperties);
/**@return the default data directory. */ this.coreProperties.setProperty(CORE_NAME, coreName);
public String getDefaultDataDir() { this.originalCoreProperties.setProperty(CORE_NAME, coreName);
return "data" + File.separator; this.cloudDesc = other.cloudDesc;
} }
public String getPropertiesName() { public String getPropertiesName() {
return coreProperties.getProperty(CORE_PROPERTIES); return coreProperties.getProperty(CORE_PROPERTIES);
} }
public void setPropertiesName(String propertiesName) {
coreProperties.put(CORE_PROPERTIES, propertiesName);
}
public String getDataDir() { public String getDataDir() {
String dataDir = coreProperties.getProperty(CORE_DATADIR); return coreProperties.getProperty(CORE_DATADIR);
if (dataDir == null) dataDir = getDefaultDataDir();
return dataDir;
}
public void setDataDir(String s) {
// normalize zero length to null.
if (StringUtils.isBlank(s)) {
coreProperties.remove(s);
} else {
coreProperties.put(CORE_DATADIR, s);
}
} }
public boolean usingDefaultDataDir() { public boolean usingDefaultDataDir() {
// DO NOT use the getDataDir method here since it'll assign something regardless. return defaultProperties.get(CORE_DATADIR).equals(coreProperties.getProperty(CORE_DATADIR));
return coreProperties.getProperty(CORE_DATADIR) == null;
} }
/**@return the core instance directory. */ /**@return the core instance directory. */
@ -200,37 +263,20 @@ public class CoreDescriptor {
return coreProperties.getProperty(CORE_INSTDIR); return coreProperties.getProperty(CORE_INSTDIR);
} }
private static String convertToAbsolute(String instDir, String solrHome) {
checkNotNull(instDir);
File f = new File(instDir);
if (f.isAbsolute())
return SolrResourceLoader.normalizeDir(instDir);
return SolrResourceLoader.normalizeDir(solrHome + SolrResourceLoader.normalizeDir(instDir));
}
/** /**
* *
* @return the core instance directory, prepended with solr_home if not an absolute path. * @return the core instance directory, prepended with solr_home if not an absolute path.
*/ */
public String getInstanceDir() { public String getInstanceDir() {
String instDir = coreProperties.getProperty(CORE_INSTDIR); return coreProperties.getProperty(CORE_ABS_INSTDIR);
if (instDir == null) return null;
if (new File(instDir).isAbsolute()) {
return SolrResourceLoader.normalizeDir(
SolrResourceLoader.normalizeDir(instDir));
}
if (coreContainer == null) return null;
if( coreContainer.cfg != null) {
String coreRootDir = coreContainer.cfg.get(
CfgProp.SOLR_COREROOTDIRECTORY, null);
if (coreRootDir != null) {
return SolrResourceLoader.normalizeDir(coreRootDir
+ SolrResourceLoader.normalizeDir(instDir));
}
}
return SolrResourceLoader.normalizeDir(coreContainer.getSolrHome() +
SolrResourceLoader.normalizeDir(instDir));
}
/**Sets the core configuration resource name. */
public void setConfigName(String name) {
if (name == null || name.length() == 0)
throw new IllegalArgumentException("name can not be null or empty");
coreProperties.put(CORE_CONFIG, name);
} }
/**@return the core configuration resource name. */ /**@return the core configuration resource name. */
@ -238,13 +284,6 @@ public class CoreDescriptor {
return coreProperties.getProperty(CORE_CONFIG); return coreProperties.getProperty(CORE_CONFIG);
} }
/**Sets the core schema resource name. */
public void setSchemaName(String name) {
if (name == null || name.length() == 0)
throw new IllegalArgumentException("name can not be null or empty");
coreProperties.put(CORE_SCHEMA, name);
}
/**@return the core schema resource name. */ /**@return the core schema resource name. */
public String getSchemaName() { public String getSchemaName() {
return coreProperties.getProperty(CORE_SCHEMA); return coreProperties.getProperty(CORE_SCHEMA);
@ -255,103 +294,57 @@ public class CoreDescriptor {
return coreProperties.getProperty(CORE_NAME); return coreProperties.getProperty(CORE_NAME);
} }
public String getCollectionName() {
return cloudDesc == null ? null : cloudDesc.getCollectionName();
}
public CoreContainer getCoreContainer() { public CoreContainer getCoreContainer() {
return coreContainer; return coreContainer;
} }
Properties getCoreProperties() {
return coreProperties;
}
/**
* Set this core's properties. Please note that some implicit values will be added to the
* Properties instance passed into this method. This means that the Properties instance
* sent to this method will have different (less) key/value pairs than the Properties
* instance returned by #getCoreProperties method.
*
* Under any circumstance, the properties passed in will override any already present.Merge
*/
public void setCoreProperties(Properties coreProperties) {
if (! loadedImplicit) {
loadedImplicit = true;
Properties p = initImplicitProperties();
this.coreProperties.putAll(p);
// The caller presumably wants whatever properties passed in to override the current core props, so just add them.
if (coreProperties != null) {
this.coreProperties.putAll(coreProperties);
}
}
}
public void addCreatedProperty(String key, String value) {
createdProperties.put(key, value);
}
public final Properties getCreatedProperties() {
return createdProperties;
}
public CloudDescriptor getCloudDescriptor() { public CloudDescriptor getCloudDescriptor() {
return cloudDesc; return cloudDesc;
} }
public void setCloudDescriptor(CloudDescriptor cloudDesc) {
this.cloudDesc = cloudDesc;
}
public boolean isLoadOnStartup() { public boolean isLoadOnStartup() {
String tmp = coreProperties.getProperty(CORE_LOADONSTARTUP, "false"); String tmp = coreProperties.getProperty(CORE_LOADONSTARTUP, "false");
return Boolean.parseBoolean(tmp); return Boolean.parseBoolean(tmp);
} }
public void setLoadOnStartup(boolean loadOnStartup) {
coreProperties.put(CORE_LOADONSTARTUP, Boolean.toString(loadOnStartup));
}
public boolean isTransient() { public boolean isTransient() {
String tmp = coreProperties.getProperty(CORE_TRANSIENT, "false"); String tmp = coreProperties.getProperty(CORE_TRANSIENT, "false");
return (Boolean.parseBoolean(tmp)); return PropertiesUtil.toBoolean(tmp);
}
public void setTransient(boolean isTransient) {
coreProperties.put(CORE_TRANSIENT, Boolean.toString(isTransient));
} }
public String getUlogDir() { public String getUlogDir() {
return coreProperties.getProperty(CORE_ULOGDIR); return coreProperties.getProperty(CORE_ULOGDIR);
} }
public void setUlogDir(String ulogDir) {
coreProperties.put(CORE_ULOGDIR, ulogDir);
}
/** /**
* Reads a property defined in the core.properties file that's replacing solr.xml (if present). * Returns a specific property defined on this CoreDescriptor
* @param prop - value to read from the properties structure. * @param prop - value to read from the properties structure.
* @param defVal - return if no property found. * @param defVal - return if no property found.
* @return associated string. May be null. * @return associated string. May be null.
*/ */
public String getProperty(String prop, String defVal) { public String getCoreProperty(String prop, String defVal) {
return coreProperties.getProperty(prop, defVal); return coreProperties.getProperty(prop, defVal);
} }
/** /**
* gReads a property defined in the core.properties file that's replacing solr.xml (if present). * Returns all properties defined on this CoreDescriptor
* @param prop value to read from the properties structure. * @return all properties defined on this CoreDescriptor
* @return associated string. May be null.
*/ */
public String getProperty(String prop) { public Properties getCoreProperties() {
return coreProperties.getProperty(prop); return coreProperties;
} }
/**
* This will eventually replace _all_ of the setters. Puts a value in the "new" (obsoleting solr.xml JIRAs) properties @Override
* structures. public String toString() {
* return new StringBuilder("CoreDescriptor[name=")
* Will replace any currently-existing property with the key "prop". .append(this.getName())
* .append(";instanceDir=")
* @param prop - property name .append(this.getInstanceDir())
* @param val - property value .append("]")
*/ .toString();
public void putProperty(String prop, String val) {
coreProperties.put(prop, val);
} }
} }

View File

@ -0,0 +1,158 @@
package org.apache.solr.core;
/*
* 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.google.common.base.Charsets;
import com.google.common.collect.Lists;
import org.apache.solr.common.SolrException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.Date;
import java.util.List;
import java.util.Properties;
/**
* Persists CoreDescriptors as properties files
*/
public class CorePropertiesLocator implements CoresLocator {
public static final String PROPERTIES_FILENAME = "core.properties";
private static final Logger logger = LoggerFactory.getLogger(CoresLocator.class);
private final File rootDirectory;
public CorePropertiesLocator(String coreDiscoveryRoot) {
this.rootDirectory = new File(coreDiscoveryRoot);
}
@Override
public void create(CoreContainer cc, CoreDescriptor... coreDescriptors) {
for (CoreDescriptor cd : coreDescriptors) {
File propFile = new File(new File(cd.getInstanceDir()), PROPERTIES_FILENAME);
if (propFile.exists())
throw new SolrException(SolrException.ErrorCode.BAD_REQUEST,
"Could not create a new core in " + cd.getInstanceDir()
+ "as another core is already defined there");
try {
Properties p = buildCoreProperties(cd);
Writer writer = new OutputStreamWriter(new FileOutputStream(propFile), Charsets.UTF_8);
p.store(writer, "Written by CorePropertiesLocator on " + new Date());
}
catch (IOException e) {
logger.error("Couldn't persist core properties to {}: {}", propFile.getAbsolutePath(), e);
}
}
}
// TODO, this isn't atomic! If we crash in the middle of a rename, we
// could end up with two cores with identical names, in which case one of
// them won't start up. Are we happy with this?
@Override
public void persist(CoreContainer cc, CoreDescriptor... coreDescriptors) {
for (CoreDescriptor cd : coreDescriptors) {
File propFile = new File(new File(cd.getInstanceDir()), PROPERTIES_FILENAME);
try {
Properties p = buildCoreProperties(cd);
Writer writer = new OutputStreamWriter(new FileOutputStream(propFile), Charsets.UTF_8);
p.store(writer, "Written by CorePropertiesLocator on " + new Date());
}
catch (IOException e) {
logger.error("Couldn't persist core properties to {}: {}", propFile.getAbsolutePath(), e);
}
}
}
@Override
public void delete(CoreContainer cc, CoreDescriptor... coreDescriptors) {
for (CoreDescriptor cd : coreDescriptors) {
File instanceDir = new File(cd.getInstanceDir());
File propertiesFile = new File(instanceDir, PROPERTIES_FILENAME);
propertiesFile.renameTo(new File(instanceDir, PROPERTIES_FILENAME + ".unloaded"));
// This is a best-effort: the core.properties file may already have been
// deleted by the core unload, so we don't worry about checking if the
// rename has succeeded.
}
}
@Override
public void rename(CoreContainer cc, CoreDescriptor oldCD, CoreDescriptor newCD) {
persist(cc, newCD);
}
@Override
public List<CoreDescriptor> discover(CoreContainer cc) {
logger.info("Looking for core definitions underneath {}", rootDirectory.getAbsolutePath());
List<CoreDescriptor> cds = Lists.newArrayList();
discoverUnder(rootDirectory, cds, cc);
logger.info("Found {} core definitions", cds.size());
return cds;
}
private void discoverUnder(File root, List<CoreDescriptor> cds, CoreContainer cc) {
if (!root.exists())
return;
for (File child : root.listFiles()) {
File propertiesFile = new File(child, PROPERTIES_FILENAME);
if (propertiesFile.exists()) {
CoreDescriptor cd = buildCoreDescriptor(propertiesFile, cc);
logger.info("Found core {} in {}", cd.getName(), cd.getInstanceDir());
cds.add(cd);
continue;
}
if (child.isDirectory())
discoverUnder(child, cds, cc);
}
}
protected CoreDescriptor buildCoreDescriptor(File propertiesFile, CoreContainer cc) {
try {
File instanceDir = propertiesFile.getParentFile();
Properties coreProperties = new Properties();
coreProperties.load(new FileInputStream(propertiesFile));
String name = createName(coreProperties, instanceDir);
return new CoreDescriptor(cc, name, instanceDir.getAbsolutePath(), coreProperties);
} catch (IOException e) {
logger.error("Couldn't load core descriptor from {}:{}", propertiesFile.getAbsolutePath(), e.toString());
return null;
}
}
protected static String createName(Properties p, File instanceDir) {
return p.getProperty(CoreDescriptor.CORE_NAME, instanceDir.getName());
}
protected Properties buildCoreProperties(CoreDescriptor cd) {
Properties p = new Properties();
p.putAll(cd.getPersistableStandardProperties());
p.putAll(cd.getPersistableUserProperties());
// We don't persist the instance directory, as that's defined by the location
// of the properties file.
p.remove(CoreDescriptor.CORE_INSTDIR);
return p;
}
}

View File

@ -0,0 +1,65 @@
package org.apache.solr.core;
/*
* 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 java.util.List;
/**
* Manage the discovery and persistence of core definitions across Solr restarts
*/
public interface CoresLocator {
/**
* Make new cores available for discovery
* @param cc the CoreContainer
* @param coreDescriptors CoreDescriptors to persist
*/
public void create(CoreContainer cc, CoreDescriptor... coreDescriptors);
/**
* Ensure that the core definitions from the passed in CoreDescriptors
* will persist across container restarts.
* @param cc the CoreContainer
* @param coreDescriptors CoreDescriptors to persist
*/
public void persist(CoreContainer cc, CoreDescriptor... coreDescriptors);
/**
* Ensure that the core definitions from the passed in CoreDescriptors
* are not available for discovery
* @param cc the CoreContainer
* @param coreDescriptors CoreDescriptors of the cores to remove
*/
public void delete(CoreContainer cc, CoreDescriptor... coreDescriptors);
/**
* Persist the new name of a renamed core
* @param cc the CoreContainer
* @param oldCD the CoreDescriptor of the core before renaming
* @param newCD the CoreDescriptor of the core after renaming
*/
public void rename(CoreContainer cc, CoreDescriptor oldCD, CoreDescriptor newCD);
/**
* Load all the CoreDescriptors from persistence store
* @param cc the CoreContainer
* @return a list of all CoreDescriptors found
*/
public List<CoreDescriptor> discover(CoreContainer cc);
}

View File

@ -17,42 +17,6 @@
package org.apache.solr.core; package org.apache.solr.core;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Writer;
import java.lang.reflect.Constructor;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.IdentityHashMap;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.locks.ReentrantLock;
import javax.xml.parsers.ParserConfigurationException;
import org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
import org.apache.lucene.codecs.Codec; import org.apache.lucene.codecs.Codec;
import org.apache.lucene.index.DirectoryReader; import org.apache.lucene.index.DirectoryReader;
@ -65,7 +29,6 @@ import org.apache.lucene.store.IndexInput;
import org.apache.lucene.store.LockObtainFailedException; import org.apache.lucene.store.LockObtainFailedException;
import org.apache.solr.cloud.CloudDescriptor; import org.apache.solr.cloud.CloudDescriptor;
import org.apache.solr.common.SolrException; import org.apache.solr.common.SolrException;
import org.apache.solr.common.SolrException.ErrorCode;
import org.apache.solr.common.cloud.Slice; import org.apache.solr.common.cloud.Slice;
import org.apache.solr.common.params.CommonParams; import org.apache.solr.common.params.CommonParams;
import org.apache.solr.common.params.CommonParams.EchoParamStyle; import org.apache.solr.common.params.CommonParams.EchoParamStyle;
@ -129,6 +92,38 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.xml.sax.SAXException; import org.xml.sax.SAXException;
import javax.xml.parsers.ParserConfigurationException;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.Writer;
import java.lang.reflect.Constructor;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.IdentityHashMap;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.locks.ReentrantLock;
/** /**
* *
@ -146,7 +141,7 @@ public final class SolrCore implements SolrInfoMBean {
private String name; private String name;
private String logid; // used to show what name is set private String logid; // used to show what name is set
private final CoreDescriptor coreDescriptor; private CoreDescriptor coreDescriptor;
private boolean isReloaded = false; private boolean isReloaded = false;
@ -306,6 +301,7 @@ public final class SolrCore implements SolrInfoMBean {
public void setName(String v) { public void setName(String v) {
this.name = v; this.name = v;
this.logid = (v==null)?"":("["+v+"] "); this.logid = (v==null)?"":("["+v+"] ");
this.coreDescriptor = new CoreDescriptor(v, this.coreDescriptor);
} }
public String getLogId() public String getLogId()
@ -849,12 +845,6 @@ public final class SolrCore implements SolrInfoMBean {
CoreContainer cc = cd.getCoreContainer(); CoreContainer cc = cd.getCoreContainer();
if (cc != null) {
if (cc.cfg != null && cc.cfg instanceof ConfigSolrXml) {
writePropFile(cd, cc);
}
}
if (cc != null && cc.isZooKeeperAware() && Slice.CONSTRUCTION.equals(cd.getCloudDescriptor().getShardState())) { if (cc != null && cc.isZooKeeperAware() && Slice.CONSTRUCTION.equals(cd.getCloudDescriptor().getShardState())) {
// set update log to buffer before publishing the core // set update log to buffer before publishing the core
getUpdateHandler().getUpdateLog().bufferUpdates(); getUpdateHandler().getUpdateLog().bufferUpdates();
@ -868,56 +858,6 @@ public final class SolrCore implements SolrInfoMBean {
// openHandles.put(this, new RuntimeException("unclosed core - name:" + getName() + " refs: " + refCount.get())); // openHandles.put(this, new RuntimeException("unclosed core - name:" + getName() + " refs: " + refCount.get()));
} }
private void writePropFile(CoreDescriptor cd, CoreContainer cc) {
File propFile = new File(cd.getInstanceDir(), "core.properties");
if (!propFile.exists()) {
propFile.getParentFile().mkdirs();
Properties props = new Properties();
props.put("name", cd.getName());
// This must be being created since there's no file here already. So write out all of the params we were
// created with. This _may_ overwrite the name above, but that's OK.
Collection<String> stds = new HashSet(Arrays.asList(CoreDescriptor.standardPropNames));
for (String prop : cd.getCreatedProperties().stringPropertyNames()) {
// Only preserve things that are legal, and let's just keep instDir right out of the persisted file even
// though it's part of the create properties on the URL.
if (! CoreDescriptor.CORE_INSTDIR.equals(prop) && stds.contains(prop)) {
props.put(prop, cd.getCreatedProperties().getProperty(prop));
}
}
if (cc.isZooKeeperAware()) {
String collection = cd.getCloudDescriptor().getCollectionName();
if (collection != null) {
props.put("collection", collection);
}
String coreNodeName = cd.getCloudDescriptor().getCoreNodeName();
if (coreNodeName != null) {
props.put("coreNodeName", coreNodeName);
}
String roles = cd.getCloudDescriptor().getRoles();
if (roles != null) {
props.put("roles", roles);
}
String shardId = cd.getCloudDescriptor().getShardId();
if (shardId != null) {
props.put("shard", shardId);
}
}
OutputStream out = null;
try {
out = new FileOutputStream(propFile);
props.store(out, "");
} catch (IOException e) {
throw new SolrException(ErrorCode.SERVER_ERROR, null, e);
} finally {
if (out != null) {
IOUtils.closeQuietly(out);
}
}
}
}
private Codec initCodec(SolrConfig solrConfig, final IndexSchema schema) { private Codec initCodec(SolrConfig solrConfig, final IndexSchema schema) {
final PluginInfo info = solrConfig.getPluginInfo(CodecFactory.class.getName()); final PluginInfo info = solrConfig.getPluginInfo(CodecFactory.class.getName());
final CodecFactory factory; final CodecFactory factory;

View File

@ -1,100 +0,0 @@
package org.apache.solr.core;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import org.apache.commons.io.IOUtils;
import org.apache.solr.common.SolrException;
import org.apache.solr.util.PropertiesUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/*
* 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.
*/
public class SolrCoreDiscoverer {
protected static Logger log = LoggerFactory.getLogger(SolrCoreDiscoverer.class);
public final static String CORE_PROP_FILE = "core.properties";
public Map<String, CoreDescriptor> discover(CoreContainer container, File root) throws IOException {
Map<String, CoreDescriptor> coreDescriptorMap = new HashMap<String, CoreDescriptor>();
walkFromHere(root, container, coreDescriptorMap);
return coreDescriptorMap;
}
// Basic recursive tree walking, looking for "core.properties" files. Once one is found, we'll stop going any
// deeper in the tree.
//
private void walkFromHere(File file, CoreContainer container, Map<String,CoreDescriptor> coreDescriptorMap)
throws IOException {
log.info("Looking for cores in " + file.getCanonicalPath());
if (! file.exists()) return;
for (File childFile : file.listFiles()) {
// This is a little tricky, we are asking if core.properties exists in a child directory of the directory passed
// in. In other words we're looking for core.properties in the grandchild directories of the parameter passed
// in. That allows us to gracefully stop recursing deep but continue looking wide.
File propFile = new File(childFile, CORE_PROP_FILE);
if (propFile.exists()) { // Stop looking after processing this file!
addCore(container, childFile, propFile, coreDescriptorMap);
continue; // Go on to the sibling directory, don't descend any deeper.
}
if (childFile.isDirectory()) {
walkFromHere(childFile, container, coreDescriptorMap);
}
}
}
private void addCore(CoreContainer container, File childFile, File propFile, Map<String,CoreDescriptor> coreDescriptorMap) throws IOException {
log.info("Discovered properties file {}, adding to cores", propFile.getAbsolutePath());
Properties propsOrig = new Properties();
InputStream is = new FileInputStream(propFile);
try {
propsOrig.load(is);
} finally {
IOUtils.closeQuietly(is);
}
Properties props = new Properties();
for (String prop : propsOrig.stringPropertyNames()) {
props.put(prop, PropertiesUtil.substituteProperty(propsOrig.getProperty(prop), null));
}
// Too much of the code depends on this value being here, but it is NOT supported in discovery mode, so
// ignore it if present in the core.properties file.
props.setProperty(CoreDescriptor.CORE_INSTDIR, childFile.getCanonicalPath());
if (props.getProperty(CoreDescriptor.CORE_NAME) == null) {
// Should default to this directory
props.setProperty(CoreDescriptor.CORE_NAME, childFile.getName());
}
CoreDescriptor desc = new CoreDescriptor(container, props);
CoreDescriptor check = coreDescriptorMap.get(desc.getName());
if (check != null) {
throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, "Core " + desc.getName() +
" defined more than once, once in " + desc.getInstanceDir() + " and once in " + check.getInstanceDir());
}
coreDescriptorMap.put(desc.getName(), desc);
}
}

View File

@ -17,32 +17,24 @@ package org.apache.solr.core;
* limitations under the License. * limitations under the License.
*/ */
import org.apache.commons.lang.StringUtils; import com.google.common.collect.Lists;
import org.apache.solr.cloud.CloudDescriptor;
import org.apache.solr.common.SolrException; import org.apache.solr.common.SolrException;
import org.apache.solr.common.params.CoreAdminParams; import org.slf4j.Logger;
import org.apache.solr.core.SolrXMLSerializer.SolrCoreXMLDef; import org.slf4j.LoggerFactory;
import org.apache.solr.util.DOMUtil;
import org.w3c.dom.Node;
import javax.xml.xpath.XPathExpressionException;
import java.io.File;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Properties;
import java.util.Set; import java.util.Set;
import java.util.TreeSet; import java.util.TreeSet;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
class SolrCores { class SolrCores {
private static SolrXMLSerializer SOLR_XML_SERIALIZER = new SolrXMLSerializer();
private static Object modifyLock = new Object(); // for locking around manipulating any of the core maps. private static Object modifyLock = new Object(); // for locking around manipulating any of the core maps.
private final Map<String, SolrCore> cores = new LinkedHashMap<String, SolrCore>(); // For "permanent" cores private final Map<String, SolrCore> cores = new LinkedHashMap<String, SolrCore>(); // For "permanent" cores
@ -57,6 +49,8 @@ class SolrCores {
private final CoreContainer container; private final CoreContainer container;
private static final Logger logger = LoggerFactory.getLogger(SolrCores.class);
// This map will hold objects that are being currently operated on. The core (value) may be null in the case of // This map will hold objects that are being currently operated on. The core (value) may be null in the case of
// initial load. The rule is, never to any operation on a core that is currently being operated upon. // initial load. The rule is, never to any operation on a core that is currently being operated upon.
private static final Set<String> pendingCoreOps = new HashSet<String>(); private static final Set<String> pendingCoreOps = new HashSet<String>();
@ -80,7 +74,9 @@ class SolrCores {
protected boolean removeEldestEntry(Map.Entry<String, SolrCore> eldest) { protected boolean removeEldestEntry(Map.Entry<String, SolrCore> eldest) {
if (size() > transientCacheSize) { if (size() > transientCacheSize) {
synchronized (modifyLock) { synchronized (modifyLock) {
pendingCloses.add(eldest.getValue()); // Essentially just queue this core up for closing. SolrCore coreToClose = eldest.getValue();
logger.info("Closing transient core [{}]", coreToClose.getName());
pendingCloses.add(coreToClose); // Essentially just queue this core up for closing.
modifyLock.notifyAll(); // Wakes up closer thread too modifyLock.notifyAll(); // Wakes up closer thread too
} }
return true; return true;
@ -227,9 +223,7 @@ class SolrCores {
cores.put(n1, c0); cores.put(n1, c0);
c0.setName(n1); c0.setName(n1);
c0.getCoreDescriptor().putProperty(CoreDescriptor.CORE_NAME, n1);
c1.setName(n0); c1.setName(n0);
c1.getCoreDescriptor().putProperty(CoreDescriptor.CORE_NAME, n0);
} }
} }
@ -314,7 +308,7 @@ class SolrCores {
if (desc == null) { if (desc == null) {
return null; return null;
} }
return new CoreDescriptor(desc); return new CoreDescriptor(cname, desc);
} }
} }
@ -325,47 +319,6 @@ class SolrCores {
} }
} }
public void persistCores(Config cfg, Properties containerProperties,
Map<String,String> rootSolrAttribs, Map<String,String> coresAttribs,
Map<String, String> loggingAttribs, Map<String,String> watcherAttribs,
Node shardHandlerNode,
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
// cores
for (Map.Entry<String,CoreDescriptor> ent : dynamicDescriptors.entrySet()) {
if (!cores.containsKey(ent.getKey())
&& !transientCores.containsKey(ent.getKey())) {
addCoreToPersistList(cfg, loader, ent.getValue(), null, solrCoreXMLDefs);
}
}
for (Map.Entry<String,SolrCore> ent : createdCores.entrySet()) {
if (!cores.containsKey(ent.getKey())
&& !transientCores.containsKey(ent.getKey())
&& !dynamicDescriptors.containsKey(ent.getKey())) {
addCoreToPersistList(cfg, loader, ent.getValue().getCoreDescriptor(),
null, solrCoreXMLDefs);
}
}
SolrXMLSerializer.SolrXMLDef solrXMLDef = new SolrXMLSerializer.SolrXMLDef();
solrXMLDef.coresDefs = solrCoreXMLDefs;
solrXMLDef.containerProperties = containerProperties;
solrXMLDef.solrAttribs = rootSolrAttribs;
solrXMLDef.coresAttribs = coresAttribs;
solrXMLDef.loggingAttribs = loggingAttribs;
solrXMLDef.watcherAttribs = watcherAttribs;
solrXMLDef.shardHandlerNode = shardHandlerNode;
SOLR_XML_SERIALIZER.persistFile(file, solrXMLDef);
}
}
// Wait here until any pending operations (load, unload or reload) are completed on this core. // Wait here until any pending operations (load, unload or reload) are completed on this core.
protected SolrCore waitAddPendingCoreOps(String name) { protected SolrCore waitAddPendingCoreOps(String name) {
@ -414,170 +367,6 @@ class SolrCores {
} }
} }
protected void persistCores(Config cfg, Map<String, SolrCore> whichCores, SolrResourceLoader loader, List<SolrCoreXMLDef> solrCoreXMLDefs) throws XPathExpressionException {
for (SolrCore solrCore : whichCores.values()) {
addCoreToPersistList(cfg, loader, solrCore.getCoreDescriptor(), getCoreToOrigName(solrCore), solrCoreXMLDefs);
}
}
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) {
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) {
propMap.put(name, rawAttribValue);
return;
}
// 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;
}
String rawComp = regularizeAttr(rawAttribValue);
if (rawComp != null && regularizeAttr(value).equals(
regularizeAttr(DOMUtil.substituteProperty(rawAttribValue, loader.getCoreProperties())))) {
propMap.put(name, rawAttribValue);
} else {
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 {
Map<String,String> coreAttribs = new HashMap<String,String>();
Properties newProps = new Properties();
// This is simple, just take anything sent in and saved away in at core creation and write it out.
if (dcore.getCreatedProperties().size() > 0) {
final List<String> stdNames = new ArrayList<String>(Arrays.asList(CoreDescriptor.standardPropNames));
coreAttribs.put(CoreDescriptor.CORE_NAME, dcore.getName()); // NOTE: may have been swapped or renamed!
for (String key : dcore.getCreatedProperties().stringPropertyNames()) {
if (! stdNames.contains(key) && ! key.startsWith(CoreAdminParams.PROPERTY_PREFIX)) continue;
if (key.indexOf(CoreAdminParams.PROPERTY_PREFIX) == 0) {
newProps.put(key.substring(CoreAdminParams.PROPERTY_PREFIX.length()), dcore.getCreatedProperties().getProperty(key));
} else if (! CoreDescriptor.CORE_NAME.equals(key)) {
coreAttribs.put(key, dcore.getCreatedProperties().getProperty(key));
}
}
// Insure instdir is persisted if it's the default since it's checked at startup even if not specified on the
// create command.
if (! dcore.getCreatedProperties().containsKey(CoreDescriptor.CORE_INSTDIR)) {
coreAttribs.put(CoreDescriptor.CORE_INSTDIR, dcore.getRawInstanceDir());
}
} else {
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);
//coreAttribs.put(CoreDescriptor.CORE_INSTDIR, dcore.getRawInstanceDir());
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));
}
}
}
}
SolrXMLSerializer.SolrCoreXMLDef solrCoreXMLDef = new SolrXMLSerializer.SolrCoreXMLDef();
solrCoreXMLDef.coreAttribs = coreAttribs;
solrCoreXMLDef.coreProperties = newProps;
solrCoreXMLDefs.add(solrCoreXMLDef);
}
protected Object getModifyLock() { protected Object getModifyLock() {
return modifyLock; return modifyLock;
} }
@ -604,4 +393,37 @@ class SolrCores {
createdCores.put(core.getName(), core); createdCores.put(core.getName(), core);
} }
} }
/**
* Return the CoreDescriptor corresponding to a given core name.
* @param coreName the name of the core
* @return the CoreDescriptor
*/
public CoreDescriptor getCoreDescriptor(String coreName) {
synchronized (modifyLock) {
if (cores.containsKey(coreName))
return cores.get(coreName).getCoreDescriptor();
if (dynamicDescriptors.containsKey(coreName))
return dynamicDescriptors.get(coreName);
return null;
}
}
/**
* Get the CoreDescriptors for every SolrCore managed here
* @return a List of CoreDescriptors
*/
public List<CoreDescriptor> getCoreDescriptors() {
List<CoreDescriptor> cds = Lists.newArrayList();
synchronized (modifyLock) {
for (String coreName : getAllCoreNames()) {
// TODO: This null check is a bit suspicious - it seems that
// getAllCoreNames might return deleted cores as well?
CoreDescriptor cd = getCoreDescriptor(coreName);
if (cd != null)
cds.add(cd);
}
}
return cds;
}
} }

View File

@ -0,0 +1,221 @@
package org.apache.solr.core;
/*
* 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.google.common.base.Charsets;
import com.google.common.collect.ImmutableList;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Writes any changes in core definitions to this instance's solr.xml
*/
public class SolrXMLCoresLocator implements CoresLocator {
private static final Logger logger = LoggerFactory.getLogger(SolrXMLCoresLocator.class);
private final File file;
private final String solrXmlTemplate;
private final ConfigSolrXmlOld cfg;
/** Core name to use if a core definition has no name */
public static final String DEFAULT_CORE_NAME = "collection1";
/**
* Create a new SolrXMLCoresLocator
* @param file a File object representing the file to write out to
* @param originalXML the original content of the solr.xml file
* @param cfg the CoreContainer's config object
*/
public SolrXMLCoresLocator(File file, String originalXML, ConfigSolrXmlOld cfg) {
this.solrXmlTemplate = buildTemplate(originalXML);
this.file = file;
this.cfg = cfg;
}
private static Pattern POPULATED_CORES_TAG
= Pattern.compile("^(.*<cores[^>]*>)(.*)(</cores>.*)$", Pattern.DOTALL);
private static Pattern EMPTY_CORES_TAG
= Pattern.compile("^(.*<cores[^>]*)/>(.*)$", Pattern.DOTALL);
private static Pattern SHARD_HANDLER_TAG
= Pattern.compile("(<shardHandlerFactory[^>]*>.*</shardHandlerFactory>)|(<shardHandlerFactory[^>]*/>)",
Pattern.DOTALL);
private static String CORES_PLACEHOLDER = "{{CORES_PLACEHOLDER}}";
// Package-private for testing
// We replace the existing <cores></cores> contents with a template pattern
// that we can later replace with the up-to-date core definitions. We also
// need to extract the <shardHandlerFactory> section, as, annoyingly, it's
// kept inside <cores/>.
static String buildTemplate(String originalXML) {
String shardHandlerConfig = "";
Matcher shfMatcher = SHARD_HANDLER_TAG.matcher(originalXML);
if (shfMatcher.find()) {
shardHandlerConfig = shfMatcher.group(0);
}
Matcher popMatcher = POPULATED_CORES_TAG.matcher(originalXML);
if (popMatcher.matches()) {
return new StringBuilder(popMatcher.group(1))
.append(CORES_PLACEHOLDER).append(shardHandlerConfig).append(popMatcher.group(3)).toString();
}
// Self-closing <cores/> tag gets expanded to <cores></cores>
Matcher emptyMatcher = EMPTY_CORES_TAG.matcher(originalXML);
if (emptyMatcher.matches())
return new StringBuilder(emptyMatcher.group(1))
.append(">").append(CORES_PLACEHOLDER).append("</cores>")
.append(emptyMatcher.group(2)).toString();
// If there's no <cores> tag at all, add one at the end of the file
return originalXML.replace("</solr>", "<cores>" + CORES_PLACEHOLDER + "</cores></solr>");
}
// protected access for testing
protected String buildSolrXML(List<CoreDescriptor> cds) {
StringBuilder builder = new StringBuilder();
for (CoreDescriptor cd : cds) {
builder.append(buildCoreTag(cd));
}
return solrXmlTemplate.replace(CORES_PLACEHOLDER, builder.toString());
}
public static final String NEWLINE = System.getProperty("line.separator");
public static final String INDENT = " ";
/**
* Serialize a coredescriptor as a String containing an XML &lt;core> tag.
* @param cd the CoreDescriptor
* @return an XML representation of the CoreDescriptor
*/
protected static String buildCoreTag(CoreDescriptor cd) {
StringBuilder builder = new StringBuilder(NEWLINE).append(INDENT).append("<core");
for (Map.Entry<Object, Object> entry : cd.getPersistableStandardProperties().entrySet()) {
builder.append(" ").append(entry.getKey()).append("=\"").append(entry.getValue()).append("\"");
}
Properties userProperties = cd.getPersistableUserProperties();
if (userProperties.isEmpty()) {
return builder.append("/>").append(NEWLINE).toString();
}
builder.append(">").append(NEWLINE);
for (Map.Entry<Object, Object> entry : userProperties.entrySet()) {
builder.append(INDENT).append(INDENT)
.append("<property name=\"").append(entry.getKey()).append("\" value=\"")
.append(entry.getValue()).append("\"/>").append(NEWLINE);
}
return builder.append("</core>").append(NEWLINE).toString();
}
@Override
public final void persist(CoreContainer cc, CoreDescriptor... coreDescriptors) {
doPersist(buildSolrXML(cc.getCoreDescriptors()));
}
protected void doPersist(String xml) {
try {
Writer writer = new OutputStreamWriter(new FileOutputStream(file), Charsets.UTF_8);
writer.write(xml);
writer.close();
logger.info("Persisted core descriptions to {}", file.getAbsolutePath());
}
catch (IOException e) {
logger.error("Couldn't persist core descriptions to {} : {}", file.getAbsolutePath(), e);
}
}
@Override
public void create(CoreContainer cc, CoreDescriptor... coreDescriptors) {
this.persist(cc, coreDescriptors);
}
@Override
public void delete(CoreContainer cc, CoreDescriptor... coreDescriptors) {
this.persist(cc, coreDescriptors);
}
@Override
public void rename(CoreContainer cc, CoreDescriptor oldCD, CoreDescriptor newCD) {
this.persist(cc, oldCD, newCD);
}
@Override
public List<CoreDescriptor> discover(CoreContainer cc) {
ImmutableList.Builder<CoreDescriptor> listBuilder = ImmutableList.builder();
for (String coreName : cfg.getAllCoreNames()) {
String name = cfg.getProperty(coreName, CoreDescriptor.CORE_NAME, DEFAULT_CORE_NAME);
String instanceDir = cfg.getProperty(coreName, CoreDescriptor.CORE_INSTDIR, "");
Properties coreProperties = new Properties();
for (String propName : CoreDescriptor.standardPropNames) {
String propValue = cfg.getProperty(coreName, propName, "");
if (StringUtils.isNotEmpty(propValue))
coreProperties.setProperty(propName, propValue);
}
coreProperties.putAll(cfg.getCoreProperties(coreName));
listBuilder.add(new CoreDescriptor(cc, name, instanceDir, coreProperties));
}
return listBuilder.build();
}
// for testing
String getTemplate() {
return solrXmlTemplate;
}
public static class NonPersistingLocator extends SolrXMLCoresLocator {
public NonPersistingLocator(File file, String originalXML, ConfigSolrXmlOld cfg) {
super(file, originalXML, cfg);
this.xml = originalXML;
}
@Override
public void doPersist(String xml) {
this.xml = xml;
}
public String xml;
}
}

View File

@ -203,7 +203,7 @@ public class ZkContainer {
if(boostrapConf) { if(boostrapConf) {
ZkController.bootstrapConf(zkController.getZkClient(), cc.cfg, solrHome); ZkController.bootstrapConf(zkController.getZkClient(), cc, solrHome);
} }
} catch (InterruptedException e) { } catch (InterruptedException e) {
@ -249,8 +249,7 @@ public class ZkContainer {
"Could not find config name for collection:" + collection); "Could not find config name for collection:" + collection);
} }
solrLoader = new ZkSolrResourceLoader(instanceDir, zkConfigName, solrLoader = new ZkSolrResourceLoader(instanceDir, zkConfigName,
loader.getClassLoader(), ConfigSolrXml.getCoreProperties(instanceDir, loader.getClassLoader(), dcore.getCoreProperties(), zkController);
dcore), zkController);
config = getSolrConfigFromZk(zkConfigName, dcore.getConfigName(), config = getSolrConfigFromZk(zkConfigName, dcore.getConfigName(),
solrLoader); solrLoader);
schema = IndexSchemaFactory.buildIndexSchema(dcore.getSchemaName(), schema = IndexSchemaFactory.buildIndexSchema(dcore.getSchemaName(),

View File

@ -17,6 +17,7 @@
package org.apache.solr.handler.admin; package org.apache.solr.handler.admin;
import com.google.common.collect.ImmutableMap;
import org.apache.commons.io.FileUtils; import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.apache.lucene.index.DirectoryReader; import org.apache.lucene.index.DirectoryReader;
@ -57,7 +58,6 @@ import org.apache.solr.update.UpdateLog;
import org.apache.solr.update.processor.UpdateRequestProcessor; import org.apache.solr.update.processor.UpdateRequestProcessor;
import org.apache.solr.update.processor.UpdateRequestProcessorChain; import org.apache.solr.update.processor.UpdateRequestProcessorChain;
import org.apache.solr.util.NumberUtils; import org.apache.solr.util.NumberUtils;
import org.apache.solr.util.PropertiesUtil;
import org.apache.solr.util.RefCounted; import org.apache.solr.util.RefCounted;
import org.apache.zookeeper.KeeperException; import org.apache.zookeeper.KeeperException;
import org.slf4j.Logger; import org.slf4j.Logger;
@ -127,7 +127,7 @@ public class CoreAdminHandler extends RequestHandlerBase {
throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, throw new SolrException(SolrException.ErrorCode.BAD_REQUEST,
"Core container instance missing"); "Core container instance missing");
} }
boolean doPersist = false; //boolean doPersist = false;
// Pick the action // Pick the action
SolrParams params = req.getParams(); SolrParams params = req.getParams();
@ -136,54 +136,54 @@ public class CoreAdminHandler extends RequestHandlerBase {
if (a != null) { if (a != null) {
action = CoreAdminAction.get(a); action = CoreAdminAction.get(a);
if (action == null) { if (action == null) {
doPersist = this.handleCustomAction(req, rsp); this.handleCustomAction(req, rsp);
} }
} }
if (action != null) { if (action != null) {
switch (action) { switch (action) {
case CREATE: { case CREATE: {
doPersist = this.handleCreateAction(req, rsp); this.handleCreateAction(req, rsp);
break; break;
} }
case RENAME: { case RENAME: {
doPersist = this.handleRenameAction(req, rsp); this.handleRenameAction(req, rsp);
break; break;
} }
case UNLOAD: { case UNLOAD: {
doPersist = this.handleUnloadAction(req, rsp); this.handleUnloadAction(req, rsp);
break; break;
} }
case STATUS: { case STATUS: {
doPersist = this.handleStatusAction(req, rsp); this.handleStatusAction(req, rsp);
break; break;
} }
case PERSIST: { case PERSIST: {
doPersist = this.handlePersistAction(req, rsp); this.handlePersistAction(req, rsp);
break; break;
} }
case RELOAD: { case RELOAD: {
doPersist = this.handleReloadAction(req, rsp); this.handleReloadAction(req, rsp);
break; break;
} }
case SWAP: { case SWAP: {
doPersist = this.handleSwapAction(req, rsp); this.handleSwapAction(req, rsp);
break; break;
} }
case MERGEINDEXES: { case MERGEINDEXES: {
doPersist = this.handleMergeAction(req, rsp); this.handleMergeAction(req, rsp);
break; break;
} }
case SPLIT: { case SPLIT: {
doPersist = this.handleSplitAction(req, rsp); this.handleSplitAction(req, rsp);
break; break;
} }
@ -209,28 +209,21 @@ public class CoreAdminHandler extends RequestHandlerBase {
} }
default: { default: {
doPersist = this.handleCustomAction(req, rsp); this.handleCustomAction(req, rsp);
break; break;
} }
case LOAD: case LOAD:
break; break;
} }
} }
// Should we persist the changes?
if (doPersist) {
cores.persist();
rsp.add("saved", cores.getConfigFile().getAbsolutePath());
}
rsp.setHttpCaching(false); rsp.setHttpCaching(false);
} }
/** /**
* Handle the core admin SPLIT action. * Handle the core admin SPLIT action.
* @return true if a modification has resulted that requires persistence
* of the CoreContainer configuration.
*/ */
protected boolean handleSplitAction(SolrQueryRequest adminReq, SolrQueryResponse rsp) throws IOException { protected void handleSplitAction(SolrQueryRequest adminReq, SolrQueryResponse rsp) throws IOException {
SolrParams params = adminReq.getParams(); SolrParams params = adminReq.getParams();
List<DocRouter.Range> ranges = null; List<DocRouter.Range> ranges = null;
@ -299,11 +292,10 @@ public class CoreAdminHandler extends RequestHandlerBase {
} }
} }
return false;
} }
protected boolean handleMergeAction(SolrQueryRequest req, SolrQueryResponse rsp) throws IOException { protected void handleMergeAction(SolrQueryRequest req, SolrQueryResponse rsp) throws IOException {
SolrParams params = req.getParams(); SolrParams params = req.getParams();
String cname = params.required().get(CoreAdminParams.CORE); String cname = params.required().get(CoreAdminParams.CORE);
SolrCore core = coreContainer.getCore(cname); SolrCore core = coreContainer.getCore(cname);
@ -386,7 +378,6 @@ public class CoreAdminHandler extends RequestHandlerBase {
core.close(); core.close();
} }
} }
return coreContainer.isPersistent();
} }
/** /**
@ -395,140 +386,93 @@ public class CoreAdminHandler extends RequestHandlerBase {
* This method could be overridden by derived classes to handle custom actions. <br> By default - this method throws a * This method could be overridden by derived classes to handle custom actions. <br> By default - this method throws a
* solr exception. Derived classes are free to write their derivation if necessary. * solr exception. Derived classes are free to write their derivation if necessary.
*/ */
protected boolean handleCustomAction(SolrQueryRequest req, SolrQueryResponse rsp) { protected void handleCustomAction(SolrQueryRequest req, SolrQueryResponse rsp) {
throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "Unsupported operation: " + throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "Unsupported operation: " +
req.getParams().get(CoreAdminParams.ACTION)); req.getParams().get(CoreAdminParams.ACTION));
} }
public static ImmutableMap<String, String> paramToProp = ImmutableMap.<String, String>builder()
.put(CoreAdminParams.CONFIG, CoreDescriptor.CORE_CONFIG)
.put(CoreAdminParams.SCHEMA, CoreDescriptor.CORE_SCHEMA)
.put(CoreAdminParams.DATA_DIR, CoreDescriptor.CORE_DATADIR)
.put(CoreAdminParams.ULOG_DIR, CoreDescriptor.CORE_ULOGDIR)
.put(CoreAdminParams.LOAD_ON_STARTUP, CoreDescriptor.CORE_LOADONSTARTUP)
.put(CoreAdminParams.TRANSIENT, CoreDescriptor.CORE_TRANSIENT)
.put(CoreAdminParams.SHARD, CoreDescriptor.CORE_SHARD)
.put(CoreAdminParams.COLLECTION, CoreDescriptor.CORE_COLLECTION)
.put(CoreAdminParams.ROLES, CoreDescriptor.CORE_ROLES)
.put(CoreAdminParams.CORE_NODE_NAME, CoreDescriptor.CORE_NODE_NAME)
.put(CoreAdminParams.SHARD_STATE, CloudDescriptor.SHARD_STATE)
.put(CoreAdminParams.SHARD_RANGE, CloudDescriptor.SHARD_RANGE)
.put(ZkStateReader.NUM_SHARDS_PROP, CloudDescriptor.NUM_SHARDS)
.build();
public static ImmutableMap<String, String> cloudParamToProp;
protected static CoreDescriptor buildCoreDescriptor(SolrParams params, CoreContainer container) {
String name = checkNotEmpty(params.get(CoreAdminParams.NAME),
"Missing parameter [" + CoreAdminParams.NAME + "]");
String instancedir = params.get(CoreAdminParams.INSTANCE_DIR);
if (StringUtils.isEmpty(instancedir))
instancedir = container.getSolrHome() + File.separator + name;
Properties coreProps = new Properties();
for (String param : paramToProp.keySet()) {
String value = params.get(param, null);
if (StringUtils.isNotEmpty(value)) {
coreProps.setProperty(paramToProp.get(param), value);
}
}
Iterator<String> paramsIt = params.getParameterNamesIterator();
while (paramsIt.hasNext()) {
String param = paramsIt.next();
if (!param.startsWith(CoreAdminParams.PROPERTY_PREFIX))
continue;
String propName = param.substring(CoreAdminParams.PROPERTY_PREFIX.length());
String propValue = params.get(param);
coreProps.setProperty(propName, propValue);
}
return new CoreDescriptor(container, name, instancedir, coreProps);
}
private static String checkNotEmpty(String value, String message) {
if (StringUtils.isEmpty(value))
throw new SolrException(ErrorCode.BAD_REQUEST, message);
return value;
}
/** /**
* Handle 'CREATE' action. * Handle 'CREATE' action.
* *
* @return true if a modification has resulted that requires persistance
* of the CoreContainer configuration.
*
* @throws SolrException in case of a configuration error. * @throws SolrException in case of a configuration error.
*/ */
protected boolean handleCreateAction(SolrQueryRequest req, SolrQueryResponse rsp) throws SolrException { protected void handleCreateAction(SolrQueryRequest req, SolrQueryResponse rsp) throws SolrException {
SolrParams params = req.getParams(); SolrParams params = req.getParams();
String name = params.get(CoreAdminParams.NAME); CoreDescriptor dcore = buildCoreDescriptor(params, coreContainer);
if (null == name || "".equals(name)) {
throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, if (coreContainer.getAllCoreNames().contains(dcore.getName())) {
"Core name is mandatory to CREATE a SolrCore"); log.warn("Creating a core with existing name is not allowed");
throw new SolrException(ErrorCode.SERVER_ERROR,
"Core with name '" + dcore.getName() + "' already exists.");
} }
CoreDescriptor dcore = null; // TODO this should be moved into CoreContainer, really...
try { try {
if (coreContainer.getAllCoreNames().contains(name)) {
log.warn("Creating a core with existing name is not allowed");
throw new SolrException(ErrorCode.SERVER_ERROR,
"Core with name '" + name + "' already exists.");
}
String instanceDir = params.get(CoreAdminParams.INSTANCE_DIR);
if (instanceDir == null) {
// instanceDir = coreContainer.getSolrHome() + "/" + name;
instanceDir = name; // bare name is already relative to solr home
} else {
instanceDir = PropertiesUtil.substituteProperty(instanceDir, null);
}
dcore = new CoreDescriptor(coreContainer, name, instanceDir);
// fillup optional parameters
String opts = params.get(CoreAdminParams.CONFIG);
if (opts != null) {
opts = PropertiesUtil.substituteProperty(opts, null);
dcore.setConfigName(opts);
}
opts = params.get(CoreAdminParams.SCHEMA);
if (opts != null) {
opts = PropertiesUtil.substituteProperty(opts, null);
dcore.setSchemaName(opts);
}
opts = params.get(CoreAdminParams.DATA_DIR);
if (opts != null) {
opts = PropertiesUtil.substituteProperty(opts, null);
dcore.setDataDir(opts);
}
opts = params.get(CoreAdminParams.ULOG_DIR);
if (opts != null)
dcore.setUlogDir(opts);
opts = params.get(CoreAdminParams.LOAD_ON_STARTUP);
if (opts != null){
Boolean value = Boolean.valueOf(opts);
dcore.setLoadOnStartup(value);
}
opts = params.get(CoreAdminParams.TRANSIENT);
if (opts != null){
Boolean value = Boolean.valueOf(opts);
dcore.setTransient(value);
}
CloudDescriptor cd = dcore.getCloudDescriptor();
if (cd != null) {
cd.setParams(req.getParams());
opts = params.get(CoreAdminParams.COLLECTION);
if (opts != null)
cd.setCollectionName(opts);
opts = params.get(CoreAdminParams.SHARD);
if (opts != null)
cd.setShardId(opts);
opts = params.get(CoreAdminParams.SHARD_RANGE);
if (opts != null)
cd.setShardRange(opts);
opts = params.get(CoreAdminParams.SHARD_STATE);
if (opts != null)
cd.setShardState(opts);
opts = params.get(CoreAdminParams.ROLES);
if (opts != null)
cd.setRoles(opts);
opts = params.get(CoreAdminParams.CORE_NODE_NAME);
if (opts != null)
cd.setCoreNodeName(opts);
Integer numShards = params.getInt(ZkStateReader.NUM_SHARDS_PROP);
if (numShards != null)
cd.setNumShards(numShards);
}
// Process all property.name=value parameters and set them as name=value core properties
Properties coreProperties = new Properties();
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 propertyName = parameterName.substring(CoreAdminParams.PROPERTY_PREFIX.length()); // skip prefix
coreProperties.put(propertyName, parameterValue);
}
}
dcore.setCoreProperties(coreProperties);
if (coreContainer.getZkController() != null) { if (coreContainer.getZkController() != null) {
coreContainer.preRegisterInZk(dcore); coreContainer.preRegisterInZk(dcore);
} }
coreContainer.getCoresLocator().create(coreContainer, dcore);
SolrCore core = coreContainer.create(dcore); SolrCore core = coreContainer.create(dcore);
coreContainer.register(dcore.getName(), core, false);
coreContainer.register(name, core, false);
rsp.add("core", core.getName()); rsp.add("core", core.getName());
return coreContainer.isPersistent(); }
} catch (Exception ex) { catch (Exception ex) {
if (coreContainer.isZooKeeperAware() && dcore != null) { if (coreContainer.isZooKeeperAware() && dcore != null) {
try { try {
coreContainer.getZkController().unregister(name, dcore); coreContainer.getZkController().unregister(dcore.getName(), dcore);
} catch (InterruptedException e) { } catch (InterruptedException e) {
Thread.currentThread().interrupt(); Thread.currentThread().interrupt();
SolrException.log(log, null, e); SolrException.log(log, null, e);
@ -552,46 +496,37 @@ public class CoreAdminHandler extends RequestHandlerBase {
} }
throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, throw new SolrException(SolrException.ErrorCode.BAD_REQUEST,
"Error CREATEing SolrCore '" + name + "': " + "Error CREATEing SolrCore '" + dcore.getName() + "': " +
ex.getMessage() + rootMsg, ex); ex.getMessage(), ex);
} }
} }
/** /**
* Handle "RENAME" Action * Handle "RENAME" Action
*
* @return true if a modification has resulted that requires persistence
* of the CoreContainer configuration.
*/ */
protected boolean handleRenameAction(SolrQueryRequest req, SolrQueryResponse rsp) throws SolrException { protected void handleRenameAction(SolrQueryRequest req, SolrQueryResponse rsp) throws SolrException {
SolrParams params = req.getParams(); SolrParams params = req.getParams();
String name = params.get(CoreAdminParams.OTHER); String name = params.get(CoreAdminParams.OTHER);
String cname = params.get(CoreAdminParams.CORE); String cname = params.get(CoreAdminParams.CORE);
boolean doPersist = false;
if (cname.equals(name)) return doPersist; if (cname.equals(name)) return;
doPersist = coreContainer.isPersistent();
coreContainer.rename(cname, name); coreContainer.rename(cname, name);
return doPersist;
} }
/** /**
* Handle "ALIAS" action * Handle "ALIAS" action
*
* @return true if a modification has resulted that requires persistance
* of the CoreContainer configuration.
*/ */
@Deprecated @Deprecated
protected boolean handleAliasAction(SolrQueryRequest req, SolrQueryResponse rsp) { protected void handleAliasAction(SolrQueryRequest req, SolrQueryResponse rsp) {
SolrParams params = req.getParams(); SolrParams params = req.getParams();
String name = params.get(CoreAdminParams.OTHER); String name = params.get(CoreAdminParams.OTHER);
String cname = params.get(CoreAdminParams.CORE); String cname = params.get(CoreAdminParams.CORE);
boolean doPersist = false; boolean doPersist = false;
if (cname.equals(name)) return doPersist; if (cname.equals(name)) return;
SolrCore core = coreContainer.getCore(cname); SolrCore core = coreContainer.getCore(cname);
if (core != null) { if (core != null) {
@ -599,17 +534,14 @@ public class CoreAdminHandler extends RequestHandlerBase {
coreContainer.register(name, core, false); coreContainer.register(name, core, false);
// no core.close() since each entry in the cores map should increase the ref // no core.close() since each entry in the cores map should increase the ref
} }
return doPersist; return;
} }
/** /**
* Handle "UNLOAD" Action * Handle "UNLOAD" Action
*
* @return true if a modification has resulted that requires persistance
* of the CoreContainer configuration.
*/ */
protected boolean handleUnloadAction(SolrQueryRequest req, protected void handleUnloadAction(SolrQueryRequest req,
SolrQueryResponse rsp) throws SolrException { SolrQueryResponse rsp) throws SolrException {
SolrParams params = req.getParams(); SolrParams params = req.getParams();
String cname = params.get(CoreAdminParams.CORE); String cname = params.get(CoreAdminParams.CORE);
@ -687,17 +619,13 @@ public class CoreAdminHandler extends RequestHandlerBase {
core.close(); core.close();
} }
} }
return coreContainer.isPersistent();
} }
/** /**
* Handle "STATUS" action * Handle "STATUS" action
*
* @return true if a modification has resulted that requires persistance
* of the CoreContainer configuration.
*/ */
protected boolean handleStatusAction(SolrQueryRequest req, SolrQueryResponse rsp) protected void handleStatusAction(SolrQueryRequest req, SolrQueryResponse rsp)
throws SolrException { throws SolrException {
SolrParams params = req.getParams(); SolrParams params = req.getParams();
@ -722,8 +650,6 @@ public class CoreAdminHandler extends RequestHandlerBase {
status.add(cname, getCoreStatus(coreContainer, cname, isIndexInfoNeeded)); status.add(cname, getCoreStatus(coreContainer, cname, isIndexInfoNeeded));
} }
rsp.add("status", status); rsp.add("status", status);
doPersist = false; // no state change
return doPersist;
} catch (Exception ex) { } catch (Exception ex) {
throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, throw new SolrException(SolrException.ErrorCode.SERVER_ERROR,
"Error handling 'status' action ", ex); "Error handling 'status' action ", ex);
@ -732,42 +658,20 @@ public class CoreAdminHandler extends RequestHandlerBase {
/** /**
* Handler "PERSIST" action * Handler "PERSIST" action
*
* @return true if a modification has resulted that requires persistence
* of the CoreContainer configuration.
*/ */
protected boolean handlePersistAction(SolrQueryRequest req, SolrQueryResponse rsp) protected void handlePersistAction(SolrQueryRequest req, SolrQueryResponse rsp)
throws SolrException { throws SolrException {
SolrParams params = req.getParams(); rsp.add("message", "The PERSIST action has been deprecated");
boolean doPersist = false;
String fileName = params.get(CoreAdminParams.FILE);
if (fileName != null) {
File file = new File(fileName);
if (!file.isAbsolute())
file = new File(coreContainer.getConfigFile().getParentFile(), fileName);
coreContainer.persistFile(file);
rsp.add("saved", file.getAbsolutePath());
doPersist = false;
} else if (!coreContainer.isPersistent()) {
throw new SolrException(SolrException.ErrorCode.FORBIDDEN, "Persistence is not enabled");
} else
doPersist = true;
return doPersist;
} }
/** /**
* Handler "RELOAD" action * Handler "RELOAD" action
*
* @return true if a modification has resulted that requires persistence
* of the CoreContainer configuration.
*/ */
protected boolean handleReloadAction(SolrQueryRequest req, SolrQueryResponse rsp) { protected void handleReloadAction(SolrQueryRequest req, SolrQueryResponse rsp) {
SolrParams params = req.getParams(); SolrParams params = req.getParams();
String cname = params.get(CoreAdminParams.CORE); String cname = params.get(CoreAdminParams.CORE);
try { try {
coreContainer.reload(cname); coreContainer.reload(cname);
return false; // no change on reload
} catch (Exception ex) { } catch (Exception ex) {
throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, "Error handling 'reload' action", ex); throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, "Error handling 'reload' action", ex);
} }
@ -775,19 +679,14 @@ public class CoreAdminHandler extends RequestHandlerBase {
/** /**
* Handle "SWAP" action * Handle "SWAP" action
*
* @return true if a modification has resulted that requires persistence
* of the CoreContainer configuration.
*/ */
protected boolean handleSwapAction(SolrQueryRequest req, SolrQueryResponse rsp) { protected void handleSwapAction(SolrQueryRequest req, SolrQueryResponse rsp) {
final SolrParams params = req.getParams(); final SolrParams params = req.getParams();
final SolrParams required = params.required(); final SolrParams required = params.required();
final String cname = params.get(CoreAdminParams.CORE); final String cname = params.get(CoreAdminParams.CORE);
boolean doPersist = params.getBool(CoreAdminParams.PERSISTENT, coreContainer.isPersistent());
String other = required.get(CoreAdminParams.OTHER); String other = required.get(CoreAdminParams.OTHER);
coreContainer.swap(cname, other); coreContainer.swap(cname, other);
return doPersist;
} }

View File

@ -129,4 +129,24 @@ public class PropertiesUtil {
} }
} }
/**
* Parse the given String value as an integer. If the string cannot
* be parsed, returns the default
* @param value the value to parse
* @param defValue the default to return if the value cannot be parsed
* @return an integer version of the passed in value
*/
public static Integer toInteger(String value, Integer defValue) {
try {
return Integer.parseInt(value);
}
catch (NumberFormatException e) {
return defValue;
}
}
public static boolean toBoolean(String value) {
return "true".equalsIgnoreCase(value) || "on".equalsIgnoreCase(value);
}
} }

View File

@ -150,14 +150,8 @@ public class ClusterStateUpdateTest extends SolrTestCaseJ4 {
CreateMode.PERSISTENT, true); CreateMode.PERSISTENT, true);
zkClient.close(); zkClient.close();
CoreDescriptor dcore = new CoreDescriptor(container1, "testcore", CoreDescriptor dcore = buildCoreDescriptor(container1, "testcore", "testcore")
"testcore"); .withDataDir(dataDir4.getAbsolutePath()).build();
dcore.setDataDir(dataDir4.getAbsolutePath());
CloudDescriptor cloudDesc = new CloudDescriptor();
cloudDesc.setCollectionName("testcore");
dcore.setCloudDescriptor(cloudDesc);
if (container1.getZkController() != null) { if (container1.getZkController() != null) {
container1.preRegisterInZk(dcore); container1.preRegisterInZk(dcore);

View File

@ -143,117 +143,6 @@ public class TestCoreContainer extends SolrTestCaseJ4 {
} }
@Test
public void testPersist() throws Exception {
final File workDir = new File(TEMP_DIR, this.getClass().getName()
+ "_persist");
if (workDir.exists()) {
FileUtils.deleteDirectory(workDir);
}
assertTrue("Failed to mkdirs workDir", workDir.mkdirs());
final CoreContainer cores = h.getCoreContainer();
cores.setPersistent(true); // is this needed since we make explicit calls?
String instDir = null;
{
SolrCore template = null;
try {
template = cores.getCore("collection1");
instDir = template.getCoreDescriptor().getRawInstanceDir();
} finally {
if (null != template) template.close();
}
}
final File instDirFile = new File(cores.getSolrHome(), instDir);
assertTrue("instDir doesn't exist: " + instDir, instDirFile.exists());
// sanity check the basic persistence of the default init
final File oneXml = new File(workDir, "1.solr.xml");
cores.persistFile(oneXml);
assertXmlFile(oneXml, "/solr[@persistent='true']",
"/solr/cores[@defaultCoreName='collection1' and not(@transientCacheSize)]",
"/solr/cores/core[@name='collection1' and @instanceDir='" + instDir +
"' and @transient='false' and @loadOnStartup='true' ]", "1=count(/solr/cores/core)");
// create some new cores and sanity check the persistence
final File dataXfile = new File(workDir, "dataX");
final String dataX = dataXfile.getAbsolutePath();
assertTrue("dataXfile mkdirs failed: " + dataX, dataXfile.mkdirs());
final File instYfile = new File(workDir, "instY");
FileUtils.copyDirectory(instDirFile, instYfile);
// :HACK: dataDir leaves off trailing "/", but instanceDir uses it
final String instY = instYfile.getAbsolutePath() + "/";
final CoreDescriptor xd = new CoreDescriptor(cores, "X", instDir);
xd.setDataDir(dataX);
final CoreDescriptor yd = new CoreDescriptor(cores, "Y", instY);
SolrCore x = null;
SolrCore y = null;
try {
x = cores.create(xd);
y = cores.create(yd);
cores.register(x, false);
cores.register(y, false);
assertEquals("cores not added?", 3, cores.getCoreNames().size());
final File twoXml = new File(workDir, "2.solr.xml");
cores.persistFile(twoXml);
assertXmlFile(twoXml, "/solr[@persistent='true']",
"/solr/cores[@defaultCoreName='collection1']",
"/solr/cores/core[@name='collection1' and @instanceDir='" + instDir
+ "']", "/solr/cores/core[@name='X' and @instanceDir='" + instDir
+ "' and @dataDir='" + dataX + "']",
"/solr/cores/core[@name='Y' and @instanceDir='" + instY + "']",
"3=count(/solr/cores/core)");
// Test for saving implicit properties, we should not do this.
assertXmlFile(twoXml, "/solr/cores/core[@name='X' and not(@solr.core.instanceDir) and not (@solr.core.configName)]");
// delete a core, check persistence again
assertNotNull("removing X returned null", cores.remove("X"));
final File threeXml = new File(workDir, "3.solr.xml");
cores.persistFile(threeXml);
assertXmlFile(threeXml, "/solr[@persistent='true']",
"/solr/cores[@defaultCoreName='collection1']",
"/solr/cores/core[@name='collection1' and @instanceDir='" + instDir + "']",
"/solr/cores/core[@name='Y' and @instanceDir='" + instY + "']",
"2=count(/solr/cores/core)");
// sanity check that persisting w/o changes has no changes
final File fourXml = new File(workDir, "4.solr.xml");
cores.persistFile(fourXml);
assertTrue("3 and 4 should be identical files",
FileUtils.contentEquals(threeXml, fourXml));
} finally {
// y is closed by the container, but
// x has been removed from the container
if (x != null) {
try {
x.close();
} catch (Exception e) {
log.error("", e);
}
}
}
}
@Test @Test

View File

@ -91,7 +91,7 @@ public class TestCoreDiscovery extends SolrTestCaseJ4 {
private void addCoreWithProps(String name, Properties stockProps) throws Exception { private void addCoreWithProps(String name, Properties stockProps) throws Exception {
File propFile = new File(new File(solrHomeDirectory, name), SolrCoreDiscoverer.CORE_PROP_FILE); File propFile = new File(new File(solrHomeDirectory, name), CorePropertiesLocator.PROPERTIES_FILENAME);
File parent = propFile.getParentFile(); File parent = propFile.getParentFile();
assertTrue("Failed to mkdirs for " + parent.getAbsolutePath(), parent.mkdirs()); assertTrue("Failed to mkdirs for " + parent.getAbsolutePath(), parent.mkdirs());
addCoreWithProps(stockProps, propFile); addCoreWithProps(stockProps, propFile);
@ -144,17 +144,17 @@ public class TestCoreDiscovery extends SolrTestCaseJ4 {
// Let's assert we did the right thing for implicit properties too. // Let's assert we did the right thing for implicit properties too.
CoreDescriptor desc = core1.getCoreDescriptor(); CoreDescriptor desc = core1.getCoreDescriptor();
assertEquals("core1", desc.getProperty("solr.core.name")); assertEquals("core1", desc.getName());
// Prove we're ignoring this even though it's set in the properties file
assertFalse("InstanceDir should be ignored", desc.getProperty("solr.core.instanceDir").contains("totallybogus"));
// This is too long and ugly to put in. Besides, it varies. // This is too long and ugly to put in. Besides, it varies.
assertNotNull(desc.getProperty("solr.core.instanceDir")); assertNotNull(desc.getInstanceDir());
assertEquals("core1", desc.getProperty("solr.core.dataDir")); // Prove we're ignoring this even though it's set in the properties file
assertEquals("solrconfig-minimal.xml", desc.getProperty("solr.core.configName")); assertFalse("InstanceDir should be ignored", desc.getInstanceDir().contains("totallybogus"));
assertEquals("schema-tiny.xml", desc.getProperty("solr.core.schemaName"));
assertEquals("core1", desc.getDataDir());
assertEquals("solrconfig-minimal.xml", desc.getConfigName());
assertEquals("schema-tiny.xml", desc.getSchemaName());
SolrCore core2 = cc.getCore("core2"); SolrCore core2 = cc.getCore("core2");
SolrCore lazy1 = cc.getCore("lazy1"); SolrCore lazy1 = cc.getCore("lazy1");
@ -180,10 +180,9 @@ public class TestCoreDiscovery extends SolrTestCaseJ4 {
cc = init(); cc = init();
fail("Should have thrown exception in testDuplicateNames"); fail("Should have thrown exception in testDuplicateNames");
} catch (SolrException se) { } catch (SolrException se) {
Throwable cause = se.getCause(); String message = se.getMessage();
String message = cause.getMessage(); assertTrue("Wrong exception thrown on duplicate core names",
assertTrue("Should have seen an exception because two cores had the same name", message.indexOf("Found multiple cores with the name [core1]") != -1);
message.indexOf("Core core1 defined more than once") != -1);
assertTrue(File.separator + "core1 should have been mentioned in the message: " + message, assertTrue(File.separator + "core1 should have been mentioned in the message: " + message,
message.indexOf(File.separator + "core1") != -1); message.indexOf(File.separator + "core1") != -1);
assertTrue(File.separator + "core2 should have been mentioned in the message:" + message, assertTrue(File.separator + "core2 should have been mentioned in the message:" + message,
@ -203,9 +202,9 @@ public class TestCoreDiscovery extends SolrTestCaseJ4 {
alt.mkdirs(); alt.mkdirs();
setMeUp(alt.getAbsolutePath()); setMeUp(alt.getAbsolutePath());
addCoreWithProps(makeCorePropFile("core1", false, true, "dataDir=core1"), addCoreWithProps(makeCorePropFile("core1", false, true, "dataDir=core1"),
new File(alt, "core1" + File.separator + SolrCoreDiscoverer.CORE_PROP_FILE)); new File(alt, "core1" + File.separator + CorePropertiesLocator.PROPERTIES_FILENAME));
addCoreWithProps(makeCorePropFile("core2", false, false, "dataDir=core2"), addCoreWithProps(makeCorePropFile("core2", false, false, "dataDir=core2"),
new File(alt, "core2" + File.separator + SolrCoreDiscoverer.CORE_PROP_FILE)); new File(alt, "core2" + File.separator + CorePropertiesLocator.PROPERTIES_FILENAME));
CoreContainer cc = init(); CoreContainer cc = init();
try { try {
SolrCore core1 = cc.getCore("core1"); SolrCore core1 = cc.getCore("core1");
@ -226,9 +225,9 @@ public class TestCoreDiscovery extends SolrTestCaseJ4 {
noCoreDir.mkdirs(); noCoreDir.mkdirs();
setMeUp(noCoreDir.getAbsolutePath()); setMeUp(noCoreDir.getAbsolutePath());
addCoreWithProps(makeCorePropFile("core1", false, true), addCoreWithProps(makeCorePropFile("core1", false, true),
new File(noCoreDir, "core1" + File.separator + SolrCoreDiscoverer.CORE_PROP_FILE)); new File(noCoreDir, "core1" + File.separator + CorePropertiesLocator.PROPERTIES_FILENAME));
addCoreWithProps(makeCorePropFile("core2", false, false), addCoreWithProps(makeCorePropFile("core2", false, false),
new File(noCoreDir, "core2" + File.separator + SolrCoreDiscoverer.CORE_PROP_FILE)); new File(noCoreDir, "core2" + File.separator + CorePropertiesLocator.PROPERTIES_FILENAME));
CoreContainer cc = init(); CoreContainer cc = init();
try { try {
SolrCore core1 = cc.getCore("core1"); SolrCore core1 = cc.getCore("core1");

View File

@ -32,6 +32,7 @@ import org.apache.solr.update.AddUpdateCommand;
import org.apache.solr.update.CommitUpdateCommand; import org.apache.solr.update.CommitUpdateCommand;
import org.apache.solr.update.UpdateHandler; import org.apache.solr.update.UpdateHandler;
import org.apache.solr.util.RefCounted; import org.apache.solr.util.RefCounted;
import org.apache.solr.util.TestHarness;
import org.junit.After; import org.junit.After;
import org.junit.BeforeClass; import org.junit.BeforeClass;
import org.junit.Test; import org.junit.Test;
@ -52,7 +53,6 @@ public class TestLazyCores extends SolrTestCaseJ4 {
private final File solrHomeDirectory = new File(TEMP_DIR, "org.apache.solr.core.TestLazyCores_testlazy"); private final File solrHomeDirectory = new File(TEMP_DIR, "org.apache.solr.core.TestLazyCores_testlazy");
private CoreContainer init() throws Exception { private CoreContainer init() throws Exception {
if (solrHomeDirectory.exists()) { if (solrHomeDirectory.exists()) {
@ -63,13 +63,17 @@ public class TestLazyCores extends SolrTestCaseJ4 {
copyMinConf(new File(solrHomeDirectory, "collection" + idx)); copyMinConf(new File(solrHomeDirectory, "collection" + idx));
} }
SolrResourceLoader loader = new SolrResourceLoader(solrHomeDirectory.getAbsolutePath());
File solrXml = new File(solrHomeDirectory, "solr.xml"); File solrXml = new File(solrHomeDirectory, "solr.xml");
FileUtils.write(solrXml, LOTS_SOLR_XML, IOUtils.CHARSET_UTF_8.toString()); FileUtils.write(solrXml, LOTS_SOLR_XML, IOUtils.CHARSET_UTF_8.toString());
final CoreContainer cores = new CoreContainer(solrHomeDirectory.getAbsolutePath()); ConfigSolrXmlOld config = (ConfigSolrXmlOld) ConfigSolr.fromFile(loader, solrXml);
cores.load();
// h.getCoreContainer().load(solrHomeDirectory.getAbsolutePath(), new File(solrHomeDirectory, "solr.xml"));
cores.setPersistent(false); CoresLocator locator = new SolrXMLCoresLocator.NonPersistingLocator(solrXml, LOTS_SOLR_XML, config);
final CoreContainer cores = new CoreContainer(loader, config, locator);
cores.load();
return cores; return cores;
} }
@ -91,15 +95,15 @@ public class TestLazyCores extends SolrTestCaseJ4 {
SolrCore core1 = cc.getCore("collection1"); SolrCore core1 = cc.getCore("collection1");
assertFalse("core1 should not be transient", core1.getCoreDescriptor().isTransient()); assertFalse("core1 should not be transient", core1.getCoreDescriptor().isTransient());
assertTrue("core1 should be loadable", core1.getCoreDescriptor().isLoadOnStartup()); assertTrue("core1 should be loadable", core1.getCoreDescriptor().isLoadOnStartup());
assertNotNull(core1.getSolrConfig()); assertNotNull(core1.getSolrConfig());
SolrCore core2 = cc.getCore("collectionLazy2"); SolrCore core2 = cc.getCore("collectionLazy2");
assertTrue("core2 should not be transient", core2.getCoreDescriptor().isTransient()); assertTrue("core2 should be transient", core2.getCoreDescriptor().isTransient());
assertTrue("core2 should be loadable", core2.getCoreDescriptor().isLoadOnStartup()); assertTrue("core2 should be loadable", core2.getCoreDescriptor().isLoadOnStartup());
SolrCore core3 = cc.getCore("collectionLazy3"); SolrCore core3 = cc.getCore("collectionLazy3");
assertTrue("core3 should not be transient", core3.getCoreDescriptor().isTransient()); assertTrue("core3 should be transient", core3.getCoreDescriptor().isTransient());
assertFalse("core3 should not be loadable", core3.getCoreDescriptor().isLoadOnStartup()); assertFalse("core3 should not be loadable", core3.getCoreDescriptor().isLoadOnStartup());
SolrCore core4 = cc.getCore("collectionLazy4"); SolrCore core4 = cc.getCore("collectionLazy4");
@ -108,7 +112,7 @@ public class TestLazyCores extends SolrTestCaseJ4 {
SolrCore core5 = cc.getCore("collectionLazy5"); SolrCore core5 = cc.getCore("collectionLazy5");
assertFalse("core5 should not be transient", core5.getCoreDescriptor().isTransient()); assertFalse("core5 should not be transient", core5.getCoreDescriptor().isTransient());
assertTrue("core5 should be loadable", core5.getCoreDescriptor().isLoadOnStartup()); assertTrue("core5 should be loadable", core5.getCoreDescriptor().isLoadOnStartup());
core1.close(); core1.close();
core2.close(); core2.close();
@ -291,11 +295,11 @@ public class TestLazyCores extends SolrTestCaseJ4 {
admin.handleRequestBody(request, resp); admin.handleRequestBody(request, resp);
fail("Should have thrown an error"); fail("Should have thrown an error");
} catch (SolrException se) { } catch (SolrException se) {
SolrException cause = (SolrException)se.getCause(); //SolrException cause = (SolrException)se.getCause();
assertEquals("Exception code should be 500", 500, cause.code()); assertEquals("Exception code should be 500", 500, se.code());
for (String err : errs) { for (String err : errs) {
assertTrue("Should have seen an exception containing the an error", assertTrue("Should have seen an exception containing the an error",
cause.getMessage().contains(err)); se.getMessage().contains(err));
} }
} }
} }
@ -343,39 +347,25 @@ public class TestLazyCores extends SolrTestCaseJ4 {
copyMinConf(new File(solrHomeDirectory, "core3")); copyMinConf(new File(solrHomeDirectory, "core3"));
copyMinConf(new File(solrHomeDirectory, "core4")); copyMinConf(new File(solrHomeDirectory, "core4"));
cc.setPersistent(true); final CoreDescriptor cd1 = buildCoreDescriptor(cc, "core1", "./core1")
CoreDescriptor d1 = new CoreDescriptor(cc, "core1", "./core1"); .isTransient(true).loadOnStartup(true).build();
d1.setTransient(true); final CoreDescriptor cd2 = buildCoreDescriptor(cc, "core2", "./core2")
d1.setLoadOnStartup(true); .isTransient(true).loadOnStartup(false).build();
d1.setSchemaName("schema.xml"); final CoreDescriptor cd3 = buildCoreDescriptor(cc, "core3", "./core3")
d1.setConfigName("solrconfig.xml"); .isTransient(false).loadOnStartup(true).build();
SolrCore core1 = cc.create(d1); final CoreDescriptor cd4 = buildCoreDescriptor(cc, "core4", "./core4")
.isTransient(false).loadOnStartup(false).build();
CoreDescriptor d2 = new CoreDescriptor(cc, "core2", "./core2");
d2.setTransient(true);
d2.setLoadOnStartup(false);
d2.setSchemaName("schema.xml");
d2.setConfigName("solrconfig.xml");
SolrCore core2 = cc.create(d2);
CoreDescriptor d3 = new CoreDescriptor(cc, "core3", "./core3"); SolrCore core1 = cc.create(cd1);
d3.setTransient(false); SolrCore core2 = cc.create(cd2);
d3.setLoadOnStartup(true); SolrCore core3 = cc.create(cd3);
d3.setSchemaName("schema.xml"); SolrCore core4 = cc.create(cd4);
d3.setConfigName("solrconfig.xml");
SolrCore core3 = cc.create(d3);
CoreDescriptor d4 = new CoreDescriptor(cc, "core4", "./core4"); SolrXMLCoresLocator.NonPersistingLocator locator =
d4.setTransient(false); (SolrXMLCoresLocator.NonPersistingLocator) cc.getCoresLocator();
d4.setLoadOnStartup(false);
d4.setSchemaName("schema.xml");
d4.setConfigName("solrconfig.xml");
SolrCore core4 = cc.create(d4);
final File oneXml = new File(solrHomeDirectory, "lazy1.solr.xml"); TestHarness.validateXPath(locator.xml,
cc.persistFile(oneXml);
assertXmlFile(oneXml,
"/solr/cores/core[@name='collection1']", "/solr/cores/core[@name='collection1']",
"/solr/cores/core[@name='collectionLazy2']", "/solr/cores/core[@name='collectionLazy2']",
"/solr/cores/core[@name='collectionLazy3']", "/solr/cores/core[@name='collectionLazy3']",
@ -388,8 +378,8 @@ public class TestLazyCores extends SolrTestCaseJ4 {
"/solr/cores/core[@name='core1']", "/solr/cores/core[@name='core1']",
"/solr/cores/core[@name='core2']", "/solr/cores/core[@name='core2']",
"/solr/cores/core[@name='core3']", "/solr/cores/core[@name='core3']",
"/solr/cores/core[@name='core4']"); "/solr/cores/core[@name='core4']",
assertXmlFile(oneXml, "13=count(/solr/cores/core)"); "13=count(/solr/cores/core)");
removeOne(cc, "collectionLazy2"); removeOne(cc, "collectionLazy2");
removeOne(cc, "collectionLazy3"); removeOne(cc, "collectionLazy3");
@ -403,11 +393,8 @@ public class TestLazyCores extends SolrTestCaseJ4 {
removeOne(cc, "core4"); removeOne(cc, "core4");
// now test that unloading a core means the core is not persisted // now test that unloading a core means the core is not persisted
TestHarness.validateXPath(locator.xml, "3=count(/solr/cores/core)");
final File twoXml = new File(solrHomeDirectory, "lazy2.solr.xml");
cc.persistFile(twoXml);
assertXmlFile(twoXml, "3=count(/solr/cores/core)");
} finally { } finally {
cc.shutdown(); cc.shutdown();
} }

View File

@ -17,37 +17,34 @@ package org.apache.solr.core;
* limitations under the License. * limitations under the License.
*/ */
import com.carrotsearch.randomizedtesting.rules.SystemPropertiesRestoreRule;
import org.apache.commons.io.FileUtils; import org.apache.commons.io.FileUtils;
import org.apache.solr.SolrTestCaseJ4; import org.apache.solr.SolrTestCaseJ4;
import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
import org.xml.sax.InputSource; import org.junit.rules.RuleChain;
import org.xml.sax.SAXException; import org.junit.rules.TestRule;
import javax.xml.parsers.ParserConfigurationException;
import java.io.File; import java.io.File;
import java.io.FileInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream;
public class TestSolrXml extends SolrTestCaseJ4 { public class TestSolrXml extends SolrTestCaseJ4 {
@Rule
public TestRule solrTestRules = RuleChain.outerRule(new SystemPropertiesRestoreRule());
private final File solrHome = new File(TEMP_DIR, TestSolrXml.getClassName() + File.separator + "solrHome"); private final File solrHome = new File(TEMP_DIR, TestSolrXml.getClassName() + File.separator + "solrHome");
@Test @Test
public void testAllInfoPresent() throws IOException, ParserConfigurationException, SAXException { public void testAllInfoPresent() throws IOException {
CoreContainer cc = null;
File testSrcRoot = new File(SolrTestCaseJ4.TEST_HOME()); File testSrcRoot = new File(SolrTestCaseJ4.TEST_HOME());
FileUtils.copyFile(new File(testSrcRoot, "solr-50-all.xml"), new File(solrHome, "solr.xml")); FileUtils.copyFile(new File(testSrcRoot, "solr-50-all.xml"), new File(solrHome, "solr.xml"));
SolrResourceLoader loader = null;
try { try {
InputStream is = new FileInputStream(new File(solrHome, "solr.xml")); loader = new SolrResourceLoader(solrHome.getAbsolutePath());
Config config = new Config(new SolrResourceLoader("solr/collection1"), null, new InputSource(is), null, false); ConfigSolr cfg = ConfigSolr.fromSolrHome(loader, solrHome.getAbsolutePath());
boolean oldStyle = (config.getNode("solr/cores", false) != null);
ConfigSolr cfg;
if (oldStyle) {
cfg = new ConfigSolrXmlOld(config);
} else {
cfg = new ConfigSolrXml(config, cc);
}
assertEquals("Did not find expected value", cfg.get(ConfigSolr.CfgProp.SOLR_ADMINHANDLER, null), "testAdminHandler"); assertEquals("Did not find expected value", cfg.get(ConfigSolr.CfgProp.SOLR_ADMINHANDLER, null), "testAdminHandler");
assertEquals("Did not find expected value", cfg.getInt(ConfigSolr.CfgProp.SOLR_CORELOADTHREADS, 0), 11); assertEquals("Did not find expected value", cfg.getInt(ConfigSolr.CfgProp.SOLR_CORELOADTHREADS, 0), 11);
@ -71,59 +68,35 @@ public class TestSolrXml extends SolrTestCaseJ4 {
assertNull("Did not find expected value", cfg.get(ConfigSolr.CfgProp.SOLR_PERSISTENT, null)); assertNull("Did not find expected value", cfg.get(ConfigSolr.CfgProp.SOLR_PERSISTENT, null));
assertNull("Did not find expected value", cfg.get(ConfigSolr.CfgProp.SOLR_CORES_DEFAULT_CORE_NAME, null)); assertNull("Did not find expected value", cfg.get(ConfigSolr.CfgProp.SOLR_CORES_DEFAULT_CORE_NAME, null));
assertNull("Did not find expected value", cfg.get(ConfigSolr.CfgProp.SOLR_ADMINPATH, null)); assertNull("Did not find expected value", cfg.get(ConfigSolr.CfgProp.SOLR_ADMINPATH, null));
} finally {
if (cc != null) cc.shutdown();
} }
finally {
loader.close();
}
} }
// Test a few property substitutions that happen to be in solr-50-all.xml. // Test a few property substitutions that happen to be in solr-50-all.xml.
public void testPropretySub() throws IOException, ParserConfigurationException, SAXException { public void testPropertySub() throws IOException {
String coreRoot = System.getProperty("coreRootDirectory");
String hostPort = System.getProperty("hostPort");
String shareSchema = System.getProperty("shareSchema");
String socketTimeout = System.getProperty("socketTimeout");
String connTimeout = System.getProperty("connTimeout");
System.setProperty("coreRootDirectory", "myCoreRoot"); System.setProperty("coreRootDirectory", "myCoreRoot");
System.setProperty("hostPort", "8888"); System.setProperty("hostPort", "8888");
System.setProperty("shareSchema", "newShareSchema"); System.setProperty("shareSchema", "newShareSchema");
System.setProperty("socketTimeout", "220"); System.setProperty("socketTimeout", "220");
System.setProperty("connTimeout", "200"); System.setProperty("connTimeout", "200");
CoreContainer cc = null;
File testSrcRoot = new File(SolrTestCaseJ4.TEST_HOME()); File testSrcRoot = new File(SolrTestCaseJ4.TEST_HOME());
FileUtils.copyFile(new File(testSrcRoot, "solr-50-all.xml"), new File(solrHome, "solr.xml")); FileUtils.copyFile(new File(testSrcRoot, "solr-50-all.xml"), new File(solrHome, "solr.xml"));
SolrResourceLoader loader = null;
try { try {
InputStream is = new FileInputStream(new File(solrHome, "solr.xml")); loader = new SolrResourceLoader(solrHome.getAbsolutePath());
Config config = new Config(new SolrResourceLoader("solr/collection1"), null, new InputSource(is), null, false); ConfigSolr cfg = ConfigSolr.fromSolrHome(loader, solrHome.getAbsolutePath());
boolean oldStyle = (config.getNode("solr/cores", false) != null);
ConfigSolr cfg;
if (oldStyle) {
cfg = new ConfigSolrXmlOld(config);
} else {
cfg = new ConfigSolrXml(config, cc);
}
assertEquals("Did not find expected value", cfg.get(ConfigSolr.CfgProp.SOLR_COREROOTDIRECTORY, null), "myCoreRoot"); assertEquals("Did not find expected value", cfg.get(ConfigSolr.CfgProp.SOLR_COREROOTDIRECTORY, null), "myCoreRoot");
assertEquals("Did not find expected value", cfg.getInt(ConfigSolr.CfgProp.SOLR_HOSTPORT, 0), 8888); assertEquals("Did not find expected value", cfg.getInt(ConfigSolr.CfgProp.SOLR_HOSTPORT, 0), 8888);
assertEquals("Did not find expected value", cfg.get(ConfigSolr.CfgProp.SOLR_SHARESCHEMA, null), "newShareSchema"); assertEquals("Did not find expected value", cfg.get(ConfigSolr.CfgProp.SOLR_SHARESCHEMA, null), "newShareSchema");
}
} finally { finally {
if (cc != null) cc.shutdown(); loader.close();
if (coreRoot != null) System.setProperty("coreRootDirectory", coreRoot);
else System.clearProperty("coreRootDirectory");
if (hostPort != null) System.setProperty("hostPort", hostPort);
else System.clearProperty("hostPort");
if (shareSchema != null) System.setProperty("shareSchema", shareSchema);
else System.clearProperty("shareSchema");
if (socketTimeout != null) System.setProperty("socketTimeout", socketTimeout);
else System.clearProperty("socketTimeout");
if (connTimeout != null) System.setProperty("connTimeout", connTimeout);
else System.clearProperty("connTimeout");
} }
} }
} }

View File

@ -18,6 +18,7 @@
package org.apache.solr.core; package org.apache.solr.core;
import com.carrotsearch.randomizedtesting.rules.SystemPropertiesRestoreRule; import com.carrotsearch.randomizedtesting.rules.SystemPropertiesRestoreRule;
import com.google.common.base.Charsets;
import org.apache.commons.io.FileUtils; import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.apache.lucene.util.IOUtils; import org.apache.lucene.util.IOUtils;
@ -25,6 +26,7 @@ import org.apache.solr.SolrTestCaseJ4;
import org.apache.solr.common.params.CoreAdminParams; import org.apache.solr.common.params.CoreAdminParams;
import org.apache.solr.handler.admin.CoreAdminHandler; import org.apache.solr.handler.admin.CoreAdminHandler;
import org.apache.solr.response.SolrQueryResponse; import org.apache.solr.response.SolrQueryResponse;
import org.apache.solr.util.TestHarness;
import org.junit.Rule; import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
import org.junit.rules.RuleChain; import org.junit.rules.RuleChain;
@ -38,8 +40,11 @@ import org.xml.sax.SAXException;
import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.ParserConfigurationException;
import java.io.ByteArrayInputStream;
import java.io.File; import java.io.File;
import java.io.FileInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -47,13 +52,6 @@ public class TestSolrXmlPersistence extends SolrTestCaseJ4 {
private File solrHomeDirectory = new File(TEMP_DIR, this.getClass().getName()); private File solrHomeDirectory = new File(TEMP_DIR, this.getClass().getName());
/*
@BeforeClass
public static void beforeClass() throws Exception {
initCore("solrconfig-minimal.xml", "schema-tiny.xml");
}
*/
@Rule @Rule
public TestRule solrTestRules = public TestRule solrTestRules =
RuleChain.outerRule(new SystemPropertiesRestoreRule()); RuleChain.outerRule(new SystemPropertiesRestoreRule());
@ -89,18 +87,7 @@ public class TestSolrXmlPersistence extends SolrTestCaseJ4 {
CoreContainer cc = init(SOLR_XML_LOTS_SYSVARS, "SystemVars1", "SystemVars2"); CoreContainer cc = init(SOLR_XML_LOTS_SYSVARS, "SystemVars1", "SystemVars2");
try { try {
origMatchesPersist(cc, SOLR_XML_LOTS_SYSVARS);
// This seems odd, but it's just a little self check to see if the comparison strings are being created correctly
persistContainedInOrig(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.
persistContainedInOrig(cc, persistXml);
// Is everything in the original contained in the persisted one?
assertXmlFile(persistXml, getAllNodes(new File(solrHomeDirectory, "solr.xml")));
} finally { } finally {
cc.shutdown(); cc.shutdown();
if (solrHomeDirectory.exists()) { if (solrHomeDirectory.exists()) {
@ -130,8 +117,7 @@ public class TestSolrXmlPersistence extends SolrTestCaseJ4 {
resp); resp);
assertNull("Exception on reload", resp.getException()); assertNull("Exception on reload", resp.getException());
persistContainedInOrig(cc, new File(solrHomeDirectory, "reload1.solr.xml")); origMatchesPersist(cc, SOLR_XML_LOTS_SYSVARS);
} finally { } finally {
cc.shutdown(); cc.shutdown();
if (solrHomeDirectory.exists()) { if (solrHomeDirectory.exists()) {
@ -149,6 +135,9 @@ public class TestSolrXmlPersistence extends SolrTestCaseJ4 {
private void doTestRename(String which) throws Exception { private void doTestRename(String which) throws Exception {
CoreContainer cc = init(SOLR_XML_LOTS_SYSVARS, "SystemVars1", "SystemVars2"); CoreContainer cc = init(SOLR_XML_LOTS_SYSVARS, "SystemVars1", "SystemVars2");
SolrXMLCoresLocator.NonPersistingLocator locator
= (SolrXMLCoresLocator.NonPersistingLocator) cc.getCoresLocator();
try { try {
final CoreAdminHandler admin = new CoreAdminHandler(cc); final CoreAdminHandler admin = new CoreAdminHandler(cc);
SolrQueryResponse resp = new SolrQueryResponse(); SolrQueryResponse resp = new SolrQueryResponse();
@ -160,31 +149,29 @@ public class TestSolrXmlPersistence extends SolrTestCaseJ4 {
resp); resp);
assertNull("Exception on rename", resp.getException()); 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 // OK, Assure that if I change everything that has been renamed with the original value for the core, it matches
// the old list // the old list
cc.persistFile(persistXml); String[] persistList = getAllNodes();
String[] persistList = getAllNodes(persistXml);
String[] expressions = new String[persistList.length]; String[] expressions = new String[persistList.length];
for (int idx = 0; idx < persistList.length; ++idx) { for (int idx = 0; idx < persistList.length; ++idx) {
expressions[idx] = persistList[idx].replaceAll("RenamedCore", which); expressions[idx] = persistList[idx].replaceAll("RenamedCore", which);
} }
assertXmlFile(origXml, expressions); //assertXmlFile(origXml, expressions);
TestHarness.validateXPath(SOLR_XML_LOTS_SYSVARS, expressions);
// Now the other way, If I replace the original name in the original XML file with "RenamedCore", does it match // Now the other way, If I replace the original name in the original XML file with "RenamedCore", does it match
// what was persisted? // what was persisted?
persistList = getAllNodes(origXml); persistList = getAllNodes(SOLR_XML_LOTS_SYSVARS);
expressions = new String[persistList.length]; expressions = new String[persistList.length];
for (int idx = 0; idx < persistList.length; ++idx) { for (int idx = 0; idx < persistList.length; ++idx) {
// /solr/cores/core[@name='SystemVars1' and @collection='${collection:collection1}'] // /solr/cores/core[@name='SystemVars1' and @collection='${collection:collection1}']
expressions[idx] = persistList[idx].replace("@name='" + which + "'", "@name='RenamedCore'"); expressions[idx] = persistList[idx].replace("@name='" + which + "'", "@name='RenamedCore'");
} }
assertXmlFile(persistXml, expressions); TestHarness.validateXPath(locator.xml, expressions);
} finally { } finally {
cc.shutdown(); cc.shutdown();
if (solrHomeDirectory.exists()) { if (solrHomeDirectory.exists()) {
@ -212,11 +199,7 @@ public class TestSolrXmlPersistence extends SolrTestCaseJ4 {
resp); resp);
assertNull("Exception on swap", resp.getException()); assertNull("Exception on swap", resp.getException());
File persistXml = new File(solrHomeDirectory, "rename.solr.xml"); String[] persistList = getAllNodes();
File origXml = new File(solrHomeDirectory, "solr.xml");
cc.persistFile(persistXml);
String[] persistList = getAllNodes(persistXml);
String[] expressions = new String[persistList.length]; String[] expressions = new String[persistList.length];
// Now manually change the names back and it should match exactly to the original XML. // Now manually change the names back and it should match exactly to the original XML.
@ -230,7 +213,8 @@ public class TestSolrXmlPersistence extends SolrTestCaseJ4 {
} }
} }
assertXmlFile(origXml, expressions); //assertXmlFile(origXml, expressions);
TestHarness.validateXPath(SOLR_XML_LOTS_SYSVARS, expressions);
} finally { } finally {
cc.shutdown(); cc.shutdown();
@ -244,8 +228,8 @@ public class TestSolrXmlPersistence extends SolrTestCaseJ4 {
public void testMinimalXml() throws Exception { public void testMinimalXml() throws Exception {
CoreContainer cc = init(SOLR_XML_MINIMAL, "SystemVars1"); CoreContainer cc = init(SOLR_XML_MINIMAL, "SystemVars1");
try { try {
persistContainedInOrig(cc, new File(solrHomeDirectory, "minimal.solr.xml")); cc.shutdown();
origContainedInPersist(cc, new File(solrHomeDirectory, "minimal.solr.xml")); origMatchesPersist(cc, SOLR_XML_MINIMAL);
} finally { } finally {
cc.shutdown(); cc.shutdown();
if (solrHomeDirectory.exists()) { if (solrHomeDirectory.exists()) {
@ -254,7 +238,13 @@ public class TestSolrXmlPersistence extends SolrTestCaseJ4 {
} }
} }
private void origMatchesPersist(CoreContainer cc, String originalSolrXML) throws Exception {
String[] expressions = getAllNodes(originalSolrXML);
SolrXMLCoresLocator.NonPersistingLocator locator
= (SolrXMLCoresLocator.NonPersistingLocator) cc.getCoresLocator();
TestHarness.validateXPath(locator.xml, expressions);
}
@Test @Test
public void testUnloadCreate() throws Exception { public void testUnloadCreate() throws Exception {
@ -275,7 +265,7 @@ public class TestSolrXmlPersistence extends SolrTestCaseJ4 {
resp); resp);
assertNull("Exception on unload", resp.getException()); assertNull("Exception on unload", resp.getException());
persistContainedInOrig(cc, new File(solrHomeDirectory, "unloadcreate1.solr.xml")); //origMatchesPersist(cc, new File(solrHomeDirectory, "unloadcreate1.solr.xml"));
String instPath = new File(solrHomeDirectory, which).getAbsolutePath(); String instPath = new File(solrHomeDirectory, which).getAbsolutePath();
admin.handleRequestBody admin.handleRequestBody
@ -286,11 +276,7 @@ public class TestSolrXmlPersistence extends SolrTestCaseJ4 {
resp); resp);
assertNull("Exception on create", resp.getException()); assertNull("Exception on create", resp.getException());
File persistXml = new File(solrHomeDirectory, "rename.solr.xml"); String[] persistList = getAllNodes();
File origXml = new File(solrHomeDirectory, "solr.xml");
cc.persistFile(persistXml);
String[] persistList = getAllNodes(persistXml);
String[] expressions = new String[persistList.length]; String[] expressions = new String[persistList.length];
// Now manually change the names back and it should match exactly to the original XML. // Now manually change the names back and it should match exactly to the original XML.
@ -312,8 +298,8 @@ public class TestSolrXmlPersistence extends SolrTestCaseJ4 {
} }
} }
assertXmlFile(origXml, expressions); //assertXmlFile(origXml, expressions);
TestHarness.validateXPath(SOLR_XML_LOTS_SYSVARS, expressions);
} finally { } finally {
cc.shutdown(); cc.shutdown();
@ -323,134 +309,17 @@ public class TestSolrXmlPersistence extends SolrTestCaseJ4 {
} }
} }
private void persistContainedInOrig(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);
}
private void origContainedInPersist(CoreContainer cc, File persistXml) throws IOException,
SAXException, ParserConfigurationException {
cc.persistFile(persistXml);
// Is everything that's in the original file persisted?
String[] expressions = getAllNodes(new File(solrHomeDirectory, "solr.xml"));
assertXmlFile(persistXml, expressions);
}
@Test
public void testCreateAndManipulateCores() throws Exception {
CoreContainer cc = init(SOLR_XML_LOTS_SYSVARS, "SystemVars1", "SystemVars2", "new_one", "new_two");
try {
final CoreAdminHandler admin = new CoreAdminHandler(cc);
String instPathOne = new File(solrHomeDirectory, "new_one").getAbsolutePath();
SolrQueryResponse resp = new SolrQueryResponse();
admin.handleRequestBody
(req(CoreAdminParams.ACTION,
CoreAdminParams.CoreAdminAction.CREATE.toString(),
CoreAdminParams.INSTANCE_DIR, instPathOne,
CoreAdminParams.NAME, "new_one"),
resp);
assertNull("Exception on create", resp.getException());
admin.handleRequestBody
(req(CoreAdminParams.ACTION,
CoreAdminParams.CoreAdminAction.CREATE.toString(),
CoreAdminParams.NAME, "new_two"),
resp);
assertNull("Exception on create", resp.getException());
File persistXml1 = new File(solrHomeDirectory, "create_man_1.xml");
origContainedInPersist(cc, persistXml1);
// We know all the original data is in persist, now check for newly-created files.
String[] expressions = new String[2];
String instHome = new File(solrHomeDirectory, "new_one").getAbsolutePath();
expressions[0] = "/solr/cores/core[@name='new_one' and @instanceDir='" + instHome + "']";
expressions[1] = "/solr/cores/core[@name='new_two' and @instanceDir='new_two" + File.separator + "']";
assertXmlFile(persistXml1, expressions);
// Next, swap a created core and check
resp = new SolrQueryResponse();
admin.handleRequestBody
(req(CoreAdminParams.ACTION,
CoreAdminParams.CoreAdminAction.SWAP.toString(),
CoreAdminParams.CORE, "new_one",
CoreAdminParams.OTHER, "SystemVars2"),
resp);
assertNull("Exception on swap", resp.getException());
File persistXml2 = new File(solrHomeDirectory, "create_man_2.xml");
cc.persistFile(persistXml2);
String[] persistList = getAllNodes(persistXml2);
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='new_one'";
String toName = "@name='SystemVars2'";
if (persistList[idx].contains(fromName)) {
expressions[idx] = persistList[idx].replace(fromName, toName);
} else {
expressions[idx] = persistList[idx].replace(toName, fromName);
}
}
assertXmlFile(persistXml1, expressions);
// Then rename the other created core and check
admin.handleRequestBody
(req(CoreAdminParams.ACTION,
CoreAdminParams.CoreAdminAction.RENAME.toString(),
CoreAdminParams.CORE, "new_two",
CoreAdminParams.OTHER, "RenamedCore"),
resp);
assertNull("Exception on rename", resp.getException());
File persistXml3 = new File(solrHomeDirectory, "create_man_3.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(persistXml3);
persistList = getAllNodes(persistXml3);
expressions = new String[persistList.length];
for (int idx = 0; idx < persistList.length; ++idx) {
expressions[idx] = persistList[idx].replaceAll("RenamedCore", "new_two");
}
assertXmlFile(persistXml2, 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(persistXml2);
expressions = new String[persistList.length];
for (int idx = 0; idx < persistList.length; ++idx) {
// /solr/cores/core[@name='SystemVars1' and @collection='${collection:collection1}']
expressions[idx] = persistList[idx].replace("@name='new_two'", "@name='RenamedCore'");
}
assertXmlFile(persistXml3, expressions);
} finally {
cc.shutdown();
if (solrHomeDirectory.exists()) {
FileUtils.deleteDirectory(solrHomeDirectory);
}
}
}
@Test @Test
public void testCreatePersistCore() throws Exception { public void testCreatePersistCore() throws Exception {
// Template for creating a core. // Template for creating a core.
CoreContainer cc = init(SOLR_XML_LOTS_SYSVARS, "SystemVars1", "SystemVars2", "props1", "props2"); CoreContainer cc = init(SOLR_XML_LOTS_SYSVARS, "SystemVars1", "SystemVars2", "props1", "props2");
SolrXMLCoresLocator.NonPersistingLocator locator
= (SolrXMLCoresLocator.NonPersistingLocator) cc.getCoresLocator();
try { try {
final CoreAdminHandler admin = new CoreAdminHandler(cc); final CoreAdminHandler admin = new CoreAdminHandler(cc);
// create a new core (using CoreAdminHandler) w/ properties // create a new core (using CoreAdminHandler) w/ properties
String instPath1 = new File(solrHomeDirectory, "props1").getAbsolutePath();
SolrQueryResponse resp = new SolrQueryResponse(); SolrQueryResponse resp = new SolrQueryResponse();
admin.handleRequestBody admin.handleRequestBody
(req(CoreAdminParams.ACTION, (req(CoreAdminParams.ACTION,
@ -480,14 +349,13 @@ public class TestSolrXmlPersistence extends SolrTestCaseJ4 {
assertNull("Exception on create", resp.getException()); assertNull("Exception on create", resp.getException());
// Everything that was in the original XML file should be in the persisted one. // 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"); TestHarness.validateXPath(locator.xml, getAllNodes(SOLR_XML_LOTS_SYSVARS));
cc.persistFile(persistXml);
assertXmlFile(persistXml, getAllNodes(new File(solrHomeDirectory, "solr.xml")));
// And the params for the new core should be in the persisted file. // And the params for the new core should be in the persisted file.
assertXmlFile TestHarness.validateXPath
(persistXml (
, "/solr/cores/core[@name='props1']/property[@name='prefix1' and @value='valuep1']" locator.xml,
"/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']/property[@name='prefix2' and @value='valueP2']"
, "/solr/cores/core[@name='props1' and @transient='true']" , "/solr/cores/core[@name='props1' and @transient='true']"
, "/solr/cores/core[@name='props1' and @loadOnStartup='true']" , "/solr/cores/core[@name='props1' and @loadOnStartup='true']"
@ -511,18 +379,124 @@ public class TestSolrXmlPersistence extends SolrTestCaseJ4 {
} }
} }
private String[] getAllNodes(File xmlFile) throws ParserConfigurationException, IOException, SAXException { @Test
public void testPersist() throws Exception {
final CoreContainer cores = init(ConfigSolrXmlOld.DEF_SOLR_XML, "collection1");
SolrXMLCoresLocator.NonPersistingLocator locator
= (SolrXMLCoresLocator.NonPersistingLocator) cores.getCoresLocator();
String instDir = null;
{
SolrCore template = null;
try {
template = cores.getCore("collection1");
instDir = template.getCoreDescriptor().getRawInstanceDir();
} finally {
if (null != template) template.close();
}
}
final File instDirFile = new File(cores.getSolrHome(), instDir);
assertTrue("instDir doesn't exist: " + instDir, instDirFile.exists());
// sanity check the basic persistence of the default init
TestHarness.validateXPath(locator.xml,
"/solr[@persistent='true']",
"/solr/cores[@defaultCoreName='collection1' and not(@transientCacheSize)]",
"/solr/cores/core[@name='collection1' and @instanceDir='" + instDir +
"' and @transient='false' and @loadOnStartup='true' ]",
"1=count(/solr/cores/core)");
// create some new cores and sanity check the persistence
final File dataXfile = new File(solrHomeDirectory, "dataX");
final String dataX = dataXfile.getAbsolutePath();
assertTrue("dataXfile mkdirs failed: " + dataX, dataXfile.mkdirs());
final File instYfile = new File(solrHomeDirectory, "instY");
FileUtils.copyDirectory(instDirFile, instYfile);
// :HACK: dataDir leaves off trailing "/", but instanceDir uses it
final String instY = instYfile.getAbsolutePath() + "/";
final CoreDescriptor xd = buildCoreDescriptor(cores, "X", instDir)
.withDataDir(dataX).build();
final CoreDescriptor yd = new CoreDescriptor(cores, "Y", instY);
SolrCore x = null;
SolrCore y = null;
try {
x = cores.create(xd);
y = cores.create(yd);
cores.register(x, false);
cores.register(y, false);
assertEquals("cores not added?", 3, cores.getCoreNames().size());
TestHarness.validateXPath(locator.xml,
"/solr[@persistent='true']",
"/solr/cores[@defaultCoreName='collection1']",
"/solr/cores/core[@name='collection1' and @instanceDir='" + instDir
+ "']", "/solr/cores/core[@name='X' and @instanceDir='" + instDir
+ "' and @dataDir='" + dataX + "']",
"/solr/cores/core[@name='Y' and @instanceDir='" + instY + "']",
"3=count(/solr/cores/core)");
// Test for saving implicit properties, we should not do this.
TestHarness.validateXPath(locator.xml,
"/solr/cores/core[@name='X' and not(@solr.core.instanceDir) and not (@solr.core.configName)]");
// delete a core, check persistence again
assertNotNull("removing X returned null", cores.remove("X"));
TestHarness.validateXPath(locator.xml, "/solr[@persistent='true']",
"/solr/cores[@defaultCoreName='collection1']",
"/solr/cores/core[@name='collection1' and @instanceDir='" + instDir + "']",
"/solr/cores/core[@name='Y' and @instanceDir='" + instY + "']",
"2=count(/solr/cores/core)");
} finally {
// y is closed by the container, but
// x has been removed from the container
if (x != null) {
try {
x.close();
} catch (Exception e) {
log.error("", e);
}
}
cores.shutdown();
}
}
private String[] getAllNodes(InputStream is) throws ParserConfigurationException, IOException, SAXException {
List<String> expressions = new ArrayList<String>(); // XPATH and value for all elements in the indicated XML List<String> expressions = new ArrayList<String>(); // XPATH and value for all elements in the indicated XML
DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory
.newInstance(); .newInstance();
DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder(); DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder();
Document document = docBuilder.parse(xmlFile); Document document = docBuilder.parse(is);
Node root = document.getDocumentElement(); Node root = document.getDocumentElement();
gatherNodes(root, expressions, ""); gatherNodes(root, expressions, "");
return expressions.toArray(new String[expressions.size()]); return expressions.toArray(new String[expressions.size()]);
} }
private String[] getAllNodes() throws ParserConfigurationException, IOException, SAXException {
return getAllNodes(new FileInputStream(new File(solrHomeDirectory, "solr.xml")));
}
private String[] getAllNodes(String xmlString) throws ParserConfigurationException, IOException, SAXException {
return getAllNodes(new ByteArrayInputStream(xmlString.getBytes(Charsets.UTF_8)));
}
/*
private void assertSolrXmlFile(String... xpathExpressions) throws IOException, SAXException {
assertXmlFile(new File(solrHomeDirectory, "solr.xml"), xpathExpressions);
}
*/
// Note this is pretty specialized for a solr.xml file because working with the DOM is such a pain. // Note this is pretty specialized for a solr.xml file because working with the DOM is such a pain.
@ -595,7 +569,7 @@ public class TestSolrXmlPersistence extends SolrTestCaseJ4 {
} }
} }
private static String SOLR_XML_LOTS_SYSVARS = public static String SOLR_XML_LOTS_SYSVARS =
"<solr persistent=\"${solr.xml.persist:false}\" coreLoadThreads=\"12\" sharedLib=\"${something:.}\" >\n" + "<solr persistent=\"${solr.xml.persist:false}\" coreLoadThreads=\"12\" sharedLib=\"${something:.}\" >\n" +
" <logging class=\"${logclass:log4j.class}\" enabled=\"{logenable:true}\">\n" + " <logging class=\"${logclass:log4j.class}\" enabled=\"{logenable:true}\">\n" +
" <watcher size=\"{watchSize:13}\" threshold=\"${logThresh:54}\" />\n" + " <watcher size=\"{watchSize:13}\" threshold=\"${logThresh:54}\" />\n" +

View File

@ -0,0 +1,122 @@
package org.apache.solr.core;
/*
* 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.google.common.collect.ImmutableList;
import org.junit.Test;
import java.io.File;
import java.util.List;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
public class TestSolrXmlPersistor {
private static final List<CoreDescriptor> EMPTY_CD_LIST = ImmutableList.<CoreDescriptor>builder().build();
@Test
public void selfClosingCoresTagIsPersisted() {
final String solrxml = "<solr><cores adminHandler=\"/admin\"/></solr>";
SolrXMLCoresLocator persistor = new SolrXMLCoresLocator(new File("testfile.xml"), solrxml, null);
assertEquals(persistor.buildSolrXML(EMPTY_CD_LIST),
"<solr><cores adminHandler=\"/admin\"></cores></solr>");
}
@Test
public void emptyCoresTagIsPersisted() {
final String solrxml = "<solr><cores adminHandler=\"/admin\"></cores></solr>";
SolrXMLCoresLocator persistor = new SolrXMLCoresLocator(new File("testfile.xml"), solrxml, null);
assertEquals(persistor.buildSolrXML(EMPTY_CD_LIST), "<solr><cores adminHandler=\"/admin\"></cores></solr>");
}
@Test
public void emptySolrXmlIsPersisted() {
final String solrxml = "<solr></solr>";
SolrXMLCoresLocator persistor = new SolrXMLCoresLocator(new File("testfile.xml"), solrxml, null);
assertEquals(persistor.buildSolrXML(EMPTY_CD_LIST), "<solr><cores></cores></solr>");
}
@Test
public void simpleCoreDescriptorIsPersisted() {
final String solrxml = "<solr><cores></cores></solr>";
SolrResourceLoader loader = new SolrResourceLoader("solr/example/solr");
CoreContainer cc = new CoreContainer(loader);
final CoreDescriptor cd = new CoreDescriptor(cc, "testcore", "instance/dir/");
List<CoreDescriptor> cds = ImmutableList.of(cd);
SolrXMLCoresLocator persistor = new SolrXMLCoresLocator(new File("testfile.xml"), solrxml, null);
assertEquals(persistor.buildSolrXML(cds),
"<solr><cores>\n"
+ " <core name=\"testcore\" instanceDir=\"instance/dir/\"/>\n"
+ "</cores></solr>");
}
@Test
public void shardHandlerInfoIsPersisted() {
final String solrxml =
"<solr>" +
"<cores adminHandler=\"whatever\">" +
"<core name=\"testcore\" instanceDir=\"instance/dir/\"/>" +
"<shardHandlerFactory name=\"shardHandlerFactory\" class=\"HttpShardHandlerFactory\">" +
"<int name=\"socketTimeout\">${socketTimeout:500}</int>" +
"<str name=\"arbitrary\">arbitraryValue</str>" +
"</shardHandlerFactory>" +
"</cores>" +
"</solr>";
SolrXMLCoresLocator locator = new SolrXMLCoresLocator(new File("testfile.xml"), solrxml, null);
assertTrue(locator.getTemplate().contains("{{CORES_PLACEHOLDER}}"));
assertTrue(locator.getTemplate().contains("<shardHandlerFactory "));
assertTrue(locator.getTemplate().contains("${socketTimeout:500}"));
}
@Test
public void simpleShardHandlerInfoIsPersisted() {
final String solrxml =
"<solr>" +
"<cores adminHandler=\"whatever\">" +
"<core name=\"testcore\" instanceDir=\"instance/dir/\"/>" +
"<shardHandlerFactory name=\"shardHandlerFactory\" class=\"HttpShardHandlerFactory\"/>" +
"</cores>" +
"</solr>";
SolrXMLCoresLocator locator = new SolrXMLCoresLocator(new File("testfile.xml"), solrxml, null);
assertTrue(locator.getTemplate().contains("{{CORES_PLACEHOLDER}}"));
assertTrue(locator.getTemplate().contains("<shardHandlerFactory "));
}
@Test
public void complexXmlIsParsed() {
SolrXMLCoresLocator locator = new SolrXMLCoresLocator(new File("testfile.xml"),
TestSolrXmlPersistence.SOLR_XML_LOTS_SYSVARS, null);
assertTrue(locator.getTemplate().contains("{{CORES_PLACEHOLDER}}"));
}
}

View File

@ -19,9 +19,9 @@ package org.apache.solr.handler.admin;
import org.apache.commons.io.FileUtils; import org.apache.commons.io.FileUtils;
import org.apache.solr.SolrTestCaseJ4; import org.apache.solr.SolrTestCaseJ4;
import org.apache.solr.common.SolrException;
import org.apache.solr.common.params.CoreAdminParams; import org.apache.solr.common.params.CoreAdminParams;
import org.apache.solr.core.CoreDescriptor; import org.apache.solr.core.CorePropertiesLocator;
import org.apache.solr.core.SolrCoreDiscoverer;
import org.apache.solr.response.SolrQueryResponse; import org.apache.solr.response.SolrQueryResponse;
import org.junit.AfterClass; import org.junit.AfterClass;
import org.junit.BeforeClass; import org.junit.BeforeClass;
@ -30,9 +30,6 @@ import org.junit.Test;
import java.io.File; import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.IOException; import java.io.IOException;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.Properties; import java.util.Properties;
public class CoreAdminCreateDiscoverTest extends SolrTestCaseJ4 { public class CoreAdminCreateDiscoverTest extends SolrTestCaseJ4 {
@ -43,6 +40,7 @@ public class CoreAdminCreateDiscoverTest extends SolrTestCaseJ4 {
private static String coreNormal = "normal"; private static String coreNormal = "normal";
private static String coreSysProps = "sys_props"; private static String coreSysProps = "sys_props";
private static String coreDuplicate = "duplicate";
@BeforeClass @BeforeClass
public static void beforeClass() throws Exception { public static void beforeClass() throws Exception {
@ -111,7 +109,7 @@ public class CoreAdminCreateDiscoverTest extends SolrTestCaseJ4 {
// verify props are in persisted file // verify props are in persisted file
Properties props = new Properties(); Properties props = new Properties();
File propFile = new File(solrHomeDirectory, coreSysProps + "/" + SolrCoreDiscoverer.CORE_PROP_FILE); File propFile = new File(solrHomeDirectory, coreSysProps + "/" + CorePropertiesLocator.PROPERTIES_FILENAME);
FileInputStream is = new FileInputStream(propFile); FileInputStream is = new FileInputStream(propFile);
try { try {
props.load(is); props.load(is);
@ -131,7 +129,8 @@ public class CoreAdminCreateDiscoverTest extends SolrTestCaseJ4 {
assertEquals("Unexpected value preserved in properties file " + propFile.getAbsolutePath(), assertEquals("Unexpected value preserved in properties file " + propFile.getAbsolutePath(),
props.getProperty(CoreAdminParams.DATA_DIR), "${DATA_TEST}"); props.getProperty(CoreAdminParams.DATA_DIR), "${DATA_TEST}");
checkOnlyKnown(propFile); assertEquals(props.size(), 4);
//checkOnlyKnown(propFile);
// Now assert that certain values are properly dereferenced in the process of creating the core, see // Now assert that certain values are properly dereferenced in the process of creating the core, see
// SOLR-4982. Really, we should be able to just verify that the index files exist. // SOLR-4982. Really, we should be able to just verify that the index files exist.
@ -150,6 +149,47 @@ public class CoreAdminCreateDiscoverTest extends SolrTestCaseJ4 {
} }
@Test
public void testCannotCreateTwoCoresWithSameInstanceDir() throws Exception {
setupCore(coreDuplicate, true);
File workDir = new File(solrHomeDirectory, coreDuplicate);
File data = new File(workDir, "data");
// Create one core
SolrQueryResponse resp = new SolrQueryResponse();
admin.handleRequestBody
(req(CoreAdminParams.ACTION,
CoreAdminParams.CoreAdminAction.CREATE.toString(),
CoreAdminParams.NAME, coreDuplicate,
CoreAdminParams.INSTANCE_DIR, workDir.getAbsolutePath(),
CoreAdminParams.CONFIG, "solrconfig_ren.xml",
CoreAdminParams.SCHEMA, "schema_ren.xml",
CoreAdminParams.DATA_DIR, data.getAbsolutePath()),
resp);
assertNull("Exception on create", resp.getException());
// Try to create another core with a different name, but the same instance dir
SolrQueryResponse resp2 = new SolrQueryResponse();
try {
admin.handleRequestBody
(req(CoreAdminParams.ACTION,
CoreAdminParams.CoreAdminAction.CREATE.toString(),
CoreAdminParams.NAME, "different_name_core",
CoreAdminParams.INSTANCE_DIR, workDir.getAbsolutePath(),
CoreAdminParams.CONFIG, "solrconfig_ren.xml",
CoreAdminParams.SCHEMA, "schema_ren.xml",
CoreAdminParams.DATA_DIR, data.getAbsolutePath()),
resp2);
fail("Creating two cores with a shared instance dir should throw an exception");
}
catch (SolrException e) {
assertTrue(e.getMessage().contains("already defined there"));
}
}
@Test @Test
public void testCreateSavesRegProps() throws Exception { public void testCreateSavesRegProps() throws Exception {
@ -174,7 +214,7 @@ public class CoreAdminCreateDiscoverTest extends SolrTestCaseJ4 {
// verify props are in persisted file // verify props are in persisted file
Properties props = new Properties(); Properties props = new Properties();
File propFile = new File(solrHomeDirectory, coreNormal + "/" + SolrCoreDiscoverer.CORE_PROP_FILE); File propFile = new File(solrHomeDirectory, coreNormal + "/" + CorePropertiesLocator.PROPERTIES_FILENAME);
FileInputStream is = new FileInputStream(propFile); FileInputStream is = new FileInputStream(propFile);
try { try {
props.load(is); props.load(is);
@ -194,7 +234,9 @@ public class CoreAdminCreateDiscoverTest extends SolrTestCaseJ4 {
assertEquals("Unexpected value preserved in properties file " + propFile.getAbsolutePath(), assertEquals("Unexpected value preserved in properties file " + propFile.getAbsolutePath(),
props.getProperty(CoreAdminParams.DATA_DIR), data.getAbsolutePath()); props.getProperty(CoreAdminParams.DATA_DIR), data.getAbsolutePath());
checkOnlyKnown(propFile); assertEquals(props.size(), 4);
//checkOnlyKnown(propFile);
// For the other 3 vars, we couldn't get past creating the core if dereferencing didn't work correctly. // For the other 3 vars, we couldn't get past creating the core if dereferencing didn't work correctly.
// Should have segments in the directory pointed to by the ${DATA_TEST}. // Should have segments in the directory pointed to by the ${DATA_TEST}.
@ -205,23 +247,4 @@ public class CoreAdminCreateDiscoverTest extends SolrTestCaseJ4 {
} }
// Insure that all the props we've preserved are ones that _should_ be in the properties file
private void checkOnlyKnown(File propFile) throws IOException {
Properties props = new Properties();
FileInputStream is = new FileInputStream(propFile);
try {
props.load(is);
} finally {
org.apache.commons.io.IOUtils.closeQuietly(is);
}
// Should never be preserving instanceDir in a core.properties file.
assertFalse("Should not be preserving instanceDir!", props.containsKey(CoreAdminParams.INSTANCE_DIR));
Collection<String> stds = new HashSet(Arrays.asList(CoreDescriptor.standardPropNames));
for (String key : props.stringPropertyNames()) {
assertTrue("Property '" + key + "' should NOT be preserved in the properties file", stds.contains(key));
}
}
} }

View File

@ -18,25 +18,25 @@
package org.apache.solr.handler.admin; package org.apache.solr.handler.admin;
import com.carrotsearch.randomizedtesting.rules.SystemPropertiesRestoreRule; import com.carrotsearch.randomizedtesting.rules.SystemPropertiesRestoreRule;
import org.apache.solr.core.CoreContainer; import org.apache.commons.io.FileUtils;
import org.apache.solr.core.SolrCore; import org.apache.solr.SolrTestCaseJ4;
import org.apache.solr.common.SolrException; import org.apache.solr.common.SolrException;
import org.apache.solr.common.params.CoreAdminParams; import org.apache.solr.common.params.CoreAdminParams;
import org.apache.solr.common.util.NamedList; import org.apache.solr.common.util.NamedList;
import org.apache.solr.core.CoreContainer;
import org.apache.solr.core.CoreDescriptor;
import org.apache.solr.core.SolrCore;
import org.apache.solr.core.SolrXMLCoresLocator;
import org.apache.solr.response.SolrQueryResponse; import org.apache.solr.response.SolrQueryResponse;
import org.apache.solr.SolrTestCaseJ4;
import java.util.Map;
import java.io.File;
import org.apache.commons.io.FileUtils;
import org.junit.BeforeClass; import org.junit.BeforeClass;
import org.junit.Rule; import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
import org.junit.rules.RuleChain; import org.junit.rules.RuleChain;
import org.junit.rules.TestRule; import org.junit.rules.TestRule;
import java.io.File;
import java.util.Map;
public class CoreAdminHandlerTest extends SolrTestCaseJ4 { public class CoreAdminHandlerTest extends SolrTestCaseJ4 {
@BeforeClass @BeforeClass
@ -72,7 +72,8 @@ public class CoreAdminHandlerTest extends SolrTestCaseJ4 {
new File(subHome, "solrconfig.snippet.randomindexconfig.xml")); new File(subHome, "solrconfig.snippet.randomindexconfig.xml"));
final CoreContainer cores = h.getCoreContainer(); final CoreContainer cores = h.getCoreContainer();
cores.setPersistent(false); // we'll do this explicitly as needed SolrXMLCoresLocator.NonPersistingLocator locator
= (SolrXMLCoresLocator.NonPersistingLocator) cores.getCoresLocator();
final CoreAdminHandler admin = new CoreAdminHandler(cores); final CoreAdminHandler admin = new CoreAdminHandler(cores);
@ -96,14 +97,9 @@ public class CoreAdminHandlerTest extends SolrTestCaseJ4 {
resp); resp);
assertNull("Exception on create", resp.getException()); assertNull("Exception on create", resp.getException());
// verify props are in persisted file
final File xml = new File(workDir, "persist-solr.xml");
cores.persistFile(xml);
// First assert that these values are persisted. // First assert that these values are persisted.
assertXmlFile h.validateXPath
(xml (locator.xml
,"/solr/cores/core[@name='" + getCoreName() + "' and @instanceDir='${INSTDIR_TEST}']" ,"/solr/cores/core[@name='" + getCoreName() + "' and @instanceDir='${INSTDIR_TEST}']"
,"/solr/cores/core[@name='" + getCoreName() + "' and @dataDir='${DATA_TEST}']" ,"/solr/cores/core[@name='" + getCoreName() + "' and @dataDir='${DATA_TEST}']"
,"/solr/cores/core[@name='" + getCoreName() + "' and @schema='${SCHEMA_TEST}']" ,"/solr/cores/core[@name='" + getCoreName() + "' and @schema='${SCHEMA_TEST}']"
@ -140,7 +136,6 @@ public class CoreAdminHandlerTest extends SolrTestCaseJ4 {
assertTrue("Failed to mkdirs workDir", workDir.mkdirs()); assertTrue("Failed to mkdirs workDir", workDir.mkdirs());
final CoreContainer cores = h.getCoreContainer(); final CoreContainer cores = h.getCoreContainer();
cores.setPersistent(false); // we'll do this explicitly as needed
final CoreAdminHandler admin = new CoreAdminHandler(cores); final CoreAdminHandler admin = new CoreAdminHandler(cores);
@ -173,16 +168,10 @@ public class CoreAdminHandlerTest extends SolrTestCaseJ4 {
resp); resp);
assertNull("Exception on create", resp.getException()); assertNull("Exception on create", resp.getException());
// verify props are in persisted file CoreDescriptor cd = cores.getCoreDescriptor("props");
assertNotNull("Core not added!", cd);
final File xml = new File(workDir, "persist-solr.xml"); assertEquals(cd.getCoreProperty("hoss", null), "man");
cores.persistFile(xml); assertEquals(cd.getCoreProperty("foo", null), "baz");
assertXmlFile
(xml
,"/solr/cores/core[@name='props']/property[@name='hoss' and @value='man']"
,"/solr/cores/core[@name='props']/property[@name='foo' and @value='baz']"
);
// attempt to create a bogus core and confirm failure // attempt to create a bogus core and confirm failure
ignoreException("Could not load config"); ignoreException("Could not load config");

View File

@ -133,21 +133,18 @@ public class SolrIndexSplitterTest extends SolrTestCaseJ4 {
SolrCore core1 = null, core2 = null; SolrCore core1 = null, core2 = null;
try { try {
CoreDescriptor dcore1 = new CoreDescriptor(h.getCoreContainer(), "split1", h.getCore().getCoreDescriptor().getInstanceDir()); String instanceDir = h.getCore().getCoreDescriptor().getInstanceDir();
dcore1.setDataDir(indexDir1.getAbsolutePath());
dcore1.setSchemaName("schema12.xml");
CoreDescriptor dcore1 = buildCoreDescriptor(h.getCoreContainer(), "split1", instanceDir)
.withDataDir(indexDir1.getAbsolutePath()).withSchema("schema12.xml").build();
if (h.getCoreContainer().getZkController() != null) { if (h.getCoreContainer().getZkController() != null) {
h.getCoreContainer().preRegisterInZk(dcore1); h.getCoreContainer().preRegisterInZk(dcore1);
} }
core1 = h.getCoreContainer().create(dcore1); core1 = h.getCoreContainer().create(dcore1);
h.getCoreContainer().register(core1, false); h.getCoreContainer().register(core1, false);
CoreDescriptor dcore2 = new CoreDescriptor(h.getCoreContainer(), "split2", h.getCore().getCoreDescriptor().getInstanceDir()); CoreDescriptor dcore2 = buildCoreDescriptor(h.getCoreContainer(), "split2", instanceDir)
dcore2.setDataDir(indexDir2.getAbsolutePath()); .withDataDir(indexDir2.getAbsolutePath()).withSchema("schema12.xml").build();
dcore2.setSchemaName("schema12.xml");
if (h.getCoreContainer().getZkController() != null) { if (h.getCoreContainer().getZkController() != null) {
h.getCoreContainer().preRegisterInZk(dcore2); h.getCoreContainer().preRegisterInZk(dcore2);
} }

View File

@ -17,22 +17,22 @@
package org.apache.solr.client.solrj.request; package org.apache.solr.client.solrj.request;
import java.io.IOException;
import java.util.Collection;
import java.util.List;
import java.util.Arrays;
import org.apache.solr.client.solrj.SolrRequest; import org.apache.solr.client.solrj.SolrRequest;
import org.apache.solr.client.solrj.SolrServer; import org.apache.solr.client.solrj.SolrServer;
import org.apache.solr.client.solrj.SolrServerException; import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.response.CoreAdminResponse; import org.apache.solr.client.solrj.response.CoreAdminResponse;
import org.apache.solr.common.cloud.ZkStateReader; import org.apache.solr.common.cloud.ZkStateReader;
import org.apache.solr.common.params.ModifiableSolrParams;
import org.apache.solr.common.params.CoreAdminParams; import org.apache.solr.common.params.CoreAdminParams;
import org.apache.solr.common.params.SolrParams;
import org.apache.solr.common.params.CoreAdminParams.CoreAdminAction; import org.apache.solr.common.params.CoreAdminParams.CoreAdminAction;
import org.apache.solr.common.params.ModifiableSolrParams;
import org.apache.solr.common.params.SolrParams;
import org.apache.solr.common.util.ContentStream; import org.apache.solr.common.util.ContentStream;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
/** /**
* This class is experimental and subject to change. * This class is experimental and subject to change.
* *
@ -534,6 +534,7 @@ public class CoreAdminRequest extends SolrRequest
return req.process( server ); return req.process( server );
} }
@Deprecated
public static CoreAdminResponse persist(String fileName, SolrServer server) throws SolrServerException, IOException public static CoreAdminResponse persist(String fileName, SolrServer server) throws SolrServerException, IOException
{ {
CoreAdminRequest.Persist req = new CoreAdminRequest.Persist(); CoreAdminRequest.Persist req = new CoreAdminRequest.Persist();

View File

@ -23,7 +23,7 @@ import java.util.Locale;
/** /**
* @since solr 1.3 * @since solr 1.3
*/ */
public interface CoreAdminParams public abstract class CoreAdminParams
{ {
/** What Core are we talking about **/ /** What Core are we talking about **/
public final static String CORE = "core"; public final static String CORE = "core";

View File

@ -22,7 +22,7 @@
persistent: Save changes made via the API to this file persistent: Save changes made via the API to this file
sharedLib: path to a lib directory that will be shared across all cores sharedLib: path to a lib directory that will be shared across all cores
--> -->
<solr persistent="true"> <solr persistent="false">
<property name="version" value="1.3"/> <property name="version" value="1.3"/>
<property name="lang" value="english, french"/> <property name="lang" value="english, french"/>

View File

@ -63,7 +63,7 @@ public abstract class AbstractEmbeddedSolrServerTestCase extends LuceneTestCase
System.setProperty("tempDir", tempDir.getAbsolutePath()); System.setProperty("tempDir", tempDir.getAbsolutePath());
System.setProperty("tests.shardhandler.randomSeed", Long.toString(random().nextLong())); System.setProperty("tests.shardhandler.randomSeed", Long.toString(random().nextLong()));
cores = CoreContainer.createAndLoad(SOLR_HOME.getAbsolutePath(), getSolrXml()); cores = CoreContainer.createAndLoad(SOLR_HOME.getAbsolutePath(), getSolrXml());
cores.setPersistent(false); //cores.setPersistent(false);
} }
protected abstract File getSolrXml() throws Exception; protected abstract File getSolrXml() throws Exception;

View File

@ -18,8 +18,6 @@
package org.apache.solr.client.solrj.embedded; package org.apache.solr.client.solrj.embedded;
import com.carrotsearch.randomizedtesting.rules.SystemPropertiesRestoreRule; import com.carrotsearch.randomizedtesting.rules.SystemPropertiesRestoreRule;
import com.google.common.io.ByteStreams;
import org.apache.commons.io.IOUtils;
import org.apache.solr.SolrTestCaseJ4; import org.apache.solr.SolrTestCaseJ4;
import org.apache.solr.client.solrj.SolrQuery; import org.apache.solr.client.solrj.SolrQuery;
import org.apache.solr.client.solrj.SolrServer; import org.apache.solr.client.solrj.SolrServer;
@ -29,30 +27,16 @@ import org.apache.solr.client.solrj.request.QueryRequest;
import org.apache.solr.client.solrj.request.UpdateRequest; import org.apache.solr.client.solrj.request.UpdateRequest;
import org.apache.solr.client.solrj.response.CoreAdminResponse; import org.apache.solr.client.solrj.response.CoreAdminResponse;
import org.apache.solr.common.SolrInputDocument; import org.apache.solr.common.SolrInputDocument;
import org.apache.solr.core.CoreContainer; import org.apache.solr.core.SolrXMLCoresLocator;
import org.apache.solr.util.FileUtils; import org.apache.solr.util.TestHarness;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule; import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
import org.junit.rules.RuleChain; import org.junit.rules.RuleChain;
import org.junit.rules.TestRule; import org.junit.rules.TestRule;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import java.io.File; import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
/** /**
* *
@ -62,56 +46,14 @@ public class TestSolrProperties extends AbstractEmbeddedSolrServerTestCase {
protected static Logger log = LoggerFactory.getLogger(TestSolrProperties.class); protected static Logger log = LoggerFactory.getLogger(TestSolrProperties.class);
private static final String SOLR_XML = "solr.xml"; private static final String SOLR_XML = "solr.xml";
private static final String SOLR_PERSIST_XML = "solr-persist.xml";
@Rule @Rule
public TestRule solrTestRules = public TestRule solrTestRules =
RuleChain.outerRule(new SystemPropertiesRestoreRule()); RuleChain.outerRule(new SystemPropertiesRestoreRule());
private static final XPathFactory xpathFactory = XPathFactory.newInstance();
@Override
@Before
public void setUp() throws Exception {
super.setUp();
}
@Override
@After
public void tearDown() throws Exception {
super.tearDown();
}
private static void dumpFile(File fileToDump) throws IOException {
System.out.println("Dumping " + fileToDump.getAbsolutePath());
InputStream is = new FileInputStream(fileToDump);
try {
ByteStreams.copy(is, System.out);
}
finally {
IOUtils.closeQuietly(is);
}
}
@Override @Override
protected File getSolrXml() throws Exception { protected File getSolrXml() throws Exception {
//This test writes on the directory where the solr.xml is located. Better to copy the solr.xml to return new File(SOLR_HOME, SOLR_XML);
//the temporary directory where we store the index
File origSolrXml = new File(SOLR_HOME, SOLR_XML);
File solrXml = new File(tempDir, SOLR_XML);
FileUtils.copyFile(origSolrXml, solrXml);
return solrXml;
}
@Override
protected void deleteAdditionalFiles() {
super.deleteAdditionalFiles();
//Cleans the solr.xml persisted while testing and the solr.xml copied to the temporary directory
File persistedFile = new File(tempDir, SOLR_PERSIST_XML);
assertTrue("Failed to delete "+persistedFile, persistedFile.delete());
File solrXml = new File(tempDir, SOLR_XML);
assertTrue("Failed to delete "+ solrXml, solrXml.delete());
} }
protected SolrServer getSolrAdmin() { protected SolrServer getSolrAdmin() {
@ -125,8 +67,8 @@ public class TestSolrProperties extends AbstractEmbeddedSolrServerTestCase {
@Test @Test
public void testProperties() throws Exception { public void testProperties() throws Exception {
String persistedSolrXml = new File(tempDir, SOLR_PERSIST_XML).getAbsolutePath(); SolrXMLCoresLocator.NonPersistingLocator locator
log.info("persistedSolrXml: {}", persistedSolrXml); = (SolrXMLCoresLocator.NonPersistingLocator) cores.getCoresLocator();
UpdateRequest up = new UpdateRequest(); UpdateRequest up = new UpdateRequest();
up.setAction(ACTION.COMMIT, true, true); up.setAction(ACTION.COMMIT, true, true);
@ -197,51 +139,22 @@ public class TestSolrProperties extends AbstractEmbeddedSolrServerTestCase {
long after = mcr.getStartTime(name).getTime(); long after = mcr.getStartTime(name).getTime();
assertTrue("should have more recent time: " + after + "," + before, after > before); assertTrue("should have more recent time: " + after + "," + before, after > before);
mcr = CoreAdminRequest.persist(persistedSolrXml, coreadmin); TestHarness.validateXPath(locator.xml,
"/solr/cores[@defaultCoreName='core0']",
DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); "/solr/cores[@host='127.0.0.1']",
FileInputStream fis = new FileInputStream(new File(persistedSolrXml)); "/solr/cores[@hostPort='${hostPort:8983}']",
try { "/solr/cores[@zkClientTimeout='8000']",
Document document = builder.parse(fis); "/solr/cores[@hostContext='${hostContext:solr}']",
fis.close(); "/solr/cores[@genericCoreNodeNames='${genericCoreNodeNames:true}']"
fis = new FileInputStream(new File(persistedSolrXml)); );
String solrPersistXml = IOUtils.toString(new InputStreamReader(fis, "UTF-8"));
//System.out.println("xml:" + solrPersistXml);
assertTrue("\"/solr/cores[@defaultCoreName='core0']\" doesn't match in:\n" + solrPersistXml,
exists("/solr/cores[@defaultCoreName='core0']", document));
assertTrue("\"/solr/cores[@host='127.0.0.1']\" doesn't match in:\n" + solrPersistXml,
exists("/solr/cores[@host='127.0.0.1']", document));
assertTrue("\"/solr/cores[@hostPort='${hostPort:8983}']\" doesn't match in:\n" + solrPersistXml,
exists("/solr/cores[@hostPort='${hostPort:8983}']", document));
assertTrue("\"/solr/cores[@zkClientTimeout='8000']\" doesn't match in:\n" + solrPersistXml,
exists("/solr/cores[@zkClientTimeout='8000']", document));
assertTrue("\"/solr/cores[@hostContext='${hostContext:solr}']\" doesn't match in:\n" + solrPersistXml,
exists("/solr/cores[@hostContext='${hostContext:solr}']", document));
assertTrue("\"/solr/cores[@genericCoreNodeNames='${genericCoreNodeNames:true}']\" doesn't match in:\n" + solrPersistXml,
exists("/solr/cores[@genericCoreNodeNames='${genericCoreNodeNames:true}']", document));
} finally {
fis.close();
}
CoreAdminRequest.renameCore(name, "renamed_core", coreadmin); CoreAdminRequest.renameCore(name, "renamed_core", coreadmin);
mcr = CoreAdminRequest.persist(persistedSolrXml, getRenamedSolrAdmin()); TestHarness.validateXPath(locator.xml,
"/solr/cores/core[@name='renamed_core']",
// fis = new FileInputStream(new File(tempDir, SOLR_PERSIST_XML)); "/solr/cores/core[@instanceDir='${theInstanceDir:./}']",
// String solrPersistXml = IOUtils.toString(fis); "/solr/cores/core[@collection='${collection:acollection}']"
// System.out.println("xml:" + solrPersistXml); );
// fis.close();
fis = new FileInputStream(new File(persistedSolrXml));
try {
Document document = builder.parse(fis);
assertTrue(exists("/solr/cores/core[@name='renamed_core']", document));
assertTrue(exists("/solr/cores/core[@instanceDir='${theInstanceDir:./}']", document));
assertTrue(exists("/solr/cores/core[@collection='${collection:acollection}']", document));
} finally {
fis.close();
}
coreadmin = getRenamedSolrAdmin(); coreadmin = getRenamedSolrAdmin();
File dataDir = new File(tempDir,"data3"); File dataDir = new File(tempDir,"data3");
@ -251,49 +164,8 @@ public class TestSolrProperties extends AbstractEmbeddedSolrServerTestCase {
coreadmin, null, null, dataDir.getAbsolutePath(), coreadmin, null, null, dataDir.getAbsolutePath(),
tlogDir.getAbsolutePath()); tlogDir.getAbsolutePath());
// fis = new FileInputStream(new File(solrXml.getParent(), SOLR_PERSIST_XML)); TestHarness.validateXPath(locator.xml, "/solr/cores/core[@name='collection1' and @instanceDir='.']");
// solrPersistXml = IOUtils.toString(fis);
// System.out.println("xml:" + solrPersistXml);
// fis.close();
mcr = CoreAdminRequest.persist(persistedSolrXml, getRenamedSolrAdmin());
// fis = new FileInputStream(new File(solrXml.getParent(), SOLR_PERSIST_XML));
// solrPersistXml = IOUtils.toString(fis);
// System.out.println("xml:" + solrPersistXml);
// fis.close();
fis = new FileInputStream(new File(persistedSolrXml));
try {
Document document = builder.parse(fis);
assertTrue(exists("/solr/cores/core[@name='collection1' and @instanceDir='.']", document));
} finally {
fis.close();
}
// test reload and parse
cores.shutdown();
// fis = new FileInputStream(new File(getSolrXml().getParent(),
// SOLR_PERSIST_XML));
// String solrPersistXml = IOUtils.toString(fis);
// System.out.println("xml:" + solrPersistXml);
// fis.close();
cores = CoreContainer.createAndLoad(SOLR_HOME.getAbsolutePath(), new File(persistedSolrXml));
//mcr = CoreAdminRequest.persist(SOLR_PERSIST_XML, getRenamedSolrAdmin());
// fis = new FileInputStream(new File(solrXml.getParent(),
// SOLR_PERSIST_XML));
// solrPersistXml = IOUtils.toString(fis);
// System.out.println("xml:" + solrPersistXml);
// fis.close();
} }
public static boolean exists(String xpathStr, Node node)
throws XPathExpressionException {
XPath xpath = xpathFactory.newXPath();
return (Boolean) xpath.evaluate(xpathStr, node, XPathConstants.BOOLEAN);
}
} }

View File

@ -35,6 +35,7 @@ import org.apache.solr.common.params.SolrParams;
import org.apache.solr.common.util.XML; import org.apache.solr.common.util.XML;
import org.apache.solr.core.ConfigSolr; import org.apache.solr.core.ConfigSolr;
import org.apache.solr.core.CoreContainer; import org.apache.solr.core.CoreContainer;
import org.apache.solr.core.CoreDescriptor;
import org.apache.solr.core.SolrConfig; import org.apache.solr.core.SolrConfig;
import org.apache.solr.core.SolrCore; import org.apache.solr.core.SolrCore;
import org.apache.solr.core.SolrResourceLoader; import org.apache.solr.core.SolrResourceLoader;
@ -73,6 +74,7 @@ import java.util.HashSet;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Properties;
import java.util.logging.ConsoleHandler; import java.util.logging.ConsoleHandler;
import java.util.logging.Handler; import java.util.logging.Handler;
import java.util.logging.Level; import java.util.logging.Level;
@ -1576,4 +1578,51 @@ public abstract class SolrTestCaseJ4 extends LuceneTestCase {
FileUtils.copyFile(new File(top, "solrconfig.snippet.randomindexconfig.xml"), new File(subHome, "solrconfig.snippet.randomindexconfig.xml")); FileUtils.copyFile(new File(top, "solrconfig.snippet.randomindexconfig.xml"), new File(subHome, "solrconfig.snippet.randomindexconfig.xml"));
} }
public static CoreDescriptorBuilder buildCoreDescriptor(CoreContainer container, String name, String instancedir) {
return new CoreDescriptorBuilder(container, name, instancedir);
}
public static class CoreDescriptorBuilder {
final String name;
final String instanceDir;
final CoreContainer container;
final Properties properties = new Properties();
public CoreDescriptorBuilder(CoreContainer container, String name, String instancedir) {
this.name = name;
this.instanceDir = instancedir;
this.container = container;
}
public CoreDescriptorBuilder withSchema(String schema) {
properties.setProperty(CoreDescriptor.CORE_SCHEMA, schema);
return this;
}
public CoreDescriptorBuilder withConfig(String config) {
properties.setProperty(CoreDescriptor.CORE_CONFIG, config);
return this;
}
public CoreDescriptorBuilder withDataDir(String datadir) {
properties.setProperty(CoreDescriptor.CORE_DATADIR, datadir);
return this;
}
public CoreDescriptor build() {
return new CoreDescriptor(container, name, instanceDir, properties);
}
public CoreDescriptorBuilder isTransient(boolean isTransient) {
properties.setProperty(CoreDescriptor.CORE_TRANSIENT, Boolean.toString(isTransient));
return this;
}
public CoreDescriptorBuilder loadOnStartup(boolean loadOnStartup) {
properties.setProperty(CoreDescriptor.CORE_LOADONSTARTUP, Boolean.toString(loadOnStartup));
return this;
}
}
} }

View File

@ -17,7 +17,6 @@
package org.apache.solr.util; package org.apache.solr.util;
import com.google.common.base.Charsets;
import org.apache.solr.common.SolrException; import org.apache.solr.common.SolrException;
import org.apache.solr.common.params.CommonParams; import org.apache.solr.common.params.CommonParams;
import org.apache.solr.common.util.NamedList; import org.apache.solr.common.util.NamedList;
@ -38,14 +37,12 @@ import org.apache.solr.schema.IndexSchema;
import org.apache.solr.schema.IndexSchemaFactory; import org.apache.solr.schema.IndexSchemaFactory;
import org.apache.solr.servlet.DirectSolrConnection; import org.apache.solr.servlet.DirectSolrConnection;
import java.io.ByteArrayInputStream;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.StringWriter; import java.io.StringWriter;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
/** /**
* This class provides a simple harness that may be useful when * This class provides a simple harness that may be useful when
* writing testcases. * writing testcases.
@ -156,7 +153,7 @@ public class TestHarness extends BaseTestHarness {
*/ */
public TestHarness(String solrHome, String solrXml) { public TestHarness(String solrHome, String solrXml) {
this(new SolrResourceLoader(solrHome), this(new SolrResourceLoader(solrHome),
ConfigSolr.fromInputStream(null, new ByteArrayInputStream(solrXml.getBytes(Charsets.UTF_8)))); ConfigSolr.fromString(solrXml));
} }
/** /**
@ -188,7 +185,7 @@ public class TestHarness extends BaseTestHarness {
+ "\" transient=\"false\" loadOnStartup=\"true\"" + "\" transient=\"false\" loadOnStartup=\"true\""
+ " shard=\"${shard:shard1}\" collection=\"${collection:collection1}\" instanceDir=\"" + coreName + "/\" />\n" + " shard=\"${shard:shard1}\" collection=\"${collection:collection1}\" instanceDir=\"" + coreName + "/\" />\n"
+ " </cores>\n" + "</solr>"; + " </cores>\n" + "</solr>";
return ConfigSolr.fromString(new SolrResourceLoader(dataDir), solrxml); return ConfigSolr.fromString(solrxml);
} }
public CoreContainer getCoreContainer() { public CoreContainer getCoreContainer() {
@ -423,4 +420,6 @@ public class TestHarness extends BaseTestHarness {
return new LocalSolrQueryRequest(TestHarness.this.getCore(), new NamedList(entries)); return new LocalSolrQueryRequest(TestHarness.this.getCore(), new NamedList(entries));
} }
} }
} }