Return-Path: X-Original-To: apmail-lucene-commits-archive@www.apache.org Delivered-To: apmail-lucene-commits-archive@www.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id A491BDB91 for ; Mon, 13 Aug 2012 13:57:02 +0000 (UTC) Received: (qmail 60272 invoked by uid 500); 13 Aug 2012 13:57:02 -0000 Mailing-List: contact commits-help@lucene.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@lucene.apache.org Delivered-To: mailing list commits@lucene.apache.org Received: (qmail 60265 invoked by uid 99); 13 Aug 2012 13:57:02 -0000 Received: from nike.apache.org (HELO nike.apache.org) (192.87.106.230) by apache.org (qpsmtpd/0.29) with ESMTP; Mon, 13 Aug 2012 13:57:02 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=5.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Mon, 13 Aug 2012 13:56:32 +0000 Received: from eris.apache.org (localhost [127.0.0.1]) by eris.apache.org (Postfix) with ESMTP id E74A12388A6E; Mon, 13 Aug 2012 13:55:43 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r1372423 [41/45] - in /lucene/dev/branches/LUCENE-2878: ./ dev-tools/ dev-tools/eclipse/ dev-tools/idea/.idea/libraries/ dev-tools/maven/ dev-tools/maven/lucene/ dev-tools/maven/lucene/analysis/common/ dev-tools/maven/lucene/analysis/icu/ d... Date: Mon, 13 Aug 2012 13:53:27 -0000 To: commits@lucene.apache.org From: simonw@apache.org X-Mailer: svnmailer-1.0.8-patched Message-Id: <20120813135543.E74A12388A6E@eris.apache.org> Modified: lucene/dev/branches/LUCENE-2878/solr/core/src/java/org/apache/solr/cloud/SyncStrategy.java URL: http://svn.apache.org/viewvc/lucene/dev/branches/LUCENE-2878/solr/core/src/java/org/apache/solr/cloud/SyncStrategy.java?rev=1372423&r1=1372422&r2=1372423&view=diff ============================================================================== --- lucene/dev/branches/LUCENE-2878/solr/core/src/java/org/apache/solr/cloud/SyncStrategy.java (original) +++ lucene/dev/branches/LUCENE-2878/solr/core/src/java/org/apache/solr/cloud/SyncStrategy.java Mon Aug 13 13:52:46 2012 @@ -17,16 +17,18 @@ package org.apache.solr.cloud; * limitations under the License. */ +import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Map; import org.apache.http.client.HttpClient; +import org.apache.solr.client.solrj.SolrServerException; import org.apache.solr.client.solrj.impl.HttpClientUtil; import org.apache.solr.client.solrj.impl.HttpSolrServer; import org.apache.solr.client.solrj.request.CoreAdminRequest.RequestRecovery; import org.apache.solr.common.SolrException; -import org.apache.solr.common.cloud.CloudState; +import org.apache.solr.common.cloud.ClusterState; import org.apache.solr.common.cloud.Slice; import org.apache.solr.common.cloud.ZkCoreNodeProps; import org.apache.solr.common.cloud.ZkNodeProps; @@ -63,12 +65,14 @@ public class SyncStrategy { shardHandler = new HttpShardHandlerFactory().getShardHandler(client); } - private static class SyncShardRequest extends ShardRequest { + private static class ShardCoreRequest extends ShardRequest { String coreName; + public String baseUrl; } public boolean sync(ZkController zkController, SolrCore core, ZkNodeProps leaderProps) { + log.info("Sync replicas to " + ZkCoreNodeProps.getCoreUrl(leaderProps)); // TODO: look at our state usage of sync // zkController.publish(core, ZkStateReader.SYNC); @@ -104,23 +108,19 @@ public class SyncStrategy { if (!success && !areAnyOtherReplicasActive(zkController, leaderProps, collection, shardId)) { -// System.out -// .println("wasnt a success but no on else i active! I am the leader"); - + log.info("Sync was not a success but no on else i active! I am the leader"); success = true; } if (success) { - // solrcloud_debug - // System.out.println("Sync success"); - // we are the leader - tell all of our replias to sync with us + log.info("Sync Success - now sync replicas to me"); syncToMe(zkController, collection, shardId, leaderProps); } else { + SolrException.log(log, "Sync Failed"); - // solrcloud_debug - // System.out.println("Sync failure"); + // lets see who seems ahead... } } catch (Exception e) { @@ -132,8 +132,8 @@ public class SyncStrategy { private boolean areAnyOtherReplicasActive(ZkController zkController, ZkNodeProps leaderProps, String collection, String shardId) { - CloudState cloudState = zkController.getZkStateReader().getCloudState(); - Map slices = cloudState.getSlices(collection); + ClusterState clusterState = zkController.getZkStateReader().getClusterState(); + Map slices = clusterState.getSlices(collection); Slice slice = slices.get(shardId); Map shards = slice.getShards(); for (Map.Entry shard : shards.entrySet()) { @@ -142,10 +142,10 @@ public class SyncStrategy { // + state // + shard.getValue().get(ZkStateReader.NODE_NAME_PROP) // + " live: " -// + cloudState.liveNodesContain(shard.getValue().get( +// + clusterState.liveNodesContain(shard.getValue().get( // ZkStateReader.NODE_NAME_PROP))); if ((state.equals(ZkStateReader.ACTIVE)) - && cloudState.liveNodesContain(shard.getValue().get( + && clusterState.liveNodesContain(shard.getValue().get( ZkStateReader.NODE_NAME_PROP)) && !new ZkCoreNodeProps(shard.getValue()).getCoreUrl().equals( new ZkCoreNodeProps(leaderProps).getCoreUrl())) { @@ -162,11 +162,7 @@ public class SyncStrategy { .getReplicaProps(collection, shardId, props.get(ZkStateReader.NODE_NAME_PROP), props.get(ZkStateReader.CORE_NAME_PROP), ZkStateReader.ACTIVE); // TODO: - // should - // there - // be a - // state - // filter? + // TODO should there be a state filter? if (nodes == null) { // I have no replicas @@ -197,19 +193,17 @@ public class SyncStrategy { leaderProps.get(ZkStateReader.NODE_NAME_PROP), leaderProps.get(ZkStateReader.CORE_NAME_PROP), ZkStateReader.ACTIVE); if (nodes == null) { - // System.out.println("I have no replicas"); - // I have no replicas + log.info(ZkCoreNodeProps.getCoreUrl(leaderProps) + " has no replicas"); return; } - //System.out.println("tell my replicas to sync"); + ZkCoreNodeProps zkLeader = new ZkCoreNodeProps(leaderProps); for (ZkCoreNodeProps node : nodes) { try { -// System.out -// .println("try and ask " + node.getCoreUrl() + " to sync"); - log.info("try and ask " + node.getCoreUrl() + " to sync"); - requestSync(zkLeader.getCoreUrl(), node.getCoreName()); - + log.info(ZkCoreNodeProps.getCoreUrl(leaderProps) + ": try and ask " + node.getCoreUrl() + " to sync"); + + requestSync(node.getBaseUrl(), node.getCoreUrl(), zkLeader.getCoreUrl(), node.getCoreName()); + } catch (Exception e) { SolrException.log(log, "Error syncing replica to leader", e); } @@ -220,24 +214,25 @@ public class SyncStrategy { ShardResponse srsp = shardHandler.takeCompletedOrError(); if (srsp == null) break; boolean success = handleResponse(srsp); - //System.out.println("got response:" + success); + if (srsp.getException() != null) { + SolrException.log(log, "Sync request error: " + srsp.getException()); + } + if (!success) { try { - log.info("Sync failed - asking replica to recover."); - //System.out.println("Sync failed - asking replica to recover."); - RequestRecovery recoverRequestCmd = new RequestRecovery(); - recoverRequestCmd.setAction(CoreAdminAction.REQUESTRECOVERY); - recoverRequestCmd.setCoreName(((SyncShardRequest)srsp.getShardRequest()).coreName); + log.info(ZkCoreNodeProps.getCoreUrl(leaderProps) + ": Sync failed - asking replica (" + srsp.getShardAddress() + ") to recover."); - HttpSolrServer server = new HttpSolrServer(zkLeader.getBaseUrl()); - server.request(recoverRequestCmd); + requestRecovery(((ShardCoreRequest)srsp.getShardRequest()).baseUrl, ((ShardCoreRequest)srsp.getShardRequest()).coreName); + } catch (Exception e) { - log.info("Could not tell a replica to recover", e); + SolrException.log(log, ZkCoreNodeProps.getCoreUrl(leaderProps) + ": Could not tell a replica to recover", e); } - shardHandler.cancelAll(); - break; + } else { + log.info(ZkCoreNodeProps.getCoreUrl(leaderProps) + ": " + " sync completed with " + srsp.getShardAddress()); } } + + } private boolean handleResponse(ShardResponse srsp) { @@ -246,14 +241,19 @@ public class SyncStrategy { if (response == null) { return false; } - boolean success = (Boolean) response.get("sync"); + Boolean success = (Boolean) response.get("sync"); + + if (success == null) { + success = false; + } return success; } - private void requestSync(String replica, String coreName) { - SyncShardRequest sreq = new SyncShardRequest(); + private void requestSync(String baseUrl, String replica, String leaderUrl, String coreName) { + ShardCoreRequest sreq = new ShardCoreRequest(); sreq.coreName = coreName; + sreq.baseUrl = baseUrl; sreq.purpose = 1; // TODO: this sucks if (replica.startsWith("http://")) @@ -264,11 +264,23 @@ public class SyncStrategy { sreq.params.set("qt","/get"); sreq.params.set("distrib",false); sreq.params.set("getVersions",Integer.toString(100)); - sreq.params.set("sync",replica); + sreq.params.set("sync",leaderUrl); shardHandler.submit(sreq, replica, sreq.params); } + private void requestRecovery(String baseUrl, String coreName) throws SolrServerException, IOException { + // TODO: do this in background threads + RequestRecovery recoverRequestCmd = new RequestRecovery(); + recoverRequestCmd.setAction(CoreAdminAction.REQUESTRECOVERY); + recoverRequestCmd.setCoreName(coreName); + + HttpSolrServer server = new HttpSolrServer(baseUrl); + server.setConnectionTimeout(45000); + server.setSoTimeout(45000); + server.request(recoverRequestCmd); + } + public static ModifiableSolrParams params(String... params) { ModifiableSolrParams msp = new ModifiableSolrParams(); for (int i = 0; i < params.length; i += 2) { Modified: lucene/dev/branches/LUCENE-2878/solr/core/src/java/org/apache/solr/cloud/ZkCLI.java URL: http://svn.apache.org/viewvc/lucene/dev/branches/LUCENE-2878/solr/core/src/java/org/apache/solr/cloud/ZkCLI.java?rev=1372423&r1=1372422&r2=1372423&view=diff ============================================================================== --- lucene/dev/branches/LUCENE-2878/solr/core/src/java/org/apache/solr/cloud/ZkCLI.java (original) +++ lucene/dev/branches/LUCENE-2878/solr/core/src/java/org/apache/solr/cloud/ZkCLI.java Mon Aug 13 13:52:46 2012 @@ -163,7 +163,7 @@ public class ZkCLI { } SolrZkClient zkClient = null; try { - zkClient = new SolrZkClient(zkServerAddress, 15000, 5000, + zkClient = new SolrZkClient(zkServerAddress, 30000, 30000, new OnReconnect() { @Override public void command() {} Modified: lucene/dev/branches/LUCENE-2878/solr/core/src/java/org/apache/solr/cloud/ZkController.java URL: http://svn.apache.org/viewvc/lucene/dev/branches/LUCENE-2878/solr/core/src/java/org/apache/solr/cloud/ZkController.java?rev=1372423&r1=1372422&r2=1372423&view=diff ============================================================================== --- lucene/dev/branches/LUCENE-2878/solr/core/src/java/org/apache/solr/cloud/ZkController.java (original) +++ lucene/dev/branches/LUCENE-2878/solr/core/src/java/org/apache/solr/cloud/ZkController.java Mon Aug 13 13:52:46 2012 @@ -38,7 +38,7 @@ import org.apache.solr.client.solrj.impl import org.apache.solr.client.solrj.request.CoreAdminRequest.WaitForState; import org.apache.solr.common.SolrException; import org.apache.solr.common.SolrException.ErrorCode; -import org.apache.solr.common.cloud.CloudState; +import org.apache.solr.common.cloud.ClusterState; import org.apache.solr.common.cloud.OnReconnect; import org.apache.solr.common.cloud.SolrZkClient; import org.apache.solr.common.cloud.ZkCmdExecutor; @@ -121,6 +121,8 @@ public final class ZkController { // may accept defaults or use mocks rather than pulling things from a CoreContainer private CoreContainer cc; + protected volatile Overseer overseer; + /** * @param cc if null, recovery will not be enabled * @param zkServerAddress @@ -170,36 +172,20 @@ public final class ZkController { shardHandler = cc.getShardHandlerFactory().getShardHandler(); adminPath = cc.getAdminPath(); } - - ElectionContext context = new OverseerElectionContext( - shardHandler, adminPath, - getNodeName(), zkStateReader); + ZkController.this.overseer = new Overseer(shardHandler, adminPath, zkStateReader); + ElectionContext context = new OverseerElectionContext(zkClient, overseer, getNodeName()); overseerElector.joinElection(context); zkStateReader.createClusterStateWatchersAndUpdate(); - List descriptors = registerOnReconnect - .getCurrentDescriptors(); - if (descriptors != null) { - // before registering as live, make sure everyone is in a - // down state - for (CoreDescriptor descriptor : descriptors) { - final String coreZkNodeName = getNodeName() + "_" - + descriptor.getName(); - try { - publish(descriptor, ZkStateReader.DOWN); - waitForLeaderToSeeDownState(descriptor, coreZkNodeName); - } catch (Exception e) { - SolrException.log(log, "", e); - } - } - } + registerAllCoresAsDown(registerOnReconnect); // we have to register as live first to pick up docs in the buffer createEphemeralLiveNode(); + List descriptors = registerOnReconnect.getCurrentDescriptors(); // re register all descriptors - if (descriptors != null) { + if (descriptors != null) { for (CoreDescriptor descriptor : descriptors) { // TODO: we need to think carefully about what happens when it was // a leader that was expired - as well as what to do about leaders/overseers @@ -228,7 +214,28 @@ public final class ZkController { cmdExecutor = new ZkCmdExecutor(); leaderElector = new LeaderElector(zkClient); zkStateReader = new ZkStateReader(zkClient); - init(); + + init(registerOnReconnect); + } + + private void registerAllCoresAsDown( + final CurrentCoreDescriptorProvider registerOnReconnect) { + List descriptors = registerOnReconnect + .getCurrentDescriptors(); + if (descriptors != null) { + // before registering as live, make sure everyone is in a + // down state + for (CoreDescriptor descriptor : descriptors) { + final String coreZkNodeName = getNodeName() + "_" + + descriptor.getName(); + try { + publish(descriptor, ZkStateReader.DOWN); + waitForLeaderToSeeDownState(descriptor, coreZkNodeName); + } catch (Exception e) { + SolrException.log(log, "", e); + } + } + } } /** @@ -236,6 +243,11 @@ public final class ZkController { */ public void close() { try { + overseer.close(); + } catch(Throwable t) { + log.error("Error closing overseer", t); + } + try { zkClient.close(); } catch (InterruptedException e) { // Restore the interrupted status @@ -262,8 +274,8 @@ public final class ZkController { /** * @return information about the cluster from ZooKeeper */ - public CloudState getCloudState() { - return zkStateReader.getCloudState(); + public ClusterState getClusterState() { + return zkStateReader.getClusterState(); } /** @@ -338,8 +350,9 @@ public final class ZkController { return zkServerAddress; } - private void init() { - + private void init(CurrentCoreDescriptorProvider registerOnReconnect) { + registerAllCoresAsDown(registerOnReconnect); + try { // makes nodes zkNode cmdExecutor.ensureExists(ZkStateReader.LIVE_NODES_ZKNODE, zkClient); @@ -358,8 +371,8 @@ public final class ZkController { } overseerElector = new LeaderElector(zkClient); - ElectionContext context = new OverseerElectionContext(shardHandler, - adminPath, getNodeName(), zkStateReader); + this.overseer = new Overseer(shardHandler, adminPath, zkStateReader); + ElectionContext context = new OverseerElectionContext(zkClient, overseer, getNodeName()); overseerElector.setup(context); overseerElector.joinElection(context); zkStateReader.createClusterStateWatchersAndUpdate(); @@ -532,18 +545,18 @@ public final class ZkController { String leaderUrl = getLeaderProps(collection, cloudDesc.getShardId()).getCoreUrl(); // now wait until our currently cloud state contains the latest leader - String cloudStateLeader = zkStateReader.getLeaderUrl(collection, cloudDesc.getShardId(), 30000); + String clusterStateLeader = zkStateReader.getLeaderUrl(collection, shardId, 30000); int tries = 0; - while (!leaderUrl.equals(cloudStateLeader)) { + while (!leaderUrl.equals(clusterStateLeader)) { if (tries == 60) { throw new SolrException(ErrorCode.SERVER_ERROR, "There is conflicting information about the leader of shard: " - + cloudDesc.getShardId()); + + cloudDesc.getShardId() + " our state says:" + clusterStateLeader + " but zookeeper says:" + leaderUrl); } Thread.sleep(1000); tries++; - cloudStateLeader = zkStateReader.getLeaderUrl(collection, - cloudDesc.getShardId(), 30000); + clusterStateLeader = zkStateReader.getLeaderUrl(collection, shardId, 30000); + leaderUrl = getLeaderProps(collection, cloudDesc.getShardId()).getCoreUrl(); } String ourUrl = ZkCoreNodeProps.getCoreUrl(baseUrl, coreName); @@ -595,7 +608,7 @@ public final class ZkController { } // make sure we have an update cluster state right away - zkStateReader.updateCloudState(true); + zkStateReader.updateClusterState(true); return shardId; } @@ -609,10 +622,10 @@ public final class ZkController { * @throws KeeperException * @throws InterruptedException */ - private ZkCoreNodeProps getLeaderProps(final String collection, final String slice) - throws KeeperException, InterruptedException { + private ZkCoreNodeProps getLeaderProps(final String collection, + final String slice) throws KeeperException, InterruptedException { int iterCount = 60; - while (iterCount-- > 0) + while (iterCount-- > 0) { try { byte[] data = zkClient.getData( ZkStateReader.getShardLeadersPath(collection, slice), null, null, @@ -623,6 +636,7 @@ public final class ZkController { } catch (NoNodeException e) { Thread.sleep(500); } + } throw new RuntimeException("Could not get leader props"); } @@ -727,7 +741,7 @@ public final class ZkController { } private boolean needsToBeAssignedShardId(final CoreDescriptor desc, - final CloudState state, final String shardZkNodeName) { + final ClusterState state, final String shardZkNodeName) { final CloudDescriptor cloudDesc = desc.getCloudDescriptor(); @@ -927,7 +941,7 @@ public final class ZkController { final String shardZkNodeName = getNodeName() + "_" + coreName; int retryCount = 120; while (retryCount-- > 0) { - final String shardId = zkStateReader.getCloudState().getShardId( + final String shardId = zkStateReader.getClusterState().getShardId( shardZkNodeName); if (shardId != null) { return shardId; @@ -995,7 +1009,7 @@ public final class ZkController { // this also gets us our assigned shard id if it was not specified publish(cd, ZkStateReader.DOWN); String shardZkNodeName = getCoreNodeName(cd); - if (cd.getCloudDescriptor().getShardId() == null && needsToBeAssignedShardId(cd, zkStateReader.getCloudState(), shardZkNodeName)) { + if (cd.getCloudDescriptor().getShardId() == null && needsToBeAssignedShardId(cd, zkStateReader.getClusterState(), shardZkNodeName)) { String shardId; shardId = doGetShardIdProcess(cd.getName(), cd.getCloudDescriptor()); cd.getCloudDescriptor().setShardId(shardId); @@ -1126,13 +1140,12 @@ public final class ZkController { */ public static void bootstrapConf(SolrZkClient zkClient, Config cfg, String solrHome) throws IOException, KeeperException, InterruptedException { - + log.info("bootstraping config into ZooKeeper using solr.xml"); NodeList nodes = (NodeList)cfg.evaluate("solr/cores/core", XPathConstants.NODESET); for (int i=0; i cores = new LinkedHashMap(); + + protected final Map coreInitFailures = + Collections.synchronizedMap(new LinkedHashMap()); + protected boolean persistent = false; protected String adminPath = null; protected String managementPath = null; @@ -676,6 +680,7 @@ public class CoreContainer throw new IllegalStateException("This CoreContainer has been shutdown"); } old = cores.put(name, core); + coreInitFailures.remove(name); /* * set both the name of the descriptor and the name of the * core, since the descriptors name is used for persisting. @@ -750,105 +755,136 @@ public class CoreContainer * @throws org.xml.sax.SAXException */ public SolrCore create(CoreDescriptor dcore) throws ParserConfigurationException, IOException, SAXException { - // Make the instanceDir relative to the cores instanceDir if not absolute - File idir = new File(dcore.getInstanceDir()); - if (!idir.isAbsolute()) { - idir = new File(solrHome, dcore.getInstanceDir()); - } - String instanceDir = idir.getPath(); - log.info("Creating SolrCore '{}' using instanceDir: {}", - dcore.getName(), instanceDir); - // Initialize the solr config - SolrResourceLoader solrLoader = null; - - SolrConfig config = null; - String zkConfigName = null; - if(zkController == null) { - solrLoader = new SolrResourceLoader(instanceDir, libLoader, getCoreProps(instanceDir, dcore.getPropertiesName(),dcore.getCoreProperties())); - config = new SolrConfig(solrLoader, dcore.getConfigName(), null); - } else { - try { - String collection = dcore.getCloudDescriptor().getCollectionName(); - zkController.createCollectionZkNode(dcore.getCloudDescriptor()); - zkConfigName = zkController.readConfigName(collection); - if (zkConfigName == null) { - log.error("Could not find config name for collection:" + collection); - throw new ZooKeeperException(SolrException.ErrorCode.SERVER_ERROR, - "Could not find config name for collection:" + collection); - } - solrLoader = new ZkSolrResourceLoader(instanceDir, zkConfigName, libLoader, getCoreProps(instanceDir, dcore.getPropertiesName(),dcore.getCoreProperties()), zkController); - config = getSolrConfigFromZk(zkConfigName, dcore.getConfigName(), solrLoader); - } catch (KeeperException e) { - log.error("", e); - throw new ZooKeeperException(SolrException.ErrorCode.SERVER_ERROR, - "", e); - } catch (InterruptedException e) { - // Restore the interrupted status - Thread.currentThread().interrupt(); - log.error("", e); - throw new ZooKeeperException(SolrException.ErrorCode.SERVER_ERROR, - "", e); - } - } - - IndexSchema schema = null; - if (indexSchemaCache != null) { - if (zkController != null) { - File schemaFile = new File(dcore.getSchemaName()); - if (!schemaFile.isAbsolute()) { - schemaFile = new File(solrLoader.getInstanceDir() + "conf" - + File.separator + dcore.getSchemaName()); - } - if (schemaFile.exists()) { - String key = schemaFile.getAbsolutePath() - + ":" - + new SimpleDateFormat("yyyyMMddHHmmss", Locale.ROOT).format(new Date( - schemaFile.lastModified())); - schema = indexSchemaCache.get(key); - if (schema == null) { - log.info("creating new schema object for core: " + dcore.name); - schema = new IndexSchema(config, dcore.getSchemaName(), null); - indexSchemaCache.put(key, schema); - } else { - log.info("re-using schema object for core: " + dcore.name); - } - } + // :TODO: would be really nice if this method wrapped any underlying errors and only threw SolrException + + final String name = dcore.getName(); + Exception failure = null; + + try { + // Make the instanceDir relative to the cores instanceDir if not absolute + File idir = new File(dcore.getInstanceDir()); + if (!idir.isAbsolute()) { + idir = new File(solrHome, dcore.getInstanceDir()); + } + String instanceDir = idir.getPath(); + log.info("Creating SolrCore '{}' using instanceDir: {}", + dcore.getName(), instanceDir); + // Initialize the solr config + SolrResourceLoader solrLoader = null; + + SolrConfig config = null; + String zkConfigName = null; + if(zkController == null) { + solrLoader = new SolrResourceLoader(instanceDir, libLoader, getCoreProps(instanceDir, dcore.getPropertiesName(),dcore.getCoreProperties())); + config = new SolrConfig(solrLoader, dcore.getConfigName(), null); } else { - // TODO: handle caching from ZooKeeper - perhaps using ZooKeepers versioning - // Don't like this cache though - how does it empty as last modified changes? - } - } - if(schema == null){ - if(zkController != null) { try { - schema = getSchemaFromZk(zkConfigName, dcore.getSchemaName(), config, solrLoader); + String collection = dcore.getCloudDescriptor().getCollectionName(); + zkController.createCollectionZkNode(dcore.getCloudDescriptor()); + + zkConfigName = zkController.readConfigName(collection); + if (zkConfigName == null) { + log.error("Could not find config name for collection:" + collection); + throw new ZooKeeperException(SolrException.ErrorCode.SERVER_ERROR, + "Could not find config name for collection:" + collection); + } + solrLoader = new ZkSolrResourceLoader(instanceDir, zkConfigName, libLoader, getCoreProps(instanceDir, dcore.getPropertiesName(),dcore.getCoreProperties()), zkController); + config = getSolrConfigFromZk(zkConfigName, dcore.getConfigName(), solrLoader); } catch (KeeperException e) { log.error("", e); throw new ZooKeeperException(SolrException.ErrorCode.SERVER_ERROR, - "", e); + "", e); } catch (InterruptedException e) { // Restore the interrupted status Thread.currentThread().interrupt(); log.error("", e); throw new ZooKeeperException(SolrException.ErrorCode.SERVER_ERROR, - "", e); + "", e); + } + } + + IndexSchema schema = null; + if (indexSchemaCache != null) { + if (zkController != null) { + File schemaFile = new File(dcore.getSchemaName()); + if (!schemaFile.isAbsolute()) { + schemaFile = new File(solrLoader.getInstanceDir() + "conf" + + File.separator + dcore.getSchemaName()); + } + if (schemaFile.exists()) { + String key = schemaFile.getAbsolutePath() + + ":" + + new SimpleDateFormat("yyyyMMddHHmmss", Locale.ROOT).format(new Date( + schemaFile.lastModified())); + schema = indexSchemaCache.get(key); + if (schema == null) { + log.info("creating new schema object for core: " + dcore.name); + schema = new IndexSchema(config, dcore.getSchemaName(), null); + indexSchemaCache.put(key, schema); + } else { + log.info("re-using schema object for core: " + dcore.name); + } + } + } else { + // TODO: handle caching from ZooKeeper - perhaps using ZooKeepers versioning + // Don't like this cache though - how does it empty as last modified changes? + } + } + if(schema == null){ + if(zkController != null) { + try { + schema = getSchemaFromZk(zkConfigName, dcore.getSchemaName(), config, solrLoader); + } catch (KeeperException e) { + log.error("", e); + throw new ZooKeeperException(SolrException.ErrorCode.SERVER_ERROR, + "", e); + } catch (InterruptedException e) { + // Restore the interrupted status + Thread.currentThread().interrupt(); + log.error("", e); + throw new ZooKeeperException(SolrException.ErrorCode.SERVER_ERROR, + "", e); + } + } else { + schema = new IndexSchema(config, dcore.getSchemaName(), null); } - } else { - schema = new IndexSchema(config, dcore.getSchemaName(), null); } - } - SolrCore core = new SolrCore(dcore.getName(), null, config, schema, dcore); + SolrCore core = new SolrCore(dcore.getName(), null, config, schema, dcore); - if (zkController == null && core.getUpdateHandler().getUpdateLog() != null) { - // always kick off recovery if we are in standalone mode. - core.getUpdateHandler().getUpdateLog().recoverFromLog(); - } + if (zkController == null && core.getUpdateHandler().getUpdateLog() != null) { + // always kick off recovery if we are in standalone mode. + core.getUpdateHandler().getUpdateLog().recoverFromLog(); + } + + return core; - return core; + // :TODO: Java7... + // http://docs.oracle.com/javase/7/docs/technotes/guides/language/catch-multiple.html + } catch (ParserConfigurationException e1) { + failure = e1; + throw e1; + } catch (IOException e2) { + failure = e2; + throw e2; + } catch (SAXException e3) { + failure = e3; + throw e3; + } catch (RuntimeException e4) { + failure = e4; + throw e4; + } finally { + synchronized (coreInitFailures) { + // remove first so insertion order is updated and newest is last + coreInitFailures.remove(name); + if (null != failure) { + coreInitFailures.put(name, failure); + } + } + } } - + /** * @return a Collection of registered SolrCores */ @@ -886,6 +922,32 @@ public class CoreContainer return lst; } + /** + * Returns an immutable Map of Exceptions that occured when initializing + * SolrCores (either at startup, or do to runtime requests to create cores) + * keyed off of the name (String) of the SolrCore that had the Exception + * during initialization. + *

+ * While the Map returned by this method is immutable and will not change + * once returned to the client, the source data used to generate this Map + * can be changed as various SolrCore operations are performed: + *

+ *
    + *
  • Failed attempts to create new SolrCores will add new Exceptions.
  • + *
  • Failed attempts to re-create a SolrCore using a name already contained in this Map will replace the Exception.
  • + *
  • Failed attempts to reload a SolrCore will cause an Exception to be added to this list -- even though the existing SolrCore with that name will continue to be available.
  • + *
  • Successful attempts to re-created a SolrCore using a name already contained in this Map will remove the Exception.
  • + *
  • Registering an existing SolrCore with a name already contained in this Map (ie: ALIAS or SWAP) will remove the Exception.
  • + *
+ */ + public Map getCoreInitFailures() { + synchronized ( coreInitFailures ) { + return Collections.unmodifiableMap(new LinkedHashMap + (coreInitFailures)); + } + } + + // ---------------- Core name related methods --------------- /** * Recreates a SolrCore. @@ -897,61 +959,90 @@ public class CoreContainer * @throws IOException * @throws SAXException */ - public void reload(String name) throws ParserConfigurationException, IOException, SAXException { - name= checkDefault(name); - SolrCore core; - synchronized(cores) { - core = cores.get(name); - } - if (core == null) - throw new SolrException( SolrException.ErrorCode.BAD_REQUEST, "No such core: " + name ); - CoreDescriptor cd = core.getCoreDescriptor(); + // :TODO: would be really nice if this method wrapped any underlying errors and only threw SolrException + + Exception failure = null; + try { + + name= checkDefault(name); + SolrCore core; + synchronized(cores) { + core = cores.get(name); + } + if (core == null) + throw new SolrException( SolrException.ErrorCode.BAD_REQUEST, "No such core: " + name ); + + CoreDescriptor cd = core.getCoreDescriptor(); - File instanceDir = new File(cd.getInstanceDir()); - if (!instanceDir.isAbsolute()) { - instanceDir = new File(getSolrHome(), cd.getInstanceDir()); - } + File instanceDir = new File(cd.getInstanceDir()); + if (!instanceDir.isAbsolute()) { + instanceDir = new File(getSolrHome(), cd.getInstanceDir()); + } - log.info("Reloading SolrCore '{}' using instanceDir: {}", - cd.getName(), instanceDir.getAbsolutePath()); + log.info("Reloading SolrCore '{}' using instanceDir: {}", + cd.getName(), instanceDir.getAbsolutePath()); - SolrResourceLoader solrLoader; - if(zkController == null) { - solrLoader = new SolrResourceLoader(instanceDir.getAbsolutePath(), libLoader, getCoreProps(instanceDir.getAbsolutePath(), cd.getPropertiesName(),cd.getCoreProperties())); - } else { - try { - String collection = cd.getCloudDescriptor().getCollectionName(); - zkController.createCollectionZkNode(cd.getCloudDescriptor()); + SolrResourceLoader solrLoader; + if(zkController == null) { + solrLoader = new SolrResourceLoader(instanceDir.getAbsolutePath(), libLoader, getCoreProps(instanceDir.getAbsolutePath(), cd.getPropertiesName(),cd.getCoreProperties())); + } else { + try { + String collection = cd.getCloudDescriptor().getCollectionName(); + zkController.createCollectionZkNode(cd.getCloudDescriptor()); - String zkConfigName = zkController.readConfigName(collection); - if (zkConfigName == null) { - log.error("Could not find config name for collection:" + collection); + String zkConfigName = zkController.readConfigName(collection); + if (zkConfigName == null) { + log.error("Could not find config name for collection:" + collection); + throw new ZooKeeperException(SolrException.ErrorCode.SERVER_ERROR, + "Could not find config name for collection:" + collection); + } + solrLoader = new ZkSolrResourceLoader(instanceDir.getAbsolutePath(), zkConfigName, libLoader, getCoreProps(instanceDir.getAbsolutePath(), cd.getPropertiesName(),cd.getCoreProperties()), zkController); + } catch (KeeperException e) { + log.error("", e); throw new ZooKeeperException(SolrException.ErrorCode.SERVER_ERROR, - "Could not find config name for collection:" + collection); + "", e); + } catch (InterruptedException e) { + // Restore the interrupted status + Thread.currentThread().interrupt(); + log.error("", e); + throw new ZooKeeperException(SolrException.ErrorCode.SERVER_ERROR, + "", e); } - solrLoader = new ZkSolrResourceLoader(instanceDir.getAbsolutePath(), zkConfigName, libLoader, getCoreProps(instanceDir.getAbsolutePath(), cd.getPropertiesName(),cd.getCoreProperties()), zkController); - } catch (KeeperException e) { - log.error("", e); - throw new ZooKeeperException(SolrException.ErrorCode.SERVER_ERROR, - "", e); - } catch (InterruptedException e) { - // Restore the interrupted status - Thread.currentThread().interrupt(); - log.error("", e); - throw new ZooKeeperException(SolrException.ErrorCode.SERVER_ERROR, - "", e); } - } - SolrCore newCore = core.reload(solrLoader); - // keep core to orig name link - String origName = coreToOrigName.remove(core); - if (origName != null) { - coreToOrigName.put(newCore, origName); + SolrCore newCore = core.reload(solrLoader, core); + // keep core to orig name link + String origName = coreToOrigName.remove(core); + if (origName != null) { + coreToOrigName.put(newCore, origName); + } + register(name, newCore, false); + + // :TODO: Java7... + // http://docs.oracle.com/javase/7/docs/technotes/guides/language/catch-multiple.html + } catch (ParserConfigurationException e1) { + failure = e1; + throw e1; + } catch (IOException e2) { + failure = e2; + throw e2; + } catch (SAXException e3) { + failure = e3; + throw e3; + } catch (RuntimeException e4) { + failure = e4; + throw e4; + } finally { + synchronized (coreInitFailures) { + // remove first so insertion order is updated and newest is last + coreInitFailures.remove(name); + if (null != failure) { + coreInitFailures.put(name, failure); + } + } } - register(name, newCore, false); } private String checkDefault(String name) { Modified: lucene/dev/branches/LUCENE-2878/solr/core/src/java/org/apache/solr/core/DirectoryFactory.java URL: http://svn.apache.org/viewvc/lucene/dev/branches/LUCENE-2878/solr/core/src/java/org/apache/solr/core/DirectoryFactory.java?rev=1372423&r1=1372422&r2=1372423&view=diff ============================================================================== --- lucene/dev/branches/LUCENE-2878/solr/core/src/java/org/apache/solr/core/DirectoryFactory.java (original) +++ lucene/dev/branches/LUCENE-2878/solr/core/src/java/org/apache/solr/core/DirectoryFactory.java Mon Aug 13 13:52:46 2012 @@ -34,7 +34,7 @@ public abstract class DirectoryFactory i /** * Indicates a Directory will no longer be used, and when it's ref count * hits 0, it can be closed. On shutdown all directories will be closed - * with this has been called or not. This is simply to allow early cleanup. + * whether this has been called or not. This is simply to allow early cleanup. * * @param directory * @throws IOException Modified: lucene/dev/branches/LUCENE-2878/solr/core/src/java/org/apache/solr/core/SolrConfig.java URL: http://svn.apache.org/viewvc/lucene/dev/branches/LUCENE-2878/solr/core/src/java/org/apache/solr/core/SolrConfig.java?rev=1372423&r1=1372422&r2=1372423&view=diff ============================================================================== --- lucene/dev/branches/LUCENE-2878/solr/core/src/java/org/apache/solr/core/SolrConfig.java (original) +++ lucene/dev/branches/LUCENE-2878/solr/core/src/java/org/apache/solr/core/SolrConfig.java Mon Aug 13 13:52:46 2012 @@ -436,9 +436,7 @@ public class SolrConfig extends Config { */ public List getPluginInfos(String type){ List result = pluginStore.get(type); - return result == null ? - (List) Collections.EMPTY_LIST: - result; + return result == null ? Collections.emptyList(): result; } public PluginInfo getPluginInfo(String type){ List result = pluginStore.get(type); @@ -446,29 +444,31 @@ public class SolrConfig extends Config { } private void initLibs() { - NodeList nodes = (NodeList) evaluate("lib", XPathConstants.NODESET); - if (nodes==null || nodes.getLength()==0) - return; + if (nodes == null || nodes.getLength() == 0) return; log.info("Adding specified lib dirs to ClassLoader"); - for (int i=0; i iwRef = null; + if (prev != null) { + iwRef = prev.getUpdateHandler().getSolrCoreState().getIndexWriter(null); + if (iwRef != null) { + final IndexWriter iw = iwRef.get(); + newReaderCreator = new Callable() { + @Override + public DirectoryReader call() throws Exception { + return DirectoryReader.open(iw, true); + } + }; + } + } + // Open the searcher *before* the update handler so we don't end up opening // one in the middle. // With lockless commits in Lucene now, this probably shouldn't be an issue anymore - getSearcher(false,false,null); + + try { + getSearcher(false,false,null,true); + } finally { + newReaderCreator = null; + if (iwRef != null) iwRef.decref(); + } String updateHandlerClass = solrConfig.getUpdateHandlerInfo().className; @@ -1049,7 +1071,8 @@ public final class SolrCore implements S private final LinkedList> _searchers = new LinkedList>(); private final LinkedList> _realtimeSearchers = new LinkedList>(); - final ExecutorService searcherExecutor = Executors.newSingleThreadExecutor(); + final ExecutorService searcherExecutor = Executors.newSingleThreadExecutor( + new DefaultSolrThreadFactory("searcherExecutor")); private int onDeckSearchers; // number of searchers preparing // Lock ordering: one can acquire the openSearcherLock and then the searcherLock, but not vice-versa. private Object searcherLock = new Object(); // the sync object for the searcher @@ -1057,7 +1080,7 @@ public final class SolrCore implements S private final int maxWarmingSearchers; // max number of on-deck searchers allowed private RefCounted realtimeSearcher; - + private Callable newReaderCreator; /** * Return a registered {@link RefCounted}<{@link SolrIndexSearcher}> with @@ -1208,9 +1231,20 @@ public final class SolrCore implements S tmp = new SolrIndexSearcher(this, schema, (realtime ? "realtime":"main"), newReader, true, !realtime, true, directoryFactory); } else { + // newestSearcher == null at this point + + if (newReaderCreator != null) { + // this is set in the constructor if there is a currently open index writer + // so that we pick up any uncommitted changes and so we don't go backwards + // in time on a core reload + DirectoryReader newReader = newReaderCreator.call(); + tmp = new SolrIndexSearcher(this, schema, (realtime ? "realtime":"main"), newReader, true, !realtime, true, directoryFactory); + } else { + // normal open that happens at startup // verbose("non-reopen START:"); tmp = new SolrIndexSearcher(this, newIndexDir, schema, getSolrConfig().indexConfig, "main", true, directoryFactory); // verbose("non-reopen DONE: searcher=",tmp); + } } List> searcherList = realtime ? _realtimeSearchers : _searchers; Modified: lucene/dev/branches/LUCENE-2878/solr/core/src/java/org/apache/solr/core/SolrResourceLoader.java URL: http://svn.apache.org/viewvc/lucene/dev/branches/LUCENE-2878/solr/core/src/java/org/apache/solr/core/SolrResourceLoader.java?rev=1372423&r1=1372422&r2=1372423&view=diff ============================================================================== --- lucene/dev/branches/LUCENE-2878/solr/core/src/java/org/apache/solr/core/SolrResourceLoader.java (original) +++ lucene/dev/branches/LUCENE-2878/solr/core/src/java/org/apache/solr/core/SolrResourceLoader.java Mon Aug 13 13:52:46 2012 @@ -17,23 +17,27 @@ package org.apache.solr.core; -import java.io.BufferedReader; import java.io.File; import java.io.FileFilter; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; -import java.io.InputStreamReader; import java.net.MalformedURLException; import java.net.URL; import java.net.URLClassLoader; import java.util.*; import java.util.concurrent.ConcurrentHashMap; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import org.apache.lucene.analysis.util.CharFilterFactory; import org.apache.lucene.analysis.util.ResourceLoaderAware; import org.apache.lucene.analysis.util.TokenFilterFactory; import org.apache.lucene.analysis.util.TokenizerFactory; +import org.apache.lucene.codecs.Codec; +import org.apache.lucene.codecs.PostingsFormat; +import org.apache.lucene.util.hash.HashFunction; +import org.apache.lucene.analysis.util.WordlistLoader; import org.apache.solr.common.ResourceLoader; import org.apache.solr.handler.admin.CoreAdminHandler; import org.apache.solr.handler.component.ShardHandlerFactory; @@ -42,7 +46,6 @@ import org.slf4j.LoggerFactory; import java.nio.charset.CharacterCodingException; import java.nio.charset.Charset; -import java.nio.charset.CodingErrorAction; import java.lang.reflect.Constructor; import javax.naming.Context; @@ -108,7 +111,7 @@ public class SolrResourceLoader implemen this.classLoader = createClassLoader(null, parent); addToClassLoader("./lib/", null); - + reloadLuceneSPI(); this.coreProperties = coreProperties; } @@ -129,7 +132,8 @@ public class SolrResourceLoader implemen * Adds every file/dir found in the baseDir which passes the specified Filter * to the ClassLoader used by this ResourceLoader. This method MUST * only be called prior to using this ResourceLoader to get any resources, otherwise - * it's behavior will be non-deterministic. + * it's behavior will be non-deterministic. You also have to {link @reloadLuceneSPI} + * before using this ResourceLoader. * * @param baseDir base directory whose children (either jars or directories of * classes) will be in the classpath, will be resolved relative @@ -145,7 +149,8 @@ public class SolrResourceLoader implemen * Adds the specific file/dir specified to the ClassLoader used by this * ResourceLoader. This method MUST * only be called prior to using this ResourceLoader to get any resources, otherwise - * it's behavior will be non-deterministic. + * it's behavior will be non-deterministic. You also have to {link #reloadLuceneSPI()} + * before using this ResourceLoader. * * @param path A jar file (or directory of classes) to be added to the classpath, * will be resolved relative the instance dir. @@ -164,6 +169,24 @@ public class SolrResourceLoader implemen } } + /** + * Reloads all Lucene SPI implementations using the new classloader. + * This method must be called after {@link #addToClassLoader(String)} + * and {@link #addToClassLoader(String,FileFilter)} before using + * this ResourceLoader. + */ + void reloadLuceneSPI() { + // Hash functions: + HashFunction.reloadHashFunctions(this.classLoader); + // Codecs: + PostingsFormat.reloadPostingsFormats(this.classLoader); + Codec.reloadCodecs(this.classLoader); + // Analysis: + CharFilterFactory.reloadCharFilters(this.classLoader); + TokenFilterFactory.reloadTokenFilters(this.classLoader); + TokenizerFactory.reloadTokenizers(this.classLoader); + } + private static URLClassLoader replaceClassLoader(final URLClassLoader oldLoader, final File base, final FileFilter filter) { @@ -248,7 +271,7 @@ public class SolrResourceLoader implemen * Override this method to customize loading schema resources. *@return the stream for the named schema */ - public InputStream openSchema(String name) { + public InputStream openSchema(String name) throws IOException { return openResource(name); } @@ -256,7 +279,7 @@ public class SolrResourceLoader implemen * Override this method to customize loading config resources. *@return the stream for the named configuration */ - public InputStream openConfig(String name) { + public InputStream openConfig(String name) throws IOException { return openResource(name); } @@ -268,7 +291,7 @@ public class SolrResourceLoader implemen * Override this method to customize loading resources. *@return the stream for the named resource */ - public InputStream openResource(String resource) { + public InputStream openResource(String resource) throws IOException { InputStream is=null; try { File f0 = new File(resource); @@ -288,10 +311,10 @@ public class SolrResourceLoader implemen if (is == null) is = classLoader.getResourceAsStream(getConfigDir() + resource); } catch (Exception e) { - throw new RuntimeException("Error opening " + resource, e); + throw new IOException("Error opening " + resource, e); } if (is==null) { - throw new RuntimeException("Can't find resource '" + resource + "' in classpath or '" + getConfigDir() + "', cwd="+System.getProperty("user.dir")); + throw new IOException("Can't find resource '" + resource + "' in classpath or '" + getConfigDir() + "', cwd="+System.getProperty("user.dir")); } return is; } @@ -333,41 +356,23 @@ public class SolrResourceLoader implemen public List getLines(String resource, Charset charset) throws IOException{ - BufferedReader input = null; - ArrayList lines; try { - input = new BufferedReader(new InputStreamReader(openResource(resource), - charset.newDecoder() - .onMalformedInput(CodingErrorAction.REPORT) - .onUnmappableCharacter(CodingErrorAction.REPORT))); - - lines = new ArrayList(); - for (String word=null; (word=input.readLine())!=null;) { - // skip initial bom marker - if (lines.isEmpty() && word.length() > 0 && word.charAt(0) == '\uFEFF') - word = word.substring(1); - // skip comments - if (word.startsWith("#")) continue; - word=word.trim(); - // skip blank lines - if (word.length()==0) continue; - lines.add(word); - } + return WordlistLoader.getLines(openResource(resource), charset); } catch (CharacterCodingException ex) { throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, - "Error loading resource (wrong encoding?): " + resource, ex); - } finally { - if (input != null) - input.close(); + "Error loading resource (wrong encoding?): " + resource, ex); } - return lines; } /* * A static map of short class name to fully qualified class name */ - private static Map classNameCache = new ConcurrentHashMap(); + private static final Map classNameCache = new ConcurrentHashMap(); + // Using this pattern, legacy analysis components from previous Solr versions are identified and delegated to SPI loader: + private static final Pattern legacyAnalysisPattern = + Pattern.compile("((\\Q"+base+".analysis.\\E)|(\\Q"+project+".\\E))([\\p{L}_$][\\p{L}\\p{N}_$]+?)(TokenFilter|Filter|Tokenizer|CharFilter)Factory"); + /** * This method loads a class either with it's FQN or a short-name (solr.class-simplename or class-simplename). * It tries to load the class with the name that is given first and if it fails, it tries all the known @@ -394,6 +399,27 @@ public class SolrResourceLoader implemen } } Class clazz = null; + + // first try legacy analysis patterns, now replaced by Lucene's Analysis package: + final Matcher m = legacyAnalysisPattern.matcher(cname); + if (m.matches()) { + final String name = m.group(4); + log.trace("Trying to load class from analysis SPI using name='{}'", name); + try { + if (CharFilterFactory.class.isAssignableFrom(expectedType)) { + return clazz = CharFilterFactory.lookupClass(name).asSubclass(expectedType); + } else if (TokenizerFactory.class.isAssignableFrom(expectedType)) { + return clazz = TokenizerFactory.lookupClass(name).asSubclass(expectedType); + } else if (TokenFilterFactory.class.isAssignableFrom(expectedType)) { + return clazz = TokenFilterFactory.lookupClass(name).asSubclass(expectedType); + } else { + log.warn("'{}' looks like an analysis factory, but caller requested different class type: {}", cname, expectedType.getName()); + } + } catch (IllegalArgumentException ex) { + // ok, we fall back to legacy loading + } + } + // first try cname == full name try { return Class.forName(cname, true, classLoader).asSubclass(expectedType); @@ -425,6 +451,12 @@ public class SolrResourceLoader implemen } } } + + static final String empty[] = new String[0]; + + public T newInstance(String name, Class expectedType) { + return newInstance(name, expectedType, empty); + } public T newInstance(String cname, Class expectedType, String ... subpackages) { Class clazz = findClass(cname, expectedType, subpackages); @@ -568,7 +600,7 @@ public class SolrResourceLoader implemen /** * Tell all {@link ResourceLoaderAware} instances about the loader */ - public void inform( ResourceLoader loader ) + public void inform( ResourceLoader loader ) throws IOException { // make a copy to avoid potential deadlock of a callback adding to the list Modified: lucene/dev/branches/LUCENE-2878/solr/core/src/java/org/apache/solr/handler/ReplicationHandler.java URL: http://svn.apache.org/viewvc/lucene/dev/branches/LUCENE-2878/solr/core/src/java/org/apache/solr/handler/ReplicationHandler.java?rev=1372423&r1=1372422&r2=1372423&view=diff ============================================================================== --- lucene/dev/branches/LUCENE-2878/solr/core/src/java/org/apache/solr/handler/ReplicationHandler.java (original) +++ lucene/dev/branches/LUCENE-2878/solr/core/src/java/org/apache/solr/handler/ReplicationHandler.java Mon Aug 13 13:52:46 2012 @@ -887,7 +887,7 @@ public class ReplicationHandler extends } // reboot the writer on the new index - core.getUpdateHandler().newIndexWriter(); + core.getUpdateHandler().newIndexWriter(true); } catch (IOException e) { LOG.warn("Unable to get IndexCommit on startup", e); Modified: lucene/dev/branches/LUCENE-2878/solr/core/src/java/org/apache/solr/handler/SnapPuller.java URL: http://svn.apache.org/viewvc/lucene/dev/branches/LUCENE-2878/solr/core/src/java/org/apache/solr/handler/SnapPuller.java?rev=1372423&r1=1372422&r2=1372423&view=diff ============================================================================== --- lucene/dev/branches/LUCENE-2878/solr/core/src/java/org/apache/solr/handler/SnapPuller.java (original) +++ lucene/dev/branches/LUCENE-2878/solr/core/src/java/org/apache/solr/handler/SnapPuller.java Mon Aug 13 13:52:46 2012 @@ -31,6 +31,7 @@ import org.apache.solr.common.params.Com import org.apache.solr.common.params.ModifiableSolrParams; import org.apache.solr.common.params.SolrParams; import org.apache.solr.common.util.FastInputStream; +import org.apache.solr.util.DefaultSolrThreadFactory; import org.apache.solr.util.FileUtils; import org.apache.solr.common.util.NamedList; import org.apache.solr.core.CachingDirectoryFactory.CloseListener; @@ -178,7 +179,8 @@ public class SnapPuller { } } }; - executorService = Executors.newSingleThreadScheduledExecutor(); + executorService = Executors.newSingleThreadScheduledExecutor( + new DefaultSolrThreadFactory("snapPuller")); long initialDelay = pollInterval - (System.currentTimeMillis() % pollInterval); executorService.scheduleAtFixedRate(task, initialDelay, pollInterval, TimeUnit.MILLISECONDS); LOG.info("Poll Scheduled at an interval of " + pollInterval + "ms"); @@ -311,7 +313,7 @@ public class SnapPuller { LOG.info("Number of files in latest index in master: " + filesToDownload.size()); // Create the sync service - fsyncService = Executors.newSingleThreadExecutor(); + fsyncService = Executors.newSingleThreadExecutor(new DefaultSolrThreadFactory("fsyncService")); // use a synchronized list because the list is read by other threads (to show details) filesDownloaded = Collections.synchronizedList(new ArrayList>()); // if the generateion of master is older than that of the slave , it means they are not compatible to be copied @@ -324,7 +326,8 @@ public class SnapPuller { successfulInstall = false; boolean deleteTmpIdxDir = true; - final File indexDir = new File(core.getIndexDir()); + // make sure it's the newest known index dir... + final File indexDir = new File(core.getNewIndexDir()); Directory oldDirectory = null; try { downloadIndexFiles(isFullCopyNeeded, tmpIndexDir, latestGeneration); @@ -534,7 +537,7 @@ public class SnapPuller { SolrQueryRequest req = new LocalSolrQueryRequest(solrCore, new ModifiableSolrParams()); // reboot the writer on the new index and get a new searcher - solrCore.getUpdateHandler().newIndexWriter(); + solrCore.getUpdateHandler().newIndexWriter(true); try { // first try to open an NRT searcher so that the new Modified: lucene/dev/branches/LUCENE-2878/solr/core/src/java/org/apache/solr/handler/admin/CollectionsHandler.java URL: http://svn.apache.org/viewvc/lucene/dev/branches/LUCENE-2878/solr/core/src/java/org/apache/solr/handler/admin/CollectionsHandler.java?rev=1372423&r1=1372422&r2=1372423&view=diff ============================================================================== --- lucene/dev/branches/LUCENE-2878/solr/core/src/java/org/apache/solr/handler/admin/CollectionsHandler.java (original) +++ lucene/dev/branches/LUCENE-2878/solr/core/src/java/org/apache/solr/handler/admin/CollectionsHandler.java Mon Aug 13 13:52:46 2012 @@ -17,9 +17,17 @@ package org.apache.solr.handler.admin; * limitations under the License. */ +import java.io.IOException; + +import org.apache.solr.client.solrj.SolrServerException; +import org.apache.solr.client.solrj.impl.HttpSolrServer; +import org.apache.solr.client.solrj.request.CoreAdminRequest; +import org.apache.solr.client.solrj.request.CoreAdminRequest.RequestSyncShard; import org.apache.solr.cloud.Overseer; import org.apache.solr.cloud.OverseerCollectionProcessor; import org.apache.solr.common.SolrException; +import org.apache.solr.common.cloud.ClusterState; +import org.apache.solr.common.cloud.ZkCoreNodeProps; import org.apache.solr.common.cloud.ZkNodeProps; import org.apache.solr.common.cloud.ZkStateReader; import org.apache.solr.common.params.CollectionParams.CollectionAction; @@ -103,6 +111,10 @@ public class CollectionsHandler extends this.handleReloadAction(req, rsp); break; } + case SYNCSHARD: { + this.handleSyncShardAction(req, rsp); + break; + } default: { throw new RuntimeException("Unknown action: " + action); @@ -123,6 +135,24 @@ public class CollectionsHandler extends // TODO: what if you want to block until the collection is available? coreContainer.getZkController().getOverseerCollectionQueue().offer(ZkStateReader.toJSON(m)); } + + private void handleSyncShardAction(SolrQueryRequest req, SolrQueryResponse rsp) throws KeeperException, InterruptedException, SolrServerException, IOException { + log.info("Syncing shard : " + req.getParamString()); + String collection = req.getParams().required().get("collection"); + String shard = req.getParams().required().get("shard"); + + ClusterState clusterState = coreContainer.getZkController().getClusterState(); + + ZkNodeProps leaderProps = clusterState.getLeader(collection, shard); + ZkCoreNodeProps nodeProps = new ZkCoreNodeProps(leaderProps); + + HttpSolrServer server = new HttpSolrServer(nodeProps.getBaseUrl()); + RequestSyncShard reqSyncShard = new CoreAdminRequest.RequestSyncShard(); + reqSyncShard.setCollection(collection); + reqSyncShard.setShard(shard); + reqSyncShard.setCoreName(nodeProps.getCoreName()); + server.request(reqSyncShard); + } private void handleDeleteAction(SolrQueryRequest req, SolrQueryResponse rsp) throws KeeperException, InterruptedException { Modified: lucene/dev/branches/LUCENE-2878/solr/core/src/java/org/apache/solr/handler/admin/CoreAdminHandler.java URL: http://svn.apache.org/viewvc/lucene/dev/branches/LUCENE-2878/solr/core/src/java/org/apache/solr/handler/admin/CoreAdminHandler.java?rev=1372423&r1=1372422&r2=1372423&view=diff ============================================================================== --- lucene/dev/branches/LUCENE-2878/solr/core/src/java/org/apache/solr/handler/admin/CoreAdminHandler.java (original) +++ lucene/dev/branches/LUCENE-2878/solr/core/src/java/org/apache/solr/handler/admin/CoreAdminHandler.java Mon Aug 13 13:52:46 2012 @@ -19,8 +19,11 @@ package org.apache.solr.handler.admin; import java.io.File; import java.io.IOException; +import java.util.Collections; import java.util.Date; +import java.util.HashMap; import java.util.Iterator; +import java.util.Map; import java.util.Properties; import org.apache.commons.io.FileUtils; @@ -28,9 +31,11 @@ import org.apache.lucene.index.Directory import org.apache.lucene.store.Directory; import org.apache.lucene.util.IOUtils; import org.apache.solr.cloud.CloudDescriptor; +import org.apache.solr.cloud.SyncStrategy; +import org.apache.solr.cloud.ZkController; import org.apache.solr.common.SolrException; import org.apache.solr.common.SolrException.ErrorCode; -import org.apache.solr.common.cloud.CloudState; +import org.apache.solr.common.cloud.ClusterState; import org.apache.solr.common.cloud.Slice; import org.apache.solr.common.cloud.ZkNodeProps; import org.apache.solr.common.cloud.ZkStateReader; @@ -47,8 +52,6 @@ import org.apache.solr.core.CoreDescript import org.apache.solr.core.DirectoryFactory; import org.apache.solr.core.SolrCore; import org.apache.solr.handler.RequestHandlerBase; -import org.apache.solr.handler.component.ShardHandler; -import org.apache.solr.handler.component.ShardHandlerFactory; import org.apache.solr.request.LocalSolrQueryRequest; import org.apache.solr.request.SolrQueryRequest; import org.apache.solr.response.SolrQueryResponse; @@ -69,8 +72,6 @@ import org.slf4j.LoggerFactory; public class CoreAdminHandler extends RequestHandlerBase { protected static Logger log = LoggerFactory.getLogger(CoreAdminHandler.class); protected final CoreContainer coreContainer; - private ShardHandlerFactory shardHandlerFactory; - private ShardHandler shardHandler; public CoreAdminHandler() { super(); @@ -87,8 +88,6 @@ public class CoreAdminHandler extends Re */ public CoreAdminHandler(final CoreContainer coreContainer) { this.coreContainer = coreContainer; - shardHandlerFactory = coreContainer.getShardHandlerFactory(); - shardHandler = shardHandlerFactory.getShardHandler(); } @@ -182,6 +181,11 @@ public class CoreAdminHandler extends Re break; } + case REQUESTSYNCSHARD: { + this.handleRequestSyncAction(req, rsp); + break; + } + default: { doPersist = this.handleCustomAction(req, rsp); break; @@ -564,13 +568,19 @@ public class CoreAdminHandler extends Re String cname = params.get(CoreAdminParams.CORE); boolean doPersist = false; NamedList status = new SimpleOrderedMap(); + Map allFailures = coreContainer.getCoreInitFailures(); try { if (cname == null) { rsp.add("defaultCoreName", coreContainer.getDefaultCoreName()); for (String name : coreContainer.getCoreNames()) { status.add(name, getCoreStatus(coreContainer, name)); } + rsp.add("initFailures", allFailures); } else { + Map failures = allFailures.containsKey(cname) + ? Collections.singletonMap(cname, allFailures.get(cname)) + : Collections.emptyMap(); + rsp.add("initFailures", failures); status.add(cname, getCoreStatus(coreContainer, cname)); } rsp.add("status", status); @@ -655,7 +665,7 @@ public class CoreAdminHandler extends Re protected void handleRequestRecoveryAction(SolrQueryRequest req, SolrQueryResponse rsp) throws IOException { final SolrParams params = req.getParams(); - + log.info("It has been requested that we recover"); String cname = params.get(CoreAdminParams.CORE); if (cname == null) { cname = ""; @@ -664,6 +674,15 @@ public class CoreAdminHandler extends Re try { core = coreContainer.getCore(cname); if (core != null) { + // try to publish as recovering right away + try { + coreContainer.getZkController().publish(core.getCoreDescriptor(), ZkStateReader.RECOVERING); + } catch (KeeperException e) { + SolrException.log(log, "", e); + } catch (InterruptedException e) { + SolrException.log(log, "", e); + } + core.getUpdateHandler().getSolrCoreState().doRecovery(coreContainer, cname); } else { SolrException.log(log, "Cound not find core to call recovery:" + cname); @@ -676,6 +695,48 @@ public class CoreAdminHandler extends Re } } + protected void handleRequestSyncAction(SolrQueryRequest req, + SolrQueryResponse rsp) throws IOException { + final SolrParams params = req.getParams(); + + log.info("I have been requested to sync up my shard"); + ZkController zkController = coreContainer.getZkController(); + if (zkController == null) { + throw new SolrException(ErrorCode.BAD_REQUEST, "Only valid for SolrCloud"); + } + + String cname = params.get(CoreAdminParams.CORE); + if (cname == null) { + throw new IllegalArgumentException(CoreAdminParams.CORE + " is required"); + } + SolrCore core = null; + try { + core = coreContainer.getCore(cname); + if (core != null) { + SyncStrategy syncStrategy = new SyncStrategy(); + + Map props = new HashMap(); + props.put(ZkStateReader.BASE_URL_PROP, zkController.getBaseUrl()); + props.put(ZkStateReader.CORE_NAME_PROP, cname); + props.put(ZkStateReader.NODE_NAME_PROP, zkController.getNodeName()); + + boolean success = syncStrategy.sync(zkController, core, new ZkNodeProps(props)); + if (!success) { + throw new SolrException(ErrorCode.SERVER_ERROR, "Sync Failed"); + } + } else { + SolrException.log(log, "Cound not find core to call sync:" + cname); + } + } finally { + // no recoveryStrat close for now + if (core != null) { + core.close(); + } + } + + + } + protected void handleWaitForStateAction(SolrQueryRequest req, SolrQueryResponse rsp) throws IOException, InterruptedException { final SolrParams params = req.getParams(); @@ -707,16 +768,16 @@ public class CoreAdminHandler extends Re // to accept updates CloudDescriptor cloudDescriptor = core.getCoreDescriptor() .getCloudDescriptor(); - CloudState cloudState = coreContainer.getZkController() - .getCloudState(); + ClusterState clusterState = coreContainer.getZkController() + .getClusterState(); String collection = cloudDescriptor.getCollectionName(); - Slice slice = cloudState.getSlice(collection, + Slice slice = clusterState.getSlice(collection, cloudDescriptor.getShardId()); if (slice != null) { ZkNodeProps nodeProps = slice.getShards().get(coreNodeName); if (nodeProps != null) { state = nodeProps.get(ZkStateReader.STATE_PROP); - live = cloudState.liveNodesContain(nodeName); + live = clusterState.liveNodesContain(nodeName); if (nodeProps != null && state.equals(waitForState)) { if (checkLive == null) { break; Modified: lucene/dev/branches/LUCENE-2878/solr/core/src/java/org/apache/solr/handler/admin/LukeRequestHandler.java URL: http://svn.apache.org/viewvc/lucene/dev/branches/LUCENE-2878/solr/core/src/java/org/apache/solr/handler/admin/LukeRequestHandler.java?rev=1372423&r1=1372422&r2=1372423&view=diff ============================================================================== --- lucene/dev/branches/LUCENE-2878/solr/core/src/java/org/apache/solr/handler/admin/LukeRequestHandler.java (original) +++ lucene/dev/branches/LUCENE-2878/solr/core/src/java/org/apache/solr/handler/admin/LukeRequestHandler.java Mon Aug 13 13:52:46 2012 @@ -390,7 +390,7 @@ public class LukeRequestHandler extends docsEnum = reader.termDocsEnum(reader.getLiveDocs(), term.field(), new BytesRef(term.text()), - false); + 0); if (docsEnum != null) { int docId; if ((docId = docsEnum.nextDoc()) != DocIdSetIterator.NO_MORE_DOCS) { Modified: lucene/dev/branches/LUCENE-2878/solr/core/src/java/org/apache/solr/handler/admin/ShowFileRequestHandler.java URL: http://svn.apache.org/viewvc/lucene/dev/branches/LUCENE-2878/solr/core/src/java/org/apache/solr/handler/admin/ShowFileRequestHandler.java?rev=1372423&r1=1372422&r2=1372423&view=diff ============================================================================== --- lucene/dev/branches/LUCENE-2878/solr/core/src/java/org/apache/solr/handler/admin/ShowFileRequestHandler.java (original) +++ lucene/dev/branches/LUCENE-2878/solr/core/src/java/org/apache/solr/handler/admin/ShowFileRequestHandler.java Mon Aug 13 13:52:46 2012 @@ -144,6 +144,9 @@ public class ShowFileRequestHandler exte if (fname.indexOf("..") >= 0) { throw new SolrException(ErrorCode.FORBIDDEN, "Invalid path: " + fname); } + if (fname.startsWith("/")) { // Only files relative to conf are valid + fname = fname.substring(1); + } adminFile = confPath + "/" + fname; } Modified: lucene/dev/branches/LUCENE-2878/solr/core/src/java/org/apache/solr/handler/component/HttpShardHandler.java URL: http://svn.apache.org/viewvc/lucene/dev/branches/LUCENE-2878/solr/core/src/java/org/apache/solr/handler/component/HttpShardHandler.java?rev=1372423&r1=1372422&r2=1372423&view=diff ============================================================================== --- lucene/dev/branches/LUCENE-2878/solr/core/src/java/org/apache/solr/handler/component/HttpShardHandler.java (original) +++ lucene/dev/branches/LUCENE-2878/solr/core/src/java/org/apache/solr/handler/component/HttpShardHandler.java Mon Aug 13 13:52:46 2012 @@ -41,7 +41,7 @@ import org.apache.solr.cloud.CloudDescri import org.apache.solr.cloud.ZkController; import org.apache.solr.common.SolrException; import org.apache.solr.common.SolrException.ErrorCode; -import org.apache.solr.common.cloud.CloudState; +import org.apache.solr.common.cloud.ClusterState; import org.apache.solr.common.cloud.Slice; import org.apache.solr.common.cloud.ZkCoreNodeProps; import org.apache.solr.common.cloud.ZkNodeProps; @@ -255,7 +255,7 @@ public class HttpShardHandler extends Sh if (rb.isDistrib) { // since the cost of grabbing cloud state is still up in the air, we grab it only // if we need it. - CloudState cloudState = null; + ClusterState clusterState = null; Map slices = null; CoreDescriptor coreDescriptor = req.getCore().getCoreDescriptor(); CloudDescriptor cloudDescriptor = coreDescriptor.getCloudDescriptor(); @@ -280,7 +280,7 @@ public class HttpShardHandler extends Sh } else if (zkController != null) { // we weren't provided with a list of slices to query, so find the list that will cover the complete index - cloudState = zkController.getCloudState(); + clusterState = zkController.getClusterState(); // This can be more efficient... we only record the name, even though we // have the shard info we need in the next step of mapping slice->shards @@ -301,12 +301,12 @@ public class HttpShardHandler extends Sh // cloud state and add them to the Map 'slices'. for (int i = 0; i < collectionList.size(); i++) { String collection = collectionList.get(i); - ClientUtils.appendMap(collection, slices, cloudState.getSlices(collection)); + ClientUtils.appendMap(collection, slices, clusterState.getSlices(collection)); } } else { // If no collections were specified, default to the collection for // this core. - slices = cloudState.getSlices(cloudDescriptor.getCollectionName()); + slices = clusterState.getSlices(cloudDescriptor.getCollectionName()); if (slices == null) { throw new SolrException(ErrorCode.BAD_REQUEST, "Could not find collection:" @@ -334,9 +334,9 @@ public class HttpShardHandler extends Sh if (zkController != null) { for (int i=0; i sliceShards = slice.getShards(); // For now, recreate the | delimited list of equivalent servers - Set liveNodes = cloudState.getLiveNodes(); + Set liveNodes = clusterState.getLiveNodes(); StringBuilder sliceShardsStr = new StringBuilder(); boolean first = true; for (ZkNodeProps nodeProps : sliceShards.values()) { Modified: lucene/dev/branches/LUCENE-2878/solr/core/src/java/org/apache/solr/handler/component/QueryElevationComponent.java URL: http://svn.apache.org/viewvc/lucene/dev/branches/LUCENE-2878/solr/core/src/java/org/apache/solr/handler/component/QueryElevationComponent.java?rev=1372423&r1=1372422&r2=1372423&view=diff ============================================================================== --- lucene/dev/branches/LUCENE-2878/solr/core/src/java/org/apache/solr/handler/component/QueryElevationComponent.java (original) +++ lucene/dev/branches/LUCENE-2878/solr/core/src/java/org/apache/solr/handler/component/QueryElevationComponent.java Mon Aug 13 13:52:46 2012 @@ -543,7 +543,7 @@ public class QueryElevationComponent ext for (String id : elevations.ids) { term.copyChars(id); if (seen.contains(id) == false && termsEnum.seekExact(term, false)) { - docsEnum = termsEnum.docs(liveDocs, docsEnum, false); + docsEnum = termsEnum.docs(liveDocs, docsEnum, 0); if (docsEnum != null) { int docId = docsEnum.nextDoc(); if (docId == DocIdSetIterator.NO_MORE_DOCS ) continue; // must have been deleted Modified: lucene/dev/branches/LUCENE-2878/solr/core/src/java/org/apache/solr/handler/component/RealTimeGetComponent.java URL: http://svn.apache.org/viewvc/lucene/dev/branches/LUCENE-2878/solr/core/src/java/org/apache/solr/handler/component/RealTimeGetComponent.java?rev=1372423&r1=1372422&r2=1372423&view=diff ============================================================================== --- lucene/dev/branches/LUCENE-2878/solr/core/src/java/org/apache/solr/handler/component/RealTimeGetComponent.java (original) +++ lucene/dev/branches/LUCENE-2878/solr/core/src/java/org/apache/solr/handler/component/RealTimeGetComponent.java Mon Aug 13 13:52:46 2012 @@ -352,14 +352,14 @@ public class RealTimeGetComponent extend String collection = cloudDescriptor.getCollectionName(); - CloudState cloudState = zkController.getCloudState(); + ClusterState clusterState = zkController.getClusterState(); Map> shardToId = new HashMap>(); for (String id : allIds) { BytesRef br = new BytesRef(); sf.getType().readableToIndexed(id, br); int hash = Hash.murmurhash3_x86_32(br.bytes, br.offset, br.length, 0); - String shard = cloudState.getShard(hash, collection); + String shard = clusterState.getShard(hash, collection); List idsForShard = shardToId.get(shard); if (idsForShard == null) { Modified: lucene/dev/branches/LUCENE-2878/solr/core/src/java/org/apache/solr/handler/component/StatsComponent.java URL: http://svn.apache.org/viewvc/lucene/dev/branches/LUCENE-2878/solr/core/src/java/org/apache/solr/handler/component/StatsComponent.java?rev=1372423&r1=1372422&r2=1372423&view=diff ============================================================================== --- lucene/dev/branches/LUCENE-2878/solr/core/src/java/org/apache/solr/handler/component/StatsComponent.java (original) +++ lucene/dev/branches/LUCENE-2878/solr/core/src/java/org/apache/solr/handler/component/StatsComponent.java Mon Aug 13 13:52:46 2012 @@ -256,13 +256,12 @@ class SimpleStats { FieldCache.DocTermsIndex facetTermsIndex; for( String facetField : facet ) { SchemaField fsf = searcher.getSchema().getField(facetField); - FieldType facetFieldType = fsf.getType(); - if (facetFieldType.isTokenized() || facetFieldType.isMultiValued()) { + if ( fsf.multiValued()) { throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, - "Stats can only facet on single-valued fields, not: " + facetField - + "[" + facetFieldType + "]"); - } + "Stats can only facet on single-valued fields, not: " + facetField ); + } + try { facetTermsIndex = FieldCache.DEFAULT.getTermsIndex(searcher.getAtomicReader(), facetField); }