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;
|
package org.apache.solr.cloud;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.TimeoutException;
|
import java.util.concurrent.TimeoutException;
|
||||||
|
|
||||||
|
@ -17,10 +19,11 @@ import org.apache.commons.cli.ParseException;
|
||||||
import org.apache.commons.cli.PosixParser;
|
import org.apache.commons.cli.PosixParser;
|
||||||
import org.apache.solr.common.cloud.OnReconnect;
|
import org.apache.solr.common.cloud.OnReconnect;
|
||||||
import org.apache.solr.common.cloud.SolrZkClient;
|
import org.apache.solr.common.cloud.SolrZkClient;
|
||||||
import org.apache.solr.core.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.solr.core.SolrResourceLoader;
|
||||||
import org.apache.zookeeper.KeeperException;
|
import org.apache.zookeeper.KeeperException;
|
||||||
import org.xml.sax.InputSource;
|
|
||||||
import org.xml.sax.SAXException;
|
import org.xml.sax.SAXException;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -172,11 +175,25 @@ public class ZkCLI {
|
||||||
SolrResourceLoader loader = new SolrResourceLoader(solrHome);
|
SolrResourceLoader loader = new SolrResourceLoader(solrHome);
|
||||||
solrHome = loader.getInstanceDir();
|
solrHome = loader.getInstanceDir();
|
||||||
|
|
||||||
InputSource cfgis = new InputSource(new File(solrHome, SOLR_XML)
|
File configFile = new File(solrHome, SOLR_XML);
|
||||||
.toURI().toASCIIString());
|
boolean isXml = true;
|
||||||
Config cfg = new Config(loader, null, cfgis, null, false);
|
if (! configFile.exists()) {
|
||||||
|
configFile = new File(solrHome, SolrProperties.SOLR_PROPERTIES_FILE);
|
||||||
|
isXml = false;
|
||||||
|
}
|
||||||
|
InputStream is = new FileInputStream(configFile);
|
||||||
|
|
||||||
if(!ZkController.checkChrootPath(zkServerAddress, true)) {
|
//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.out.println("A chroot was specified in zkHost but the znode doesn't exist. ");
|
||||||
System.exit(1);
|
System.exit(1);
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,8 +39,6 @@ import java.util.concurrent.TimeoutException;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
import javax.xml.xpath.XPathConstants;
|
|
||||||
|
|
||||||
import org.apache.commons.io.FileUtils;
|
import org.apache.commons.io.FileUtils;
|
||||||
import org.apache.solr.client.solrj.impl.HttpSolrServer;
|
import org.apache.solr.client.solrj.impl.HttpSolrServer;
|
||||||
import org.apache.solr.client.solrj.request.CoreAdminRequest.WaitForState;
|
import org.apache.solr.client.solrj.request.CoreAdminRequest.WaitForState;
|
||||||
|
@ -60,14 +58,14 @@ import org.apache.solr.common.cloud.ZkNodeProps;
|
||||||
import org.apache.solr.common.cloud.ZkStateReader;
|
import org.apache.solr.common.cloud.ZkStateReader;
|
||||||
import org.apache.solr.common.cloud.ZooKeeperException;
|
import org.apache.solr.common.cloud.ZooKeeperException;
|
||||||
import org.apache.solr.common.params.SolrParams;
|
import org.apache.solr.common.params.SolrParams;
|
||||||
import org.apache.solr.core.Config;
|
import org.apache.solr.core.ConfigSolr;
|
||||||
import org.apache.solr.core.CoreContainer;
|
import org.apache.solr.core.CoreContainer;
|
||||||
import org.apache.solr.core.CoreDescriptor;
|
import org.apache.solr.core.CoreDescriptor;
|
||||||
import org.apache.solr.core.SolrCore;
|
import org.apache.solr.core.SolrCore;
|
||||||
import org.apache.solr.handler.component.ShardHandler;
|
import org.apache.solr.handler.component.ShardHandler;
|
||||||
import org.apache.solr.update.UpdateLog;
|
import org.apache.solr.update.UpdateLog;
|
||||||
import org.apache.solr.update.UpdateShardHandler;
|
import org.apache.solr.update.UpdateShardHandler;
|
||||||
import org.apache.solr.util.DOMUtil;
|
import org.apache.solr.util.PropertiesUtil;
|
||||||
import org.apache.zookeeper.CreateMode;
|
import org.apache.zookeeper.CreateMode;
|
||||||
import org.apache.zookeeper.KeeperException;
|
import org.apache.zookeeper.KeeperException;
|
||||||
import org.apache.zookeeper.KeeperException.NoNodeException;
|
import org.apache.zookeeper.KeeperException.NoNodeException;
|
||||||
|
@ -75,8 +73,6 @@ import org.apache.zookeeper.KeeperException.SessionExpiredException;
|
||||||
import org.apache.zookeeper.data.Stat;
|
import org.apache.zookeeper.data.Stat;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.w3c.dom.Node;
|
|
||||||
import org.w3c.dom.NodeList;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle ZooKeeper interactions.
|
* Handle ZooKeeper interactions.
|
||||||
|
@ -1409,20 +1405,19 @@ public final class ZkController {
|
||||||
/**
|
/**
|
||||||
* If in SolrCloud mode, upload config sets for each SolrCore in solr.xml.
|
* If in SolrCloud mode, upload config sets for each SolrCore in solr.xml.
|
||||||
*/
|
*/
|
||||||
public static void bootstrapConf(SolrZkClient zkClient, Config cfg, String solrHome) throws IOException,
|
public static void bootstrapConf(SolrZkClient zkClient, ConfigSolr cfg, String solrHome) throws IOException,
|
||||||
KeeperException, InterruptedException {
|
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++) {
|
log.info("bootstraping config into ZooKeeper using solr.xml");
|
||||||
Node node = nodes.item(i);
|
List<String> allCoreNames = cfg.getAllCoreNames();
|
||||||
String rawName = DOMUtil.substituteProperty(DOMUtil.getAttr(node, "name", null), new Properties());
|
for (String coreName : allCoreNames) {
|
||||||
String instanceDir = DOMUtil.getAttr(node, "instanceDir", null);
|
String rawName = PropertiesUtil.substituteProperty(cfg.getProperty(coreName, "name", null), new Properties());
|
||||||
|
String instanceDir = cfg.getProperty(coreName, "instanceDir", null);
|
||||||
File idir = new File(instanceDir);
|
File idir = new File(instanceDir);
|
||||||
if (!idir.isAbsolute()) {
|
if (!idir.isAbsolute()) {
|
||||||
idir = new File(solrHome, instanceDir);
|
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) {
|
if (confName == null) {
|
||||||
confName = rawName;
|
confName = rawName;
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,15 +34,13 @@ import javax.xml.namespace.QName;
|
||||||
import javax.xml.parsers.DocumentBuilder;
|
import javax.xml.parsers.DocumentBuilder;
|
||||||
import javax.xml.parsers.DocumentBuilderFactory;
|
import javax.xml.parsers.DocumentBuilderFactory;
|
||||||
import javax.xml.parsers.ParserConfigurationException;
|
import javax.xml.parsers.ParserConfigurationException;
|
||||||
|
import javax.xml.transform.TransformerException;
|
||||||
import javax.xml.xpath.XPath;
|
import javax.xml.xpath.XPath;
|
||||||
import javax.xml.xpath.XPathConstants;
|
import javax.xml.xpath.XPathConstants;
|
||||||
import javax.xml.xpath.XPathExpressionException;
|
import javax.xml.xpath.XPathExpressionException;
|
||||||
import javax.xml.xpath.XPathFactory;
|
import javax.xml.xpath.XPathFactory;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Locale;
|
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -67,6 +65,17 @@ public class Config {
|
||||||
this( loader, name, null, null );
|
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
|
public Config(SolrResourceLoader loader, String name, InputSource is, String prefix) throws ParserConfigurationException, IOException, SAXException
|
||||||
{
|
{
|
||||||
|
|
|
@ -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.util.Properties;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
|
||||||
|
import org.apache.commons.lang.StringUtils;
|
||||||
import org.apache.solr.cloud.CloudDescriptor;
|
import org.apache.solr.cloud.CloudDescriptor;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -28,29 +29,93 @@ import org.apache.solr.cloud.CloudDescriptor;
|
||||||
* @since solr 1.3
|
* @since solr 1.3
|
||||||
*/
|
*/
|
||||||
public class CoreDescriptor {
|
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;
|
private CloudDescriptor cloudDesc;
|
||||||
|
|
||||||
public CoreDescriptor(CoreContainer coreContainer, String name, String instanceDir) {
|
private CoreDescriptor(CoreContainer cont) {
|
||||||
this.coreContainer = coreContainer;
|
// Just a place to put initialization since it's a pain to add to the descriptor in every c'tor.
|
||||||
this.name = name;
|
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) {
|
if (name == null) {
|
||||||
throw new RuntimeException("Core needs a name");
|
throw new RuntimeException("Core needs a name");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
coreProperties.put(CORE_NAME, name);
|
||||||
|
|
||||||
if(coreContainer != null && coreContainer.getZkController() != null) {
|
if(coreContainer != null && coreContainer.getZkController() != null) {
|
||||||
this.cloudDesc = new CloudDescriptor();
|
this.cloudDesc = new CloudDescriptor();
|
||||||
// cloud collection defaults to core name
|
// cloud collection defaults to core name
|
||||||
|
@ -61,27 +126,18 @@ public class CoreDescriptor {
|
||||||
throw new NullPointerException("Missing required \'instanceDir\'");
|
throw new NullPointerException("Missing required \'instanceDir\'");
|
||||||
}
|
}
|
||||||
instanceDir = SolrResourceLoader.normalizeDir(instanceDir);
|
instanceDir = SolrResourceLoader.normalizeDir(instanceDir);
|
||||||
this.instanceDir = instanceDir;
|
coreProperties.put(CORE_INSTDIR, instanceDir);
|
||||||
this.configName = getDefaultConfigName();
|
coreProperties.put(CORE_CONFIG, getDefaultConfigName());
|
||||||
this.schemaName = getDefaultSchemaName();
|
coreProperties.put(CORE_SCHEMA, getDefaultSchemaName());
|
||||||
}
|
}
|
||||||
|
|
||||||
public CoreDescriptor(CoreDescriptor descr) {
|
public Properties initImplicitProperties() {
|
||||||
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() {
|
|
||||||
Properties implicitProperties = new Properties(coreContainer.getContainerProperties());
|
Properties implicitProperties = new Properties(coreContainer.getContainerProperties());
|
||||||
implicitProperties.setProperty("solr.core.name", name);
|
implicitProperties.setProperty(CORE_NAME, getName());
|
||||||
implicitProperties.setProperty("solr.core.instanceDir", instanceDir);
|
implicitProperties.setProperty(CORE_INSTDIR, getInstanceDir());
|
||||||
implicitProperties.setProperty("solr.core.dataDir", getDataDir());
|
implicitProperties.setProperty(CORE_DATADIR, getDataDir());
|
||||||
implicitProperties.setProperty("solr.core.configName", configName);
|
implicitProperties.setProperty(CORE_CONFIG, getConfigName());
|
||||||
implicitProperties.setProperty("solr.core.schemaName", schemaName);
|
implicitProperties.setProperty(CORE_SCHEMA, getSchemaName());
|
||||||
return implicitProperties;
|
return implicitProperties;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -101,41 +157,47 @@ public class CoreDescriptor {
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getPropertiesName() {
|
public String getPropertiesName() {
|
||||||
return propertiesName;
|
return coreProperties.getProperty(CORE_PROPERTIES);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setPropertiesName(String propertiesName) {
|
public void setPropertiesName(String propertiesName) {
|
||||||
this.propertiesName = propertiesName;
|
coreProperties.put(CORE_PROPERTIES, propertiesName);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getDataDir() {
|
public String getDataDir() {
|
||||||
String dataDir = this.dataDir;
|
String dataDir = coreProperties.getProperty(CORE_DATADIR);
|
||||||
if (dataDir == null) dataDir = getDefaultDataDir();
|
if (dataDir == null) {
|
||||||
|
dataDir = getDefaultDataDir();
|
||||||
|
}
|
||||||
if (new File(dataDir).isAbsolute()) {
|
if (new File(dataDir).isAbsolute()) {
|
||||||
return dataDir;
|
return dataDir;
|
||||||
} else {
|
} else {
|
||||||
if (new File(instanceDir).isAbsolute()) {
|
if (new File(getInstanceDir()).isAbsolute()) {
|
||||||
return SolrResourceLoader.normalizeDir(SolrResourceLoader.normalizeDir(instanceDir) + dataDir);
|
return SolrResourceLoader.normalizeDir(SolrResourceLoader.normalizeDir(getInstanceDir()) + dataDir);
|
||||||
} else {
|
} else {
|
||||||
return SolrResourceLoader.normalizeDir(coreContainer.getSolrHome() +
|
return SolrResourceLoader.normalizeDir(coreContainer.getSolrHome() +
|
||||||
SolrResourceLoader.normalizeDir(instanceDir) + dataDir);
|
SolrResourceLoader.normalizeDir(getRawInstanceDir()) + dataDir);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setDataDir(String s) {
|
public void setDataDir(String s) {
|
||||||
dataDir = s;
|
|
||||||
// normalize zero length to null.
|
// 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() {
|
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. */
|
/**@return the core instance directory. */
|
||||||
public String getRawInstanceDir() {
|
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.
|
* @return the core instance directory, prepended with solr_home if not an absolute path.
|
||||||
*/
|
*/
|
||||||
public String getInstanceDir() {
|
public String getInstanceDir() {
|
||||||
String instDir = this.instanceDir;
|
String instDir = coreProperties.getProperty(CORE_INSTDIR);
|
||||||
if (instDir == null) return null; // No worse than before.
|
if (instDir == null) return null; // No worse than before.
|
||||||
|
|
||||||
if (new File(instDir).isAbsolute()) {
|
if (new File(instDir).isAbsolute()) {
|
||||||
return SolrResourceLoader.normalizeDir(SolrResourceLoader.normalizeDir(instanceDir));
|
return SolrResourceLoader.normalizeDir(
|
||||||
|
SolrResourceLoader.normalizeDir(instDir));
|
||||||
}
|
}
|
||||||
return SolrResourceLoader.normalizeDir(coreContainer.getSolrHome() +
|
return SolrResourceLoader.normalizeDir(coreContainer.getSolrHome() +
|
||||||
SolrResourceLoader.normalizeDir(instDir));
|
SolrResourceLoader.normalizeDir(instDir));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Sets the core configuration resource name. */
|
/**Sets the core configuration resource name. */
|
||||||
public void setConfigName(String name) {
|
public void setConfigName(String name) {
|
||||||
if (name == null || name.length() == 0)
|
if (name == null || name.length() == 0)
|
||||||
throw new IllegalArgumentException("name can not be null or empty");
|
throw new IllegalArgumentException("name can not be null or empty");
|
||||||
this.configName = name;
|
coreProperties.put(CORE_CONFIG, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**@return the core configuration resource name. */
|
/**@return the core configuration resource name. */
|
||||||
public String getConfigName() {
|
public String getConfigName() {
|
||||||
return this.configName;
|
return coreProperties.getProperty(CORE_CONFIG);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Sets the core schema resource name. */
|
/**Sets the core schema resource name. */
|
||||||
public void setSchemaName(String name) {
|
public void setSchemaName(String name) {
|
||||||
if (name == null || name.length() == 0)
|
if (name == null || name.length() == 0)
|
||||||
throw new IllegalArgumentException("name can not be null or empty");
|
throw new IllegalArgumentException("name can not be null or empty");
|
||||||
this.schemaName = name;
|
coreProperties.put(CORE_SCHEMA, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**@return the core schema resource name. */
|
/**@return the core schema resource name. */
|
||||||
public String getSchemaName() {
|
public String getSchemaName() {
|
||||||
return this.schemaName;
|
return coreProperties.getProperty(CORE_SCHEMA);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**@return the initial core name */
|
/**@return the initial core name */
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return this.name;
|
return coreProperties.getProperty(CORE_NAME);
|
||||||
}
|
}
|
||||||
|
|
||||||
public CoreContainer getCoreContainer() {
|
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
|
* 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
|
* 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.
|
* instance returned by #getCoreProperties method.
|
||||||
|
*
|
||||||
|
* Under any circumstance, the properties passed in will override any already present.Merge
|
||||||
*/
|
*/
|
||||||
public void setCoreProperties(Properties coreProperties) {
|
public void setCoreProperties(Properties coreProperties) {
|
||||||
if (this.coreProperties == null) {
|
if (this.coreProperties == null) {
|
||||||
Properties p = initImplicitProperties();
|
Properties p = initImplicitProperties();
|
||||||
this.coreProperties = new Properties(p);
|
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;
|
this.cloudDesc = cloudDesc;
|
||||||
}
|
}
|
||||||
public boolean isLoadOnStartup() {
|
public boolean isLoadOnStartup() {
|
||||||
return loadOnStartup;
|
String tmp = coreProperties.getProperty(CORE_LOADONSTARTUP, "false");
|
||||||
|
return Boolean.parseBoolean(tmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setLoadOnStartup(boolean loadOnStartup) {
|
public void setLoadOnStartup(boolean loadOnStartup) {
|
||||||
this.loadOnStartup = loadOnStartup;
|
coreProperties.put(CORE_LOADONSTARTUP, Boolean.toString(loadOnStartup));
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isTransient() {
|
public boolean isTransient() {
|
||||||
return isTransient;
|
String tmp = coreProperties.getProperty(CORE_TRANSIENT, "false");
|
||||||
|
return (Boolean.parseBoolean(tmp));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setTransient(boolean aTransient) {
|
public void setTransient(boolean isTransient) {
|
||||||
this.isTransient = aTransient;
|
coreProperties.put(CORE_TRANSIENT, Boolean.toString(isTransient));
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getUlogDir() {
|
public String getUlogDir() {
|
||||||
return ulogDir;
|
return coreProperties.getProperty(CORE_ULOGDIR);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setUlogDir(String 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 );
|
this.setName( name );
|
||||||
resourceLoader = config.getResourceLoader();
|
resourceLoader = config.getResourceLoader();
|
||||||
if (dataDir == null){
|
if (dataDir == null){
|
||||||
if(cd.usingDefaultDataDir()) dataDir = config.getDataDir();
|
if(cd.usingDefaultDataDir()) {
|
||||||
if(dataDir == null) dataDir = cd.getDataDir();
|
dataDir = config.getDataDir();
|
||||||
|
}
|
||||||
|
if(dataDir == null) {
|
||||||
|
dataDir = cd.getDataDir();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dataDir = SolrResourceLoader.normalizeDir(dataDir);
|
dataDir = SolrResourceLoader.normalizeDir(dataDir);
|
||||||
|
|
||||||
log.info(logid+"Opening new SolrCore at " + resourceLoader.getInstanceDir() + ", dataDir="+dataDir);
|
log.info(logid+"Opening new SolrCore at " + resourceLoader.getInstanceDir() + ", dataDir="+dataDir);
|
||||||
|
|
||||||
if (schema==null) {
|
if (schema==null) {
|
||||||
|
@ -1316,7 +1319,7 @@ public final class SolrCore implements SolrInfoMBean {
|
||||||
*
|
*
|
||||||
* This method acquires openSearcherLock - do not call with searckLock held!
|
* 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;
|
SolrIndexSearcher tmp;
|
||||||
RefCounted<SolrIndexSearcher> newestSearcher = null;
|
RefCounted<SolrIndexSearcher> newestSearcher = null;
|
||||||
boolean nrt = solrConfig.reopenReaders && updateHandlerReopens;
|
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 final List<ResourceLoaderAware> waitingForResources = Collections.synchronizedList(new ArrayList<ResourceLoaderAware>());
|
||||||
private static final Charset UTF_8 = Charset.forName("UTF-8");
|
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 final Properties coreProperties;
|
||||||
|
|
||||||
private volatile boolean live;
|
private volatile boolean live;
|
||||||
|
|
|
@ -32,6 +32,7 @@ import java.util.Properties;
|
||||||
import javax.xml.parsers.ParserConfigurationException;
|
import javax.xml.parsers.ParserConfigurationException;
|
||||||
|
|
||||||
import org.apache.commons.io.FileUtils;
|
import org.apache.commons.io.FileUtils;
|
||||||
|
import org.apache.commons.lang.StringUtils;
|
||||||
import org.apache.lucene.index.DirectoryReader;
|
import org.apache.lucene.index.DirectoryReader;
|
||||||
import org.apache.lucene.store.Directory;
|
import org.apache.lucene.store.Directory;
|
||||||
import org.apache.lucene.util.IOUtils;
|
import org.apache.lucene.util.IOUtils;
|
||||||
|
@ -661,7 +662,7 @@ public class CoreAdminHandler extends RequestHandlerBase {
|
||||||
try {
|
try {
|
||||||
if (cname == null) {
|
if (cname == null) {
|
||||||
rsp.add("defaultCoreName", coreContainer.getDefaultCoreName());
|
rsp.add("defaultCoreName", coreContainer.getDefaultCoreName());
|
||||||
for (String name : coreContainer.getCoreNames()) {
|
for (String name : coreContainer.getAllCoreNames()) {
|
||||||
status.add(name, getCoreStatus(coreContainer, name, isIndexInfoNeeded));
|
status.add(name, getCoreStatus(coreContainer, name, isIndexInfoNeeded));
|
||||||
}
|
}
|
||||||
rsp.add("initFailures", allFailures);
|
rsp.add("initFailures", allFailures);
|
||||||
|
@ -954,33 +955,60 @@ 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>();
|
NamedList<Object> info = new SimpleOrderedMap<Object>();
|
||||||
SolrCore core = cores.getCore(cname);
|
|
||||||
if (core != null) {
|
if (!cores.isLoaded(cname)) { // Lazily-loaded core, fill in what we can.
|
||||||
try {
|
// It would be a real mistake to load the cores just to get the status
|
||||||
info.add("name", core.getName());
|
CoreDescriptor desc = cores.getUnloadedCoreDescriptor(cname);
|
||||||
info.add("isDefaultCore", core.getName().equals(cores.getDefaultCoreName()));
|
if (desc != null) {
|
||||||
info.add("instanceDir", normalizePath(core.getResourceLoader().getInstanceDir()));
|
info.add("name", desc.getName());
|
||||||
info.add("dataDir", normalizePath(core.getDataDir()));
|
info.add("isDefaultCore", desc.getName().equals(cores.getDefaultCoreName()));
|
||||||
info.add("config", core.getConfigResource());
|
info.add("instanceDir", desc.getInstanceDir());
|
||||||
info.add("schema", core.getSchemaResource());
|
// None of the following are guaranteed to be present in a not-yet-loaded core.
|
||||||
info.add("startTime", new Date(core.getStartTime()));
|
String tmp = desc.getDataDir();
|
||||||
info.add("uptime", System.currentTimeMillis() - core.getStartTime());
|
if (StringUtils.isNotBlank(tmp)) info.add("dataDir", tmp);
|
||||||
if (isIndexInfoNeeded) {
|
tmp = desc.getConfigName();
|
||||||
RefCounted<SolrIndexSearcher> searcher = core.getSearcher();
|
if (StringUtils.isNotBlank(tmp)) info.add("config", tmp);
|
||||||
try {
|
tmp = desc.getSchemaName();
|
||||||
SimpleOrderedMap<Object> indexInfo = LukeRequestHandler.getIndexInfo(searcher.get().getIndexReader());
|
if (StringUtils.isNotBlank(tmp)) info.add("schema", tmp);
|
||||||
long size = getIndexSize(core);
|
info.add("isLoaded", "false");
|
||||||
indexInfo.add("sizeInBytes", size);
|
}
|
||||||
indexInfo.add("size", NumberUtils.readableSize(size));
|
} else {
|
||||||
info.add("index", indexInfo);
|
SolrCore core = cores.getCore(cname);
|
||||||
} finally {
|
if (core != null) {
|
||||||
searcher.decref();
|
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;
|
return info;
|
||||||
|
|
|
@ -58,7 +58,7 @@ public final class SchemaField extends FieldProperties {
|
||||||
/** Create a new SchemaField with the given name and type,
|
/** Create a new SchemaField with the given name and type,
|
||||||
* and with the specified properties. Properties are *not*
|
* and with the specified properties. Properties are *not*
|
||||||
* inherited from the type in this case, so users of this
|
* 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.
|
* using all the default properties from the type.
|
||||||
*/
|
*/
|
||||||
public SchemaField(String name, FieldType type, int properties, String defaultValue ) {
|
public SchemaField(String name, FieldType type, int properties, String defaultValue ) {
|
||||||
|
|
|
@ -289,117 +289,18 @@ public class DOMUtil {
|
||||||
|
|
||||||
// handle child by node type
|
// handle child by node type
|
||||||
if (child.getNodeType() == Node.TEXT_NODE) {
|
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) {
|
} else if (child.getNodeType() == Node.ELEMENT_NODE) {
|
||||||
// handle child elements with recursive call
|
// handle child elements with recursive call
|
||||||
NamedNodeMap attributes = child.getAttributes();
|
NamedNodeMap attributes = child.getAttributes();
|
||||||
for (int i = 0; i < attributes.getLength(); i++) {
|
for (int i = 0; i < attributes.getLength(); i++) {
|
||||||
Node attribute = attributes.item(i);
|
Node attribute = attributes.item(i);
|
||||||
attribute.setNodeValue(substituteProperty(attribute.getNodeValue(), properties));
|
attribute.setNodeValue(PropertiesUtil.substituteProperty(attribute.getNodeValue(), properties));
|
||||||
}
|
}
|
||||||
substituteProperties(child, 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;
|
import org.junit.BeforeClass;
|
||||||
|
|
||||||
@Slow
|
@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"));
|
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() {
|
private CoreContainer getCoreContainer() {
|
||||||
CoreContainer cc = new CoreContainer(TEMP_DIR.getAbsolutePath()) {
|
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.commons.io.FileUtils;
|
||||||
import org.apache.lucene.util.IOUtils;
|
import org.apache.lucene.util.IOUtils;
|
||||||
import org.apache.solr.SolrTestCaseJ4;
|
import org.apache.solr.SolrTestCaseJ4;
|
||||||
import org.apache.solr.common.SolrInputDocument;
|
|
||||||
import org.apache.solr.common.util.NamedList;
|
import org.apache.solr.common.util.NamedList;
|
||||||
import org.apache.solr.request.LocalSolrQueryRequest;
|
import org.apache.solr.request.LocalSolrQueryRequest;
|
||||||
import org.apache.solr.request.SolrQueryRequest;
|
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.CommitUpdateCommand;
|
||||||
import org.apache.solr.update.UpdateHandler;
|
import org.apache.solr.update.UpdateHandler;
|
||||||
import org.apache.solr.util.RefCounted;
|
import org.apache.solr.util.RefCounted;
|
||||||
|
import org.junit.After;
|
||||||
import org.junit.BeforeClass;
|
import org.junit.BeforeClass;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
|
@ -43,47 +43,44 @@ public class TestLazyCores extends SolrTestCaseJ4 {
|
||||||
|
|
||||||
@BeforeClass
|
@BeforeClass
|
||||||
public static void beforeClass() throws Exception {
|
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 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 void copyConfFiles(File home, String subdir) throws IOException {
|
private void copyConfFiles(File home, String subdir) throws IOException {
|
||||||
|
|
||||||
File subHome = new File(new File(home, subdir), "conf");
|
File subHome = new File(new File(home, subdir), "conf");
|
||||||
assertTrue("Failed to make subdirectory ", subHome.mkdirs());
|
assertTrue("Failed to make subdirectory ", subHome.mkdirs());
|
||||||
String top = SolrTestCaseJ4.TEST_HOME() + "/collection1/conf";
|
String top = SolrTestCaseJ4.TEST_HOME() + "/collection1/conf";
|
||||||
for (String file : _necessaryConfs) {
|
FileUtils.copyFile(new File(top, "schema-tiny.xml"), new File(subHome, "schema-tiny.xml"));
|
||||||
FileUtils.copyFile(new File(top, file), new File(subHome, file));
|
FileUtils.copyFile(new File(top, "solrconfig-minimal.xml"), new File(subHome, "solrconfig-minimal.xml"));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private CoreContainer init() throws Exception {
|
private CoreContainer init() throws Exception {
|
||||||
|
|
||||||
if (_solrHomeDirectory.exists()) {
|
if (solrHomeDirectory.exists()) {
|
||||||
FileUtils.deleteDirectory(_solrHomeDirectory);
|
FileUtils.deleteDirectory(solrHomeDirectory);
|
||||||
}
|
}
|
||||||
assertTrue("Failed to mkdirs workDir", _solrHomeDirectory.mkdirs());
|
assertTrue("Failed to mkdirs workDir", solrHomeDirectory.mkdirs());
|
||||||
for (int idx = 1; idx < 10; ++idx) {
|
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());
|
FileUtils.write(solrXml, LOTS_SOLR_XML, IOUtils.CHARSET_UTF_8.toString());
|
||||||
final CoreContainer cores = new CoreContainer(_solrHomeDirectory.getAbsolutePath());
|
final CoreContainer cores = new CoreContainer(solrHomeDirectory.getAbsolutePath());
|
||||||
cores.load(_solrHomeDirectory.getAbsolutePath(), solrXml);
|
cores.load(solrHomeDirectory.getAbsolutePath(), solrXml);
|
||||||
// h.getCoreContainer().load(_solrHomeDirectory.getAbsolutePath(), new File(_solrHomeDirectory, "solr.xml"));
|
// h.getCoreContainer().load(solrHomeDirectory.getAbsolutePath(), new File(solrHomeDirectory, "solr.xml"));
|
||||||
|
|
||||||
cores.setPersistent(false);
|
cores.setPersistent(false);
|
||||||
return cores;
|
return cores;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
public void after() throws Exception {
|
public void after() throws Exception {
|
||||||
if (_solrHomeDirectory.exists()) {
|
if (solrHomeDirectory.exists()) {
|
||||||
FileUtils.deleteDirectory(_solrHomeDirectory);
|
FileUtils.deleteDirectory(solrHomeDirectory);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -155,29 +152,29 @@ public class TestLazyCores extends SolrTestCaseJ4 {
|
||||||
|
|
||||||
// Just get a couple of searches to work!
|
// Just get a couple of searches to work!
|
||||||
assertQ("test prefix query",
|
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']"
|
, "//result[@numFound='2']"
|
||||||
);
|
);
|
||||||
|
|
||||||
assertQ("test raw query",
|
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']"
|
, "//result[@numFound='2']"
|
||||||
);
|
);
|
||||||
|
|
||||||
// Now just insure that the normal searching on "collection1" finds _0_ on the same query that found _2_ above.
|
// 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.
|
// Use of makeReq above and req below is tricky, very tricky.
|
||||||
assertQ("test raw query",
|
assertQ("test raw query",
|
||||||
req("q", "{!raw f=v_t}hello")
|
req("q", "{!raw f=v_t}hello", "wt", "xml")
|
||||||
, "//result[@numFound='0']"
|
, "//result[@numFound='0']"
|
||||||
);
|
);
|
||||||
|
|
||||||
// no analysis is done, so these should match nothing
|
// no analysis is done, so these should match nothing
|
||||||
assertQ("test raw query",
|
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']"
|
, "//result[@numFound='0']"
|
||||||
);
|
);
|
||||||
assertQ("test raw query",
|
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']"
|
, "//result[@numFound='0']"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -196,8 +193,8 @@ public class TestLazyCores extends SolrTestCaseJ4 {
|
||||||
try {
|
try {
|
||||||
// First check that all the cores that should be loaded at startup actually are.
|
// First check that all the cores that should be loaded at startup actually are.
|
||||||
|
|
||||||
checkInCores(cc, "collection1", "collectionLazy2", "collectionLazy5");
|
checkInCores(cc, "collection1", "collectionLazy2", "collectionLazy5");
|
||||||
checkNotInCores(cc,"collectionLazy3", "collectionLazy4", "collectionLazy6",
|
checkNotInCores(cc, "collectionLazy3", "collectionLazy4", "collectionLazy6",
|
||||||
"collectionLazy7", "collectionLazy8", "collectionLazy9");
|
"collectionLazy7", "collectionLazy8", "collectionLazy9");
|
||||||
|
|
||||||
// By putting these in non-alpha order, we're also checking that we're not just seeing an artifact.
|
// 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 case for SOLR-4300
|
||||||
@Test
|
@Test
|
||||||
public void testRace() throws Exception {
|
public void testRace() throws Exception {
|
||||||
final List<SolrCore> _theCores = new ArrayList<SolrCore>();
|
final List<SolrCore> theCores = new ArrayList<SolrCore>();
|
||||||
final CoreContainer cc = init();
|
final CoreContainer cc = init();
|
||||||
try {
|
try {
|
||||||
|
|
||||||
|
@ -261,23 +258,20 @@ public class TestLazyCores extends SolrTestCaseJ4 {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
SolrCore core = cc.getCore("collectionLazy3");
|
SolrCore core = cc.getCore("collectionLazy3");
|
||||||
synchronized (_theCores) {
|
synchronized (theCores) {
|
||||||
_theCores.add(core);
|
theCores.add(core);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
threads[idx].start();
|
threads[idx].start();
|
||||||
}
|
}
|
||||||
|
|
||||||
for (Thread thread : threads) {
|
for (Thread thread : threads) {
|
||||||
thread.join();
|
thread.join();
|
||||||
}
|
}
|
||||||
|
for (int idx = 0; idx < theCores.size() - 1; ++idx) {
|
||||||
for (int idx = 0; idx < _theCores.size() - 1; ++idx) {
|
assertEquals("Cores should be the same!", theCores.get(idx), theCores.get(idx + 1));
|
||||||
assertEquals("Cores should be the same!", _theCores.get(idx), _theCores.get(idx + 1));
|
|
||||||
}
|
}
|
||||||
|
for (SolrCore core : theCores) {
|
||||||
for (SolrCore core : _theCores) {
|
|
||||||
core.close();
|
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();
|
Collection<String> names = cc.getCoreNames();
|
||||||
for (String name : nameCheck) {
|
for (String name : nameCheck) {
|
||||||
assertFalse("core " + name + " was found in the list of cores", names.contains(name));
|
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();
|
Collection<String> names = cc.getCoreNames();
|
||||||
for (String name : nameCheck) {
|
for (String name : nameCheck) {
|
||||||
assertTrue("core " + name + " was not found in the list of cores", names.contains(name));
|
assertTrue("core " + name + " was not found in the list of cores", names.contains(name));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void addLazy(SolrCore core, String... fieldValues) throws IOException {
|
private void addLazy(SolrCore core, String... fieldValues) throws IOException {
|
||||||
UpdateHandler updater = core.getUpdateHandler();
|
UpdateHandler updater = core.getUpdateHandler();
|
||||||
SolrQueryRequest req = makeReq(core);
|
AddUpdateCommand cmd = new AddUpdateCommand(makeReq(core));
|
||||||
AddUpdateCommand cmd = new AddUpdateCommand(req);
|
cmd.solrDoc = sdoc(fieldValues);
|
||||||
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]);
|
|
||||||
}
|
|
||||||
|
|
||||||
updater.addDoc(cmd);
|
updater.addDoc(cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -333,15 +318,32 @@ public class TestLazyCores extends SolrTestCaseJ4 {
|
||||||
|
|
||||||
private final static String LOTS_SOLR_XML = " <solr persistent=\"false\"> " +
|
private final static String LOTS_SOLR_XML = " <solr persistent=\"false\"> " +
|
||||||
"<cores adminPath=\"/admin/cores\" defaultCoreName=\"collectionLazy2\" transientCacheSize=\"4\"> " +
|
"<cores adminPath=\"/admin/cores\" defaultCoreName=\"collectionLazy2\" transientCacheSize=\"4\"> " +
|
||||||
"<core name=\"collection1\" instanceDir=\"collection1\" /> " +
|
"<core name=\"collection1\" instanceDir=\"collection1\" config=\"solrconfig-minimal.xml\" schema=\"schema-tiny.xml\" /> " +
|
||||||
"<core name=\"collectionLazy2\" instanceDir=\"collection2\" transient=\"true\" loadOnStartup=\"true\" /> " +
|
|
||||||
"<core name=\"collectionLazy3\" instanceDir=\"collection3\" transient=\"on\" loadOnStartup=\"false\"/> " +
|
"<core name=\"collectionLazy2\" instanceDir=\"collection2\" transient=\"true\" loadOnStartup=\"true\" " +
|
||||||
"<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\"/> " +
|
|
||||||
"<core name=\"collectionLazy6\" instanceDir=\"collection6\" transient=\"true\" loadOnStartup=\"false\" /> " +
|
"<core name=\"collectionLazy3\" instanceDir=\"collection3\" transient=\"on\" loadOnStartup=\"false\" " +
|
||||||
"<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\" /> " +
|
|
||||||
"<core name=\"collectionLazy9\" instanceDir=\"collection9\" transient=\"true\" loadOnStartup=\"false\" /> " +
|
"<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> " +
|
"</cores> " +
|
||||||
"</solr>";
|
"</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");
|
hostPort = System.getProperty("hostPort");
|
||||||
hostContext = "solr";
|
hostContext = "solr";
|
||||||
defaultCoreName = CoreContainer.DEFAULT_DEFAULT_CORE_NAME;
|
defaultCoreName = CoreContainer.DEFAULT_DEFAULT_CORE_NAME;
|
||||||
initShardHandler(null);
|
initShardHandler();
|
||||||
initZooKeeper(System.getProperty("zkHost"), 10000);
|
initZooKeeper(System.getProperty("zkHost"), 10000);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue