You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by si...@apache.org on 2012/08/13 15:53:27 UTC

svn commit: r1372423 [45/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...

Modified: lucene/dev/branches/LUCENE-2878/solr/example/solr/collection1/conf/velocity/facet_fields.vm
URL: http://svn.apache.org/viewvc/lucene/dev/branches/LUCENE-2878/solr/example/solr/collection1/conf/velocity/facet_fields.vm?rev=1372423&r1=1372422&r2=1372423&view=diff
==============================================================================
--- lucene/dev/branches/LUCENE-2878/solr/example/solr/collection1/conf/velocity/facet_fields.vm (original)
+++ lucene/dev/branches/LUCENE-2878/solr/example/solr/collection1/conf/velocity/facet_fields.vm Mon Aug 13 13:52:46 2012
@@ -1,6 +1,8 @@
 #if($response.facetFields)
     <h2 #annTitle("Facets generated by adding &facet.field= to the request")>Field Facets</h2>
     #foreach($field in $response.facetFields)
+      ## Hide facets without value
+      #if($field.values.size() > 0)
       <span class="facet-field">$field.name</span>
 
       <ul>
@@ -8,5 +10,6 @@
             <li><a href="#url_for_facet_filter($field.name, $facet.name)">$facet.name</a> ($facet.count)</li>
         #end
       </ul>
+      #end
     #end
   #end
\ No newline at end of file

Modified: lucene/dev/branches/LUCENE-2878/solr/example/solr/collection1/conf/velocity/facet_ranges.vm
URL: http://svn.apache.org/viewvc/lucene/dev/branches/LUCENE-2878/solr/example/solr/collection1/conf/velocity/facet_ranges.vm?rev=1372423&r1=1372422&r2=1372423&view=diff
==============================================================================
--- lucene/dev/branches/LUCENE-2878/solr/example/solr/collection1/conf/velocity/facet_ranges.vm (original)
+++ lucene/dev/branches/LUCENE-2878/solr/example/solr/collection1/conf/velocity/facet_ranges.vm Mon Aug 13 13:52:46 2012
@@ -1,5 +1,7 @@
 <h2 #annTitle("Facets generated by adding &facet.range= to the request")>Range Facets</h2>
 #foreach ($field in $response.response.facet_counts.facet_ranges)
+  ## Hide facets without value
+  #if($field.value.counts.size() > 0)
 	#set($name = $field.key)
 	#set($display = $name)
 	#set($f = $field.value.counts)
@@ -9,4 +11,5 @@
 	#set($before = $field.value.before)
 	#set($after = $field.value.after)
 	#display_facet_range($f, $display, $name, $start, $end, $gap, $before, $after)
+  #end
 #end
\ No newline at end of file

Modified: lucene/dev/branches/LUCENE-2878/solr/example/solr/collection1/conf/velocity/hit.vm
URL: http://svn.apache.org/viewvc/lucene/dev/branches/LUCENE-2878/solr/example/solr/collection1/conf/velocity/hit.vm?rev=1372423&r1=1372422&r2=1372423&view=diff
==============================================================================
--- lucene/dev/branches/LUCENE-2878/solr/example/solr/collection1/conf/velocity/hit.vm (original)
+++ lucene/dev/branches/LUCENE-2878/solr/example/solr/collection1/conf/velocity/hit.vm Mon Aug 13 13:52:46 2012
@@ -1,5 +1,11 @@
 #set($docId = $doc.getFieldValue('id'))
 
 <div class="result-document">
-  #parse("doc.vm")
+#if($doc.getFieldValue('name'))
+  #parse("product-doc.vm")
+#elseif($doc.getFieldValue('compName_s'))
+  #parse("join-doc.vm")
+#else
+  #parse("richtext-doc.vm")
+#end
 </div>

Modified: lucene/dev/branches/LUCENE-2878/solr/example/solr/collection1/conf/velocity/hitGrouped.vm
URL: http://svn.apache.org/viewvc/lucene/dev/branches/LUCENE-2878/solr/example/solr/collection1/conf/velocity/hitGrouped.vm?rev=1372423&r1=1372422&r2=1372423&view=diff
==============================================================================
--- lucene/dev/branches/LUCENE-2878/solr/example/solr/collection1/conf/velocity/hitGrouped.vm (original)
+++ lucene/dev/branches/LUCENE-2878/solr/example/solr/collection1/conf/velocity/hitGrouped.vm Mon Aug 13 13:52:46 2012
@@ -6,7 +6,13 @@
     <div class="group-doclist" #annTitle("Contains the top scoring documents in the group")>
       #foreach ($doc in $group.doclist)
         #set($docId = $doc.getFieldValue('id'))
-        #parse("doc.vm")
+        #if($doc.getFieldValue('name'))
+          #parse("product-doc.vm")
+        #elseif($doc.getFieldValue('compName_s'))
+          #parse("join-doc.vm")
+        #else
+          #parse("richtext-doc.vm")
+        #end
       #end
     </div>
     #end</div>

Modified: lucene/dev/branches/LUCENE-2878/solr/example/solr/collection1/conf/velocity/layout.vm
URL: http://svn.apache.org/viewvc/lucene/dev/branches/LUCENE-2878/solr/example/solr/collection1/conf/velocity/layout.vm?rev=1372423&r1=1372422&r2=1372423&view=diff
==============================================================================
--- lucene/dev/branches/LUCENE-2878/solr/example/solr/collection1/conf/velocity/layout.vm (original)
+++ lucene/dev/branches/LUCENE-2878/solr/example/solr/collection1/conf/velocity/layout.vm Mon Aug 13 13:52:46 2012
@@ -3,7 +3,7 @@
   #parse("head.vm")
 </head>
   <body>
-    <div id="admin"><a href="#url_for_solr">Solr Admin</a></div>
+    <div id="admin"><a href="#url_root/#/#core_name">Solr Admin</a></div>
     <div id="header">
       #parse("header.vm")
     </div>

Modified: lucene/dev/branches/LUCENE-2878/solr/example/solr/collection1/conf/velocity/main.css
URL: http://svn.apache.org/viewvc/lucene/dev/branches/LUCENE-2878/solr/example/solr/collection1/conf/velocity/main.css?rev=1372423&r1=1372422&r2=1372423&view=diff
==============================================================================
--- lucene/dev/branches/LUCENE-2878/solr/example/solr/collection1/conf/velocity/main.css (original)
+++ lucene/dev/branches/LUCENE-2878/solr/example/solr/collection1/conf/velocity/main.css Mon Aug 13 13:52:46 2012
@@ -167,6 +167,10 @@ a {
   width:60%;
 }
 
+.result-body{
+  background: #ddd;
+}
+
 .mlt{
   
 }

Modified: lucene/dev/branches/LUCENE-2878/solr/solrj/build.xml
URL: http://svn.apache.org/viewvc/lucene/dev/branches/LUCENE-2878/solr/solrj/build.xml?rev=1372423&r1=1372422&r2=1372423&view=diff
==============================================================================
--- lucene/dev/branches/LUCENE-2878/solr/solrj/build.xml (original)
+++ lucene/dev/branches/LUCENE-2878/solr/solrj/build.xml Mon Aug 13 13:52:46 2012
@@ -20,6 +20,9 @@
 
   <property name="ivy.retrieve.pattern" value="${common-solr.dir}/lib/[artifact]-[revision].[ext]"/>
 
+  <!-- we cannot sync because solr/core and solr/solrj share the same lib/... clean this up! -->
+  <property name="ivy.sync" value="false"/>
+
   <import file="../common-build.xml"/>
 
   <!-- Specialized common-solr.test.classpath, to remove the Solr core test output -->

Modified: lucene/dev/branches/LUCENE-2878/solr/solrj/ivy.xml
URL: http://svn.apache.org/viewvc/lucene/dev/branches/LUCENE-2878/solr/solrj/ivy.xml?rev=1372423&r1=1372422&r2=1372423&view=diff
==============================================================================
--- lucene/dev/branches/LUCENE-2878/solr/solrj/ivy.xml (original)
+++ lucene/dev/branches/LUCENE-2878/solr/solrj/ivy.xml Mon Aug 13 13:52:46 2012
@@ -20,7 +20,7 @@
     <info organisation="org.apache.solr" module="solrj"/>
 
     <dependencies>
-      <dependency org="org.apache.zookeeper" name="zookeeper" rev="3.3.5" transitive="false"/>
+      <dependency org="org.apache.zookeeper" name="zookeeper" rev="3.3.6" transitive="false"/>
       <dependency org="org.slf4j" name="log4j-over-slf4j" rev="1.6.4" transitive="false"/>
       <dependency org="org.apache.httpcomponents" name="httpcore" rev="4.1.4" transitive="false"/>
       <dependency org="org.apache.httpcomponents" name="httpclient" rev="4.1.3" transitive="false"/>

Modified: lucene/dev/branches/LUCENE-2878/solr/solrj/src/java/org/apache/solr/client/solrj/impl/CloudSolrServer.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/LUCENE-2878/solr/solrj/src/java/org/apache/solr/client/solrj/impl/CloudSolrServer.java?rev=1372423&r1=1372422&r2=1372423&view=diff
==============================================================================
--- lucene/dev/branches/LUCENE-2878/solr/solrj/src/java/org/apache/solr/client/solrj/impl/CloudSolrServer.java (original)
+++ lucene/dev/branches/LUCENE-2878/solr/solrj/src/java/org/apache/solr/client/solrj/impl/CloudSolrServer.java Mon Aug 13 13:52:46 2012
@@ -32,9 +32,10 @@ import org.apache.http.client.HttpClient
 import org.apache.solr.client.solrj.SolrRequest;
 import org.apache.solr.client.solrj.SolrServer;
 import org.apache.solr.client.solrj.SolrServerException;
+import org.apache.solr.client.solrj.request.IsUpdateRequest;
 import org.apache.solr.client.solrj.util.ClientUtils;
 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;
@@ -61,6 +62,18 @@ public class CloudSolrServer extends Sol
   private LBHttpSolrServer lbServer;
   private HttpClient myClient;
   Random rand = new Random();
+  
+  // since the state shouldn't change often, should be very cheap reads
+  private volatile List<String> urlList;
+  
+  private volatile List<String> leaderUrlList;
+  private volatile List<String> replicasList;
+  
+  private volatile int lastClusterStateHashCode;
+  
+  private final boolean updatesToLeaders;
+
+  
   /**
    * @param zkHost The client endpoint of the zookeeper quorum containing the cloud state,
    * in the form HOST:PORT.
@@ -69,6 +82,7 @@ public class CloudSolrServer extends Sol
       this.zkHost = zkHost;
       this.myClient = HttpClientUtil.createClient(null);
       this.lbServer = new LBHttpSolrServer(myClient);
+      this.updatesToLeaders = true;
   }
 
   /**
@@ -79,6 +93,19 @@ public class CloudSolrServer extends Sol
   public CloudSolrServer(String zkHost, LBHttpSolrServer lbServer) {
     this.zkHost = zkHost;
     this.lbServer = lbServer;
+    this.updatesToLeaders = true;
+  }
+  
+  /**
+   * @param zkHost The client endpoint of the zookeeper quorum containing the cloud state,
+   * in the form HOST:PORT.
+   * @param lbServer LBHttpSolrServer instance for requests. 
+   * @param updatesToLeaders sends updates only to leaders - defaults to true
+   */
+  public CloudSolrServer(String zkHost, LBHttpSolrServer lbServer, boolean updatesToLeaders) {
+    this.zkHost = zkHost;
+    this.lbServer = lbServer;
+    this.updatesToLeaders = updatesToLeaders;
   }
 
   public ZkStateReader getZkStateReader() {
@@ -139,7 +166,14 @@ public class CloudSolrServer extends Sol
 
     // TODO: if you can hash here, you could favor the shard leader
     
-    CloudState cloudState = zkStateReader.getCloudState();
+    ClusterState clusterState = zkStateReader.getClusterState();
+    boolean sendToLeaders = false;
+    List<String> replicas = null;
+    
+    if (request instanceof IsUpdateRequest && updatesToLeaders) {
+      sendToLeaders = true;
+      replicas = new ArrayList<String>();
+    }
 
     SolrParams reqParams = request.getParams();
     if (reqParams == null) {
@@ -154,42 +188,70 @@ public class CloudSolrServer extends Sol
     // Extract each comma separated collection name and store in a List.
     List<String> collectionList = StrUtils.splitSmart(collection, ",", true);
     
+    // TODO: not a big deal because of the caching, but we could avoid looking at every shard
+    // when getting leaders if we tweaked some things
+    
     // Retrieve slices from the cloud state and, for each collection specified,
     // add it to the Map of slices.
     Map<String,Slice> slices = new HashMap<String,Slice>();
     for (int i = 0; i < collectionList.size(); i++) {
       String coll= collectionList.get(i);
-      ClientUtils.appendMap(coll, slices, cloudState.getSlices(coll));
+      ClientUtils.appendMap(coll, slices, clusterState.getSlices(coll));
     }
 
-    Set<String> liveNodes = cloudState.getLiveNodes();
+    Set<String> liveNodes = clusterState.getLiveNodes();
 
-    // IDEA: have versions on various things... like a global cloudState version
-    // or shardAddressVersion (which only changes when the shards change)
-    // to allow caching.
-
-    // build a map of unique nodes
-    // TODO: allow filtering by group, role, etc
-    Map<String,ZkNodeProps> nodes = new HashMap<String,ZkNodeProps>();
-    List<String> urlList = new ArrayList<String>();
-    for (Slice slice : slices.values()) {
-      for (ZkNodeProps nodeProps : slice.getShards().values()) {
-        ZkCoreNodeProps coreNodeProps = new ZkCoreNodeProps(nodeProps);
-        String node = coreNodeProps.getNodeName();
-        if (!liveNodes.contains(coreNodeProps.getNodeName())
-            || !coreNodeProps.getState().equals(
-                ZkStateReader.ACTIVE)) continue;
-        if (nodes.put(node, nodeProps) == null) {
-          String url = coreNodeProps.getCoreUrl();
-          urlList.add(url);
+    if (sendToLeaders && leaderUrlList == null || !sendToLeaders && urlList == null || clusterState.hashCode() != this.lastClusterStateHashCode) {
+    
+      // build a map of unique nodes
+      // TODO: allow filtering by group, role, etc
+      Map<String,ZkNodeProps> nodes = new HashMap<String,ZkNodeProps>();
+      List<String> urlList = new ArrayList<String>();
+      for (Slice slice : slices.values()) {
+        for (ZkNodeProps nodeProps : slice.getShards().values()) {
+          ZkCoreNodeProps coreNodeProps = new ZkCoreNodeProps(nodeProps);
+          String node = coreNodeProps.getNodeName();
+          if (!liveNodes.contains(coreNodeProps.getNodeName())
+              || !coreNodeProps.getState().equals(ZkStateReader.ACTIVE)) continue;
+          if (nodes.put(node, nodeProps) == null) {
+            if (!sendToLeaders || (sendToLeaders && coreNodeProps.isLeader())) {
+              String url = coreNodeProps.getCoreUrl();
+              urlList.add(url);
+            } else if (sendToLeaders) {
+              String url = coreNodeProps.getCoreUrl();
+              replicas.add(url);
+            }
+          }
         }
       }
+      if (sendToLeaders) {
+        this.leaderUrlList = urlList; 
+        this.replicasList = replicas;
+      } else {
+        this.urlList = urlList;
+      }
+      this.lastClusterStateHashCode = clusterState.hashCode();
+    }
+    
+    List<String> theUrlList;
+    if (sendToLeaders) {
+      theUrlList = new ArrayList<String>(leaderUrlList.size());
+      theUrlList.addAll(leaderUrlList);
+    } else {
+      theUrlList = new ArrayList<String>(urlList.size());
+      theUrlList.addAll(urlList);
     }
+    Collections.shuffle(theUrlList, rand);
+    if (replicas != null) {
+      ArrayList<String> theReplicas = new ArrayList<String>(replicasList.size());
+      theReplicas.addAll(replicasList);
+      Collections.shuffle(theReplicas, rand);
 
-    Collections.shuffle(urlList, rand);
-    //System.out.println("########################## MAKING REQUEST TO " + urlList);
+      theUrlList.addAll(theReplicas);
+    }
+    //System.out.println("########################## MAKING REQUEST TO " + theUrlList);
  
-    LBHttpSolrServer.Req req = new LBHttpSolrServer.Req(request, urlList);
+    LBHttpSolrServer.Req req = new LBHttpSolrServer.Req(request, theUrlList);
     LBHttpSolrServer.Rsp rsp = lbServer.request(req);
     return rsp.getResponse();
   }
@@ -211,4 +273,16 @@ public class CloudSolrServer extends Sol
   public LBHttpSolrServer getLbServer() {
     return lbServer;
   }
+
+  List<String> getUrlList() {
+    return urlList;
+  }
+
+  List<String> getLeaderUrlList() {
+    return leaderUrlList;
+  }
+
+  List<String> getReplicasList() {
+    return replicasList;
+  }
 }

Modified: lucene/dev/branches/LUCENE-2878/solr/solrj/src/java/org/apache/solr/client/solrj/impl/ConcurrentUpdateSolrServer.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/LUCENE-2878/solr/solrj/src/java/org/apache/solr/client/solrj/impl/ConcurrentUpdateSolrServer.java?rev=1372423&r1=1372422&r2=1372423&view=diff
==============================================================================
--- lucene/dev/branches/LUCENE-2878/solr/solrj/src/java/org/apache/solr/client/solrj/impl/ConcurrentUpdateSolrServer.java (original)
+++ lucene/dev/branches/LUCENE-2878/solr/solrj/src/java/org/apache/solr/client/solrj/impl/ConcurrentUpdateSolrServer.java Mon Aug 13 13:52:46 2012
@@ -49,6 +49,7 @@ import org.apache.solr.common.params.Mod
 import org.apache.solr.common.params.SolrParams;
 import org.apache.solr.common.params.UpdateParams;
 import org.apache.solr.common.util.NamedList;
+import org.apache.solr.common.util.SolrjNamedThreadFactory;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -71,7 +72,8 @@ public class ConcurrentUpdateSolrServer 
       .getLogger(ConcurrentUpdateSolrServer.class);
   private HttpSolrServer server;
   final BlockingQueue<UpdateRequest> queue;
-  final ExecutorService scheduler = Executors.newCachedThreadPool();
+  final ExecutorService scheduler = Executors.newCachedThreadPool(
+      new SolrjNamedThreadFactory("concurrentUpdateScheduler"));
   final Queue<Runner> runners;
   volatile CountDownLatch lock = null; // used to block everything
   final int threadCount;

Modified: lucene/dev/branches/LUCENE-2878/solr/solrj/src/java/org/apache/solr/client/solrj/impl/HttpSolrServer.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/LUCENE-2878/solr/solrj/src/java/org/apache/solr/client/solrj/impl/HttpSolrServer.java?rev=1372423&r1=1372422&r2=1372423&view=diff
==============================================================================
--- lucene/dev/branches/LUCENE-2878/solr/solrj/src/java/org/apache/solr/client/solrj/impl/HttpSolrServer.java (original)
+++ lucene/dev/branches/LUCENE-2878/solr/solrj/src/java/org/apache/solr/client/solrj/impl/HttpSolrServer.java Mon Aug 13 13:52:46 2012
@@ -369,9 +369,6 @@ public class HttpSolrServer extends Solr
                 + " sent back a redirect (" + httpStatus + ").");
           }
           break;
-        case HttpStatus.SC_NOT_FOUND:
-          throw new SolrServerException("Server at " + getBaseURL()
-              + " was not found (404).");
         default:
           throw new SolrException(SolrException.ErrorCode.getErrorCode(httpStatus), "Server at " + getBaseURL()
               + " returned non ok status:" + httpStatus + ", message:"

Modified: lucene/dev/branches/LUCENE-2878/solr/solrj/src/java/org/apache/solr/client/solrj/impl/LBHttpSolrServer.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/LUCENE-2878/solr/solrj/src/java/org/apache/solr/client/solrj/impl/LBHttpSolrServer.java?rev=1372423&r1=1372422&r2=1372423&view=diff
==============================================================================
--- lucene/dev/branches/LUCENE-2878/solr/solrj/src/java/org/apache/solr/client/solrj/impl/LBHttpSolrServer.java (original)
+++ lucene/dev/branches/LUCENE-2878/solr/solrj/src/java/org/apache/solr/client/solrj/impl/LBHttpSolrServer.java Mon Aug 13 13:52:46 2012
@@ -21,6 +21,7 @@ import org.apache.solr.client.solrj.*;
 import org.apache.solr.client.solrj.response.QueryResponse;
 import org.apache.solr.common.params.ModifiableSolrParams;
 import org.apache.solr.common.util.NamedList;
+import org.apache.solr.common.util.SolrjNamedThreadFactory;
 import org.apache.solr.common.SolrException;
 
 import java.io.IOException;
@@ -397,7 +398,7 @@ public class LBHttpSolrServer extends So
   public void setSoTimeout(int timeout) {
     HttpClientUtil.setSoTimeout(httpClient, timeout);
   }
-  
+
   @Override
   public void shutdown() {
     if (aliveCheckExecutor != null) {
@@ -555,7 +556,8 @@ public class LBHttpSolrServer extends So
     if (aliveCheckExecutor == null) {
       synchronized (this) {
         if (aliveCheckExecutor == null) {
-          aliveCheckExecutor = Executors.newSingleThreadScheduledExecutor();
+          aliveCheckExecutor = Executors.newSingleThreadScheduledExecutor(
+              new SolrjNamedThreadFactory("aliveCheckExecutor"));
           aliveCheckExecutor.scheduleAtFixedRate(
                   getAliveCheckRunner(new WeakReference<LBHttpSolrServer>(this)),
                   this.interval, this.interval, TimeUnit.MILLISECONDS);

Modified: lucene/dev/branches/LUCENE-2878/solr/solrj/src/java/org/apache/solr/client/solrj/request/AbstractUpdateRequest.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/LUCENE-2878/solr/solrj/src/java/org/apache/solr/client/solrj/request/AbstractUpdateRequest.java?rev=1372423&r1=1372422&r2=1372423&view=diff
==============================================================================
--- lucene/dev/branches/LUCENE-2878/solr/solrj/src/java/org/apache/solr/client/solrj/request/AbstractUpdateRequest.java (original)
+++ lucene/dev/branches/LUCENE-2878/solr/solrj/src/java/org/apache/solr/client/solrj/request/AbstractUpdateRequest.java Mon Aug 13 13:52:46 2012
@@ -30,7 +30,7 @@ import java.io.IOException;
  *
  *
  **/
-public abstract class AbstractUpdateRequest extends SolrRequest {
+public abstract class AbstractUpdateRequest extends SolrRequest implements IsUpdateRequest {
   protected ModifiableSolrParams params;
   protected int commitWithin = -1;
 

Modified: lucene/dev/branches/LUCENE-2878/solr/solrj/src/java/org/apache/solr/client/solrj/request/CoreAdminRequest.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/LUCENE-2878/solr/solrj/src/java/org/apache/solr/client/solrj/request/CoreAdminRequest.java?rev=1372423&r1=1372422&r2=1372423&view=diff
==============================================================================
--- lucene/dev/branches/LUCENE-2878/solr/solrj/src/java/org/apache/solr/client/solrj/request/CoreAdminRequest.java (original)
+++ lucene/dev/branches/LUCENE-2878/solr/solrj/src/java/org/apache/solr/client/solrj/request/CoreAdminRequest.java Mon Aug 13 13:52:46 2012
@@ -221,6 +221,44 @@ public class CoreAdminRequest extends So
     }
   }
   
+  public static class RequestSyncShard extends CoreAdminRequest {
+    private String shard;
+    private String collection;
+    
+    public RequestSyncShard() {
+      action = CoreAdminAction.REQUESTSYNCSHARD;
+    }
+
+    @Override
+    public SolrParams getParams() {
+      if( action == null ) {
+        throw new RuntimeException( "no action specified!" );
+      }
+      ModifiableSolrParams params = new ModifiableSolrParams();
+      params.set(CoreAdminParams.ACTION, action.toString());
+      params.set("shard", shard);
+      params.set("collection", collection);
+      params.set(CoreAdminParams.CORE, core);
+      return params;
+    }
+
+    public String getShard() {
+      return shard;
+    }
+
+    public void setShard(String shard) {
+      this.shard = shard;
+    }
+
+    public String getCollection() {
+      return collection;
+    }
+
+    public void setCollection(String collection) {
+      this.collection = collection;
+    }
+  }
+  
     //a persist core request
   public static class Persist extends CoreAdminRequest {
     protected String fileName = null;

Modified: lucene/dev/branches/LUCENE-2878/solr/solrj/src/java/org/apache/solr/client/solrj/request/DirectXmlRequest.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/LUCENE-2878/solr/solrj/src/java/org/apache/solr/client/solrj/request/DirectXmlRequest.java?rev=1372423&r1=1372422&r2=1372423&view=diff
==============================================================================
--- lucene/dev/branches/LUCENE-2878/solr/solrj/src/java/org/apache/solr/client/solrj/request/DirectXmlRequest.java (original)
+++ lucene/dev/branches/LUCENE-2878/solr/solrj/src/java/org/apache/solr/client/solrj/request/DirectXmlRequest.java Mon Aug 13 13:52:46 2012
@@ -34,7 +34,7 @@ import org.apache.solr.common.util.Conte
  *
  * @since solr 1.3
  */
-public class DirectXmlRequest extends SolrRequest
+public class DirectXmlRequest extends SolrRequest implements IsUpdateRequest
 {
   final String xml;
   private SolrParams params;

Modified: lucene/dev/branches/LUCENE-2878/solr/solrj/src/java/org/apache/solr/common/cloud/ConnectionManager.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/LUCENE-2878/solr/solrj/src/java/org/apache/solr/common/cloud/ConnectionManager.java?rev=1372423&r1=1372422&r2=1372423&view=diff
==============================================================================
--- lucene/dev/branches/LUCENE-2878/solr/solrj/src/java/org/apache/solr/common/cloud/ConnectionManager.java (original)
+++ lucene/dev/branches/LUCENE-2878/solr/solrj/src/java/org/apache/solr/common/cloud/ConnectionManager.java Mon Aug 13 13:52:46 2012
@@ -47,6 +47,8 @@ class ConnectionManager implements Watch
 
   private OnReconnect onReconnect;
 
+  private volatile boolean isClosed = false;
+
   public ConnectionManager(String name, SolrZkClient client, String zkServerAddress, int zkClientTimeout, ZkClientConnectionStrategy strat, OnReconnect onConnect) {
     this.name = name;
     this.client = client;
@@ -68,6 +70,8 @@ class ConnectionManager implements Watch
       log.info("Watcher " + this + " name:" + name + " got event " + event
           + " path:" + event.getPath() + " type:" + event.getType());
     }
+    
+    checkClosed();
 
     state = event.getState();
     if (state == KeeperState.SyncConnected) {
@@ -81,11 +85,18 @@ class ConnectionManager implements Watch
         connectionStrategy.reconnect(zkServerAddress, zkClientTimeout, this,
             new ZkClientConnectionStrategy.ZkUpdate() {
               @Override
-              public void update(SolrZooKeeper keeper)
-                  throws InterruptedException, TimeoutException {
+              public void update(SolrZooKeeper keeper) throws TimeoutException {
                 synchronized (connectionStrategy) {
-                  waitForConnected(SolrZkClient.DEFAULT_CLIENT_CONNECT_TIMEOUT);
-                  client.updateKeeper(keeper);
+                  checkClosed();
+                  try {
+                    waitForConnected(SolrZkClient.DEFAULT_CLIENT_CONNECT_TIMEOUT);
+                    checkClosed();
+                    client.updateKeeper(keeper);
+                  } catch (InterruptedException e) {
+                    // we must have been asked to stop
+                    throw new RuntimeException("Giving up on connecting - we were interrupted");
+                  }
+                  checkClosed();
                   if (onReconnect != null) {
                     onReconnect.command();
                   }
@@ -95,6 +106,7 @@ class ConnectionManager implements Watch
                 }
                 
               }
+
             });
       } catch (Exception e) {
         SolrException.log(log, "", e);
@@ -109,7 +121,13 @@ class ConnectionManager implements Watch
   }
 
   public synchronized boolean isConnected() {
-    return connected;
+    return !isClosed && connected;
+  }
+  
+  // we use a volatile rather than sync
+  // to avoid deadlock on shutdown
+  public void close() {
+    this.isClosed = true;
   }
 
   public synchronized KeeperState state() {
@@ -122,12 +140,20 @@ class ConnectionManager implements Watch
     long left = waitForConnection;
     while (!connected && left > 0) {
       wait(left);
+      checkClosed();
       left = expire - System.currentTimeMillis();
     }
     if (!connected) {
       throw new TimeoutException("Could not connect to ZooKeeper " + zkServerAddress + " within " + waitForConnection + " ms");
     }
   }
+  
+  private synchronized void checkClosed() {
+    if (isClosed) {
+      log.info("Not acting because I am closed");
+      return;
+    }
+  }
 
   public synchronized void waitForDisconnected(long timeout)
       throws InterruptedException, TimeoutException {

Modified: lucene/dev/branches/LUCENE-2878/solr/solrj/src/java/org/apache/solr/common/cloud/SolrZkClient.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/LUCENE-2878/solr/solrj/src/java/org/apache/solr/common/cloud/SolrZkClient.java?rev=1372423&r1=1372422&r2=1372423&view=diff
==============================================================================
--- lucene/dev/branches/LUCENE-2878/solr/solrj/src/java/org/apache/solr/common/cloud/SolrZkClient.java (original)
+++ lucene/dev/branches/LUCENE-2878/solr/solrj/src/java/org/apache/solr/common/cloud/SolrZkClient.java Mon Aug 13 13:52:46 2012
@@ -654,7 +654,11 @@ public class SolrZkClient {
   public void close() throws InterruptedException {
     if (isClosed) return; // it's okay if we over close - same as solrcore
     isClosed = true;
-    keeper.close();
+    try {
+      keeper.close();
+    } finally {
+      connManager.close();
+    }
     numCloses.incrementAndGet();
   }
 

Modified: lucene/dev/branches/LUCENE-2878/solr/solrj/src/java/org/apache/solr/common/cloud/ZkCoreNodeProps.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/LUCENE-2878/solr/solrj/src/java/org/apache/solr/common/cloud/ZkCoreNodeProps.java?rev=1372423&r1=1372422&r2=1372423&view=diff
==============================================================================
--- lucene/dev/branches/LUCENE-2878/solr/solrj/src/java/org/apache/solr/common/cloud/ZkCoreNodeProps.java (original)
+++ lucene/dev/branches/LUCENE-2878/solr/solrj/src/java/org/apache/solr/common/cloud/ZkCoreNodeProps.java Mon Aug 13 13:52:46 2012
@@ -45,6 +45,10 @@ public class ZkCoreNodeProps {
     return nodeProps.get(ZkStateReader.CORE_NAME_PROP);
   }
   
+  public static String getCoreUrl(ZkNodeProps nodeProps) {
+    return getCoreUrl(nodeProps.get(ZkStateReader.BASE_URL_PROP), nodeProps.get(ZkStateReader.CORE_NAME_PROP));
+  }
+  
   public static String getCoreUrl(String baseUrl, String coreName) {
     StringBuilder sb = new StringBuilder();
     if (baseUrl == null) return null;
@@ -70,5 +74,9 @@ public class ZkCoreNodeProps {
     return nodeProps;
   }
 
+  public boolean isLeader() {
+    return nodeProps.containsKey(ZkStateReader.LEADER_PROP);
+  }
+
 
 }

Modified: lucene/dev/branches/LUCENE-2878/solr/solrj/src/java/org/apache/solr/common/cloud/ZkStateReader.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/LUCENE-2878/solr/solrj/src/java/org/apache/solr/common/cloud/ZkStateReader.java?rev=1372423&r1=1372422&r2=1372423&view=diff
==============================================================================
--- lucene/dev/branches/LUCENE-2878/solr/solrj/src/java/org/apache/solr/common/cloud/ZkStateReader.java (original)
+++ lucene/dev/branches/LUCENE-2878/solr/solrj/src/java/org/apache/solr/common/cloud/ZkStateReader.java Mon Aug 13 13:52:46 2012
@@ -42,6 +42,7 @@ import org.apache.zookeeper.KeeperExcept
 import org.apache.zookeeper.WatchedEvent;
 import org.apache.zookeeper.Watcher;
 import org.apache.zookeeper.Watcher.Event.EventType;
+import org.apache.zookeeper.data.Stat;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -68,7 +69,7 @@ public class ZkStateReader {
   public static final String DOWN = "down";
   public static final String SYNC = "sync";
   
-  private volatile CloudState cloudState;
+  private volatile ClusterState clusterState;
 
   private static final long SOLRCLOUD_UPDATE_DELAY = Long.parseLong(System.getProperty("solrcloud.update.delay", "5000"));
 
@@ -120,7 +121,7 @@ public class ZkStateReader {
   }
   private ScheduledExecutorService updateCloudExecutor = Executors.newScheduledThreadPool(1, new ZKTF());
 
-  private boolean cloudStateUpdateScheduled;
+  private boolean clusterStateUpdateScheduled;
 
   private SolrZkClient zkClient;
   
@@ -158,13 +159,13 @@ public class ZkStateReader {
   }
   
   // load and publish a new CollectionInfo
-  public void updateCloudState(boolean immediate) throws KeeperException, InterruptedException {
-    updateCloudState(immediate, false);
+  public void updateClusterState(boolean immediate) throws KeeperException, InterruptedException {
+    updateClusterState(immediate, false);
   }
   
   // load and publish a new CollectionInfo
   public void updateLiveNodes() throws KeeperException, InterruptedException {
-    updateCloudState(true, true);
+    updateClusterState(true, true);
   }
   
   public synchronized void createClusterStateWatchersAndUpdate() throws KeeperException,
@@ -185,21 +186,22 @@ public class ZkStateReader {
           if (EventType.None.equals(event.getType())) {
             return;
           }
-          log.info("A cluster state change has occurred");
+          log.info("A cluster state change has occurred - updating...");
           try {
             
             // delayed approach
-            // ZkStateReader.this.updateCloudState(false, false);
+            // ZkStateReader.this.updateClusterState(false, false);
             synchronized (ZkStateReader.this.getUpdateLock()) {
               // remake watch
               final Watcher thisWatch = this;
-              byte[] data = zkClient.getData(CLUSTER_STATE, thisWatch, null,
+              Stat stat = new Stat();
+              byte[] data = zkClient.getData(CLUSTER_STATE, thisWatch, stat ,
                   true);
               
-              CloudState clusterState = CloudState.load(data,
-                  ZkStateReader.this.cloudState.getLiveNodes());
+              ClusterState clusterState = ClusterState.load(stat.getVersion(), data,
+                  ZkStateReader.this.clusterState.getLiveNodes());
               // update volatile
-              cloudState = clusterState;
+              ZkStateReader.this.clusterState = clusterState;
             }
           } catch (KeeperException e) {
             if (e.code() == KeeperException.Code.SESSIONEXPIRED
@@ -236,15 +238,17 @@ public class ZkStateReader {
               log.info("Updating live nodes");
               try {
                 // delayed approach
-                // ZkStateReader.this.updateCloudState(false, true);
+                // ZkStateReader.this.updateClusterState(false, true);
                 synchronized (ZkStateReader.this.getUpdateLock()) {
                   List<String> liveNodes = zkClient.getChildren(
                       LIVE_NODES_ZKNODE, this, true);
                   Set<String> liveNodesSet = new HashSet<String>();
                   liveNodesSet.addAll(liveNodes);
-                  CloudState clusterState = new CloudState(liveNodesSet,
-                      ZkStateReader.this.cloudState.getCollectionStates());
-                  ZkStateReader.this.cloudState = clusterState;
+                  ClusterState clusterState = new ClusterState(
+                      ZkStateReader.this.clusterState.getZkClusterStateVersion(),
+                      liveNodesSet, ZkStateReader.this.clusterState
+                          .getCollectionStates());
+                  ZkStateReader.this.clusterState = clusterState;
                 }
               } catch (KeeperException e) {
                 if (e.code() == KeeperException.Code.SESSIONEXPIRED
@@ -267,52 +271,53 @@ public class ZkStateReader {
     
       Set<String> liveNodeSet = new HashSet<String>();
       liveNodeSet.addAll(liveNodes);
-      CloudState clusterState = CloudState.load(zkClient, liveNodeSet);
-      this.cloudState = clusterState;
+      ClusterState clusterState = ClusterState.load(zkClient, liveNodeSet);
+      this.clusterState = clusterState;
     }
   }
   
   
   // load and publish a new CollectionInfo
-  private synchronized void updateCloudState(boolean immediate,
+  private synchronized void updateClusterState(boolean immediate,
       final boolean onlyLiveNodes) throws KeeperException,
       InterruptedException {
-    log.info("Manual update of cluster state initiated");
     // build immutable CloudInfo
     
     if (immediate) {
-      CloudState clusterState;
+      ClusterState clusterState;
       synchronized (getUpdateLock()) {
-      List<String> liveNodes = zkClient.getChildren(LIVE_NODES_ZKNODE, null, true);
-      Set<String> liveNodesSet = new HashSet<String>();
-      liveNodesSet.addAll(liveNodes);
-      
+        List<String> liveNodes = zkClient.getChildren(LIVE_NODES_ZKNODE, null,
+            true);
+        Set<String> liveNodesSet = new HashSet<String>();
+        liveNodesSet.addAll(liveNodes);
+        
         if (!onlyLiveNodes) {
           log.info("Updating cloud state from ZooKeeper... ");
           
-          clusterState = CloudState.load(zkClient, liveNodesSet);
+          clusterState = ClusterState.load(zkClient, liveNodesSet);
         } else {
           log.info("Updating live nodes from ZooKeeper... ");
-          clusterState = new CloudState(liveNodesSet,
-              ZkStateReader.this.cloudState.getCollectionStates());
+          clusterState = new ClusterState(
+              ZkStateReader.this.clusterState.getZkClusterStateVersion(), liveNodesSet,
+              ZkStateReader.this.clusterState.getCollectionStates());
         }
       }
 
-      this.cloudState = clusterState;
+      this.clusterState = clusterState;
     } else {
-      if (cloudStateUpdateScheduled) {
+      if (clusterStateUpdateScheduled) {
         log.info("Cloud state update for ZooKeeper already scheduled");
         return;
       }
       log.info("Scheduling cloud state update from ZooKeeper...");
-      cloudStateUpdateScheduled = true;
+      clusterStateUpdateScheduled = true;
       updateCloudExecutor.schedule(new Runnable() {
         
         public void run() {
           log.info("Updating cluster state from ZooKeeper...");
           synchronized (getUpdateLock()) {
-            cloudStateUpdateScheduled = false;
-            CloudState clusterState;
+            clusterStateUpdateScheduled = false;
+            ClusterState clusterState;
             try {
               List<String> liveNodes = zkClient.getChildren(LIVE_NODES_ZKNODE,
                   null, true);
@@ -322,13 +327,13 @@ public class ZkStateReader {
               if (!onlyLiveNodes) {
                 log.info("Updating cloud state from ZooKeeper... ");
                 
-                clusterState = CloudState.load(zkClient, liveNodesSet);
+                clusterState = ClusterState.load(zkClient, liveNodesSet);
               } else {
                 log.info("Updating live nodes from ZooKeeper... ");
-                clusterState = new CloudState(liveNodesSet, ZkStateReader.this.cloudState.getCollectionStates());
+                clusterState = new ClusterState(ZkStateReader.this.clusterState .getZkClusterStateVersion(), liveNodesSet, ZkStateReader.this.clusterState.getCollectionStates());
               }
               
-              ZkStateReader.this.cloudState = clusterState;
+              ZkStateReader.this.clusterState = clusterState;
               
             } catch (KeeperException e) {
               if (e.code() == KeeperException.Code.SESSIONEXPIRED
@@ -347,7 +352,7 @@ public class ZkStateReader {
                   SolrException.ErrorCode.SERVER_ERROR, "", e);
             } 
             // update volatile
-            ZkStateReader.this.cloudState = cloudState;
+            ZkStateReader.this.clusterState = clusterState;
           }
         }
       }, SOLRCLOUD_UPDATE_DELAY, TimeUnit.MILLISECONDS);
@@ -358,8 +363,8 @@ public class ZkStateReader {
   /**
    * @return information about the cluster from ZooKeeper
    */
-  public CloudState getCloudState() {
-    return cloudState;
+  public ClusterState getClusterState() {
+    return clusterState;
   }
   
   public Object getUpdateLock() {
@@ -412,9 +417,8 @@ public class ZkStateReader {
   public ZkNodeProps getLeaderProps(String collection, String shard, int timeout) throws InterruptedException {
     long timeoutAt = System.currentTimeMillis() + timeout;
     while (System.currentTimeMillis() < timeoutAt) {
-      if (cloudState != null) {
-        final CloudState currentState = cloudState;      
-        final ZkNodeProps nodeProps = currentState.getLeader(collection, shard);
+      if (clusterState != null) {    
+        final ZkNodeProps nodeProps = clusterState.getLeader(collection, shard);
         if (nodeProps != null) {
           return nodeProps;
         }
@@ -453,15 +457,15 @@ public class ZkStateReader {
   
   public List<ZkCoreNodeProps> getReplicaProps(String collection,
       String shardId, String thisNodeName, String coreName, String mustMatchStateFilter, String mustNotMatchStateFilter) {
-    CloudState cloudState = this.cloudState;
-    if (cloudState == null) {
+    ClusterState clusterState = this.clusterState;
+    if (clusterState == null) {
       return null;
     }
-    Map<String,Slice> slices = cloudState.getSlices(collection);
+    Map<String,Slice> slices = clusterState.getSlices(collection);
     if (slices == null) {
       throw new ZooKeeperException(ErrorCode.BAD_REQUEST,
           "Could not find collection in zk: " + collection + " "
-              + cloudState.getCollections());
+              + clusterState.getCollections());
     }
     
     Slice replicas = slices.get(shardId);
@@ -475,7 +479,7 @@ public class ZkStateReader {
     for (Entry<String,ZkNodeProps> entry : shardMap.entrySet()) {
       ZkCoreNodeProps nodeProps = new ZkCoreNodeProps(entry.getValue());
       String coreNodeName = nodeProps.getNodeName() + "_" + nodeProps.getCoreName();
-      if (cloudState.liveNodesContain(nodeProps.getNodeName()) && !coreNodeName.equals(filterNodeName)) {
+      if (clusterState.liveNodesContain(nodeProps.getNodeName()) && !coreNodeName.equals(filterNodeName)) {
         if (mustMatchStateFilter == null || mustMatchStateFilter.equals(nodeProps.getState())) {
           if (mustNotMatchStateFilter == null || !mustNotMatchStateFilter.equals(nodeProps.getState())) {
             nodes.add(nodeProps);

Modified: lucene/dev/branches/LUCENE-2878/solr/solrj/src/java/org/apache/solr/common/params/CollectionParams.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/LUCENE-2878/solr/solrj/src/java/org/apache/solr/common/params/CollectionParams.java?rev=1372423&r1=1372422&r2=1372423&view=diff
==============================================================================
--- lucene/dev/branches/LUCENE-2878/solr/solrj/src/java/org/apache/solr/common/params/CollectionParams.java (original)
+++ lucene/dev/branches/LUCENE-2878/solr/solrj/src/java/org/apache/solr/common/params/CollectionParams.java Mon Aug 13 13:52:46 2012
@@ -28,7 +28,7 @@ public interface CollectionParams 
 
 
   public enum CollectionAction {
-    CREATE, DELETE, RELOAD;
+    CREATE, DELETE, RELOAD, SYNCSHARD;
     
     public static CollectionAction get( String p )
     {

Modified: lucene/dev/branches/LUCENE-2878/solr/solrj/src/java/org/apache/solr/common/params/CoreAdminParams.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/LUCENE-2878/solr/solrj/src/java/org/apache/solr/common/params/CoreAdminParams.java?rev=1372423&r1=1372422&r2=1372423&view=diff
==============================================================================
--- lucene/dev/branches/LUCENE-2878/solr/solrj/src/java/org/apache/solr/common/params/CoreAdminParams.java (original)
+++ lucene/dev/branches/LUCENE-2878/solr/solrj/src/java/org/apache/solr/common/params/CoreAdminParams.java Mon Aug 13 13:52:46 2012
@@ -93,7 +93,8 @@ public interface CoreAdminParams 
     RENAME,
     MERGEINDEXES,
     PREPRECOVERY, 
-    REQUESTRECOVERY;
+    REQUESTRECOVERY, 
+    REQUESTSYNCSHARD;
     
     public static CoreAdminAction get( String p )
     {

Modified: lucene/dev/branches/LUCENE-2878/solr/solrj/src/java/org/apache/solr/common/util/FastOutputStream.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/LUCENE-2878/solr/solrj/src/java/org/apache/solr/common/util/FastOutputStream.java?rev=1372423&r1=1372422&r2=1372423&view=diff
==============================================================================
--- lucene/dev/branches/LUCENE-2878/solr/solrj/src/java/org/apache/solr/common/util/FastOutputStream.java (original)
+++ lucene/dev/branches/LUCENE-2878/solr/solrj/src/java/org/apache/solr/common/util/FastOutputStream.java Mon Aug 13 13:52:46 2012
@@ -23,10 +23,10 @@ import java.io.*;
  *  Internal Solr use only, subject to change.
  */
 public class FastOutputStream extends OutputStream implements DataOutput {
-  private final OutputStream out;
-  private final byte[] buf;
-  private long written;  // how many bytes written to the underlying stream
-  private int pos;
+  protected final OutputStream out;
+  protected byte[] buf;
+  protected long written;  // how many bytes written to the underlying stream
+  protected int pos;
 
   public FastOutputStream(OutputStream w) {
   // use default BUFSIZE of BufferedOutputStream so if we wrap that
@@ -57,7 +57,7 @@ public class FastOutputStream extends Ou
 
   public void write(byte b) throws IOException {
     if (pos >= buf.length) {
-      out.write(buf);
+      flush(buf, 0, buf.length);
       written += pos;
       pos=0;
     }
@@ -73,18 +73,18 @@ public class FastOutputStream extends Ou
     } else if (len<buf.length) {
       // if the data to write is small enough, buffer it.
       System.arraycopy(arr, off, buf, pos, space);
-      out.write(buf);
+      flush(buf, 0, buf.length);
       written += buf.length;
       pos = len-space;
       System.arraycopy(arr, off+space, buf, 0, pos);
     } else {
       if (pos>0) {
-        out.write(buf,0,pos);  // flush
+        flush(buf,0,pos);  // flush
         written += pos;
         pos=0;
       }
       // don't buffer, just write to sink
-      out.write(arr, off, len);
+      flush(arr, off, len);
       written += len;            
     }
   }
@@ -168,13 +168,13 @@ public class FastOutputStream extends Ou
   @Override
   public void flush() throws IOException {
     flushBuffer();
-    out.flush();
+    if (out != null) out.flush();
   }
 
   @Override
   public void close() throws IOException {
     flushBuffer();
-    out.close();
+    if (out != null) out.close();
   }
 
   /** Only flushes the buffer of the FastOutputStream, not that of the
@@ -182,12 +182,17 @@ public class FastOutputStream extends Ou
    */
   public void flushBuffer() throws IOException {
     if (pos > 0) {
-      out.write(buf, 0, pos);
+      flush(buf, 0, pos);
       written += pos;
       pos=0;
     }
   }
 
+  /** All writes to the sink will go through this method */
+  public void flush(byte[] buf, int offset, int len) throws IOException {
+    out.write(buf, offset, len);
+  }
+
   public long size() {
     return written + pos;
   }

Modified: lucene/dev/branches/LUCENE-2878/solr/solrj/src/java/org/apache/solr/common/util/Hash.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/LUCENE-2878/solr/solrj/src/java/org/apache/solr/common/util/Hash.java?rev=1372423&r1=1372422&r2=1372423&view=diff
==============================================================================
--- lucene/dev/branches/LUCENE-2878/solr/solrj/src/java/org/apache/solr/common/util/Hash.java (original)
+++ lucene/dev/branches/LUCENE-2878/solr/solrj/src/java/org/apache/solr/common/util/Hash.java Mon Aug 13 13:52:46 2012
@@ -291,4 +291,132 @@ public class Hash {
     return h1;
   }
 
+
+
+  /** Returns the MurmurHash3_x86_32 hash of the UTF-8 bytes of the String without actually encoding
+   * the string to a temporary buffer.  This is more than 2x faster than hashing the result
+   * of String.getBytes().
+   */
+  public static int murmurhash3_x86_32(CharSequence data, int offset, int len, int seed) {
+
+    final int c1 = 0xcc9e2d51;
+    final int c2 = 0x1b873593;
+
+    int h1 = seed;
+
+    int pos = offset;
+    int end = offset + len;
+    int k1 = 0;
+    int k2 = 0;
+    int shift = 0;
+    int bits = 0;
+    int nBytes = 0;   // length in UTF8 bytes
+
+
+    while (pos < end) {
+      int code = data.charAt(pos++);
+      if (code < 0x80) {
+        k2 = code;
+        bits = 8;
+
+        /***
+         // optimized ascii implementation (currently slower!!! code size?)
+         if (shift == 24) {
+         k1 = k1 | (code << 24);
+
+         k1 *= c1;
+         k1 = (k1 << 15) | (k1 >>> 17);  // ROTL32(k1,15);
+         k1 *= c2;
+
+         h1 ^= k1;
+         h1 = (h1 << 13) | (h1 >>> 19);  // ROTL32(h1,13);
+         h1 = h1*5+0xe6546b64;
+
+         shift = 0;
+         nBytes += 4;
+         k1 = 0;
+         } else {
+         k1 |= code << shift;
+         shift += 8;
+         }
+         continue;
+         ***/
+
+      }
+      else if (code < 0x800) {
+        k2 = (0xC0 | (code >> 6))
+            | ((0x80 | (code & 0x3F)) << 8);
+        bits = 16;
+      }
+      else if (code < 0xD800 || code > 0xDFFF || pos>=end) {
+        // we check for pos>=end to encode an unpaired surrogate as 3 bytes.
+        k2 = (0xE0 | (code >> 12))
+            | ((0x80 | ((code >> 6) & 0x3F)) << 8)
+            | ((0x80 | (code & 0x3F)) << 16);
+        bits = 24;
+      } else {
+        // surrogate pair
+        // int utf32 = pos < end ? (int) data.charAt(pos++) : 0;
+        int utf32 = (int) data.charAt(pos++);
+        utf32 = ((code - 0xD7C0) << 10) + (utf32 & 0x3FF);
+        k2 = (0xff & (0xF0 | (utf32 >> 18)))
+            | ((0x80 | ((utf32 >> 12) & 0x3F))) << 8
+            | ((0x80 | ((utf32 >> 6) & 0x3F))) << 16
+            |  (0x80 | (utf32 & 0x3F)) << 24;
+        bits = 32;
+      }
+
+
+      k1 |= k2 << shift;
+
+      // int used_bits = 32 - shift;  // how many bits of k2 were used in k1.
+      // int unused_bits = bits - used_bits; //  (bits-(32-shift)) == bits+shift-32  == bits-newshift
+
+      shift += bits;
+      if (shift >= 32) {
+        // mix after we have a complete word
+
+        k1 *= c1;
+        k1 = (k1 << 15) | (k1 >>> 17);  // ROTL32(k1,15);
+        k1 *= c2;
+
+        h1 ^= k1;
+        h1 = (h1 << 13) | (h1 >>> 19);  // ROTL32(h1,13);
+        h1 = h1*5+0xe6546b64;
+
+        shift -= 32;
+        // unfortunately, java won't let you shift 32 bits off, so we need to check for 0
+        if (shift != 0) {
+          k1 = k2 >>> (bits-shift);   // bits used == bits - newshift
+        } else {
+          k1 = 0;
+        }
+        nBytes += 4;
+      }
+
+    } // inner
+
+    // handle tail
+    if (shift > 0) {
+      nBytes += shift >> 3;
+      k1 *= c1;
+      k1 = (k1 << 15) | (k1 >>> 17);  // ROTL32(k1,15);
+      k1 *= c2;
+      h1 ^= k1;
+    }
+
+    // finalization
+    h1 ^= nBytes;
+
+    // fmix(h1);
+    h1 ^= h1 >>> 16;
+    h1 *= 0x85ebca6b;
+    h1 ^= h1 >>> 13;
+    h1 *= 0xc2b2ae35;
+    h1 ^= h1 >>> 16;
+
+    return h1;
+  }
+
+
 }

Modified: lucene/dev/branches/LUCENE-2878/solr/solrj/src/java/org/apache/zookeeper/SolrZooKeeper.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/LUCENE-2878/solr/solrj/src/java/org/apache/zookeeper/SolrZooKeeper.java?rev=1372423&r1=1372422&r2=1372423&view=diff
==============================================================================
--- lucene/dev/branches/LUCENE-2878/solr/solrj/src/java/org/apache/zookeeper/SolrZooKeeper.java (original)
+++ lucene/dev/branches/LUCENE-2878/solr/solrj/src/java/org/apache/zookeeper/SolrZooKeeper.java Mon Aug 13 13:52:46 2012
@@ -19,9 +19,12 @@ package org.apache.zookeeper;
 
 import java.io.IOException;
 import java.nio.channels.SocketChannel;
+import java.util.List;
+import java.util.concurrent.CopyOnWriteArrayList;
 
 // we use this class to expose nasty stuff for tests
 public class SolrZooKeeper extends ZooKeeper {
+  List<Thread> spawnedThreads = new CopyOnWriteArrayList<Thread>();
 
   public SolrZooKeeper(String connectString, int sessionTimeout,
       Watcher watcher) throws IOException {
@@ -38,21 +41,32 @@ public class SolrZooKeeper extends ZooKe
    * @param ms the number of milliseconds to pause.
    */
   public void pauseCnxn(final long ms) {
-    new Thread() {
+    Thread t = new Thread() {
       public void run() {
-        synchronized (cnxn) {
-          try {
+        try {
+          synchronized (cnxn) {
             try {
               ((SocketChannel) cnxn.sendThread.sockKey.channel()).socket()
                   .close();
             } catch (Exception e) {
-
             }
             Thread.sleep(ms);
-          } catch (InterruptedException e) {}
-        }
+          }
+
+          // Wait a long while to make sure we properly clean up these threads.
+          Thread.sleep(500000);
+        } catch (InterruptedException e) {}
       }
-    }.start();
+    };
+    t.start();
+    spawnedThreads.add(t);
   }
 
+  @Override
+  public synchronized void close() throws InterruptedException {
+    for (Thread t : spawnedThreads) {
+      t.interrupt();
+    }
+    super.close();
+  }
 }

Modified: lucene/dev/branches/LUCENE-2878/solr/solrj/src/test/org/apache/solr/client/solrj/SolrExampleTests.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/LUCENE-2878/solr/solrj/src/test/org/apache/solr/client/solrj/SolrExampleTests.java?rev=1372423&r1=1372422&r2=1372423&view=diff
==============================================================================
--- lucene/dev/branches/LUCENE-2878/solr/solrj/src/test/org/apache/solr/client/solrj/SolrExampleTests.java (original)
+++ lucene/dev/branches/LUCENE-2878/solr/solrj/src/test/org/apache/solr/client/solrj/SolrExampleTests.java Mon Aug 13 13:52:46 2012
@@ -711,16 +711,11 @@ abstract public class SolrExampleTests e
     assertNumFound( "*:*", 3 ); // make sure it got in
     
     // should be able to handle multiple delete commands in a single go
-    StringWriter xml = new StringWriter();
-    xml.append( "<delete>" );
+    List<String> ids = new ArrayList<String>();
     for( SolrInputDocument d : doc ) {
-      xml.append( "<id>" );
-      XML.escapeCharData( (String)d.getField( "id" ).getFirstValue(), xml );
-      xml.append( "</id>" );
+      ids.add(d.getFieldValue("id").toString());
     }
-    xml.append( "</delete>" );
-    DirectXmlRequest up = new DirectXmlRequest( "/update", xml.toString() );
-    server.request( up );
+    server.deleteById(ids);
     server.commit();
     assertNumFound( "*:*", 0 ); // make sure it got out
   }

Modified: lucene/dev/branches/LUCENE-2878/solr/solrj/src/test/org/apache/solr/client/solrj/TestLBHttpSolrServer.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/LUCENE-2878/solr/solrj/src/test/org/apache/solr/client/solrj/TestLBHttpSolrServer.java?rev=1372423&r1=1372422&r2=1372423&view=diff
==============================================================================
--- lucene/dev/branches/LUCENE-2878/solr/solrj/src/test/org/apache/solr/client/solrj/TestLBHttpSolrServer.java (original)
+++ lucene/dev/branches/LUCENE-2878/solr/solrj/src/test/org/apache/solr/client/solrj/TestLBHttpSolrServer.java Mon Aug 13 13:52:46 2012
@@ -21,7 +21,9 @@ import junit.framework.Assert;
 import org.apache.commons.io.FileUtils;
 import org.apache.http.client.HttpClient;
 import org.apache.lucene.util.LuceneTestCase;
+import org.apache.lucene.util.QuickPatchThreadsFilter;
 import org.apache.lucene.util.LuceneTestCase.Slow;
+import org.apache.solr.SolrIgnoredThreadsFilter;
 import org.apache.solr.SolrTestCaseJ4;
 import org.apache.solr.client.solrj.embedded.JettySolrRunner;
 import org.apache.solr.client.solrj.impl.HttpClientUtil;
@@ -35,6 +37,8 @@ import org.apache.solr.util.AbstractSolr
 import org.junit.AfterClass;
 import org.junit.BeforeClass;
 
+import com.carrotsearch.randomizedtesting.annotations.ThreadLeakFilters;
+
 import java.io.File;
 import java.io.IOException;
 import java.util.ArrayList;
@@ -48,6 +52,10 @@ import java.util.Set;
  * @since solr 1.4
  */
 @Slow
+@ThreadLeakFilters(defaultFilters = true, filters = {
+    SolrIgnoredThreadsFilter.class,
+    QuickPatchThreadsFilter.class
+})
 public class TestLBHttpSolrServer extends LuceneTestCase {
   SolrInstance[] solr = new SolrInstance[3];
   HttpClient httpClient;
@@ -237,7 +245,7 @@ public class TestLBHttpSolrServer extend
     }
 
     public String getSchemaFile() {
-      return "solrj/solr/conf/schema-replication1.xml";
+      return "solrj/solr/collection1/conf/schema-replication1.xml";
     }
 
     public String getConfDir() {
@@ -249,7 +257,7 @@ public class TestLBHttpSolrServer extend
     }
 
     public String getSolrConfigFile() {
-      return "solrj/solr/conf/solrconfig-slave1.xml";
+      return "solrj/solr/collection1/conf/solrconfig-slave1.xml";
     }
 
     public void setUp() throws Exception {

Modified: lucene/dev/branches/LUCENE-2878/solr/test-framework/src/java/org/apache/solr/BaseDistributedSearchTestCase.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/LUCENE-2878/solr/test-framework/src/java/org/apache/solr/BaseDistributedSearchTestCase.java?rev=1372423&r1=1372422&r2=1372423&view=diff
==============================================================================
--- lucene/dev/branches/LUCENE-2878/solr/test-framework/src/java/org/apache/solr/BaseDistributedSearchTestCase.java (original)
+++ lucene/dev/branches/LUCENE-2878/solr/test-framework/src/java/org/apache/solr/BaseDistributedSearchTestCase.java Mon Aug 13 13:52:46 2012
@@ -450,11 +450,25 @@ public abstract class BaseDistributedSea
 //    System.out.println("resp b:" + b);
     boolean ordered = (flags & UNORDERED) == 0;
 
+    if (!ordered) {
+      Map mapA = new HashMap(a.size());
+      for (int i=0; i<a.size(); i++) {
+        Object prev = mapA.put(a.getName(i), a.getVal(i));
+      }
+
+      Map mapB = new HashMap(b.size());
+      for (int i=0; i<b.size(); i++) {
+        Object prev = mapB.put(b.getName(i), b.getVal(i));
+      }
+
+      return compare(mapA, mapB, flags, handle);
+    }
+
     int posa = 0, posb = 0;
     int aSkipped = 0, bSkipped = 0;
 
     for (; ;) {
-      if (posa >= a.size() || posb >= b.size()) {
+      if (posa >= a.size() && posb >= b.size()) {
         break;
       }
 
@@ -468,29 +482,27 @@ public abstract class BaseDistributedSea
         posa++;
         flagsa = flags(handle, namea);
         if ((flagsa & SKIP) != 0) {
+          namea = null; vala = null;
           aSkipped++;
           continue;
         }
         break;
       }
 
-      if (!ordered) posb = 0;  // reset if not ordered
-
       while (posb < b.size()) {
         nameb = b.getName(posb);
         valb = b.getVal(posb);
         posb++;
         flagsb = flags(handle, nameb);
         if ((flagsb & SKIP) != 0) {
+          nameb = null; valb = null;
           bSkipped++;
           continue;
         }
         if (eq(namea, nameb)) {
           break;
         }
-        if (ordered) {
-          return "." + namea + "!=" + nameb + " (unordered or missing)";
-        }
+        return "." + namea + "!=" + nameb + " (unordered or missing)";
         // if unordered, continue until we find the right field.
       }
 
@@ -503,7 +515,7 @@ public abstract class BaseDistributedSea
 
 
     if (a.size() - aSkipped != b.size() - bSkipped) {
-      return ".size()==" + a.size() + "," + b.size() + "skipped=" + aSkipped + "," + bSkipped;
+      return ".size()==" + a.size() + "," + b.size() + " skipped=" + aSkipped + "," + bSkipped;
     }
 
     return null;

Modified: lucene/dev/branches/LUCENE-2878/solr/test-framework/src/java/org/apache/solr/SolrTestCaseJ4.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/LUCENE-2878/solr/test-framework/src/java/org/apache/solr/SolrTestCaseJ4.java?rev=1372423&r1=1372422&r2=1372423&view=diff
==============================================================================
--- lucene/dev/branches/LUCENE-2878/solr/test-framework/src/java/org/apache/solr/SolrTestCaseJ4.java (original)
+++ lucene/dev/branches/LUCENE-2878/solr/test-framework/src/java/org/apache/solr/SolrTestCaseJ4.java Mon Aug 13 13:52:46 2012
@@ -24,6 +24,7 @@ import java.util.logging.*;
 import javax.xml.xpath.XPathExpressionException;
 
 import org.apache.lucene.util.LuceneTestCase;
+import org.apache.lucene.util.QuickPatchThreadsFilter;
 import org.apache.noggit.*;
 import org.apache.solr.common.*;
 import org.apache.solr.common.cloud.SolrZkClient;
@@ -38,6 +39,7 @@ import org.apache.solr.schema.SchemaFiel
 import org.apache.solr.search.SolrIndexSearcher;
 import org.apache.solr.servlet.DirectSolrConnection;
 import org.apache.solr.util.AbstractSolrTestCase;
+import org.apache.solr.util.RevertDefaultThreadHandlerRule;
 import org.apache.solr.util.TestHarness;
 import org.junit.*;
 import org.junit.rules.RuleChain;
@@ -46,20 +48,25 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.xml.sax.SAXException;
 
-import com.carrotsearch.randomizedtesting.annotations.ThreadLeaks;
+import com.carrotsearch.randomizedtesting.annotations.ThreadLeakFilters;
 import com.carrotsearch.randomizedtesting.rules.SystemPropertiesRestoreRule;
 
 /**
  * A junit4 Solr test harness that extends LuceneTestCaseJ4.
  * Unlike {@link AbstractSolrTestCase}, a new core is not created for each test method.
  */
+@ThreadLeakFilters(defaultFilters = true, filters = {
+    SolrIgnoredThreadsFilter.class,
+    QuickPatchThreadsFilter.class
+})
 public abstract class SolrTestCaseJ4 extends LuceneTestCase {
-  public static int DEFAULT_CONNECTION_TIMEOUT = 500;  // default socket connection timeout in ms
+  public static int DEFAULT_CONNECTION_TIMEOUT = 1000;  // default socket connection timeout in ms
 
 
   @ClassRule
   public static TestRule solrClassRules = 
-    RuleChain.outerRule(new SystemPropertiesRestoreRule());
+    RuleChain.outerRule(new SystemPropertiesRestoreRule())
+             .around(new RevertDefaultThreadHandlerRule());
 
   @Rule
   public TestRule solrTestRules = 
@@ -1388,11 +1395,10 @@ public abstract class SolrTestCaseJ4 ext
       return file;
     } catch (Exception e) {
       /* more friendly than NPE */
-      throw new RuntimeException("Cannot find resource: " + name);
+      throw new RuntimeException("Cannot find resource: " + new File(name).getAbsolutePath());
     }
   }
   
-  // TODO: use solr rather than solr/collection1
   public static String TEST_HOME() {
     return getFile("solr/collection1").getParent();
   }

Modified: lucene/dev/branches/LUCENE-2878/solr/test-framework/src/java/org/apache/solr/analysis/StringMockSolrResourceLoader.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/LUCENE-2878/solr/test-framework/src/java/org/apache/solr/analysis/StringMockSolrResourceLoader.java?rev=1372423&r1=1372422&r2=1372423&view=diff
==============================================================================
--- lucene/dev/branches/LUCENE-2878/solr/test-framework/src/java/org/apache/solr/analysis/StringMockSolrResourceLoader.java (original)
+++ lucene/dev/branches/LUCENE-2878/solr/test-framework/src/java/org/apache/solr/analysis/StringMockSolrResourceLoader.java Mon Aug 13 13:52:46 2012
@@ -32,11 +32,7 @@ class StringMockSolrResourceLoader imple
     this.text = text;
   }
 
-  public List<String> getLines(String resource) throws IOException {
-    return Arrays.asList(text.split("\n"));
-  }
-
-  public <T> T newInstance(String cname, Class<T> expectedType, String... subpackages) {
+  public <T> T newInstance(String cname, Class<T> expectedType) {
     return null;
   }
 

Modified: lucene/dev/branches/LUCENE-2878/solr/test-framework/src/java/org/apache/solr/core/MockDirectoryFactory.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/LUCENE-2878/solr/test-framework/src/java/org/apache/solr/core/MockDirectoryFactory.java?rev=1372423&r1=1372422&r2=1372423&view=diff
==============================================================================
--- lucene/dev/branches/LUCENE-2878/solr/test-framework/src/java/org/apache/solr/core/MockDirectoryFactory.java (original)
+++ lucene/dev/branches/LUCENE-2878/solr/test-framework/src/java/org/apache/solr/core/MockDirectoryFactory.java Mon Aug 13 13:52:46 2012
@@ -31,12 +31,14 @@ public class MockDirectoryFactory extend
 
   @Override
   protected Directory create(String path) throws IOException {
-    MockDirectoryWrapper dir = LuceneTestCase.newDirectory();
+    Directory dir = LuceneTestCase.newDirectory();
     // Somehow removing unref'd files in Solr tests causes
     // problems... there's some interaction w/
     // CachingDirectoryFactory.  Once we track down where Solr
     // isn't closing an IW, we can re-enable this:
-    dir.setAssertNoUnrefencedFilesOnClose(false);
+    if (dir instanceof MockDirectoryWrapper) {
+      ((MockDirectoryWrapper)dir).setAssertNoUnrefencedFilesOnClose(false);
+    }
     return dir;
   }
   

Modified: lucene/dev/branches/LUCENE-2878/solr/test-framework/src/java/org/apache/solr/core/MockFSDirectoryFactory.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/LUCENE-2878/solr/test-framework/src/java/org/apache/solr/core/MockFSDirectoryFactory.java?rev=1372423&r1=1372422&r2=1372423&view=diff
==============================================================================
--- lucene/dev/branches/LUCENE-2878/solr/test-framework/src/java/org/apache/solr/core/MockFSDirectoryFactory.java (original)
+++ lucene/dev/branches/LUCENE-2878/solr/test-framework/src/java/org/apache/solr/core/MockFSDirectoryFactory.java Mon Aug 13 13:52:46 2012
@@ -31,12 +31,14 @@ public class MockFSDirectoryFactory exte
 
   @Override
   public Directory create(String path) throws IOException {
-    MockDirectoryWrapper dir = LuceneTestCase.newFSDirectory(new File(path));
+    Directory dir = LuceneTestCase.newFSDirectory(new File(path));
     // Somehow removing unref'd files in Solr tests causes
     // problems... there's some interaction w/
     // CachingDirectoryFactory.  Once we track down where Solr
     // isn't closing an IW, we can re-enable this:
-    dir.setAssertNoUnrefencedFilesOnClose(false);
+    if (dir instanceof MockDirectoryWrapper) {
+      ((MockDirectoryWrapper)dir).setAssertNoUnrefencedFilesOnClose(false);
+    }
     return dir;
   }
 }

Modified: lucene/dev/branches/LUCENE-2878/solr/test-framework/src/java/org/apache/solr/util/AbstractSolrTestCase.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/LUCENE-2878/solr/test-framework/src/java/org/apache/solr/util/AbstractSolrTestCase.java?rev=1372423&r1=1372422&r2=1372423&view=diff
==============================================================================
--- lucene/dev/branches/LUCENE-2878/solr/test-framework/src/java/org/apache/solr/util/AbstractSolrTestCase.java (original)
+++ lucene/dev/branches/LUCENE-2878/solr/test-framework/src/java/org/apache/solr/util/AbstractSolrTestCase.java Mon Aug 13 13:52:46 2012
@@ -25,6 +25,8 @@ import java.util.*;
 import javax.xml.xpath.XPathExpressionException;
 
 import org.apache.lucene.util.LuceneTestCase;
+import org.apache.lucene.util.QuickPatchThreadsFilter;
+import org.apache.solr.SolrIgnoredThreadsFilter;
 import org.apache.solr.SolrTestCaseJ4;
 import org.apache.solr.common.*;
 import org.apache.solr.common.params.CommonParams;
@@ -38,7 +40,7 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.xml.sax.SAXException;
 
-import com.carrotsearch.randomizedtesting.annotations.ThreadLeaks;
+import com.carrotsearch.randomizedtesting.annotations.ThreadLeakFilters;
 import com.carrotsearch.randomizedtesting.rules.SystemPropertiesRestoreRule;
 
 /**
@@ -54,6 +56,10 @@ import com.carrotsearch.randomizedtestin
  * @see #setUp
  * @see #tearDown
  */
+@ThreadLeakFilters(defaultFilters = true, filters = {
+    SolrIgnoredThreadsFilter.class,
+    QuickPatchThreadsFilter.class
+})
 public abstract class AbstractSolrTestCase extends LuceneTestCase {
   protected SolrConfig solrConfig;
 
@@ -98,7 +104,8 @@ public abstract class AbstractSolrTestCa
   
   @ClassRule
   public static TestRule solrClassRules = 
-    RuleChain.outerRule(new SystemPropertiesRestoreRule());
+    RuleChain.outerRule(new SystemPropertiesRestoreRule())
+             .around(new RevertDefaultThreadHandlerRule());
 
   @Rule
   public TestRule solrTestRules = 

Modified: lucene/dev/branches/LUCENE-2878/solr/test-framework/src/java/org/apache/solr/util/ExternalPaths.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/LUCENE-2878/solr/test-framework/src/java/org/apache/solr/util/ExternalPaths.java?rev=1372423&r1=1372422&r2=1372423&view=diff
==============================================================================
--- lucene/dev/branches/LUCENE-2878/solr/test-framework/src/java/org/apache/solr/util/ExternalPaths.java (original)
+++ lucene/dev/branches/LUCENE-2878/solr/test-framework/src/java/org/apache/solr/util/ExternalPaths.java Mon Aug 13 13:52:46 2012
@@ -25,7 +25,7 @@ import java.io.File;
  * @lucene.internal
  */
 public class ExternalPaths {
-  private static final String SOURCE_HOME = determineSourceHome();
+  public static final String SOURCE_HOME = determineSourceHome();
   public static String WEBAPP_HOME = new File(SOURCE_HOME, "webapp/web").getAbsolutePath();
   public static String EXAMPLE_HOME = new File(SOURCE_HOME, "example/solr").getAbsolutePath();
   public static String EXAMPLE_MULTICORE_HOME = new File(SOURCE_HOME, "example/multicore").getAbsolutePath();

Modified: lucene/dev/branches/LUCENE-2878/solr/test-framework/src/java/org/apache/solr/util/TestHarness.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/LUCENE-2878/solr/test-framework/src/java/org/apache/solr/util/TestHarness.java?rev=1372423&r1=1372422&r2=1372423&view=diff
==============================================================================
--- lucene/dev/branches/LUCENE-2878/solr/test-framework/src/java/org/apache/solr/util/TestHarness.java (original)
+++ lucene/dev/branches/LUCENE-2878/solr/test-framework/src/java/org/apache/solr/util/TestHarness.java Mon Aug 13 13:52:46 2012
@@ -71,8 +71,8 @@ import java.util.Map;
  *
  */
 public class TestHarness {
+  String coreName;
   protected CoreContainer container;
-  private SolrCore core;
   private final ThreadLocal<DocumentBuilder> builderTL = new ThreadLocal<DocumentBuilder>();
   private final ThreadLocal<XPath> xpathTL = new ThreadLocal<XPath>();
   public UpdateRequestHandler updater;
@@ -114,11 +114,8 @@ public class TestHarness {
       container = init.initialize();
       if (coreName == null)
         coreName = CoreContainer.DEFAULT_DEFAULT_CORE_NAME;
-      // get the core & decrease its refcount:
-      // the container holds the core for the harness lifetime
-      core = container.getCore(coreName);
-      if (core != null)
-        core.close();
+
+      this.coreName = coreName;
 
       updater = new UpdateRequestHandler();
       updater.init( null );
@@ -206,10 +203,30 @@ public class TestHarness {
     return container;
   }
 
+  /** Gets a core that does not have it's refcount incremented (i.e. there is no need to
+   * close when done).  This is not MT safe in conjunction with reloads!
+   */
   public SolrCore getCore() {
+    // get the core & decrease its refcount:
+    // the container holds the core for the harness lifetime
+    SolrCore core = container.getCore(coreName);
+    if (core != null)
+      core.close();
     return core;
   }
-        
+
+  /** Gets the core with it's reference count incremented.
+   * You must call core.close() when done!
+   */
+  public SolrCore getCoreInc() {
+    return container.getCore(coreName);
+  }
+
+
+  public void reload() throws Exception {
+    container.reload(coreName);
+  }
+
   /**
    * Processes an "update" (add, commit or optimize) and
    * returns the response as a String.
@@ -218,6 +235,7 @@ public class TestHarness {
    * @return The XML response to the update
    */
   public String update(String xml) {
+    SolrCore core = getCoreInc();
     DirectSolrConnection connection = new DirectSolrConnection(core);
     SolrRequestHandler handler = core.getRequestHandler("/update");
     // prefer the handler mapped to /update, but use our generic backup handler
@@ -231,6 +249,8 @@ public class TestHarness {
       throw (SolrException)e;
     } catch (Exception e) {
       throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, e);
+    } finally {
+      core.close();
     }
   }
   
@@ -324,6 +344,7 @@ public class TestHarness {
    * @see LocalSolrQueryRequest
    */
   public String query(String handler, SolrQueryRequest req) throws Exception {
+    SolrCore core = getCoreInc();
     try {
       SolrQueryResponse rsp = new SolrQueryResponse();
       SolrRequestInfo.setRequestInfo(new SolrRequestInfo(req, rsp));
@@ -341,18 +362,24 @@ public class TestHarness {
     } finally {
       req.close();
       SolrRequestInfo.clearRequestInfo();
+      core.close();
     }
   }
 
   /** It is the users responsibility to close the request object when done with it.
    * This method does not set/clear SolrRequestInfo */
   public SolrQueryResponse queryAndResponse(String handler, SolrQueryRequest req) throws Exception {
-    SolrQueryResponse rsp = new SolrQueryResponse();
-    core.execute(core.getRequestHandler(handler),req,rsp);
-    if (rsp.getException() != null) {
-      throw rsp.getException();
+    SolrCore core = getCoreInc();
+    try {
+      SolrQueryResponse rsp = new SolrQueryResponse();
+      core.execute(core.getRequestHandler(handler),req,rsp);
+      if (rsp.getException() != null) {
+        throw rsp.getException();
+      }
+      return rsp;
+    } finally {
+      core.close();
     }
-    return rsp;
   }
 
 
@@ -578,6 +605,10 @@ public class TestHarness {
      *       ignored.</b>
      *   </li>
      * </ul>
+     *
+     * TODO: this isn't really safe in the presense of core reloads!
+     * Perhaps the best we could do is increment the core reference count
+     * and decrement it in the request close() method?
      */
     public LocalSolrQueryRequest makeRequest(String ... q) {
       if (q.length==1) {

Modified: lucene/dev/branches/LUCENE-2878/solr/testlogging.properties
URL: http://svn.apache.org/viewvc/lucene/dev/branches/LUCENE-2878/solr/testlogging.properties?rev=1372423&r1=1372422&r2=1372423&view=diff
==============================================================================
--- lucene/dev/branches/LUCENE-2878/solr/testlogging.properties (original)
+++ lucene/dev/branches/LUCENE-2878/solr/testlogging.properties Mon Aug 13 13:52:46 2012
@@ -10,6 +10,7 @@ java.util.logging.ConsoleHandler.formatt
 #org.apache.solr.update.processor.LogUpdateProcessor=FINEST
 #org.apache.solr.update.processor.DistributedUpdateProcessor=FINEST
 #org.apache.solr.update.PeerSync.level=FINEST
+#org.apache.solr.cloud.RecoveryStrategy.level=FINEST
 #org.apache.solr.update.UpdateLog.level=FINE
 #org.apache.solr.update.TransactionLog.level=FINEST
 

Modified: lucene/dev/branches/LUCENE-2878/solr/webapp/web/admin.html
URL: http://svn.apache.org/viewvc/lucene/dev/branches/LUCENE-2878/solr/webapp/web/admin.html?rev=1372423&r1=1372422&r2=1372423&view=diff
==============================================================================
--- lucene/dev/branches/LUCENE-2878/solr/webapp/web/admin.html (original)
+++ lucene/dev/branches/LUCENE-2878/solr/webapp/web/admin.html Mon Aug 13 13:52:46 2012
@@ -63,7 +63,15 @@ limitations under the License.
     </div>
 
     <div id="main" class="clearfix">
-        
+    
+      <div id="init-failures">
+
+          <h2>SolrCore Initialization Failures</h2>
+          <ul></ul>
+          <p>Please check your logs for more information</p>
+                
+      </div>
+
       <div id="content-wrapper">
         <div id="content">
                   
@@ -87,8 +95,8 @@ limitations under the License.
 
             <li id="cloud" class="global optional"><p><a href="#/~cloud">Cloud</a></p>
               <ul>
-                <li class="tree"><a href="#/~cloud">Tree</a></li>
-                <li class="graph"><a href="#/~cloud?view=graph">Graph</a></li>
+                <li class="tree"><a href="#/~cloud?view=tree">Tree</a></li>
+                <li class="graph"><a href="#/~cloud">Graph</a></li>
                 <li class="rgraph"><a href="#/~cloud?view=rgraph">Graph (Radial)</a></li>
                 <li class="dump"><a href="#/~cloud">Dump</a></li>
               </ul>

Modified: lucene/dev/branches/LUCENE-2878/solr/webapp/web/css/styles/common.css
URL: http://svn.apache.org/viewvc/lucene/dev/branches/LUCENE-2878/solr/webapp/web/css/styles/common.css?rev=1372423&r1=1372422&r2=1372423&view=diff
==============================================================================
--- lucene/dev/branches/LUCENE-2878/solr/webapp/web/css/styles/common.css (original)
+++ lucene/dev/branches/LUCENE-2878/solr/webapp/web/css/styles/common.css Mon Aug 13 13:52:46 2012
@@ -284,6 +284,38 @@ ul
   border-color: #66b866;
 }
 
+#init-failures
+{
+  border: 1px solid #f00;
+  display: none;
+  margin-left: 150px;
+  margin-bottom: 20px;
+}
+
+#main.error #init-failures
+{
+  margin-left: 0;
+}
+
+#init-failures h2,
+#init-failures ul,
+#init-failures p
+{
+  padding: 10px;
+}
+
+#init-failures h2
+{
+  background-color: #f00;
+  color: #fff;
+  font-weight: bold;
+}
+
+#init-failures p
+{
+  color: #c0c0c0;
+  padding-top: 0;
+}
 
 #content-wrapper
 {

Modified: lucene/dev/branches/LUCENE-2878/solr/webapp/web/js/scripts/app.js
URL: http://svn.apache.org/viewvc/lucene/dev/branches/LUCENE-2878/solr/webapp/web/js/scripts/app.js?rev=1372423&r1=1372422&r2=1372423&view=diff
==============================================================================
--- lucene/dev/branches/LUCENE-2878/solr/webapp/web/js/scripts/app.js (original)
+++ lucene/dev/branches/LUCENE-2878/solr/webapp/web/js/scripts/app.js Mon Aug 13 13:52:46 2012
@@ -152,6 +152,24 @@ var solr_admin = function( app_config )
 
   this.timeout = null;
 
+  show_global_error = function( error )
+  {
+    var main = $( '#main' );
+
+    $( 'div[id$="-wrapper"]', main )
+      .remove();
+
+    main
+      .addClass( 'error' )
+      .append( error );
+
+    var pre_tags = $( 'pre', main );
+    if( 0 !== pre_tags.size() )
+    {
+      hljs.highlightBlock( pre_tags.get(0) ); 
+    }
+  };
+
   this.run = function()
   {
     $.ajax
@@ -167,9 +185,11 @@ var solr_admin = function( app_config )
         success : function( response )
         {
           self.cores_data = response.status;
+          var core_count = 0;
 
           for( var core_name in response.status )
           {
+            core_count++;
             var core_path = config.solr_path + '/' + core_name;
             var schema =  response['status'][core_name]['schema'];
             var solrconfig =  response['status'][core_name]['config'];
@@ -211,10 +231,44 @@ var solr_admin = function( app_config )
               .append( core_tpl );
           }
 
+          if( response.initFailures )
+          {
+            var failures = [];
+            for( var core_name in response.initFailures )
+            {
+              failures.push
+              (
+                '<li>' + 
+                  '<strong>' + core_name.esc() + ':</strong>' + "\n" +
+                  response.initFailures[core_name].esc() + "\n" +
+                '</li>'
+              );
+            }
+
+            if( 0 !== failures.length )
+            {
+              var init_failures = $( '#init-failures' );
+
+              init_failures.show();
+              $( 'ul', init_failures ).html( failures.join( "\n" ) );
+            }
+          }
+
+          if( 0 === core_count )
+          {
+            show_global_error
+            (
+              '<div class="message">There are no SolrCores running — for the current functionality ' +
+              'we require at least one SolrCore, sorry :)</div>'
+            );
+            return;
+          } // else: we have at least one core....
+
+          var system_url = environment_basepath + '/admin/system?wt=json';
           $.ajax
           (
             {
-              url : environment_basepath + '/admin/system?wt=json',
+              url : system_url,
               dataType : 'json',
               beforeSend : function( arr, form, options )
               {
@@ -280,23 +334,17 @@ var solr_admin = function( app_config )
               },
               error : function()
               {
-                var main = $( '#main' );
-
-                $( 'div[id$="-wrapper"]', main )
-                  .remove();
-
-                main
-                  .addClass( 'error' )
-                  .append
-                  (
-                    '<div class="message">This interface requires that you activate the admin request handlers, add the following configuration to your <code>solrconfig.xml:</code></div>' +
-                    '<div class="code"><pre class="syntax language-xml"><code>' +
-                    '<!-- Admin Handlers - This will register all the standard admin RequestHandlers. -->'.esc() + "\n" +
-                    '<requestHandler name="/admin/" class="solr.admin.AdminHandlers" />'.esc() +
-                    '</code></pre></div>'
-                  );
-
-                hljs.highlightBlock( $( 'pre', main ).get(0) );
+                show_global_error
+                (
+                  '<div class="message"><p>Unable to load environment info from <code>' + system_url.esc() + '</code>.</p>' +
+                  '<p>This interface requires that you activate the admin request handlers in all SolrCores by adding the ' +
+                  'following configuration to your <code>solrconfig.xml</code>:</p></div>' + "\n" +
+
+                  '<div class="code"><pre class="syntax language-xml"><code>' +
+                  '<!-- Admin Handlers - This will register all the standard admin RequestHandlers. -->'.esc() + "\n" +
+                  '<requestHandler name="/admin/" class="solr.admin.AdminHandlers" />'.esc() +
+                  '</code></pre></div>'
+                );
               },
               complete : function()
               {
@@ -317,4 +365,4 @@ var solr_admin = function( app_config )
 
 };
 
-var app = new solr_admin( app_config );
\ No newline at end of file
+var app = new solr_admin( app_config );