SOLR-4196, steps toward making solr.xml obsolete

git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1451797 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Erick Erickson 2013-03-02 01:01:12 +00:00
parent 05cc3a4706
commit aa22ceb97d
21 changed files with 2797 additions and 846 deletions

View File

@ -1,7 +1,9 @@
package org.apache.solr.cloud;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.concurrent.TimeoutException;
@ -17,10 +19,11 @@ import org.apache.commons.cli.ParseException;
import org.apache.commons.cli.PosixParser;
import org.apache.solr.common.cloud.OnReconnect;
import org.apache.solr.common.cloud.SolrZkClient;
import org.apache.solr.core.Config;
import org.apache.solr.core.ConfigSolr;
import org.apache.solr.core.ConfigSolrXmlBackCompat;
import org.apache.solr.core.SolrProperties;
import org.apache.solr.core.SolrResourceLoader;
import org.apache.zookeeper.KeeperException;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
/*
@ -171,12 +174,26 @@ public class ZkCLI {
}
SolrResourceLoader loader = new SolrResourceLoader(solrHome);
solrHome = loader.getInstanceDir();
InputSource cfgis = new InputSource(new File(solrHome, SOLR_XML)
.toURI().toASCIIString());
Config cfg = new Config(loader, null, cfgis, null, false);
if(!ZkController.checkChrootPath(zkServerAddress, true)) {
File configFile = new File(solrHome, SOLR_XML);
boolean isXml = true;
if (! configFile.exists()) {
configFile = new File(solrHome, SolrProperties.SOLR_PROPERTIES_FILE);
isXml = false;
}
InputStream is = new FileInputStream(configFile);
//ConfigSolrXmlThunk cfg = new ConfigSolrXmlThunk(null, loader, is, false, true);
ConfigSolr cfg;
if (isXml) {
cfg = new ConfigSolrXmlBackCompat(loader, null, is, null, false);
} else {
cfg = new SolrProperties(null, is, null);
}
if(!ZkController.checkChrootPath(zkServerAddress, true)) {
System.out.println("A chroot was specified in zkHost but the znode doesn't exist. ");
System.exit(1);
}

View File

@ -39,8 +39,6 @@ import java.util.concurrent.TimeoutException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.xml.xpath.XPathConstants;
import org.apache.commons.io.FileUtils;
import org.apache.solr.client.solrj.impl.HttpSolrServer;
import org.apache.solr.client.solrj.request.CoreAdminRequest.WaitForState;
@ -60,14 +58,14 @@ import org.apache.solr.common.cloud.ZkNodeProps;
import org.apache.solr.common.cloud.ZkStateReader;
import org.apache.solr.common.cloud.ZooKeeperException;
import org.apache.solr.common.params.SolrParams;
import org.apache.solr.core.Config;
import org.apache.solr.core.ConfigSolr;
import org.apache.solr.core.CoreContainer;
import org.apache.solr.core.CoreDescriptor;
import org.apache.solr.core.SolrCore;
import org.apache.solr.handler.component.ShardHandler;
import org.apache.solr.update.UpdateLog;
import org.apache.solr.update.UpdateShardHandler;
import org.apache.solr.util.DOMUtil;
import org.apache.solr.util.PropertiesUtil;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.KeeperException.NoNodeException;
@ -75,8 +73,6 @@ import org.apache.zookeeper.KeeperException.SessionExpiredException;
import org.apache.zookeeper.data.Stat;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
/**
* Handle ZooKeeper interactions.
@ -1409,20 +1405,19 @@ public final class ZkController {
/**
* If in SolrCloud mode, upload config sets for each SolrCore in solr.xml.
*/
public static void bootstrapConf(SolrZkClient zkClient, Config cfg, String solrHome) throws IOException,
public static void bootstrapConf(SolrZkClient zkClient, ConfigSolr cfg, String solrHome) throws IOException,
KeeperException, InterruptedException {
log.info("bootstraping config into ZooKeeper using solr.xml");
NodeList nodes = (NodeList)cfg.evaluate("solr/cores/core", XPathConstants.NODESET);
for (int i=0; i<nodes.getLength(); i++) {
Node node = nodes.item(i);
String rawName = DOMUtil.substituteProperty(DOMUtil.getAttr(node, "name", null), new Properties());
String instanceDir = DOMUtil.getAttr(node, "instanceDir", null);
log.info("bootstraping config into ZooKeeper using solr.xml");
List<String> allCoreNames = cfg.getAllCoreNames();
for (String coreName : allCoreNames) {
String rawName = PropertiesUtil.substituteProperty(cfg.getProperty(coreName, "name", null), new Properties());
String instanceDir = cfg.getProperty(coreName, "instanceDir", null);
File idir = new File(instanceDir);
if (!idir.isAbsolute()) {
idir = new File(solrHome, instanceDir);
}
String confName = DOMUtil.substituteProperty(DOMUtil.getAttr(node, "collection", null), new Properties());
String confName = PropertiesUtil.substituteProperty(cfg.getProperty(coreName, "collection", null), new Properties());
if (confName == null) {
confName = rawName;
}

View File

@ -34,15 +34,13 @@ import javax.xml.namespace.QName;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
import java.util.concurrent.atomic.AtomicBoolean;
/**
@ -67,7 +65,18 @@ public class Config {
this( loader, name, null, null );
}
/**
* For the transition from using solr.xml to solr.properties, see SOLR-4196. Remove
* for 5.0, thus it's already deprecated
* @param loader - Solr resource loader
* @param cfg - SolrConfig, for backwards compatability with solr.xml layer.
* @throws TransformerException if the XML file is mal-formed
*/
@Deprecated
public Config(SolrResourceLoader loader, Config cfg) throws TransformerException {
this(loader, null, ConfigSolrXmlBackCompat.copyDoc(cfg.getDocument()));
}
public Config(SolrResourceLoader loader, String name, InputSource is, String prefix) throws ParserConfigurationException, IOException, SAXException
{
this(loader, name, is, prefix, true);

View File

@ -0,0 +1,83 @@
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 org.apache.solr.cloud.ZkController;
import org.apache.solr.handler.component.ShardHandlerFactory;
import org.apache.solr.schema.IndexSchema;
import org.apache.zookeeper.KeeperException;
import java.io.File;
import java.util.List;
import java.util.Map;
import java.util.Properties;
/**
* ConfigSolr is a new interface to aid us in obsoleting solr.xml and replacing it with solr.properties. The problem here
* is that the Config class is used for _all_ the xml file, e.g. solrconfig.xml and we can't mess with _that_ as part
* of this issue. Primarily used in CoreContainer at present.
* <p/>
* This is already deprecated, it's only intended to exist for while transitioning to properties-based replacement for
* solr.xml
*
* @since solr 4.2
*/
@Deprecated
public interface ConfigSolr {
public static enum ConfLevel {
SOLR, SOLR_CORES, SOLR_CORES_CORE, SOLR_LOGGING, SOLR_LOGGING_WATCHER
}
;
public int getInt(ConfLevel level, String tag, int def);
public boolean getBool(ConfLevel level, String tag, boolean defValue);
public String get(ConfLevel level, String tag, String def);
public void substituteProperties();
public ShardHandlerFactory initShardHandler();
public Properties getSolrProperties(ConfigSolr cfg, String context);
public IndexSchema getSchemaFromZk(ZkController zkController, String zkConfigName, String schemaName,
SolrConfig config) throws KeeperException, InterruptedException;
public SolrConfig getSolrConfigFromZk(ZkController zkController, String zkConfigName, String solrConfigFileName,
SolrResourceLoader resourceLoader);
public void initPersist();
public void addPersistCore(String coreName, Properties attribs, Map<String, String> props);
public void addPersistAllCores(Properties containerProperties, Map<String, String> rootSolrAttribs, Map<String, String> coresAttribs,
File file);
public String getCoreNameFromOrig(String origCoreName, SolrResourceLoader loader, String coreName);
public List<String> getAllCoreNames();
public String getProperty(String coreName, String property, String defaultVal);
public Properties readCoreProperties(String coreName);
public Map<String, String> readCoreAttributes(String coreName);
}

View File

@ -0,0 +1,358 @@
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 org.apache.solr.cloud.ZkController;
import org.apache.solr.common.SolrException;
import org.apache.solr.handler.component.HttpShardHandlerFactory;
import org.apache.solr.handler.component.ShardHandlerFactory;
import org.apache.solr.schema.IndexSchema;
import org.apache.solr.util.DOMUtil;
import org.apache.solr.util.PropertiesUtil;
import org.apache.solr.util.SystemIdResolver;
import org.apache.zookeeper.KeeperException;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMResult;
import javax.xml.transform.dom.DOMSource;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
/**
* ConfigSolrXmlBackCompat
* <p/>
* This class is entirely to localize the backwards compatibility for dealing with specific issues when transitioning
* from solr.xml to a solr.properties-based, enumeration/discovery of defined cores. See SOLR-4196 for background.
* <p/>
* As of Solr 5.0, solr.xml will be deprecated, use SolrProperties.
*
* @since solr 4.2
* @deprecated use {@link org.apache.solr.core.SolrProperties} instead
*/
@Deprecated
public class ConfigSolrXmlBackCompat extends Config implements ConfigSolr {
private static Map<ConfLevel, String> prefixes;
private NodeList coreNodes = null;
static {
prefixes = new HashMap<ConfLevel, String>();
prefixes.put(ConfLevel.SOLR, "solr/@");
prefixes.put(ConfLevel.SOLR_CORES, "solr/cores/@");
prefixes.put(ConfLevel.SOLR_CORES_CORE, "solr/cores/core/@");
prefixes.put(ConfLevel.SOLR_LOGGING, "solr/logging/@");
prefixes.put(ConfLevel.SOLR_LOGGING_WATCHER, "solr/logging/watcher/@");
}
public ConfigSolrXmlBackCompat(SolrResourceLoader loader, String name, InputStream is, String prefix,
boolean subProps) throws ParserConfigurationException, IOException, SAXException {
super(loader, name, new InputSource(is), prefix, subProps);
coreNodes = (NodeList) evaluate("solr/cores/core",
XPathConstants.NODESET);
}
public ConfigSolrXmlBackCompat(SolrResourceLoader loader, Config cfg) throws TransformerException {
super(loader, null, copyDoc(cfg.getDocument())); // Mimics a call from CoreContainer.
coreNodes = (NodeList) evaluate("solr/cores/core",
XPathConstants.NODESET);
}
public static Document copyDoc(Document doc) throws TransformerException {
TransformerFactory tfactory = TransformerFactory.newInstance();
Transformer tx = tfactory.newTransformer();
DOMSource source = new DOMSource(doc);
DOMResult result = new DOMResult();
tx.transform(source, result);
return (Document) result.getNode();
}
@Override
public int getInt(ConfLevel level, String tag, int def) {
return getInt(prefixes.get(level) + tag, def);
}
@Override
public boolean getBool(ConfLevel level, String tag, boolean defValue) {
return getBool(prefixes.get(level) + tag, defValue);
}
@Override
public String get(ConfLevel level, String tag, String def) {
return get(prefixes.get(level) + tag, def);
}
public ShardHandlerFactory initShardHandler() {
PluginInfo info = null;
Node shfn = getNode("solr/cores/shardHandlerFactory", false);
if (shfn != null) {
info = new PluginInfo(shfn, "shardHandlerFactory", false, true);
} else {
Map m = new HashMap();
m.put("class", HttpShardHandlerFactory.class.getName());
info = new PluginInfo("shardHandlerFactory", m, null, Collections.<PluginInfo>emptyList());
}
HttpShardHandlerFactory fac = new HttpShardHandlerFactory();
if (info != null) {
fac.init(info);
}
return fac;
}
@Override
public Properties getSolrProperties(ConfigSolr cfg, String context) {
try {
return readProperties(((NodeList) evaluate(
context, XPathConstants.NODESET)).item(0));
} catch (Throwable e) {
SolrException.log(log, null, e);
}
return null;
}
Properties readProperties(Node node) throws XPathExpressionException {
XPath xpath = getXPath();
NodeList props = (NodeList) xpath.evaluate("property", node, XPathConstants.NODESET);
Properties properties = new Properties();
for (int i = 0; i < props.getLength(); i++) {
Node prop = props.item(i);
properties.setProperty(DOMUtil.getAttr(prop, "name"), DOMUtil.getAttr(prop, "value"));
}
return properties;
}
@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 = attribute.getNodeValue();
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;
}
public IndexSchema getSchemaFromZk(ZkController zkController, String zkConfigName, String schemaName,
SolrConfig config)
throws KeeperException, InterruptedException {
byte[] configBytes = zkController.getConfigFileData(zkConfigName, schemaName);
InputSource is = new InputSource(new ByteArrayInputStream(configBytes));
is.setSystemId(SystemIdResolver.createSystemIdFromResourceName(schemaName));
IndexSchema schema = new IndexSchema(config, schemaName, is);
return schema;
}
@Override
public SolrConfig getSolrConfigFromZk(ZkController zkController, String zkConfigName, String solrConfigFileName,
SolrResourceLoader resourceLoader) {
SolrConfig cfg = null;
try {
byte[] config = zkController.getConfigFileData(zkConfigName, solrConfigFileName);
InputSource is = new InputSource(new ByteArrayInputStream(config));
is.setSystemId(SystemIdResolver.createSystemIdFromResourceName(solrConfigFileName));
cfg = solrConfigFileName == null ? new SolrConfig(
resourceLoader, SolrConfig.DEFAULT_CONF_FILE, is) : new SolrConfig(
resourceLoader, solrConfigFileName, is);
} catch (Exception e) {
throw new SolrException(SolrException.ErrorCode.SERVER_ERROR,
"getSolrConfigFromZK failed for " + zkConfigName + " " + solrConfigFileName, e);
}
return cfg;
}
static List<SolrXMLSerializer.SolrCoreXMLDef> solrCoreXMLDefs = new ArrayList<SolrXMLSerializer.SolrCoreXMLDef>();
// Do this when re-using a ConfigSolrXmlBackCompat.
// These two methods are part of SOLR-4196 and are awkward, should go away with 5.0
@Override
public void initPersist() {
initPersistStatic();
}
public static void initPersistStatic() {
solrCoreXMLDefs = new ArrayList<SolrXMLSerializer.SolrCoreXMLDef>();
solrXMLSerializer = new SolrXMLSerializer();
}
@Override
public void addPersistCore(String coreName, Properties attribs, Map<String, String> props) {
addPersistCore(attribs, props);
}
static void addPersistCore(Properties props, Map<String, String> attribs) {
SolrXMLSerializer.SolrCoreXMLDef solrCoreXMLDef = new SolrXMLSerializer.SolrCoreXMLDef();
solrCoreXMLDef.coreAttribs = attribs;
solrCoreXMLDef.coreProperties = props;
solrCoreXMLDefs.add(solrCoreXMLDef);
}
private static SolrXMLSerializer solrXMLSerializer = new SolrXMLSerializer();
@Override
public void addPersistAllCores(Properties containerProperties, Map<String, String> rootSolrAttribs, Map<String, String> coresAttribs,
File file) {
addPersistAllCoresStatic(containerProperties, rootSolrAttribs, coresAttribs, file);
}
// Fortunately, we don't iterate over these too often, so the waste is probably tolerable.
@Override
public String getCoreNameFromOrig(String origCoreName, SolrResourceLoader loader, String coreName) {
// look for an existing node
synchronized (coreNodes) {
// first look for an exact match
Node coreNode = null;
for (int i = 0; i < coreNodes.getLength(); i++) {
Node node = coreNodes.item(i);
String name = DOMUtil.getAttr(node, CoreDescriptor.CORE_NAME, null);
if (origCoreName.equals(name)) {
if (coreName.equals(origCoreName)) {
return name;
}
return coreName;
}
}
if (coreNode == null) {
// see if we match with substitution
for (int i = 0; i < coreNodes.getLength(); i++) {
Node node = coreNodes.item(i);
String name = DOMUtil.getAttr(node, CoreDescriptor.CORE_NAME, null);
if (origCoreName.equals(PropertiesUtil.substituteProperty(name,
loader.getCoreProperties()))) {
if (coreName.equals(origCoreName)) {
return name;
}
return coreName;
}
}
}
}
return null;
}
@Override
public List<String> getAllCoreNames() {
List<String> ret = new ArrayList<String>();
synchronized (coreNodes) {
for (int idx = 0; idx < coreNodes.getLength(); ++idx) {
Node node = coreNodes.item(idx);
ret.add(DOMUtil.getAttr(node, CoreDescriptor.CORE_NAME, null));
}
}
return ret;
}
@Override
public String getProperty(String coreName, String property, String defaultVal) {
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))) {
return DOMUtil.getAttr(node, property, defaultVal);
}
}
}
return defaultVal;
}
@Override
public Properties readCoreProperties(String coreName) {
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))) {
try {
return readProperties(node);
} catch (XPathExpressionException e) {
return null;
}
}
}
}
return null;
}
static void addPersistAllCoresStatic(Properties containerProperties, Map<String, String> rootSolrAttribs, Map<String, String> coresAttribs,
File file) {
SolrXMLSerializer.SolrXMLDef solrXMLDef = new SolrXMLSerializer.SolrXMLDef();
solrXMLDef.coresDefs = solrCoreXMLDefs;
solrXMLDef.containerProperties = containerProperties;
solrXMLDef.solrAttribs = rootSolrAttribs;
solrXMLDef.coresAttribs = coresAttribs;
solrXMLSerializer.persistFile(file, solrXMLDef);
}
static final String DEF_SOLR_XML = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n"
+ "<solr persistent=\"false\">\n"
+ " <cores adminPath=\"/admin/cores\" defaultCoreName=\""
+ CoreContainer.DEFAULT_DEFAULT_CORE_NAME
+ "\""
+ " host=\"${host:}\" hostPort=\"${hostPort:}\" hostContext=\"${hostContext:}\" zkClientTimeout=\"${zkClientTimeout:15000}\""
+ ">\n"
+ " <core name=\""
+ CoreContainer.DEFAULT_DEFAULT_CORE_NAME
+ "\" shard=\"${shard:}\" collection=\"${collection:}\" instanceDir=\"collection1\" />\n"
+ " </cores>\n" + "</solr>";
}

File diff suppressed because it is too large Load Diff

View File

@ -20,6 +20,7 @@ package org.apache.solr.core;
import java.util.Properties;
import java.io.File;
import org.apache.commons.lang.StringUtils;
import org.apache.solr.cloud.CloudDescriptor;
/**
@ -28,29 +29,93 @@ import org.apache.solr.cloud.CloudDescriptor;
* @since solr 1.3
*/
public class CoreDescriptor {
protected String name;
protected String instanceDir;
protected String dataDir;
protected String ulogDir;
protected String configName;
protected String propertiesName;
protected String schemaName;
private final CoreContainer coreContainer;
private Properties coreProperties;
private boolean loadOnStartup = true;
private boolean isTransient = false;
// Properties file name constants
public static final String CORE_NAME = "name";
public static final String CORE_CONFIG = "config";
public static final String CORE_INSTDIR = "instanceDir";
public static final String CORE_DATADIR = "dataDir";
public static final String CORE_ULOGDIR = "ulogDir";
public static final String CORE_SCHEMA = "schema";
public static final String CORE_SHARD = "shard";
public static final String CORE_COLLECTION = "collection";
public static final String CORE_ROLES = "roles";
public static final String CORE_PROPERTIES = "properties";
public static final String CORE_LOADONSTARTUP = "loadOnStartup";
public static final String CORE_TRANSIENT = "transient";
public static final String CORE_NODE_NAME = "coreNodeName";
static final String[] standardPropNames = {
CORE_NAME,
CORE_CONFIG,
CORE_INSTDIR,
CORE_DATADIR,
CORE_ULOGDIR,
CORE_SCHEMA,
CORE_SHARD,
CORE_COLLECTION,
CORE_ROLES,
CORE_PROPERTIES,
CORE_LOADONSTARTUP,
CORE_TRANSIENT
};
// 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();
private final CoreContainer coreContainer;
private CloudDescriptor cloudDesc;
public CoreDescriptor(CoreContainer coreContainer, String name, String instanceDir) {
this.coreContainer = coreContainer;
this.name = name;
private CoreDescriptor(CoreContainer cont) {
// Just a place to put initialization since it's a pain to add to the descriptor in every c'tor.
this.coreContainer = cont;
coreProperties.put(CORE_LOADONSTARTUP, "true");
coreProperties.put(CORE_TRANSIENT, "false");
}
public CoreDescriptor(CoreContainer container, String name, String instanceDir) {
this(container);
doInit(name, instanceDir);
}
public CoreDescriptor(CoreDescriptor descr) {
this(descr.coreContainer);
coreProperties.put(CORE_INSTDIR, descr.getInstanceDir());
coreProperties.put(CORE_CONFIG, descr.getConfigName());
coreProperties.put(CORE_SCHEMA, descr.getSchemaName());
coreProperties.put(CORE_NAME, descr.getName());
coreProperties.put(CORE_DATADIR, descr.getDataDir());
}
/**
* CoreDescriptor - create a core descriptor given default properties from a core.properties file. This will be
* 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.
* @param propsIn - A properties structure "core.properties" found while walking the file tree to discover cores.
* Any properties set in this param will overwrite the any defaults.
*/
public CoreDescriptor(CoreContainer container, Properties propsIn) {
this(container);
// Set some default, normalize a directory or two
doInit(propsIn.getProperty(CORE_NAME), propsIn.getProperty(CORE_INSTDIR));
coreProperties.putAll(propsIn);
}
private void doInit(String name, String instanceDir) {
if (name == null) {
throw new RuntimeException("Core needs a name");
}
coreProperties.put(CORE_NAME, name);
if(coreContainer != null && coreContainer.getZkController() != null) {
this.cloudDesc = new CloudDescriptor();
// cloud collection defaults to core name
@ -61,27 +126,18 @@ public class CoreDescriptor {
throw new NullPointerException("Missing required \'instanceDir\'");
}
instanceDir = SolrResourceLoader.normalizeDir(instanceDir);
this.instanceDir = instanceDir;
this.configName = getDefaultConfigName();
this.schemaName = getDefaultSchemaName();
coreProperties.put(CORE_INSTDIR, instanceDir);
coreProperties.put(CORE_CONFIG, getDefaultConfigName());
coreProperties.put(CORE_SCHEMA, getDefaultSchemaName());
}
public CoreDescriptor(CoreDescriptor descr) {
this.instanceDir = descr.instanceDir;
this.configName = descr.configName;
this.schemaName = descr.schemaName;
this.name = descr.name;
this.dataDir = descr.dataDir;
coreContainer = descr.coreContainer;
}
private Properties initImplicitProperties() {
public Properties initImplicitProperties() {
Properties implicitProperties = new Properties(coreContainer.getContainerProperties());
implicitProperties.setProperty("solr.core.name", name);
implicitProperties.setProperty("solr.core.instanceDir", instanceDir);
implicitProperties.setProperty("solr.core.dataDir", getDataDir());
implicitProperties.setProperty("solr.core.configName", configName);
implicitProperties.setProperty("solr.core.schemaName", schemaName);
implicitProperties.setProperty(CORE_NAME, getName());
implicitProperties.setProperty(CORE_INSTDIR, getInstanceDir());
implicitProperties.setProperty(CORE_DATADIR, getDataDir());
implicitProperties.setProperty(CORE_CONFIG, getConfigName());
implicitProperties.setProperty(CORE_SCHEMA, getSchemaName());
return implicitProperties;
}
@ -101,41 +157,47 @@ public class CoreDescriptor {
}
public String getPropertiesName() {
return propertiesName;
return coreProperties.getProperty(CORE_PROPERTIES);
}
public void setPropertiesName(String propertiesName) {
this.propertiesName = propertiesName;
coreProperties.put(CORE_PROPERTIES, propertiesName);
}
public String getDataDir() {
String dataDir = this.dataDir;
if (dataDir == null) dataDir = getDefaultDataDir();
String dataDir = coreProperties.getProperty(CORE_DATADIR);
if (dataDir == null) {
dataDir = getDefaultDataDir();
}
if (new File(dataDir).isAbsolute()) {
return dataDir;
} else {
if (new File(instanceDir).isAbsolute()) {
return SolrResourceLoader.normalizeDir(SolrResourceLoader.normalizeDir(instanceDir) + dataDir);
if (new File(getInstanceDir()).isAbsolute()) {
return SolrResourceLoader.normalizeDir(SolrResourceLoader.normalizeDir(getInstanceDir()) + dataDir);
} else {
return SolrResourceLoader.normalizeDir(coreContainer.getSolrHome() +
SolrResourceLoader.normalizeDir(instanceDir) + dataDir);
SolrResourceLoader.normalizeDir(getRawInstanceDir()) + dataDir);
}
}
}
public void setDataDir(String s) {
dataDir = s;
// normalize zero length to null.
if (dataDir != null && dataDir.length()==0) dataDir=null;
if (StringUtils.isBlank(s)) {
coreProperties.remove(s);
} else {
coreProperties.put(CORE_DATADIR, s);
}
}
public boolean usingDefaultDataDir() {
return this.dataDir == null;
// DO NOT use the getDataDir method here since it'll assign something regardless.
return coreProperties.getProperty(CORE_DATADIR) == null;
}
/**@return the core instance directory. */
public String getRawInstanceDir() {
return this.instanceDir;
return coreProperties.getProperty(CORE_INSTDIR);
}
/**
@ -143,42 +205,44 @@ public class CoreDescriptor {
* @return the core instance directory, prepended with solr_home if not an absolute path.
*/
public String getInstanceDir() {
String instDir = this.instanceDir;
String instDir = coreProperties.getProperty(CORE_INSTDIR);
if (instDir == null) return null; // No worse than before.
if (new File(instDir).isAbsolute()) {
return SolrResourceLoader.normalizeDir(SolrResourceLoader.normalizeDir(instanceDir));
return SolrResourceLoader.normalizeDir(
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");
this.configName = name;
coreProperties.put(CORE_CONFIG, name);
}
/**@return the core configuration resource name. */
public String getConfigName() {
return this.configName;
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");
this.schemaName = name;
coreProperties.put(CORE_SCHEMA, name);
}
/**@return the core schema resource name. */
public String getSchemaName() {
return this.schemaName;
return coreProperties.getProperty(CORE_SCHEMA);
}
/**@return the initial core name */
public String getName() {
return this.name;
return coreProperties.getProperty(CORE_NAME);
}
public CoreContainer getCoreContainer() {
@ -192,15 +256,19 @@ public class CoreDescriptor {
/**
* 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
* set to this method will have different (less) key/value pairs than the Properties
* 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 (this.coreProperties == null) {
Properties p = initImplicitProperties();
this.coreProperties = new Properties(p);
if(coreProperties != null)
this.coreProperties.putAll(coreProperties);
}
// 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);
}
}
@ -212,26 +280,59 @@ public class CoreDescriptor {
this.cloudDesc = cloudDesc;
}
public boolean isLoadOnStartup() {
return loadOnStartup;
String tmp = coreProperties.getProperty(CORE_LOADONSTARTUP, "false");
return Boolean.parseBoolean(tmp);
}
public void setLoadOnStartup(boolean loadOnStartup) {
this.loadOnStartup = loadOnStartup;
coreProperties.put(CORE_LOADONSTARTUP, Boolean.toString(loadOnStartup));
}
public boolean isTransient() {
return isTransient;
String tmp = coreProperties.getProperty(CORE_TRANSIENT, "false");
return (Boolean.parseBoolean(tmp));
}
public void setTransient(boolean aTransient) {
this.isTransient = aTransient;
public void setTransient(boolean isTransient) {
coreProperties.put(CORE_TRANSIENT, Boolean.toString(isTransient));
}
public String getUlogDir() {
return ulogDir;
return coreProperties.getProperty(CORE_ULOGDIR);
}
public void setUlogDir(String ulogDir) {
this.ulogDir = ulogDir;
coreProperties.put(CORE_ULOGDIR, ulogDir);
}
/**
* Reads a property defined in the core.properties file that's replacing solr.xml (if present).
* @param prop - value to read from the properties structure.
* @param defVal - return if no property found.
* @return associated string. May be null.
*/
public String getProperty(String prop, String defVal) {
return coreProperties.getProperty(prop, defVal);
}
/**
* gReads a property defined in the core.properties file that's replacing solr.xml (if present).
* @param prop value to read from the properties structure.
* @return associated string. May be null.
*/
public String getProperty(String prop) {
return coreProperties.getProperty(prop);
}
/**
* This will eventually replace _all_ of the setters. Puts a value in the "new" (obsoleting solr.xml JIRAs) properties
* structures.
*
* Will replace any currently-existing property with the key "prop".
*
* @param prop - property name
* @param val - property value
*/
public void putProperty(String prop, String val) {
coreProperties.put(prop, val);
}
}

View File

@ -657,12 +657,15 @@ public final class SolrCore implements SolrInfoMBean {
this.setName( name );
resourceLoader = config.getResourceLoader();
if (dataDir == null){
if(cd.usingDefaultDataDir()) dataDir = config.getDataDir();
if(dataDir == null) dataDir = cd.getDataDir();
if(cd.usingDefaultDataDir()) {
dataDir = config.getDataDir();
}
if(dataDir == null) {
dataDir = cd.getDataDir();
}
}
dataDir = SolrResourceLoader.normalizeDir(dataDir);
log.info(logid+"Opening new SolrCore at " + resourceLoader.getInstanceDir() + ", dataDir="+dataDir);
if (schema==null) {
@ -1316,7 +1319,7 @@ public final class SolrCore implements SolrInfoMBean {
*
* This method acquires openSearcherLock - do not call with searckLock held!
*/
public RefCounted<SolrIndexSearcher> openNewSearcher(boolean updateHandlerReopens, boolean realtime) {
public RefCounted<SolrIndexSearcher> openNewSearcher(boolean updateHandlerReopens, boolean realtime) {
SolrIndexSearcher tmp;
RefCounted<SolrIndexSearcher> newestSearcher = null;
boolean nrt = solrConfig.reopenReaders && updateHandlerReopens;

View File

@ -0,0 +1,575 @@
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 org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.solr.cloud.ZkController;
import org.apache.solr.common.SolrException;
import org.apache.solr.common.util.NamedList;
import org.apache.solr.handler.component.HttpShardHandlerFactory;
import org.apache.solr.handler.component.ShardHandlerFactory;
import org.apache.solr.schema.IndexSchema;
import org.apache.solr.util.PropertiesUtil;
import org.apache.solr.util.SystemIdResolver;
import org.apache.zookeeper.KeeperException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xml.sax.InputSource;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
/**
* This is the new way of dealing with solr properties replacing solr.xml. This is simply a high-level set of
* properties. Cores are no longer defined in the solr.xml file, they are discovered by enumerating all of the
* directories under the base path and creating cores as necessary.
*
* @since Solr 4.2
*/
public class SolrProperties implements ConfigSolr {
public final static String SOLR_PROPERTIES_FILE = "solr.properties";
public final static String SOLR_XML_FILE = "solr.xml";
final static String CORE_PROP_FILE = "core.properties";
private final static String SHARD_HANDLER_FACTORY = "shardHandlerFactory";
private final static String SHARD_HANDLER_NAME = SHARD_HANDLER_FACTORY + ".name";
private final static String SHARD_HANDLER_CLASS = SHARD_HANDLER_FACTORY + ".class";
public static final Logger log = LoggerFactory.getLogger(SolrProperties.class);
protected final CoreContainer container;
protected Properties solrProperties = new Properties();
protected final Properties origsolrprops = new Properties();
protected String name;
protected SolrResourceLoader loader;
private final Map<String, CoreDescriptorPlus> coreDescriptorPlusMap = new HashMap<String, CoreDescriptorPlus>();
private static Map<ConfLevel, String> prefixesprefixes;
static {
prefixesprefixes = new HashMap<ConfLevel, String>();
prefixesprefixes.put(ConfLevel.SOLR_CORES, "cores.");
prefixesprefixes.put(ConfLevel.SOLR_LOGGING, "logging.");
prefixesprefixes.put(ConfLevel.SOLR_LOGGING_WATCHER, "logging.watcher.");
}
/**
* Create a SolrProperties object given just the resource loader
*
* @param container - the container for this Solr instance. There should be one and only one...
* @param loader - Solr resource loader
* @param solrCfg - a config file whose values will be transferred to the properties object that can be changed
* @throws IOException - It's possible to walk a very deep tree, if that process goes awry, or if reading any
* of the files found doesn't work, you'll get an IO exception
*/
SolrProperties(CoreContainer container, SolrResourceLoader loader, SolrProperties solrCfg) throws IOException {
origsolrprops.putAll(solrCfg.getOriginalProperties());
this.loader = loader;
this.container = container;
init(solrCfg.name);
}
/**
* Create a SolrProperties object from an opened input stream, useful for creating defaults
*
* @param container - the container for this Solr instance. There should be one and only one...
* @param is - Input stream for loading properties.
* @param fileName - the name for this properties object.
* @throws IOException - It's possible to walk a very deep tree, if that process goes awry, or if reading any
* of the files found doesn't work, you'll get an IO exception
*/
public SolrProperties(CoreContainer container, InputStream is, String fileName) throws IOException {
origsolrprops.load(is);
this.container = container;
init(fileName);
}
//Just localize the common constructor operations
private void init(String name) throws IOException {
this.name = name;
for (String s : origsolrprops.stringPropertyNames()) {
solrProperties.put(s, System.getProperty(s, origsolrprops.getProperty(s)));
}
synchronized (coreDescriptorPlusMap) {
walkFromHere(new File(container.getSolrHome()), container);
}
}
// Just localizes default substitution and the ability to log an error if the value isn't present.
private String getVal(String path, boolean errIfMissing, String defVal) {
String val = solrProperties.getProperty(path, defVal);
if (StringUtils.isNotBlank(val)) {
log.debug(name + ' ' + path + val);
return val;
}
if (!errIfMissing) {
log.debug(name + "missing optional " + path);
return null;
}
throw new RuntimeException(name + " missing " + path);
}
/**
* Get a property and convert it to a boolean value. Does not log a message if the value is absent
*
* @param prop - name of the property to fetch
* @param defValue - value to return if the property is absent
* @return property value or default if property is not present.
*/
public boolean getBool(String prop, boolean defValue) {
String def = defValue ? "true" : "false";
String val = getVal(prop, false, def);
return (StringUtils.equalsIgnoreCase(val, "true"));
}
/**
* Fetch a string value, for the given property. Does not log a message if the valued is absent.
*
* @param prop - the property name to fetch
* @param def - the default value to return if not present
* @return - the fetched property or the default value if the property is absent
*/
public String get(String prop, String def) {
String val = getVal(prop, false, def);
if (val == null || val.length() == 0) {
return def;
}
return val;
}
/**
* Fetch the string value of the property. May log a message and returns null if absent
*
* @param prop - the name of the property to fetch
* @param errIfMissing - if true, log a message that the property is not present
* @return - the property value or null if absent
*/
public String getVal(String prop, boolean errIfMissing) {
return getVal(prop, errIfMissing, null);
}
/**
* Returns a property as an integer
*
* @param prop - the name of the property to fetch
* @param defVal - the value to return if the property is missing
* @return - the fetch property as an int or the def value if absent
*/
public int getInt(String prop, int defVal) {
String val = getVal(prop, false, Integer.toString(defVal));
return Integer.parseInt(val);
}
@Override
public int getInt(ConfLevel level, String tag, int def) {
return getInt(prefixesprefixes.get(level) + tag, def);
}
@Override
public boolean getBool(ConfLevel level, String tag, boolean defValue) {
return getBool(prefixesprefixes.get(level) + tag, defValue);
}
@Override
public String get(ConfLevel level, String tag, String def) {
return get(prefixesprefixes.get(level) + tag, def);
}
/**
* For all values in the properties structure, find if any system properties are defined and substitute them.
*/
public void substituteProperties() {
for (String prop : solrProperties.stringPropertyNames()) {
String subProp = PropertiesUtil.substituteProperty(solrProperties.getProperty(prop), solrProperties);
if (subProp != null && !subProp.equals(solrProperties.getProperty(prop))) {
solrProperties.put(prop, subProp);
}
}
}
/**
* Fetches the properties as originally read from the properties file without any system variable substitution
*
* @return - a copy of the original properties.
*/
public Properties getOriginalProperties() {
Properties ret = new Properties();
ret.putAll(origsolrprops);
return ret;
}
@Override
public ShardHandlerFactory initShardHandler(/*boolean isTest*/) {
PluginInfo info = null;
Map<String, String> attrs = new HashMap<String, String>();
NamedList args = new NamedList();
boolean haveHandler = false;
for (String s : solrProperties.stringPropertyNames()) {
String val = solrProperties.getProperty(s);
if (s.indexOf(SHARD_HANDLER_FACTORY) != -1) {
haveHandler = true;
if (SHARD_HANDLER_NAME.equals(s) || SHARD_HANDLER_CLASS.equals(s)) {
attrs.put(s, val);
} else {
args.add(s, val);
}
}
}
if (haveHandler) {
// public PluginInfo(String type, Map<String, String> attrs ,NamedList initArgs, List<PluginInfo> children) {
info = new PluginInfo(SHARD_HANDLER_FACTORY, attrs, args, null);
} else {
Map m = new HashMap();
m.put("class", HttpShardHandlerFactory.class.getName());
info = new PluginInfo("shardHandlerFactory", m, null, Collections.<PluginInfo>emptyList());
}
HttpShardHandlerFactory fac = new HttpShardHandlerFactory();
if (info != null) {
fac.init(info);
}
return fac;
}
// Strictly for compatibility with i'face. TODO: remove for 5.0
@Override
public Properties getSolrProperties(ConfigSolr cfg, String context) {
return getSolrProperties();
}
/**
* Return the original properties that were defined, without substitutions from solr.properties
*
* @return - the Properties as originally defined.
*/
public Properties getSolrProperties() {
return solrProperties;
}
/**
* given a core and attributes, find the core.properties file from whence it came and update it with the current
* <p/>
* Note, when the cores were discovered, we stored away the path that it came from for reference later. Remember
* that these cores aren't necessarily loaded all the time, they may be transient.
* It's not clear what the magic is that the calling methods (see CoreContainer) are doing, but they seem to be
* "doing the right thing" so that the attribs properties are the ones that contain the correct data. All the
* tests pass, but it's magic at this point.
*
* @param coreName - the core whose attributes we are to change
* @param attribs - the attribs to change to, see note above.
* @param props - ignored, here to make the i'face work in combination with ConfigSolrXmlBackCompat
*/
@Override
public void addPersistCore(String coreName, Properties attribs, Map<String, String> props) {
String val = container.getContainerProperties().getProperty("solr.persistent", "false");
if (!Boolean.parseBoolean(val)) return;
CoreDescriptorPlus plus;
plus = coreDescriptorPlusMap.get(coreName);
if (plus == null) {
log.error("Expected to find core for persisting, but we did not. Core: " + coreName);
return;
}
Properties outProps = new Properties();
// I don't quite get this, but somehow the attribs passed in are the originals (plus any newly-added ones). Never
// one to look a gift horse in the mouth I'll just use that.
// Take care NOT to write out properties like ${blah blah blah}
outProps.putAll(attribs);
Properties corePropsOrig = plus.getPropsOrig();
for (String prop : corePropsOrig.stringPropertyNames()) {
val = corePropsOrig.getProperty(prop);
if (val.indexOf("$") != -1) { // it was originally a system property, keep it so
outProps.put(prop, val);
continue;
}
// Make sure anything that used to be in the properties file still is.
if (outProps.getProperty(prop) == null) {
outProps.put(prop, val);
}
}
// Any of our standard properties that weren't in the original properties file should NOT be persisted, I think
for (String prop : CoreDescriptor.standardPropNames) {
if (corePropsOrig.getProperty(prop) == null) {
outProps.remove(prop);
}
}
try {
outProps.store(new FileOutputStream(plus.getFilePath()), null);
} catch (IOException e) {
log.error("Failed to persist core {}, filepath {}", coreName, plus.getFilePath());
}
}
/**
* PersistSolrProperties persists the Solr.properties file only,
* <p/>
* The old version (i.e. using solr.xml) persisted _everything_ in a single file. This version will just
* persist the solr.properties file for an individual core.
* The individual cores were persisted in addPersistCore calls above.
*/
// It seems like a lot of this could be done by using the Properties defaults
/**
* PersistSolrProperties persists the Solr.properties file only,
* <p/>
* The old version (i.e. using solr.xml) persisted _everything_ in a single file. This version will just
* persist the solr.properties file for an individual core.
* The individual cores were persisted in addPersistCore calls above.
* <p/>
* TODO: Remove all parameters for 5.0 when we obsolete ConfigSolrXmlBackCompat
*
* @param containerProperties - ignored, here for back compat.
* @param rootSolrAttribs - ignored, here for back compat.
* @param coresAttribs - ignored, here for back compat.
* @param file - ignored, here for back compat.
*/
@Override
public void addPersistAllCores(Properties containerProperties, Map<String, String> rootSolrAttribs,
Map<String, String> coresAttribs, File file) {
String val = container.getContainerProperties().getProperty("solr.persistent", "false");
if (!Boolean.parseBoolean(val)) return;
// First persist solr.properties
File parent = new File(container.getSolrHome());
File props = new File(parent, SOLR_PROPERTIES_FILE);
Properties propsOut = new Properties();
propsOut.putAll(container.getContainerProperties());
for (String prop : origsolrprops.stringPropertyNames()) {
String toTest = origsolrprops.getProperty(prop);
if (toTest.indexOf("$") != -1) { // Don't store away things that should be system properties
propsOut.put(prop, toTest);
}
}
try {
propsOut.store(new FileOutputStream(props), null);
} catch (IOException e) {
log.error("Failed to persist file " + props.getAbsolutePath(), e);
}
}
// Copied verbatim from the old code, presumably this will be tested when we eliminate solr.xml
@Override
public IndexSchema getSchemaFromZk(ZkController zkController, String zkConfigName, String schemaName,
SolrConfig config)
throws KeeperException, InterruptedException {
byte[] configBytes = zkController.getConfigFileData(zkConfigName, schemaName);
InputSource is = new InputSource(new ByteArrayInputStream(configBytes));
is.setSystemId(SystemIdResolver.createSystemIdFromResourceName(schemaName));
IndexSchema schema = new IndexSchema(config, schemaName, is);
return schema;
}
// Copied verbatim from the old code, presumably this will be tested when we eliminate solr.xml
@Override
public SolrConfig getSolrConfigFromZk(ZkController zkController, String zkConfigName, String solrConfigFileName,
SolrResourceLoader resourceLoader) {
SolrConfig cfg = null;
try {
byte[] config = zkController.getConfigFileData(zkConfigName, solrConfigFileName);
InputSource is = new InputSource(new ByteArrayInputStream(config));
is.setSystemId(SystemIdResolver.createSystemIdFromResourceName(solrConfigFileName));
cfg = solrConfigFileName == null ? new SolrConfig(
resourceLoader, SolrConfig.DEFAULT_CONF_FILE, is) : new SolrConfig(
resourceLoader, solrConfigFileName, is);
} catch (Exception e) {
throw new SolrException(SolrException.ErrorCode.SERVER_ERROR,
"getSolrConfigFromZK failed for " + zkConfigName + " " + solrConfigFileName, e);
}
return cfg;
}
@Override
public void initPersist() {
//NOOP
}
// Basic recursive tree walking, looking for "core.properties" files. Once one is found, we'll stop going any
// deeper in the tree.
//
// @param file - the directory we're to either read the properties file from or recurse into.
private void walkFromHere(File file, CoreContainer container) throws IOException {
log.info("Looking for cores in " + file.getAbsolutePath());
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 top recursing deep but continue looking wide.
File propFile = new File(childFile, CORE_PROP_FILE);
if (propFile.exists()) { // Stop looking after processing this file!
log.info("Discovered properties file {}, adding to cores", propFile.getAbsolutePath());
Properties propsOrig = new Properties();
propsOrig.load(new FileInputStream(propFile));
Properties props = new Properties();
for (String prop : propsOrig.stringPropertyNames()) {
props.put(prop, PropertiesUtil.substituteProperty(propsOrig.getProperty(prop), null));
}
if (props.getProperty(CoreDescriptor.CORE_INSTDIR) == null) {
props.setProperty(CoreDescriptor.CORE_INSTDIR, childFile.getPath());
}
if (props.getProperty(CoreDescriptor.CORE_NAME) == null) {
// Should default to this directory
props.setProperty(CoreDescriptor.CORE_NAME, file.getName());
}
CoreDescriptor desc = new CoreDescriptor(container, props);
CoreDescriptorPlus plus = new CoreDescriptorPlus(propFile.getAbsolutePath(), desc, propsOrig);
coreDescriptorPlusMap.put(desc.getName(), plus);
continue; // Go on to the sibling directory
}
if (childFile.isDirectory()) {
walkFromHere(childFile, container);
}
}
}
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
public String getCoreNameFromOrig(String origCoreName, SolrResourceLoader loader, String coreName) {
// first look for an exact match
for (Map.Entry<String, CoreDescriptorPlus> ent : coreDescriptorPlusMap.entrySet()) {
String name = ent.getValue().getCoreDescriptor().getProperty(CoreDescriptor.CORE_NAME, null);
if (origCoreName.equals(name)) {
if (coreName.equals(origCoreName)) {
return name;
}
return coreName;
}
}
for (Map.Entry<String, CoreDescriptorPlus> ent : coreDescriptorPlusMap.entrySet()) {
String name = ent.getValue().getCoreDescriptor().getProperty(CoreDescriptor.CORE_NAME, null);
// see if we match with substitution
if (origCoreName.equals(PropertiesUtil.substituteProperty(name, loader.getCoreProperties()))) {
if (coreName.equals(origCoreName)) {
return name;
}
return coreName;
}
}
return null;
}
@Override
public List<String> getAllCoreNames() {
List<String> ret;
ret = new ArrayList<String>(coreDescriptorPlusMap.keySet());
return ret;
}
@Override
public String getProperty(String coreName, String property, String defaultVal) {
CoreDescriptorPlus plus = coreDescriptorPlusMap.get(coreName);
if (plus == null) return defaultVal;
CoreDescriptor desc = plus.getCoreDescriptor();
if (desc == null) return defaultVal;
return desc.getProperty(property, defaultVal);
}
@Override
public Properties readCoreProperties(String coreName) {
CoreDescriptorPlus plus = coreDescriptorPlusMap.get(coreName);
if (plus == null) return null;
return new Properties(plus.getCoreDescriptor().getCoreProperties());
}
@Override
public Map<String, String> readCoreAttributes(String coreName) {
return new HashMap<String, String>(); // Should be a no-op.
}
}
// It's mightily convenient to have all of the original path names and property values when persisting cores, so
// this little convenience class is just for that.
// Also, let's keep track of anything we added here, especially the instance dir for persistence purposes. We don't
// want, for instance, to persist instanceDir if it was not specified originally.
//
// I suspect that for persistence purposes, we may want to expand this idea to record, say, ${blah}
class CoreDescriptorPlus {
private CoreDescriptor coreDescriptor;
private String filePath;
private Properties propsOrig;
CoreDescriptorPlus(String filePath, CoreDescriptor descriptor, Properties propsOrig) {
coreDescriptor = descriptor;
this.filePath = filePath;
this.propsOrig = propsOrig;
}
CoreDescriptor getCoreDescriptor() {
return coreDescriptor;
}
String getFilePath() {
return filePath;
}
Properties getPropsOrig() {
return propsOrig;
}
}

View File

@ -83,6 +83,7 @@ public class SolrResourceLoader implements ResourceLoader
private final List<ResourceLoaderAware> waitingForResources = Collections.synchronizedList(new ArrayList<ResourceLoaderAware>());
private static final Charset UTF_8 = Charset.forName("UTF-8");
//TODO: Solr5. Remove this completely when you obsolete putting <core> tags in solr.xml (See Solr-4196)
private final Properties coreProperties;
private volatile boolean live;
@ -105,7 +106,7 @@ public class SolrResourceLoader implements ResourceLoader
this.instanceDir);
} else{
this.instanceDir = normalizeDir(instanceDir);
log.info("new SolrResourceLoader for directory: '{}'",
log.info("new SolrResourceLoader for directory: '{}'",
this.instanceDir);
}

View File

@ -32,6 +32,7 @@ import java.util.Properties;
import javax.xml.parsers.ParserConfigurationException;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.store.Directory;
import org.apache.lucene.util.IOUtils;
@ -661,7 +662,7 @@ public class CoreAdminHandler extends RequestHandlerBase {
try {
if (cname == null) {
rsp.add("defaultCoreName", coreContainer.getDefaultCoreName());
for (String name : coreContainer.getCoreNames()) {
for (String name : coreContainer.getAllCoreNames()) {
status.add(name, getCoreStatus(coreContainer, name, isIndexInfoNeeded));
}
rsp.add("initFailures", allFailures);
@ -954,38 +955,65 @@ public class CoreAdminHandler extends RequestHandlerBase {
}
protected NamedList<Object> getCoreStatus(CoreContainer cores, String cname, boolean isIndexInfoNeeded) throws IOException {
/**
* Returns the core status for a particular core.
* @param cores - the enclosing core container
* @param cname - the core to return
* @param isIndexInfoNeeded - add what may be expensive index information. NOT returned if the core is not loaded
* @return - a named list of key/value pairs from the core.
* @throws IOException - LukeRequestHandler can throw an I/O exception
*/
protected NamedList<Object> getCoreStatus(CoreContainer cores, String cname, boolean isIndexInfoNeeded) throws IOException {
NamedList<Object> info = new SimpleOrderedMap<Object>();
SolrCore core = cores.getCore(cname);
if (core != null) {
try {
info.add("name", core.getName());
info.add("isDefaultCore", core.getName().equals(cores.getDefaultCoreName()));
info.add("instanceDir", normalizePath(core.getResourceLoader().getInstanceDir()));
info.add("dataDir", normalizePath(core.getDataDir()));
info.add("config", core.getConfigResource());
info.add("schema", core.getSchemaResource());
info.add("startTime", new Date(core.getStartTime()));
info.add("uptime", System.currentTimeMillis() - core.getStartTime());
if (isIndexInfoNeeded) {
RefCounted<SolrIndexSearcher> searcher = core.getSearcher();
try {
SimpleOrderedMap<Object> indexInfo = LukeRequestHandler.getIndexInfo(searcher.get().getIndexReader());
long size = getIndexSize(core);
indexInfo.add("sizeInBytes", size);
indexInfo.add("size", NumberUtils.readableSize(size));
info.add("index", indexInfo);
} finally {
searcher.decref();
if (!cores.isLoaded(cname)) { // Lazily-loaded core, fill in what we can.
// It would be a real mistake to load the cores just to get the status
CoreDescriptor desc = cores.getUnloadedCoreDescriptor(cname);
if (desc != null) {
info.add("name", desc.getName());
info.add("isDefaultCore", desc.getName().equals(cores.getDefaultCoreName()));
info.add("instanceDir", desc.getInstanceDir());
// None of the following are guaranteed to be present in a not-yet-loaded core.
String tmp = desc.getDataDir();
if (StringUtils.isNotBlank(tmp)) info.add("dataDir", tmp);
tmp = desc.getConfigName();
if (StringUtils.isNotBlank(tmp)) info.add("config", tmp);
tmp = desc.getSchemaName();
if (StringUtils.isNotBlank(tmp)) info.add("schema", tmp);
info.add("isLoaded", "false");
}
} else {
SolrCore core = cores.getCore(cname);
if (core != null) {
try {
info.add("name", core.getName());
info.add("isDefaultCore", core.getName().equals(cores.getDefaultCoreName()));
info.add("instanceDir", normalizePath(core.getResourceLoader().getInstanceDir()));
info.add("dataDir", normalizePath(core.getDataDir()));
info.add("config", core.getConfigResource());
info.add("schema", core.getSchemaResource());
info.add("startTime", new Date(core.getStartTime()));
info.add("uptime", System.currentTimeMillis() - core.getStartTime());
if (isIndexInfoNeeded) {
RefCounted<SolrIndexSearcher> searcher = core.getSearcher();
try {
SimpleOrderedMap<Object> indexInfo = LukeRequestHandler.getIndexInfo(searcher.get().getIndexReader());
long size = getIndexSize(core);
indexInfo.add("sizeInBytes", size);
indexInfo.add("size", NumberUtils.readableSize(size));
info.add("index", indexInfo);
} finally {
searcher.decref();
}
}
} finally {
core.close();
}
} finally {
core.close();
}
}
return info;
}
private long getIndexSize(SolrCore core) {
Directory dir;
long size = 0;

View File

@ -58,7 +58,7 @@ public final class SchemaField extends FieldProperties {
/** Create a new SchemaField with the given name and type,
* and with the specified properties. Properties are *not*
* inherited from the type in this case, so users of this
* constructor should derive the properties from type.getProperties()
* constructor should derive the properties from type.getSolrProperties()
* using all the default properties from the type.
*/
public SchemaField(String name, FieldType type, int properties, String defaultValue ) {

View File

@ -289,117 +289,18 @@ public class DOMUtil {
// handle child by node type
if (child.getNodeType() == Node.TEXT_NODE) {
child.setNodeValue(substituteProperty(child.getNodeValue(), properties));
child.setNodeValue(PropertiesUtil.substituteProperty(child.getNodeValue(), properties));
} else if (child.getNodeType() == Node.ELEMENT_NODE) {
// handle child elements with recursive call
NamedNodeMap attributes = child.getAttributes();
for (int i = 0; i < attributes.getLength(); i++) {
Node attribute = attributes.item(i);
attribute.setNodeValue(substituteProperty(attribute.getNodeValue(), properties));
attribute.setNodeValue(PropertiesUtil.substituteProperty(attribute.getNodeValue(), properties));
}
substituteProperties(child, properties);
}
}
}
/*
* This method borrowed from Ant's PropertyHelper.replaceProperties:
* http://svn.apache.org/repos/asf/ant/core/trunk/src/main/org/apache/tools/ant/PropertyHelper.java
*/
public static String substituteProperty(String value, Properties coreProperties) {
if (value == null || value.indexOf('$') == -1) {
return value;
}
List<String> fragments = new ArrayList<String>();
List<String> propertyRefs = new ArrayList<String>();
parsePropertyString(value, fragments, propertyRefs);
StringBuilder sb = new StringBuilder();
Iterator<String> i = fragments.iterator();
Iterator<String> j = propertyRefs.iterator();
while (i.hasNext()) {
String fragment = i.next();
if (fragment == null) {
String propertyName = j.next();
String defaultValue = null;
int colon_index = propertyName.indexOf(':');
if (colon_index > -1) {
defaultValue = propertyName.substring(colon_index + 1);
propertyName = propertyName.substring(0,colon_index);
}
if (coreProperties != null) {
fragment = coreProperties.getProperty(propertyName);
}
if (fragment == null) {
fragment = System.getProperty(propertyName, defaultValue);
}
if (fragment == null) {
throw new SolrException( SolrException.ErrorCode.SERVER_ERROR, "No system property or default value specified for " + propertyName + " value:" + value);
}
}
sb.append(fragment);
}
return sb.toString();
}
/*
* This method borrowed from Ant's PropertyHelper.parsePropertyStringDefault:
* http://svn.apache.org/repos/asf/ant/core/trunk/src/main/org/apache/tools/ant/PropertyHelper.java
*/
private static void parsePropertyString(String value, List<String> fragments, List<String> propertyRefs) {
int prev = 0;
int pos;
//search for the next instance of $ from the 'prev' position
while ((pos = value.indexOf("$", prev)) >= 0) {
//if there was any text before this, add it as a fragment
//TODO, this check could be modified to go if pos>prev;
//seems like this current version could stick empty strings
//into the list
if (pos > 0) {
fragments.add(value.substring(prev, pos));
}
//if we are at the end of the string, we tack on a $
//then move past it
if (pos == (value.length() - 1)) {
fragments.add("$");
prev = pos + 1;
} else if (value.charAt(pos + 1) != '{') {
//peek ahead to see if the next char is a property or not
//not a property: insert the char as a literal
/*
fragments.addElement(value.substring(pos + 1, pos + 2));
prev = pos + 2;
*/
if (value.charAt(pos + 1) == '$') {
//backwards compatibility two $ map to one mode
fragments.add("$");
prev = pos + 2;
} else {
//new behaviour: $X maps to $X for all values of X!='$'
fragments.add(value.substring(pos, pos + 2));
prev = pos + 2;
}
} else {
//property found, extract its name or bail on a typo
int endName = value.indexOf('}', pos);
if (endName < 0) {
throw new RuntimeException("Syntax error in property: " + value);
}
String propertyName = value.substring(pos + 2, endName);
fragments.add(null);
propertyRefs.add(propertyName);
prev = endName + 1;
}
}
//no more $ signs found
//if there is any tail to the string, append it
if (prev < value.length()) {
fragments.add(value.substring(prev));
}
}
}

View File

@ -0,0 +1,132 @@
package org.apache.solr.util;
/*
* 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 org.apache.solr.common.SolrException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;
/**
* Breaking out some utility methods into a separate class as part of SOLR-4196. These utils have nothing to do with
* the DOM (they came from DomUtils) and it's really confusing to see them in something labeled DOM
*/
public class PropertiesUtil {
/*
* This method borrowed from Ant's PropertyHelper.replaceProperties:
* http://svn.apache.org/repos/asf/ant/core/trunk/src/main/org/apache/tools/ant/PropertyHelper.java
*/
public static String substituteProperty(String value, Properties coreProperties) {
if (value == null || value.indexOf('$') == -1) {
return value;
}
List<String> fragments = new ArrayList<String>();
List<String> propertyRefs = new ArrayList<String>();
parsePropertyString(value, fragments, propertyRefs);
StringBuilder sb = new StringBuilder();
Iterator<String> i = fragments.iterator();
Iterator<String> j = propertyRefs.iterator();
while (i.hasNext()) {
String fragment = i.next();
if (fragment == null) {
String propertyName = j.next();
String defaultValue = null;
int colon_index = propertyName.indexOf(':');
if (colon_index > -1) {
defaultValue = propertyName.substring(colon_index + 1);
propertyName = propertyName.substring(0, colon_index);
}
if (coreProperties != null) {
fragment = coreProperties.getProperty(propertyName);
}
if (fragment == null) {
fragment = System.getProperty(propertyName, defaultValue);
}
if (fragment == null) {
throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, "No system property or default value specified for " + propertyName + " value:" + value);
}
}
sb.append(fragment);
}
return sb.toString();
}
/*
* This method borrowed from Ant's PropertyHelper.parsePropertyStringDefault:
* http://svn.apache.org/repos/asf/ant/core/trunk/src/main/org/apache/tools/ant/PropertyHelper.java
*/
private static void parsePropertyString(String value, List<String> fragments, List<String> propertyRefs) {
int prev = 0;
int pos;
//search for the next instance of $ from the 'prev' position
while ((pos = value.indexOf("$", prev)) >= 0) {
//if there was any text before this, add it as a fragment
//TODO, this check could be modified to go if pos>prev;
//seems like this current version could stick empty strings
//into the list
if (pos > 0) {
fragments.add(value.substring(prev, pos));
}
//if we are at the end of the string, we tack on a $
//then move past it
if (pos == (value.length() - 1)) {
fragments.add("$");
prev = pos + 1;
} else if (value.charAt(pos + 1) != '{') {
//peek ahead to see if the next char is a property or not
//not a property: insert the char as a literal
/*
fragments.addElement(value.substring(pos + 1, pos + 2));
prev = pos + 2;
*/
if (value.charAt(pos + 1) == '$') {
//backwards compatibility two $ map to one mode
fragments.add("$");
prev = pos + 2;
} else {
//new behaviour: $X maps to $X for all values of X!='$'
fragments.add(value.substring(pos, pos + 2));
prev = pos + 2;
}
} else {
//property found, extract its name or bail on a typo
int endName = value.indexOf('}', pos);
if (endName < 0) {
throw new RuntimeException("Syntax error in property: " + value);
}
String propertyName = value.substring(pos + 2, endName);
fragments.add(null);
propertyRefs.add(propertyName);
prev = endName + 1;
}
}
//no more $ signs found
//if there is any tail to the string, append it
if (prev < value.length()) {
fragments.add(value.substring(prev));
}
}
}

View File

@ -0,0 +1,38 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!--
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.
-->
<schema name="tiny" version="1.1">
<types>
<fieldType name="string" class="solr.StrField"/>
</types>
<fields>
<field name="id" type="string" indexed="true" stored="true" required="true"/>
<field name="text" type="text" indexed="true" stored="true"/>
<dynamicField name="*_t" type="text" indexed="true" stored="true"/>
<dynamicField name="*" type="string" indexed="true" stored="true"/>
</fields>
<uniqueKey>id</uniqueKey>
<types>
<fieldtype name="text" class="solr.TextField">
<analyzer>
<tokenizer class="solr.WhitespaceTokenizerFactory"/>
<filter class="solr.LowerCaseFilterFactory"/>
</analyzer>
</fieldtype>
</types>
</schema>

View File

@ -0,0 +1,76 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!--
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.
-->
<!-- For testing, I need to create some custom directories on the fly, particularly for some of the new
discovery-based core configuration. Trying a minimal configuration to cut down the setup time.
use in conjunction with schema-minimal.xml perhaps? -->
<config>
<luceneMatchVersion>LUCENE_41</luceneMatchVersion>
<dataDir>${solr.data.dir:}</dataDir>
<directoryFactory name="DirectoryFactory"
class="${solr.directoryFactory:solr.NRTCachingDirectoryFactory}"/>
<indexConfig>
</indexConfig>
<jmx/>
<updateHandler class="solr.DirectUpdateHandler2">
<!--updateLog>
<str name="dir">${solr.ulog.dir:}</str>
</updateLog-->
</updateHandler>
<query>
<enableLazyFieldLoading>true</enableLazyFieldLoading>
<queryResultWindowSize>20</queryResultWindowSize>
<queryResultMaxDocsCached>20</queryResultMaxDocsCached>
<useColdSearcher>true</useColdSearcher>
<maxWarmingSearchers>1</maxWarmingSearchers>
</query>
<requestHandler name="/admin/" class="solr.admin.AdminHandlers" />
<requestDispatcher handleSelect="false">
<httpCaching never304="true"/>
</requestDispatcher>
<requestHandler name="/select" class="solr.SearchHandler">
<lst name="defaults">
<str name="echoParams">explicit</str>
<str name="wt">json</str>
<str name="indent">true</str>
<str name="df">text</str>
</lst>
</requestHandler>
<requestHandler name="/update" class="solr.UpdateRequestHandler">
</requestHandler>
<queryResponseWriter name="json" class="solr.JSONResponseWriter">
<!-- For the purposes of the tutorial, JSON responses are written as
plain text so that they are easy to read in *any* browser.
If you expect a MIME type of "application/json" just remove this override.
-->
<str name="content-type">text/plain; charset=UTF-8</str>
</queryResponseWriter>
</config>

View File

@ -34,7 +34,7 @@ import org.junit.Before;
import org.junit.BeforeClass;
@Slow
public class ChaosMonkeySafeLeaderTest extends AbstractFullDistribZkTestBase {
public class ChaosMonkeySafeLeaderTest extends AbstractFullDistribZkTestBase {
private static final Integer RUN_LENGTH = Integer.parseInt(System.getProperty("solr.tests.cloud.cm.runlength", "-1"));

View File

@ -242,7 +242,7 @@ public class ZkControllerTest extends SolrTestCaseJ4 {
private CoreContainer getCoreContainer() {
CoreContainer cc = new CoreContainer(TEMP_DIR.getAbsolutePath()) {
{
initShardHandler(null);
initShardHandler();
}
};

View File

@ -20,7 +20,6 @@ package org.apache.solr.core;
import org.apache.commons.io.FileUtils;
import org.apache.lucene.util.IOUtils;
import org.apache.solr.SolrTestCaseJ4;
import org.apache.solr.common.SolrInputDocument;
import org.apache.solr.common.util.NamedList;
import org.apache.solr.request.LocalSolrQueryRequest;
import org.apache.solr.request.SolrQueryRequest;
@ -29,6 +28,7 @@ import org.apache.solr.update.AddUpdateCommand;
import org.apache.solr.update.CommitUpdateCommand;
import org.apache.solr.update.UpdateHandler;
import org.apache.solr.util.RefCounted;
import org.junit.After;
import org.junit.BeforeClass;
import org.junit.Test;
@ -43,47 +43,44 @@ public class TestLazyCores extends SolrTestCaseJ4 {
@BeforeClass
public static void beforeClass() throws Exception {
initCore("solrconfig.xml", "schema.xml");
initCore("solrconfig-minimal.xml", "schema-tiny.xml");
}
private final File _solrHomeDirectory = new File(TEMP_DIR, "org.apache.solr.core.TestLazyCores_testlazy");
private static String[] _necessaryConfs = {"schema.xml", "solrconfig.xml", "stopwords.txt", "synonyms.txt",
"protwords.txt", "old_synonyms.txt", "currency.xml", "open-exchange-rates.json", "mapping-ISOLatin1Accent.txt"};
private final File solrHomeDirectory = new File(TEMP_DIR, "org.apache.solr.core.TestLazyCores_testlazy");
private void copyConfFiles(File home, String subdir) throws IOException {
File subHome = new File(new File(home, subdir), "conf");
assertTrue("Failed to make subdirectory ", subHome.mkdirs());
String top = SolrTestCaseJ4.TEST_HOME() + "/collection1/conf";
for (String file : _necessaryConfs) {
FileUtils.copyFile(new File(top, file), new File(subHome, file));
}
FileUtils.copyFile(new File(top, "schema-tiny.xml"), new File(subHome, "schema-tiny.xml"));
FileUtils.copyFile(new File(top, "solrconfig-minimal.xml"), new File(subHome, "solrconfig-minimal.xml"));
}
private CoreContainer init() throws Exception {
if (_solrHomeDirectory.exists()) {
FileUtils.deleteDirectory(_solrHomeDirectory);
if (solrHomeDirectory.exists()) {
FileUtils.deleteDirectory(solrHomeDirectory);
}
assertTrue("Failed to mkdirs workDir", _solrHomeDirectory.mkdirs());
assertTrue("Failed to mkdirs workDir", solrHomeDirectory.mkdirs());
for (int idx = 1; idx < 10; ++idx) {
copyConfFiles(_solrHomeDirectory, "collection" + idx);
copyConfFiles(solrHomeDirectory, "collection" + idx);
}
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());
final CoreContainer cores = new CoreContainer(_solrHomeDirectory.getAbsolutePath());
cores.load(_solrHomeDirectory.getAbsolutePath(), solrXml);
// h.getCoreContainer().load(_solrHomeDirectory.getAbsolutePath(), new File(_solrHomeDirectory, "solr.xml"));
final CoreContainer cores = new CoreContainer(solrHomeDirectory.getAbsolutePath());
cores.load(solrHomeDirectory.getAbsolutePath(), solrXml);
// h.getCoreContainer().load(solrHomeDirectory.getAbsolutePath(), new File(solrHomeDirectory, "solr.xml"));
cores.setPersistent(false);
return cores;
}
@After
public void after() throws Exception {
if (_solrHomeDirectory.exists()) {
FileUtils.deleteDirectory(_solrHomeDirectory);
if (solrHomeDirectory.exists()) {
FileUtils.deleteDirectory(solrHomeDirectory);
}
}
@ -155,29 +152,29 @@ public class TestLazyCores extends SolrTestCaseJ4 {
// Just get a couple of searches to work!
assertQ("test prefix query",
makeReq(core4, "q", "{!prefix f=v_t}hel")
makeReq(core4, "q", "{!prefix f=v_t}hel", "wt", "xml")
, "//result[@numFound='2']"
);
assertQ("test raw query",
makeReq(core4, "q", "{!raw f=v_t}hello")
makeReq(core4, "q", "{!raw f=v_t}hello", "wt", "xml")
, "//result[@numFound='2']"
);
// Now just insure that the normal searching on "collection1" finds _0_ on the same query that found _2_ above.
// Use of makeReq above and req below is tricky, very tricky.
assertQ("test raw query",
req("q", "{!raw f=v_t}hello")
req("q", "{!raw f=v_t}hello", "wt", "xml")
, "//result[@numFound='0']"
);
// no analysis is done, so these should match nothing
assertQ("test raw query",
makeReq(core4, "q", "{!raw f=v_t}Hello")
makeReq(core4, "q", "{!raw f=v_t}Hello", "wt", "xml")
, "//result[@numFound='0']"
);
assertQ("test raw query",
makeReq(core4, "q", "{!raw f=v_f}1.5")
makeReq(core4, "q", "{!raw f=v_f}1.5", "wt", "xml")
, "//result[@numFound='0']"
);
@ -196,8 +193,8 @@ public class TestLazyCores extends SolrTestCaseJ4 {
try {
// First check that all the cores that should be loaded at startup actually are.
checkInCores(cc, "collection1", "collectionLazy2", "collectionLazy5");
checkNotInCores(cc,"collectionLazy3", "collectionLazy4", "collectionLazy6",
checkInCores(cc, "collection1", "collectionLazy2", "collectionLazy5");
checkNotInCores(cc, "collectionLazy3", "collectionLazy4", "collectionLazy6",
"collectionLazy7", "collectionLazy8", "collectionLazy9");
// By putting these in non-alpha order, we're also checking that we're not just seeing an artifact.
@ -251,7 +248,7 @@ public class TestLazyCores extends SolrTestCaseJ4 {
// Test case for SOLR-4300
@Test
public void testRace() throws Exception {
final List<SolrCore> _theCores = new ArrayList<SolrCore>();
final List<SolrCore> theCores = new ArrayList<SolrCore>();
final CoreContainer cc = init();
try {
@ -261,23 +258,20 @@ public class TestLazyCores extends SolrTestCaseJ4 {
@Override
public void run() {
SolrCore core = cc.getCore("collectionLazy3");
synchronized (_theCores) {
_theCores.add(core);
synchronized (theCores) {
theCores.add(core);
}
}
};
threads[idx].start();
}
for (Thread thread : threads) {
thread.join();
}
for (int idx = 0; idx < _theCores.size() - 1; ++idx) {
assertEquals("Cores should be the same!", _theCores.get(idx), _theCores.get(idx + 1));
for (int idx = 0; idx < theCores.size() - 1; ++idx) {
assertEquals("Cores should be the same!", theCores.get(idx), theCores.get(idx + 1));
}
for (SolrCore core : _theCores) {
for (SolrCore core : theCores) {
core.close();
}
@ -286,33 +280,24 @@ public class TestLazyCores extends SolrTestCaseJ4 {
}
}
private void checkNotInCores(CoreContainer cc, String... nameCheck) {
public static void checkNotInCores(CoreContainer cc, String... nameCheck) {
Collection<String> names = cc.getCoreNames();
for (String name : nameCheck) {
assertFalse("core " + name + " was found in the list of cores", names.contains(name));
}
}
private void checkInCores(CoreContainer cc, String... nameCheck) {
public static void checkInCores(CoreContainer cc, String... nameCheck) {
Collection<String> names = cc.getCoreNames();
for (String name : nameCheck) {
assertTrue("core " + name + " was not found in the list of cores", names.contains(name));
}
}
private void addLazy(SolrCore core, String... fieldValues) throws IOException {
UpdateHandler updater = core.getUpdateHandler();
SolrQueryRequest req = makeReq(core);
AddUpdateCommand cmd = new AddUpdateCommand(req);
if ((fieldValues.length % 2) != 0) {
throw new RuntimeException("The length of the string array (query arguments) needs to be even");
}
cmd.solrDoc = new SolrInputDocument();
for (int idx = 0; idx < fieldValues.length; idx += 2) {
cmd.solrDoc.addField(fieldValues[idx], fieldValues[idx + 1]);
}
AddUpdateCommand cmd = new AddUpdateCommand(makeReq(core));
cmd.solrDoc = sdoc(fieldValues);
updater.addDoc(cmd);
}
@ -333,15 +318,32 @@ public class TestLazyCores extends SolrTestCaseJ4 {
private final static String LOTS_SOLR_XML = " <solr persistent=\"false\"> " +
"<cores adminPath=\"/admin/cores\" defaultCoreName=\"collectionLazy2\" transientCacheSize=\"4\"> " +
"<core name=\"collection1\" instanceDir=\"collection1\" /> " +
"<core name=\"collectionLazy2\" instanceDir=\"collection2\" transient=\"true\" loadOnStartup=\"true\" /> " +
"<core name=\"collectionLazy3\" instanceDir=\"collection3\" transient=\"on\" loadOnStartup=\"false\"/> " +
"<core name=\"collectionLazy4\" instanceDir=\"collection4\" transient=\"false\" loadOnStartup=\"false\"/> " +
"<core name=\"collectionLazy5\" instanceDir=\"collection5\" transient=\"false\" loadOnStartup=\"true\"/> " +
"<core name=\"collectionLazy6\" instanceDir=\"collection6\" transient=\"true\" loadOnStartup=\"false\" /> " +
"<core name=\"collectionLazy7\" instanceDir=\"collection7\" transient=\"true\" loadOnStartup=\"false\" /> " +
"<core name=\"collectionLazy8\" instanceDir=\"collection8\" transient=\"true\" loadOnStartup=\"false\" /> " +
"<core name=\"collectionLazy9\" instanceDir=\"collection9\" transient=\"true\" loadOnStartup=\"false\" /> " +
"<core name=\"collection1\" instanceDir=\"collection1\" config=\"solrconfig-minimal.xml\" schema=\"schema-tiny.xml\" /> " +
"<core name=\"collectionLazy2\" instanceDir=\"collection2\" transient=\"true\" loadOnStartup=\"true\" " +
" config=\"solrconfig-minimal.xml\" schema=\"schema-tiny.xml\" /> " +
"<core name=\"collectionLazy3\" instanceDir=\"collection3\" transient=\"on\" loadOnStartup=\"false\" " +
"config=\"solrconfig-minimal.xml\" schema=\"schema-tiny.xml\" /> " +
"<core name=\"collectionLazy4\" instanceDir=\"collection4\" transient=\"false\" loadOnStartup=\"false\" " +
"config=\"solrconfig-minimal.xml\" schema=\"schema-tiny.xml\" /> " +
"<core name=\"collectionLazy5\" instanceDir=\"collection5\" transient=\"false\" loadOnStartup=\"true\" " +
"config=\"solrconfig-minimal.xml\" schema=\"schema-tiny.xml\" /> " +
"<core name=\"collectionLazy6\" instanceDir=\"collection6\" transient=\"true\" loadOnStartup=\"false\" " +
"config=\"solrconfig-minimal.xml\" schema=\"schema-tiny.xml\" /> " +
"<core name=\"collectionLazy7\" instanceDir=\"collection7\" transient=\"true\" loadOnStartup=\"false\" " +
"config=\"solrconfig-minimal.xml\" schema=\"schema-tiny.xml\" /> " +
"<core name=\"collectionLazy8\" instanceDir=\"collection8\" transient=\"true\" loadOnStartup=\"false\" " +
"config=\"solrconfig-minimal.xml\" schema=\"schema-tiny.xml\" /> " +
"<core name=\"collectionLazy9\" instanceDir=\"collection9\" transient=\"true\" loadOnStartup=\"false\" " +
"config=\"solrconfig-minimal.xml\" schema=\"schema-tiny.xml\" /> " +
"</cores> " +
"</solr>";
}

View File

@ -0,0 +1,389 @@
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 F ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import org.apache.commons.io.FileUtils;
import org.apache.lucene.util.IOUtils;
import org.apache.solr.SolrTestCaseJ4;
import org.junit.After;
import org.junit.BeforeClass;
import org.junit.Test;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.StringReader;
import java.util.Properties;
import java.util.Set;
public class TestSolrDiscoveryProperties extends SolrTestCaseJ4 {
private static String NEW_LINE = System.getProperty("line.separator");
@BeforeClass
public static void beforeClass() throws Exception {
initCore();
}
private final File solrHomeDirectory = new File(TEMP_DIR, "org.apache.solr.core.TestSolrProperties" + File.separator + "solrHome");
private void setMeUp() throws Exception {
if (solrHomeDirectory.exists()) {
FileUtils.deleteDirectory(solrHomeDirectory);
}
assertTrue("Failed to mkdirs workDir", solrHomeDirectory.mkdirs());
System.setProperty("solr.solr.home", solrHomeDirectory.getAbsolutePath());
}
private void addSolrPropertiesFile(String... extras) throws Exception {
File solrProps = new File(solrHomeDirectory, SolrProperties.SOLR_PROPERTIES_FILE);
Properties props = new Properties();
props.load(new StringReader(SOLR_PROPERTIES));
for (String extra : extras) {
String[] parts = extra.split("=");
props.put(parts[0], parts[1]);
}
props.store(new FileOutputStream(solrProps.getAbsolutePath()), null);
}
private void addSolrXml() throws Exception {
File tmpFile = new File(solrHomeDirectory, SolrProperties.SOLR_XML_FILE);
FileUtils.write(tmpFile, SOLR_XML, IOUtils.CHARSET_UTF_8.toString());
}
private Properties makeCorePropFile(String name, boolean isLazy, boolean loadOnStartup, String... extraProps) {
Properties props = new Properties();
props.put(CoreDescriptor.CORE_NAME, name);
props.put(CoreDescriptor.CORE_SCHEMA, "schema-tiny.xml");
props.put(CoreDescriptor.CORE_CONFIG, "solrconfig-minimal.xml");
props.put(CoreDescriptor.CORE_TRANSIENT, Boolean.toString(isLazy));
props.put(CoreDescriptor.CORE_LOADONSTARTUP, Boolean.toString(loadOnStartup));
props.put(CoreDescriptor.CORE_DATADIR, "${core.dataDir:stuffandnonsense}");
for (String extra : extraProps) {
String[] parts = extra.split("=");
props.put(parts[0], parts[1]);
}
return props;
}
private void addCoreWithProps(Properties stockProps) throws Exception {
File propFile = new File(solrHomeDirectory,
stockProps.getProperty(CoreDescriptor.CORE_NAME) + File.separator + SolrProperties.CORE_PROP_FILE);
File parent = propFile.getParentFile();
assertTrue("Failed to mkdirs for " + parent.getAbsolutePath(), parent.mkdirs());
stockProps.store(new FileOutputStream(propFile), null);
addConfFiles(new File(parent, "conf"));
}
private void addConfFiles(File confDir) throws Exception {
String top = SolrTestCaseJ4.TEST_HOME() + "/collection1/conf";
assertTrue("Failed to mkdirs for " + confDir.getAbsolutePath(), confDir.mkdirs());
FileUtils.copyFile(new File(top, "schema-tiny.xml"), new File(confDir, "schema-tiny.xml"));
FileUtils.copyFile(new File(top, "solrconfig-minimal.xml"), new File(confDir, "solrconfig-minimal.xml"));
}
private void addConfigsForBackCompat() throws Exception {
addConfFiles(new File(solrHomeDirectory, "collection1" + File.separator + "conf"));
}
private CoreContainer init() throws Exception {
CoreContainer.Initializer init = new CoreContainer.Initializer();
final CoreContainer cores = init.initialize();
cores.setPersistent(false);
return cores;
}
@After
public void after() throws Exception {
if (solrHomeDirectory.exists()) {
FileUtils.deleteDirectory(solrHomeDirectory);
}
}
// Test the basic setup, create some dirs with core.properties files in them, but no solr.xml (a solr.properties
// instead) and insure that we find all the cores and can load them.
@Test
public void testPropertiesFile() throws Exception {
setMeUp();
addSolrPropertiesFile();
// name, isLazy, loadOnStartup
addCoreWithProps(makeCorePropFile("core1", false, true));
addCoreWithProps(makeCorePropFile("core2", false, false));
// I suspect what we're adding in here is a "configset" rather than a schema or solrconfig.
//
addCoreWithProps(makeCorePropFile("lazy1", true, false));
CoreContainer cc = init();
try {
Properties props = cc.containerProperties;
assertEquals("/admin/cores/props", props.getProperty("cores.adminPath"));
assertEquals("/admin/cores/props", cc.getAdminPath());
assertEquals("defcore", props.getProperty("cores.defaultCoreName"));
assertEquals("defcore", cc.getDefaultCoreName());
assertEquals("222.333.444.555", props.getProperty("host"));
assertEquals("6000", props.getProperty("port")); // getProperty actually looks at original props.
assertEquals("/solrprop", props.getProperty("cores.hostContext"));
assertEquals("20", props.getProperty("cores.zkClientTimeout"));
TestLazyCores.checkInCores(cc, "core1");
TestLazyCores.checkNotInCores(cc, "lazy1", "core2", "collection1");
SolrCore core1 = cc.getCore("core1");
SolrCore core2 = cc.getCore("core2");
SolrCore lazy1 = cc.getCore("lazy1");
TestLazyCores.checkInCores(cc, "core1", "core2", "lazy1");
core1.close();
core2.close();
lazy1.close();
} finally {
cc.shutdown();
}
}
// Check that the various flavors of persistence work, including saving the state of a core when it's being swapped
// out. Added a test in here to insure that files that have config variables are saved with the config vars not the
// substitutions.
@Test
public void testPersistTrue() throws Exception {
setMeUp();
addSolrPropertiesFile();
System.setProperty("solr.persistent", "true");
Properties special = makeCorePropFile("core1", false, true);
special.put(CoreDescriptor.CORE_INSTDIR, "${core1inst:anothersillypath}");
addCoreWithProps(special);
addCoreWithProps(makeCorePropFile("core2", false, false));
addCoreWithProps(makeCorePropFile("lazy1", true, true));
addCoreWithProps(makeCorePropFile("lazy2", true, true));
addCoreWithProps(makeCorePropFile("lazy3", true, false));
System.setProperty("core1inst", "core1");
CoreContainer cc = init();
SolrCore coreC1 = cc.getCore("core1");
addCoreProps(coreC1, "addedPropC1=addedC1", "addedPropC1B=foo", "addedPropC1C=bar");
SolrCore coreC2 = cc.getCore("core2");
addCoreProps(coreC2, "addedPropC2=addedC2", "addedPropC2B=foo", "addedPropC2C=bar");
SolrCore coreL1 = cc.getCore("lazy1");
addCoreProps(coreL1, "addedPropL1=addedL1", "addedPropL1B=foo", "addedPropL1C=bar");
SolrCore coreL2 = cc.getCore("lazy2");
addCoreProps(coreL2, "addedPropL2=addedL2", "addedPropL2B=foo", "addedPropL2C=bar");
SolrCore coreL3 = cc.getCore("lazy3");
addCoreProps(coreL3, "addedPropL3=addedL3", "addedPropL3B=foo", "addedPropL3C=bar");
try {
cc.persist();
// Insure that one of the loaded cores was swapped out, with a cache size of 2 lazy1 should be gone.
TestLazyCores.checkInCores(cc, "core1", "core2", "lazy2", "lazy3");
TestLazyCores.checkNotInCores(cc, "lazy1");
checkSolrProperties(cc);
File xmlFile = new File(solrHomeDirectory, "solr.xml");
assertFalse("Solr.xml should NOT exist", xmlFile.exists());
Properties orig = makeCorePropFile("core1", false, true);
orig.put(CoreDescriptor.CORE_INSTDIR, "${core1inst:anothersillypath}");
checkCoreProps(orig, "addedPropC1=addedC1", "addedPropC1B=foo", "addedPropC1C=bar");
orig = makeCorePropFile("core2", false, false);
checkCoreProps(orig, "addedPropC2=addedC2", "addedPropC2B=foo", "addedPropC2C=bar");
// This test insures that a core that was swapped out has its properties file persisted. Currently this happens
// as the file is removed from the cache.
orig = makeCorePropFile("lazy1", true, true);
checkCoreProps(orig, "addedPropL1=addedL1", "addedPropL1B=foo", "addedPropL1C=bar");
orig = makeCorePropFile("lazy2", true, true);
checkCoreProps(orig, "addedPropL2=addedL2", "addedPropL2B=foo", "addedPropL2C=bar");
orig = makeCorePropFile("lazy3", true, false);
checkCoreProps(orig, "addedPropL3=addedL3", "addedPropL3B=foo", "addedPropL3C=bar");
coreC1.close();
coreC2.close();
coreL1.close();
coreL2.close();
coreL3.close();
} finally {
cc.shutdown();
}
}
// Make sure that, even if we do call persist, nothing's saved unless the flag is set in solr.properties.
@Test
public void testPersistFalse() throws Exception {
setMeUp();
addSolrPropertiesFile();
addCoreWithProps(makeCorePropFile("core1", false, true));
addCoreWithProps(makeCorePropFile("core2", false, false));
addCoreWithProps(makeCorePropFile("lazy1", true, true));
addCoreWithProps(makeCorePropFile("lazy2", false, true));
CoreContainer cc = init();
SolrCore coreC1 = cc.getCore("core1");
addCoreProps(coreC1, "addedPropC1=addedC1", "addedPropC1B=foo", "addedPropC1C=bar");
SolrCore coreC2 = cc.getCore("core2");
addCoreProps(coreC2, "addedPropC2=addedC2", "addedPropC2B=foo", "addedPropC2C=bar");
SolrCore coreL1 = cc.getCore("lazy1");
addCoreProps(coreL1, "addedPropL1=addedL1", "addedPropL1B=foo", "addedPropL1C=bar");
SolrCore coreL2 = cc.getCore("lazy2");
addCoreProps(coreL2, "addedPropL2=addedL2", "addedPropL2B=foo", "addedPropL2C=bar");
try {
cc.persist();
checkSolrProperties(cc);
checkCoreProps(makeCorePropFile("core1", false, true));
checkCoreProps(makeCorePropFile("core2", false, false));
checkCoreProps(makeCorePropFile("lazy1", true, true));
checkCoreProps(makeCorePropFile("lazy2", false, true));
coreC1.close();
coreC2.close();
coreL1.close();
coreL2.close();
} finally {
cc.shutdown();
}
}
void addCoreProps(SolrCore core, String... propPairs) {
for (String keyval : propPairs) {
String[] pair = keyval.split("=");
core.getCoreDescriptor().putProperty(pair[0], pair[1]);
}
}
// Insure that the solr.properties is as it should be after persisting _and_, in some cases, different than
// what's in memory
void checkSolrProperties(CoreContainer cc, String... checkMemPairs) throws Exception {
Properties orig = new Properties();
orig.load(new StringReader(SOLR_PROPERTIES));
Properties curr = cc.getContainerProperties();
Properties persisted = new Properties();
persisted.load(new FileInputStream(new File(solrHomeDirectory, SolrProperties.SOLR_PROPERTIES_FILE)));
assertEquals("Persisted and original should be the same size", orig.size(), persisted.size());
for (String prop : orig.stringPropertyNames()) {
assertEquals("Values of original should match current", orig.getProperty(prop), persisted.getProperty(prop));
}
Properties specialProps = new Properties();
for (String special : checkMemPairs) {
String[] pair = special.split("=");
specialProps.put(pair[0], pair[1]);
}
// OK, current should match original except if the property is "special"
for (String prop : curr.stringPropertyNames()) {
String val = specialProps.getProperty(prop);
if (val != null) { // Compare curr and val
assertEquals("Modified property should be in current container properties", val, curr.getProperty(prop));
}
}
}
// Insure that the properties in the core passed in are exactly what's in the default core.properties below plus
// whatever extra is passed in.
void checkCoreProps(Properties orig, String... extraProps) throws Exception {
// Read the persisted file.
Properties props = new Properties();
File propParent = new File(solrHomeDirectory, orig.getProperty(CoreDescriptor.CORE_NAME));
props.load(new FileInputStream(new File(propParent, SolrProperties.CORE_PROP_FILE)));
Set<String> propSet = props.stringPropertyNames();
assertEquals("Persisted properties should NOT contain extra properties", propSet.size(), orig.size());
for (String prop : orig.stringPropertyNames()) {
assertEquals("Original and new properties should be equal for " + prop, props.getProperty(prop), orig.getProperty(prop));
}
for (String prop : extraProps) {
String[] pair = prop.split("=");
assertNull("Modified parameters should not be present for " + prop, props.getProperty(pair[0]));
}
}
// If there's a solr.xml AND a properties file, make sure that the xml file is loaded and the properties file
// is ignored.
@Test
public void testBackCompatXml() throws Exception {
setMeUp();
addSolrPropertiesFile();
addSolrXml();
addConfigsForBackCompat();
CoreContainer cc = init();
try {
Properties props = cc.getContainerProperties();
assertEquals("/admin/cores", cc.getAdminPath());
assertEquals("collectionLazy2", cc.getDefaultCoreName());
// Shouldn't get these in properties at this point
assertNull(props.getProperty("cores.adminPath"));
assertNull(props.getProperty("cores.defaultCoreName"));
assertNull(props.getProperty("host"));
assertNull(props.getProperty("port")); // getProperty actually looks at original props.
assertNull(props.getProperty("cores.hostContext"));
assertNull(props.getProperty("cores.zkClientTimeout"));
} finally {
cc.shutdown();
}
}
// For this test I want some of these to be different than what would be in solr.xml by default.
private final static String SOLR_PROPERTIES =
"persistent=${persistent:false}" + NEW_LINE +
"cores.adminPath=/admin/cores/props" + NEW_LINE +
"cores.defaultCoreName=defcore" + NEW_LINE +
"host=222.333.444.555" + NEW_LINE +
"port=6000" + NEW_LINE +
"cores.hostContext=/solrprop" + NEW_LINE +
"cores.zkClientTimeout=20" + NEW_LINE +
"cores.transientCacheSize=2";
// For testing whether finding a solr.xml overrides looking at solr.properties
private final static String SOLR_XML = " <solr persistent=\"false\"> " +
"<cores adminPath=\"/admin/cores\" defaultCoreName=\"collectionLazy2\" transientCacheSize=\"4\"> " +
"<core name=\"collection1\" instanceDir=\"collection1\" config=\"solrconfig-minimal.xml\" schema=\"schema-tiny.xml\" /> " +
"</cores> " +
"</solr>";
}

View File

@ -191,7 +191,7 @@ public class TestHarness {
hostPort = System.getProperty("hostPort");
hostContext = "solr";
defaultCoreName = CoreContainer.DEFAULT_DEFAULT_CORE_NAME;
initShardHandler(null);
initShardHandler();
initZooKeeper(System.getProperty("zkHost"), 10000);
}
};