mirror of https://github.com/apache/lucene.git
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:
parent
05cc3a4706
commit
aa22ceb97d
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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
|
@ -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 <core> </core> 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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 ) {
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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>
|
|
@ -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>
|
|
@ -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"));
|
||||
|
||||
|
|
|
@ -242,7 +242,7 @@ public class ZkControllerTest extends SolrTestCaseJ4 {
|
|||
private CoreContainer getCoreContainer() {
|
||||
CoreContainer cc = new CoreContainer(TEMP_DIR.getAbsolutePath()) {
|
||||
{
|
||||
initShardHandler(null);
|
||||
initShardHandler();
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -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>";
|
||||
}
|
||||
|
|
|
@ -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>";
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue