You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by rm...@apache.org on 2013/08/19 23:31:36 UTC

svn commit: r1515615 [2/2] - in /lucene/dev/branches/lucene5178: ./ dev-tools/ dev-tools/maven/ lucene/ lucene/core/ lucene/core/src/java/org/apache/lucene/index/ lucene/core/src/test/org/apache/lucene/index/ solr/ solr/core/ solr/core/src/java/org/apa...

Modified: lucene/dev/branches/lucene5178/lucene/core/src/java/org/apache/lucene/index/IndexWriter.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene5178/lucene/core/src/java/org/apache/lucene/index/IndexWriter.java?rev=1515615&r1=1515614&r2=1515615&view=diff
==============================================================================
--- lucene/dev/branches/lucene5178/lucene/core/src/java/org/apache/lucene/index/IndexWriter.java (original)
+++ lucene/dev/branches/lucene5178/lucene/core/src/java/org/apache/lucene/index/IndexWriter.java Mon Aug 19 21:31:34 2013
@@ -30,6 +30,7 @@ import java.util.LinkedList;
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
+import java.util.Queue;
 import java.util.Set;
 import java.util.concurrent.atomic.AtomicInteger;
 
@@ -182,7 +183,7 @@ import org.apache.lucene.util.ThreadInte
  * referenced by the "front" of the index). For this, IndexFileDeleter
  * keeps track of the last non commit checkpoint.
  */
-public class IndexWriter implements Closeable, TwoPhaseCommit {
+public class IndexWriter implements Closeable, TwoPhaseCommit{
   
   private static final int UNBOUNDED_MAX_MERGE_SEGMENTS = -1;
   
@@ -227,6 +228,7 @@ public class IndexWriter implements Clos
   final FieldNumbers globalFieldNumberMap;
 
   private DocumentsWriter docWriter;
+  private final Queue<Event> eventQueue;
   final IndexFileDeleter deleter;
 
   // used by forceMerge to note those needing merging
@@ -360,7 +362,7 @@ public class IndexWriter implements Clos
       synchronized (fullFlushLock) {
         boolean success = false;
         try {
-          anySegmentFlushed = docWriter.flushAllThreads();
+          anySegmentFlushed = docWriter.flushAllThreads(this);
           if (!anySegmentFlushed) {
             // prevent double increment since docWriter#doFlush increments the flushcount
             // if we flushed anything.
@@ -730,7 +732,9 @@ public class IndexWriter implements Clos
 
       // start with previous field numbers, but new FieldInfos
       globalFieldNumberMap = getFieldNumberMap();
-      docWriter = new DocumentsWriter(codec, config, directory, this, globalFieldNumberMap, bufferedDeletesStream);
+      config.getFlushPolicy().init(config);
+      docWriter = new DocumentsWriter(this, config, directory);
+      eventQueue = docWriter.eventQueue();
 
       // Default deleter (for backwards compatibility) is
       // KeepOnlyLastCommitDeleter:
@@ -961,7 +965,7 @@ public class IndexWriter implements Clos
         if (doFlush) {
           flush(waitForMerges, true);
         } else {
-          docWriter.abort(); // already closed -- never sync on IW 
+          docWriter.abort(this); // already closed -- never sync on IW 
         }
         
       } finally {
@@ -1033,7 +1037,7 @@ public class IndexWriter implements Clos
       synchronized(this) {
         closed = true;
       }
-      assert oldWriter.perThreadPool.numDeactivatedThreadStates() == oldWriter.perThreadPool.getMaxThreadStates();
+      assert oldWriter.perThreadPool.numDeactivatedThreadStates() == oldWriter.perThreadPool.getMaxThreadStates() : "" +  oldWriter.perThreadPool.numDeactivatedThreadStates() + " " +  oldWriter.perThreadPool.getMaxThreadStates();
     } catch (OutOfMemoryError oom) {
       handleOOM(oom, "closeInternal");
     } finally {
@@ -1280,9 +1284,10 @@ public class IndexWriter implements Clos
     ensureOpen();
     try {
       boolean success = false;
-      boolean anySegmentFlushed = false;
       try {
-        anySegmentFlushed = docWriter.updateDocuments(docs, analyzer, delTerm);
+        if (docWriter.updateDocuments(docs, analyzer, delTerm)) {
+          processEvents(true, false);
+        }
         success = true;
       } finally {
         if (!success) {
@@ -1291,9 +1296,6 @@ public class IndexWriter implements Clos
           }
         }
       }
-      if (anySegmentFlushed) {
-        maybeMerge(MergeTrigger.SEGMENT_FLUSH, UNBOUNDED_MAX_MERGE_SEGMENTS);
-      }
     } catch (OutOfMemoryError oom) {
       handleOOM(oom, "updateDocuments");
     }
@@ -1313,7 +1315,9 @@ public class IndexWriter implements Clos
   public void deleteDocuments(Term term) throws IOException {
     ensureOpen();
     try {
-      docWriter.deleteTerms(term);
+      if (docWriter.deleteTerms(term)) {
+        processEvents(true, false);
+      }
     } catch (OutOfMemoryError oom) {
       handleOOM(oom, "deleteDocuments(Term)");
     }
@@ -1412,7 +1416,9 @@ public class IndexWriter implements Clos
   public void deleteDocuments(Term... terms) throws IOException {
     ensureOpen();
     try {
-      docWriter.deleteTerms(terms);
+      if (docWriter.deleteTerms(terms)) {
+        processEvents(true, false);
+      }
     } catch (OutOfMemoryError oom) {
       handleOOM(oom, "deleteDocuments(Term..)");
     }
@@ -1432,7 +1438,9 @@ public class IndexWriter implements Clos
   public void deleteDocuments(Query query) throws IOException {
     ensureOpen();
     try {
-      docWriter.deleteQueries(query);
+      if (docWriter.deleteQueries(query)) {
+        processEvents(true, false);
+      }
     } catch (OutOfMemoryError oom) {
       handleOOM(oom, "deleteDocuments(Query)");
     }
@@ -1454,7 +1462,9 @@ public class IndexWriter implements Clos
   public void deleteDocuments(Query... queries) throws IOException {
     ensureOpen();
     try {
-      docWriter.deleteQueries(queries);
+      if (docWriter.deleteQueries(queries)) {
+        processEvents(true, false);
+      }
     } catch (OutOfMemoryError oom) {
       handleOOM(oom, "deleteDocuments(Query..)");
     }
@@ -1505,9 +1515,10 @@ public class IndexWriter implements Clos
     ensureOpen();
     try {
       boolean success = false;
-      boolean anySegmentFlushed = false;
       try {
-        anySegmentFlushed = docWriter.updateDocument(doc, analyzer, term);
+        if (docWriter.updateDocument(doc, analyzer, term)) {
+          processEvents(true, false);
+        }
         success = true;
       } finally {
         if (!success) {
@@ -1516,10 +1527,6 @@ public class IndexWriter implements Clos
           }
         }
       }
-
-      if (anySegmentFlushed) {
-        maybeMerge(MergeTrigger.SEGMENT_FLUSH, UNBOUNDED_MAX_MERGE_SEGMENTS);
-      }
     } catch (OutOfMemoryError oom) {
       handleOOM(oom, "updateDocument");
     }
@@ -1730,7 +1737,6 @@ public class IndexWriter implements Clos
       // complete
       ensureOpen();
     }
-
     // NOTE: in the ConcurrentMergeScheduler case, when
     // doWait is false, we can return immediately while
     // background threads accomplish the merging
@@ -2009,8 +2015,9 @@ public class IndexWriter implements Clos
       mergeScheduler.close();
 
       bufferedDeletesStream.clear();
+      processEvents(false, true);
       docWriter.close(); // mark it as closed first to prevent subsequent indexing actions/flushes 
-      docWriter.abort(); // don't sync on IW here
+      docWriter.abort(this); // don't sync on IW here
       synchronized(this) {
 
         if (pendingCommit != null) {
@@ -2102,7 +2109,8 @@ public class IndexWriter implements Clos
          * sure it's just like a fresh index.
          */
       try {
-        docWriter.lockAndAbortAll();
+        docWriter.lockAndAbortAll(this);
+        processEvents(false, true);
         synchronized (this) {
           try {
             // Abort any running merges
@@ -2135,7 +2143,7 @@ public class IndexWriter implements Clos
           }
         }
       } finally {
-        docWriter.unlockAllAfterAbortAll();
+        docWriter.unlockAllAfterAbortAll(this);
       }
     }
   }
@@ -2243,33 +2251,40 @@ public class IndexWriter implements Clos
    * Atomically adds the segment private delete packet and publishes the flushed
    * segments SegmentInfo to the index writer.
    */
-  synchronized void publishFlushedSegment(SegmentInfoPerCommit newSegment,
+  void publishFlushedSegment(SegmentInfoPerCommit newSegment,
       FrozenBufferedDeletes packet, FrozenBufferedDeletes globalPacket) throws IOException {
-    // Lock order IW -> BDS
-    synchronized (bufferedDeletesStream) {
-      if (infoStream.isEnabled("IW")) {
-        infoStream.message("IW", "publishFlushedSegment");
-      }
-      
-      if (globalPacket != null && globalPacket.any()) {
-        bufferedDeletesStream.push(globalPacket);
-      } 
-      // Publishing the segment must be synched on IW -> BDS to make the sure
-      // that no merge prunes away the seg. private delete packet
-      final long nextGen;
-      if (packet != null && packet.any()) {
-        nextGen = bufferedDeletesStream.push(packet);
-      } else {
-        // Since we don't have a delete packet to apply we can get a new
-        // generation right away
-        nextGen = bufferedDeletesStream.getNextGen();
-      }
-      if (infoStream.isEnabled("IW")) {
-        infoStream.message("IW", "publish sets newSegment delGen=" + nextGen + " seg=" + segString(newSegment));
+    try {
+      synchronized (this) {
+        // Lock order IW -> BDS
+        synchronized (bufferedDeletesStream) {
+          if (infoStream.isEnabled("IW")) {
+            infoStream.message("IW", "publishFlushedSegment");
+          }
+          
+          if (globalPacket != null && globalPacket.any()) {
+            bufferedDeletesStream.push(globalPacket);
+          } 
+          // Publishing the segment must be synched on IW -> BDS to make the sure
+          // that no merge prunes away the seg. private delete packet
+          final long nextGen;
+          if (packet != null && packet.any()) {
+            nextGen = bufferedDeletesStream.push(packet);
+          } else {
+            // Since we don't have a delete packet to apply we can get a new
+            // generation right away
+            nextGen = bufferedDeletesStream.getNextGen();
+          }
+          if (infoStream.isEnabled("IW")) {
+            infoStream.message("IW", "publish sets newSegment delGen=" + nextGen + " seg=" + segString(newSegment));
+          }
+          newSegment.setBufferedDeletesGen(nextGen);
+          segmentInfos.add(newSegment);
+          checkpoint();
+        }
       }
-      newSegment.setBufferedDeletesGen(nextGen);
-      segmentInfos.add(newSegment);
-      checkpoint();
+    } finally {
+      flushCount.incrementAndGet();
+      doAfterFlush();
     }
   }
 
@@ -2705,12 +2720,13 @@ public class IndexWriter implements Clos
           boolean flushSuccess = false;
           boolean success = false;
           try {
-            anySegmentsFlushed = docWriter.flushAllThreads();
+            anySegmentsFlushed = docWriter.flushAllThreads(this);
             if (!anySegmentsFlushed) {
               // prevent double increment since docWriter#doFlush increments the flushcount
               // if we flushed anything.
               flushCount.incrementAndGet();
             }
+            processEvents(false, true);
             flushSuccess = true;
 
             synchronized(this) {
@@ -2750,7 +2766,7 @@ public class IndexWriter implements Clos
       } catch (OutOfMemoryError oom) {
         handleOOM(oom, "prepareCommit");
       }
- 
+     
       boolean success = false;
       try {
         if (anySegmentsFlushed) {
@@ -2765,7 +2781,7 @@ public class IndexWriter implements Clos
           }
         }
       }
-
+      
       startCommit(toCommit);
     }
   }
@@ -2950,10 +2966,11 @@ public class IndexWriter implements Clos
       synchronized (fullFlushLock) {
       boolean flushSuccess = false;
         try {
-          anySegmentFlushed = docWriter.flushAllThreads();
+          anySegmentFlushed = docWriter.flushAllThreads(this);
           flushSuccess = true;
         } finally {
           docWriter.finishFullFlush(flushSuccess);
+          processEvents(false, true);
         }
       }
       synchronized(this) {
@@ -4307,4 +4324,65 @@ public class IndexWriter implements Clos
   synchronized final void flushFailed(SegmentInfo info) throws IOException {
     deleter.refresh(info.name);
   }
+  
+  final int purge(boolean forced) throws IOException {
+    return docWriter.purgeBuffer(this, forced);
+  }
+
+  final void applyDeletesAndPurge(boolean forcePurge) throws IOException {
+    try {
+      purge(forcePurge);
+    } finally {
+      applyAllDeletes();
+      flushCount.incrementAndGet();
+    }
+  }
+  final void doAfterSegmentFlushed(boolean triggerMerge, boolean forcePurge) throws IOException {
+    try {
+      purge(forcePurge);
+    } finally {
+      if (triggerMerge) {
+        maybeMerge(MergeTrigger.SEGMENT_FLUSH, UNBOUNDED_MAX_MERGE_SEGMENTS);
+      }
+    }
+    
+  }
+  
+  private boolean processEvents(boolean triggerMerge, boolean forcePurge) throws IOException {
+    return processEvents(eventQueue, triggerMerge, forcePurge);
+  }
+  
+  private boolean processEvents(Queue<Event> queue, boolean triggerMerge, boolean forcePurge) throws IOException {
+    Event event;
+    boolean processed = false;
+    while((event = queue.poll()) != null)  {
+      processed = true;
+      event.process(this, triggerMerge, forcePurge);
+    }
+    return processed;
+  }
+  
+  /**
+   * Interface for internal atomic events. See {@link DocumentsWriter} for details. Events are executed concurrently and no order is guaranteed.
+   * Each event should only rely on the serializeability within it's process method. All actions that must happen before or after a certain action must be
+   * encoded inside the {@link #process(IndexWriter, boolean, boolean)} method.
+   *
+   */
+  static interface Event {
+    
+    /**
+     * Processes the event. This method is called by the {@link IndexWriter}
+     * passed as the first argument.
+     * 
+     * @param writer
+     *          the {@link IndexWriter} that executes the event.
+     * @param triggerMerge
+     *          <code>false</code> iff this event should not trigger any segment merges
+     * @param clearBuffers
+     *          <code>true</code> iff this event should clear all buffers associated with the event.
+     * @throws IOException
+     *           if an {@link IOException} occurs
+     */
+    void process(IndexWriter writer, boolean triggerMerge, boolean clearBuffers) throws IOException;
+  }
 }

Modified: lucene/dev/branches/lucene5178/lucene/core/src/test/org/apache/lucene/index/TestFlushByRamOrCountsPolicy.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene5178/lucene/core/src/test/org/apache/lucene/index/TestFlushByRamOrCountsPolicy.java?rev=1515615&r1=1515614&r2=1515615&view=diff
==============================================================================
--- lucene/dev/branches/lucene5178/lucene/core/src/test/org/apache/lucene/index/TestFlushByRamOrCountsPolicy.java (original)
+++ lucene/dev/branches/lucene5178/lucene/core/src/test/org/apache/lucene/index/TestFlushByRamOrCountsPolicy.java Mon Aug 19 21:31:34 2013
@@ -281,7 +281,10 @@ public class TestFlushByRamOrCountsPolic
     Iterator<ThreadState> allActiveThreads = flushControl.allActiveThreadStates();
     long bytesUsed = 0;
     while (allActiveThreads.hasNext()) {
-      bytesUsed += allActiveThreads.next().dwpt.bytesUsed();
+      ThreadState next = allActiveThreads.next();
+      if (next.dwpt != null) {
+        bytesUsed += next.dwpt.bytesUsed();
+      }
     }
     assertEquals(bytesUsed, flushControl.activeBytes());
   }

Modified: lucene/dev/branches/lucene5178/lucene/core/src/test/org/apache/lucene/index/TestIndexWriter.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene5178/lucene/core/src/test/org/apache/lucene/index/TestIndexWriter.java?rev=1515615&r1=1515614&r2=1515615&view=diff
==============================================================================
--- lucene/dev/branches/lucene5178/lucene/core/src/test/org/apache/lucene/index/TestIndexWriter.java (original)
+++ lucene/dev/branches/lucene5178/lucene/core/src/test/org/apache/lucene/index/TestIndexWriter.java Mon Aug 19 21:31:34 2013
@@ -1702,7 +1702,6 @@ public class TestIndexWriter extends Luc
 
       w.deleteAll();
       w.commit();
-
       // Make sure we accumulate no files except for empty
       // segments_N and segments.gen:
       assertTrue(d.listAll().length <= 2);

Modified: lucene/dev/branches/lucene5178/lucene/core/src/test/org/apache/lucene/index/TestIndexWriterForceMerge.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene5178/lucene/core/src/test/org/apache/lucene/index/TestIndexWriterForceMerge.java?rev=1515615&r1=1515614&r2=1515615&view=diff
==============================================================================
--- lucene/dev/branches/lucene5178/lucene/core/src/test/org/apache/lucene/index/TestIndexWriterForceMerge.java (original)
+++ lucene/dev/branches/lucene5178/lucene/core/src/test/org/apache/lucene/index/TestIndexWriterForceMerge.java Mon Aug 19 21:31:34 2013
@@ -83,7 +83,7 @@ public class TestIndexWriterForceMerge e
     IndexWriter writer = new IndexWriter(dir, newIndexWriterConfig(
       TEST_VERSION_CURRENT, new MockAnalyzer(random()))
       .setMaxBufferedDocs(2).setMergePolicy(ldmp).setMergeScheduler(new ConcurrentMergeScheduler()));
-
+    
     for(int iter=0;iter<10;iter++) {
       for(int i=0;i<19;i++)
         writer.addDocument(doc);
@@ -96,7 +96,6 @@ public class TestIndexWriterForceMerge e
       sis.read(dir);
 
       final int segCount = sis.size();
-
       writer.forceMerge(7);
       writer.commit();
       writer.waitForMerges();
@@ -108,7 +107,7 @@ public class TestIndexWriterForceMerge e
       if (segCount < 7)
         assertEquals(segCount, optSegCount);
       else
-        assertEquals(7, optSegCount);
+        assertEquals("seg: " + segCount, 7, optSegCount);
     }
     writer.close();
     dir.close();

Modified: lucene/dev/branches/lucene5178/solr/CHANGES.txt
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene5178/solr/CHANGES.txt?rev=1515615&r1=1515614&r2=1515615&view=diff
==============================================================================
--- lucene/dev/branches/lucene5178/solr/CHANGES.txt (original)
+++ lucene/dev/branches/lucene5178/solr/CHANGES.txt Mon Aug 19 21:31:34 2013
@@ -91,7 +91,9 @@ New Features
 * SOLR-4808: Persist and use router,replicationFactor and maxShardsPerNode at Collection and Shard level (Noble Paul, Shalin Mangar)
 * SOLR-5006: CREATESHARD command for 'implicit' shards (Noble Paul)
 * SOLR-5017: Allow sharding based on the value of a field (Noble Paul)
-* SOLR-4222:create custom sharded collection via collections API (Noble Paul)
+* SOLR-4222: create custom sharded collection via collections API (Noble Paul)
+* SOLR-4718: Allow solr.xml to be stored in ZooKeeper
+* SOLR-5156: Enhance ZkCLI to allow uploading of arbitrary files to ZK.
 
 Bug Fixes
 ----------------------
@@ -130,7 +132,14 @@ Bug Fixes
   of divide by zero, and makes estimated hit counts meaningful in non-optimized
   indexes.  (hossman)
   
-* SOLR-5164: Can not create a collection via collections API (cloud mode) (Erick Erickson)
+* SOLR-3936: Fixed QueryElevationComponent sorting when used with Grouping
+  (Michael Garski via hossman)
+
+* SOLR-5171: SOLR Admin gui works in IE9, breaks in IE10. (Joseph L Howard via
+  steffkes)
+
+* SOLR-5174: Admin UI - Query View doesn't highlight (json) Result if it 
+  contains HTML Tags (steffkes)
 
 Optimizations
 ----------------------
@@ -148,8 +157,8 @@ Other Changes
   The solr.clustering.enabled system property is set to 'true' by default.
   (ehatcher, Dawid Weiss)
 
-* SOLR-4914: Factor out core list persistence and discovery into a
-  new CoresLocator interface. (Alan Woodward)
+* SOLR-4914, SOLR-5162: Factor out core list persistence and discovery into a
+  new CoresLocator interface. (Alan Woodward, Shawn Heisey)
 
 * SOLR-5056: Improve type safety of ConfigSolr class. (Alan Woodward)
 

Modified: lucene/dev/branches/lucene5178/solr/core/src/java/org/apache/solr/client/solrj/embedded/JettySolrRunner.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene5178/solr/core/src/java/org/apache/solr/client/solrj/embedded/JettySolrRunner.java?rev=1515615&r1=1515614&r2=1515615&view=diff
==============================================================================
--- lucene/dev/branches/lucene5178/solr/core/src/java/org/apache/solr/client/solrj/embedded/JettySolrRunner.java (original)
+++ lucene/dev/branches/lucene5178/solr/core/src/java/org/apache/solr/client/solrj/embedded/JettySolrRunner.java Mon Aug 19 21:31:34 2013
@@ -26,7 +26,6 @@ import java.util.Random;
 import java.util.SortedMap;
 import java.util.TreeMap;
 import java.util.concurrent.atomic.AtomicLong;
-
 import java.net.URL;
 import java.net.MalformedURLException;
 
@@ -499,6 +498,10 @@ public class JettySolrRunner {
   public void setCoreNodeName(String coreNodeName) {
     this.coreNodeName = coreNodeName;
   }
+
+  public String getSolrHome() {
+    return solrHome;
+  }
 }
 
 class NoLog implements Logger {

Modified: lucene/dev/branches/lucene5178/solr/core/src/java/org/apache/solr/cloud/ZkCLI.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene5178/solr/core/src/java/org/apache/solr/cloud/ZkCLI.java?rev=1515615&r1=1515614&r2=1515615&view=diff
==============================================================================
--- lucene/dev/branches/lucene5178/solr/core/src/java/org/apache/solr/cloud/ZkCLI.java (original)
+++ lucene/dev/branches/lucene5178/solr/core/src/java/org/apache/solr/cloud/ZkCLI.java Mon Aug 19 21:31:34 2013
@@ -3,6 +3,7 @@ package org.apache.solr.cloud;
 import org.apache.commons.cli.CommandLine;
 import org.apache.commons.cli.CommandLineParser;
 import org.apache.commons.cli.HelpFormatter;
+import org.apache.commons.io.IOUtils;
 import org.apache.commons.cli.Option;
 import org.apache.commons.cli.OptionBuilder;
 import org.apache.commons.cli.Options;
@@ -19,7 +20,9 @@ import org.xml.sax.SAXException;
 
 import javax.xml.parsers.ParserConfigurationException;
 import java.io.File;
+import java.io.FileInputStream;
 import java.io.IOException;
+import java.io.InputStream;
 import java.util.List;
 import java.util.concurrent.TimeoutException;
 
@@ -44,6 +47,7 @@ public class ZkCLI {
   
   private static final String MAKEPATH = "makepath";
   private static final String PUT = "put";
+  private static final String PUT_FILE = "putfile";
   private static final String DOWNCONFIG = "downconfig";
   private static final String ZK_CLI_NAME = "ZkCLI";
   private static final String HELP = "help";
@@ -87,7 +91,8 @@ public class ZkCLI {
         .hasArg(true)
         .withDescription(
             "cmd to run: " + BOOTSTRAP + ", " + UPCONFIG + ", " + DOWNCONFIG
-                + ", " + LINKCONFIG + ", " + MAKEPATH + ", "+ PUT + ", "+ LIST + ", " + CLEAR).create(CMD));
+                + ", " + LINKCONFIG + ", " + MAKEPATH + ", " + PUT + ", " + PUT_FILE + ","
+                + LIST + ", " + CLEAR).create(CMD));
 
     Option zkHostOption = new Option("z", ZKHOST, true,
         "ZooKeeper host address");
@@ -131,6 +136,7 @@ public class ZkCLI {
         System.out.println("zkcli.sh -zkhost localhost:9983 -cmd " + LINKCONFIG + " -" + COLLECTION + " collection1" + " -" + CONFNAME + " myconf");
         System.out.println("zkcli.sh -zkhost localhost:9983 -cmd " + MAKEPATH + " /apache/solr");
         System.out.println("zkcli.sh -zkhost localhost:9983 -cmd " + PUT + " /solr.conf 'conf data'");
+        System.out.println("zkcli.sh -zkhost localhost:9983 -cmd " + PUT_FILE + " /solr.xml /User/myuser/solr/solr.xml");
         System.out.println("zkcli.sh -zkhost localhost:9983 -cmd " + CLEAR + " /solr");
         System.out.println("zkcli.sh -zkhost localhost:9983 -cmd " + LIST);
         return;
@@ -244,6 +250,20 @@ public class ZkCLI {
           }
           zkClient.create(arglist.get(0).toString(), arglist.get(1).toString().getBytes("UTF-8"),
                           acl, CreateMode.PERSISTENT, true);
+        } else if (line.getOptionValue(CMD).equals(PUT_FILE)) {
+          List arglist = line.getArgList();
+          if (arglist.size() != 2) {
+            System.out.println("-" + PUT_FILE + " requires two args - the path to create in ZK and the path to the local file");
+            System.exit(1);
+          }
+          InputStream is = new FileInputStream(arglist.get(1).toString());
+          try {
+            zkClient.create(arglist.get(0).toString(), IOUtils.toByteArray(is),
+                ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT, true);
+          } finally {
+            IOUtils.closeQuietly(is);
+          }
+
         }
       } finally {
         if (solrPort != null) {

Modified: lucene/dev/branches/lucene5178/solr/core/src/java/org/apache/solr/core/ConfigSolr.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene5178/solr/core/src/java/org/apache/solr/core/ConfigSolr.java?rev=1515615&r1=1515614&r2=1515615&view=diff
==============================================================================
--- lucene/dev/branches/lucene5178/solr/core/src/java/org/apache/solr/core/ConfigSolr.java (original)
+++ lucene/dev/branches/lucene5178/solr/core/src/java/org/apache/solr/core/ConfigSolr.java Mon Aug 19 21:31:34 2013
@@ -61,10 +61,7 @@ public abstract class ConfigSolr {
       else {
         inputStream = new FileInputStream(configFile);
       }
-      ByteArrayOutputStream baos = new ByteArrayOutputStream();
-      ByteStreams.copy(inputStream, baos);
-      String originalXml = IOUtils.toString(new ByteArrayInputStream(baos.toByteArray()), "UTF-8");
-      return fromInputStream(loader, new ByteArrayInputStream(baos.toByteArray()), configFile, originalXml);
+      return fromInputStream(loader, inputStream);
     }
     catch (Exception e) {
       throw new SolrException(SolrException.ErrorCode.SERVER_ERROR,
@@ -76,13 +73,17 @@ public abstract class ConfigSolr {
   }
 
   public static ConfigSolr fromString(String xml) {
-    return fromInputStream(null, new ByteArrayInputStream(xml.getBytes(Charsets.UTF_8)), null, xml);
+    return fromInputStream(null, new ByteArrayInputStream(xml.getBytes(Charsets.UTF_8)));
   }
 
-  public static ConfigSolr fromInputStream(SolrResourceLoader loader, InputStream is, File file, String originalXml) {
+  public static ConfigSolr fromInputStream(SolrResourceLoader loader, InputStream is) {
     try {
-      Config config = new Config(loader, null, new InputSource(is), null, false);
-      return fromConfig(config, file, originalXml);
+      ByteArrayOutputStream baos = new ByteArrayOutputStream();
+      ByteStreams.copy(is, baos);
+      String originalXml = IOUtils.toString(new ByteArrayInputStream(baos.toByteArray()), "UTF-8");
+      ByteArrayInputStream dup = new ByteArrayInputStream(baos.toByteArray());
+      Config config = new Config(loader, null, new InputSource(dup), null, false);
+      return fromConfig(config, originalXml);
     }
     catch (Exception e) {
       throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, e);
@@ -93,9 +94,9 @@ public abstract class ConfigSolr {
     return fromFile(loader, new File(solrHome, SOLR_XML_FILE));
   }
 
-  public static ConfigSolr fromConfig(Config config, File file, String originalXml) {
+  public static ConfigSolr fromConfig(Config config, String originalXml) {
     boolean oldStyle = (config.getNode("solr/cores", false) != null);
-    return oldStyle ? new ConfigSolrXmlOld(config, file, originalXml)
+    return oldStyle ? new ConfigSolrXmlOld(config, originalXml)
                     : new ConfigSolrXml(config);
   }
   

Modified: lucene/dev/branches/lucene5178/solr/core/src/java/org/apache/solr/core/ConfigSolrXmlOld.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene5178/solr/core/src/java/org/apache/solr/core/ConfigSolrXmlOld.java?rev=1515615&r1=1515614&r2=1515615&view=diff
==============================================================================
--- lucene/dev/branches/lucene5178/solr/core/src/java/org/apache/solr/core/ConfigSolrXmlOld.java (original)
+++ lucene/dev/branches/lucene5178/solr/core/src/java/org/apache/solr/core/ConfigSolrXmlOld.java Mon Aug 19 21:31:34 2013
@@ -55,15 +55,15 @@ public class ConfigSolrXmlOld extends Co
     return "solr/cores/shardHandlerFactory";
   }
 
-  public ConfigSolrXmlOld(Config config, File configFile, String originalXML) {
+  public ConfigSolrXmlOld(Config config, String originalXML) {
     super(config);
     try {
       checkForIllegalConfig();
       fillPropMap();
       config.substituteProperties();
       initCoreList();
-      this.persistor = isPersistent() ? new SolrXMLCoresLocator(configFile, originalXML, this)
-                                      : new SolrXMLCoresLocator.NonPersistingLocator(configFile, originalXML, this);
+      this.persistor = isPersistent() ? new SolrXMLCoresLocator(originalXML, this)
+                                      : new SolrXMLCoresLocator.NonPersistingLocator(originalXML, this);
     }
     catch (IOException e) {
       throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, e);

Modified: lucene/dev/branches/lucene5178/solr/core/src/java/org/apache/solr/core/CoreContainer.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene5178/solr/core/src/java/org/apache/solr/core/CoreContainer.java?rev=1515615&r1=1515614&r2=1515615&view=diff
==============================================================================
--- lucene/dev/branches/lucene5178/solr/core/src/java/org/apache/solr/core/CoreContainer.java (original)
+++ lucene/dev/branches/lucene5178/solr/core/src/java/org/apache/solr/core/CoreContainer.java Mon Aug 19 21:31:34 2013
@@ -480,7 +480,7 @@ public class CoreContainer {
     SolrResourceLoader solrLoader = null;
 
     SolrConfig config = null;
-    solrLoader = new SolrResourceLoader(instanceDir, loader.getClassLoader(), dcore.getCoreProperties());
+    solrLoader = new SolrResourceLoader(instanceDir, loader.getClassLoader(), dcore.getSubstitutableProperties());
     try {
       config = new SolrConfig(solrLoader, dcore.getConfigName(), null);
     } catch (Exception e) {
@@ -646,7 +646,7 @@ public class CoreContainer {
         SolrResourceLoader solrLoader;
         if(zkSys.getZkController() == null) {
           solrLoader = new SolrResourceLoader(instanceDir.getAbsolutePath(), loader.getClassLoader(),
-                                                cd.getCoreProperties());
+                                                cd.getSubstitutableProperties());
         } else {
           try {
             String collection = cd.getCloudDescriptor().getCollectionName();
@@ -659,7 +659,7 @@ public class CoreContainer {
                                            "Could not find config name for collection:" + collection);
             }
             solrLoader = new ZkSolrResourceLoader(instanceDir.getAbsolutePath(), zkConfigName, loader.getClassLoader(),
-                cd.getCoreProperties(), zkSys.getZkController());
+                cd.getSubstitutableProperties(), zkSys.getZkController());
           } catch (KeeperException e) {
             log.error("", e);
             throw new ZooKeeperException(SolrException.ErrorCode.SERVER_ERROR,

Modified: lucene/dev/branches/lucene5178/solr/core/src/java/org/apache/solr/core/CoreDescriptor.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene5178/solr/core/src/java/org/apache/solr/core/CoreDescriptor.java?rev=1515615&r1=1515614&r2=1515615&view=diff
==============================================================================
--- lucene/dev/branches/lucene5178/solr/core/src/java/org/apache/solr/core/CoreDescriptor.java (original)
+++ lucene/dev/branches/lucene5178/solr/core/src/java/org/apache/solr/core/CoreDescriptor.java Mon Aug 19 21:31:34 2013
@@ -119,6 +119,9 @@ public class CoreDescriptor {
   /** The properties for this core, as available through getProperty() */
   protected final Properties coreProperties = new Properties();
 
+  /** The properties for this core, substitutable by resource loaders */
+  protected final Properties substitutableProperties = new Properties();
+
   /**
    * Create a new CoreDescriptor.
    * @param container       the CoreDescriptor's container
@@ -160,6 +163,7 @@ public class CoreDescriptor {
     }
 
     loadExtraProperties();
+    buildSubstitutableProperties();
 
     // TODO maybe make this a CloudCoreDescriptor subclass?
     if (container.isZooKeeperAware()) {
@@ -201,6 +205,20 @@ public class CoreDescriptor {
     }
   }
 
+  /**
+   * Create the properties object used by resource loaders, etc, for property
+   * substitution.  The default solr properties are prefixed with 'solr.core.', so,
+   * e.g., 'name' becomes 'solr.core.name'
+   */
+  protected void buildSubstitutableProperties() {
+    for (String propName : coreProperties.stringPropertyNames()) {
+      String propValue = coreProperties.getProperty(propName);
+      if (!isUserDefinedProperty(propName))
+        propName = "solr.core." + propName;
+      substitutableProperties.setProperty(propName, propValue);
+    }
+  }
+
   protected File resolvePaths(String filepath) {
     File file = new File(filepath);
     if (file.isAbsolute())
@@ -336,11 +354,11 @@ public class CoreDescriptor {
   }
 
   /**
-   * Returns all properties defined on this CoreDescriptor
-   * @return all properties defined on this CoreDescriptor
+   * Returns all substitutable properties defined on this CoreDescriptor
+   * @return all substitutable properties defined on this CoreDescriptor
    */
-  public Properties getCoreProperties() {
-    return coreProperties;
+  public Properties getSubstitutableProperties() {
+    return substitutableProperties;
   }
 
   @Override

Modified: lucene/dev/branches/lucene5178/solr/core/src/java/org/apache/solr/core/SolrCore.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene5178/solr/core/src/java/org/apache/solr/core/SolrCore.java?rev=1515615&r1=1515614&r2=1515615&view=diff
==============================================================================
--- lucene/dev/branches/lucene5178/solr/core/src/java/org/apache/solr/core/SolrCore.java (original)
+++ lucene/dev/branches/lucene5178/solr/core/src/java/org/apache/solr/core/SolrCore.java Mon Aug 19 21:31:34 2013
@@ -2241,6 +2241,7 @@ public final class SolrCore implements S
     lst.add("coreName", name==null ? "(null)" : name);
     lst.add("startTime", new Date(startTime));
     lst.add("refCount", getOpenCount());
+    lst.add("instanceDir", resourceLoader.getInstanceDir());
     lst.add("indexDir", getIndexDir());
 
     CoreDescriptor cd = getCoreDescriptor();

Modified: lucene/dev/branches/lucene5178/solr/core/src/java/org/apache/solr/core/SolrXMLCoresLocator.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene5178/solr/core/src/java/org/apache/solr/core/SolrXMLCoresLocator.java?rev=1515615&r1=1515614&r2=1515615&view=diff
==============================================================================
--- lucene/dev/branches/lucene5178/solr/core/src/java/org/apache/solr/core/SolrXMLCoresLocator.java (original)
+++ lucene/dev/branches/lucene5178/solr/core/src/java/org/apache/solr/core/SolrXMLCoresLocator.java Mon Aug 19 21:31:34 2013
@@ -41,7 +41,6 @@ public class SolrXMLCoresLocator impleme
 
   private static final Logger logger = LoggerFactory.getLogger(SolrXMLCoresLocator.class);
 
-  private final File file;
   private final String solrXmlTemplate;
   private final ConfigSolrXmlOld cfg;
 
@@ -50,13 +49,11 @@ public class SolrXMLCoresLocator impleme
 
   /**
    * Create a new SolrXMLCoresLocator
-   * @param file          a File object representing the file to write out to
    * @param originalXML   the original content of the solr.xml file
    * @param cfg           the CoreContainer's config object
    */
-  public SolrXMLCoresLocator(File file, String originalXML, ConfigSolrXmlOld cfg) {
+  public SolrXMLCoresLocator(String originalXML, ConfigSolrXmlOld cfg) {
     this.solrXmlTemplate = buildTemplate(originalXML);
-    this.file = file;
     this.cfg = cfg;
   }
 
@@ -147,6 +144,7 @@ public class SolrXMLCoresLocator impleme
   }
 
   protected void doPersist(String xml) {
+    File file = new File(cfg.config.getResourceLoader().getInstanceDir(), ConfigSolr.SOLR_XML_FILE);
     try {
       Writer writer = new OutputStreamWriter(new FileOutputStream(file), Charsets.UTF_8);
       writer.write(xml);
@@ -204,8 +202,8 @@ public class SolrXMLCoresLocator impleme
 
   public static class NonPersistingLocator extends SolrXMLCoresLocator {
 
-    public NonPersistingLocator(File file, String originalXML, ConfigSolrXmlOld cfg) {
-      super(file, originalXML, cfg);
+    public NonPersistingLocator(String originalXML, ConfigSolrXmlOld cfg) {
+      super(originalXML, cfg);
       this.xml = originalXML;
     }
 

Modified: lucene/dev/branches/lucene5178/solr/core/src/java/org/apache/solr/core/ZkContainer.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene5178/solr/core/src/java/org/apache/solr/core/ZkContainer.java?rev=1515615&r1=1515614&r2=1515615&view=diff
==============================================================================
--- lucene/dev/branches/lucene5178/solr/core/src/java/org/apache/solr/core/ZkContainer.java (original)
+++ lucene/dev/branches/lucene5178/solr/core/src/java/org/apache/solr/core/ZkContainer.java Mon Aug 19 21:31:34 2013
@@ -227,7 +227,7 @@ public class ZkContainer {
             "Could not find config name for collection:" + collection);
       }
       solrLoader = new ZkSolrResourceLoader(instanceDir, zkConfigName,
-          loader.getClassLoader(), dcore.getCoreProperties(), zkController);
+          loader.getClassLoader(), dcore.getSubstitutableProperties(), zkController);
       config = getSolrConfigFromZk(zkConfigName, dcore.getConfigName(),
           solrLoader);
       schema = IndexSchemaFactory.buildIndexSchema(dcore.getSchemaName(),

Modified: lucene/dev/branches/lucene5178/solr/core/src/java/org/apache/solr/handler/admin/CoreAdminHandler.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene5178/solr/core/src/java/org/apache/solr/handler/admin/CoreAdminHandler.java?rev=1515615&r1=1515614&r2=1515615&view=diff
==============================================================================
--- lucene/dev/branches/lucene5178/solr/core/src/java/org/apache/solr/handler/admin/CoreAdminHandler.java (original)
+++ lucene/dev/branches/lucene5178/solr/core/src/java/org/apache/solr/handler/admin/CoreAdminHandler.java Mon Aug 19 21:31:34 2013
@@ -410,7 +410,8 @@ public class CoreAdminHandler extends Re
         "Missing parameter [" + CoreAdminParams.NAME + "]");
     String instancedir = params.get(CoreAdminParams.INSTANCE_DIR);
     if (StringUtils.isEmpty(instancedir)) {
-      instancedir = name; // Already relative to solrHome, we haven't been given an absolute path.
+      instancedir = name; // will be resolved later against solr.home
+      //instancedir = container.getSolrHome() + "/" + name;
     }
 
     Properties coreProps = new Properties();

Modified: lucene/dev/branches/lucene5178/solr/core/src/java/org/apache/solr/handler/component/QueryElevationComponent.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene5178/solr/core/src/java/org/apache/solr/handler/component/QueryElevationComponent.java?rev=1515615&r1=1515614&r2=1515615&view=diff
==============================================================================
--- lucene/dev/branches/lucene5178/solr/core/src/java/org/apache/solr/handler/component/QueryElevationComponent.java (original)
+++ lucene/dev/branches/lucene5178/solr/core/src/java/org/apache/solr/handler/component/QueryElevationComponent.java Mon Aug 19 21:31:34 2013
@@ -44,6 +44,7 @@ import org.apache.solr.common.SolrExcept
 import org.apache.solr.common.params.QueryElevationParams;
 import org.apache.solr.common.params.SolrParams;
 import org.apache.solr.schema.IndexSchema;
+import org.apache.solr.search.grouping.GroupingSpecification;
 import org.apache.solr.util.DOMUtil;
 import org.apache.solr.common.util.NamedList;
 import org.apache.solr.common.util.SimpleOrderedMap;
@@ -424,23 +425,25 @@ public class QueryElevationComponent ext
         }));
       } else {
         // Check if the sort is based on score
-        boolean modify = false;
         SortField[] current = sortSpec.getSort().getSort();
-        ArrayList<SortField> sorts = new ArrayList<SortField>(current.length + 1);
-        // Perhaps force it to always sort by score
-        if (force && current[0].getType() != SortField.Type.SCORE) {
-          sorts.add(new SortField("_elevate_", comparator, true));
-          modify = true;
-        }
-        for (SortField sf : current) {
-          if (sf.getType() == SortField.Type.SCORE) {
-            sorts.add(new SortField("_elevate_", comparator, !sf.getReverse()));
-            modify = true;
-          }
-          sorts.add(sf);
+        Sort modified = this.modifySort(current, force, comparator);
+        if(modified != null) {
+          sortSpec.setSort(modified);
         }
-        if (modify) {
-          sortSpec.setSort(new Sort(sorts.toArray(new SortField[sorts.size()])));
+      }
+
+      // alter the sorting in the grouping specification if there is one
+      GroupingSpecification groupingSpec = rb.getGroupingSpec();
+      if(groupingSpec != null) {
+        SortField[] groupSort = groupingSpec.getGroupSort().getSort();
+        Sort modGroupSort = this.modifySort(groupSort, force, comparator);
+        if(modGroupSort != null) {
+          groupingSpec.setGroupSort(modGroupSort);
+        }
+        SortField[] withinGroupSort = groupingSpec.getSortWithinGroup().getSort();
+        Sort modWithinGroupSort = this.modifySort(withinGroupSort, force, comparator);
+        if(modWithinGroupSort != null) {
+          groupingSpec.setSortWithinGroup(modWithinGroupSort);
         }
       }
     }
@@ -466,6 +469,25 @@ public class QueryElevationComponent ext
     }
   }
 
+  private Sort modifySort(SortField[] current, boolean force, ElevationComparatorSource comparator) {
+    boolean modify = false;
+    ArrayList<SortField> sorts = new ArrayList<SortField>(current.length + 1);
+    // Perhaps force it to always sort by score
+    if (force && current[0].getType() != SortField.Type.SCORE) {
+      sorts.add(new SortField("_elevate_", comparator, true));
+      modify = true;
+    }
+    for (SortField sf : current) {
+      if (sf.getType() == SortField.Type.SCORE) {
+        sorts.add(new SortField("_elevate_", comparator, !sf.getReverse()));
+        modify = true;
+      }
+      sorts.add(sf);
+    }
+
+    return modify ? new Sort(sorts.toArray(new SortField[sorts.size()])) : null;
+  }
+
   @Override
   public void process(ResponseBuilder rb) throws IOException {
     // Do nothing -- the real work is modifying the input query

Modified: lucene/dev/branches/lucene5178/solr/core/src/java/org/apache/solr/servlet/SolrDispatchFilter.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene5178/solr/core/src/java/org/apache/solr/servlet/SolrDispatchFilter.java?rev=1515615&r1=1515614&r2=1515615&view=diff
==============================================================================
--- lucene/dev/branches/lucene5178/solr/core/src/java/org/apache/solr/servlet/SolrDispatchFilter.java (original)
+++ lucene/dev/branches/lucene5178/solr/core/src/java/org/apache/solr/servlet/SolrDispatchFilter.java Mon Aug 19 21:31:34 2013
@@ -18,12 +18,14 @@
 package org.apache.solr.servlet;
 
 import org.apache.commons.io.IOUtils;
+import org.apache.commons.lang.StringUtils;
 import org.apache.solr.common.SolrException;
 import org.apache.solr.common.SolrException.ErrorCode;
 import org.apache.solr.common.cloud.Aliases;
 import org.apache.solr.common.cloud.ClusterState;
 import org.apache.solr.common.cloud.Replica;
 import org.apache.solr.common.cloud.Slice;
+import org.apache.solr.common.cloud.SolrZkClient;
 import org.apache.solr.common.cloud.ZkCoreNodeProps;
 import org.apache.solr.common.cloud.ZkNodeProps;
 import org.apache.solr.common.cloud.ZkStateReader;
@@ -35,9 +37,11 @@ import org.apache.solr.common.util.Conte
 import org.apache.solr.common.util.NamedList;
 import org.apache.solr.common.util.SimpleOrderedMap;
 import org.apache.solr.common.util.StrUtils;
+import org.apache.solr.core.ConfigSolr;
 import org.apache.solr.core.CoreContainer;
 import org.apache.solr.core.SolrConfig;
 import org.apache.solr.core.SolrCore;
+import org.apache.solr.core.SolrResourceLoader;
 import org.apache.solr.handler.ContentStreamHandlerBase;
 import org.apache.solr.request.SolrQueryRequest;
 import org.apache.solr.request.SolrQueryRequestBase;
@@ -60,6 +64,7 @@ import javax.servlet.ServletRequest;
 import javax.servlet.ServletResponse;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
+import java.io.ByteArrayInputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
@@ -131,12 +136,44 @@ public class SolrDispatchFilter implemen
     log.info("SolrDispatchFilter.init() done");
   }
 
+  private ConfigSolr loadConfigSolr(SolrResourceLoader loader) {
+
+    String solrxmlLocation = System.getProperty("solr.solrxml.location", "solrhome");
+
+    if (solrxmlLocation == null || "solrhome".equalsIgnoreCase(solrxmlLocation))
+      return ConfigSolr.fromSolrHome(loader, loader.getInstanceDir());
+
+    if ("zookeeper".equalsIgnoreCase(solrxmlLocation)) {
+      String zkHost = System.getProperty("zkHost");
+      log.info("Trying to read solr.xml from " + zkHost);
+      if (StringUtils.isEmpty(zkHost))
+        throw new SolrException(ErrorCode.SERVER_ERROR,
+            "Could not load solr.xml from zookeeper: zkHost system property not set");
+      SolrZkClient zkClient = new SolrZkClient(zkHost, 30000);
+      try {
+        if (!zkClient.exists("/solr.xml", true))
+          throw new SolrException(ErrorCode.SERVER_ERROR, "Could not load solr.xml from zookeeper: node not found");
+        byte[] data = zkClient.getData("/solr.xml", null, null, true);
+        return ConfigSolr.fromInputStream(loader, new ByteArrayInputStream(data));
+      } catch (Exception e) {
+        throw new SolrException(ErrorCode.SERVER_ERROR, "Could not load solr.xml from zookeeper", e);
+      } finally {
+        zkClient.close();
+      }
+    }
+
+    throw new SolrException(ErrorCode.SERVER_ERROR,
+        "Bad solr.solrxml.location set: " + solrxmlLocation + " - should be 'solrhome' or 'zookeeper'");
+  }
+
   /**
    * Override this to change CoreContainer initialization
    * @return a CoreContainer to hold this server's cores
    */
   protected CoreContainer createCoreContainer() {
-    CoreContainer cores = new CoreContainer();
+    SolrResourceLoader loader = new SolrResourceLoader(SolrResourceLoader.locateSolrHome());
+    ConfigSolr config = loadConfigSolr(loader);
+    CoreContainer cores = new CoreContainer(loader, config);
     cores.load();
     return cores;
   }

Modified: lucene/dev/branches/lucene5178/solr/core/src/test-files/solr/solr.xml
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene5178/solr/core/src/test-files/solr/solr.xml?rev=1515615&r1=1515614&r2=1515615&view=diff
==============================================================================
--- lucene/dev/branches/lucene5178/solr/core/src/test-files/solr/solr.xml (original)
+++ lucene/dev/branches/lucene5178/solr/core/src/test-files/solr/solr.xml Mon Aug 19 21:31:34 2013
@@ -30,7 +30,7 @@
   -->
   <cores adminPath="/admin/cores" defaultCoreName="collection1" host="127.0.0.1" hostPort="${hostPort:8983}" 
          hostContext="${hostContext:solr}" zkClientTimeout="${solr.zkclienttimeout:30000}" numShards="${numShards:3}" shareSchema="${shareSchema:false}" 
-         genericCoreNodeNames="${genericCoreNodeNames:true}"
+         genericCoreNodeNames="${genericCoreNodeNames:true}" leaderVoteWait="0"
          distribUpdateConnTimeout="${distribUpdateConnTimeout:15000}" distribUpdateSoTimeout="${distribUpdateSoTimeout:120000}">
     <core name="collection1" instanceDir="collection1" shard="${shard:}" collection="${collection:collection1}" config="${solrconfig:solrconfig.xml}" schema="${schema:schema.xml}"
           coreNodeName="${coreNodeName:}"/>

Modified: lucene/dev/branches/lucene5178/solr/core/src/test/org/apache/solr/cloud/CollectionsAPIDistributedZkTest.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene5178/solr/core/src/test/org/apache/solr/cloud/CollectionsAPIDistributedZkTest.java?rev=1515615&r1=1515614&r2=1515615&view=diff
==============================================================================
--- lucene/dev/branches/lucene5178/solr/core/src/test/org/apache/solr/cloud/CollectionsAPIDistributedZkTest.java (original)
+++ lucene/dev/branches/lucene5178/solr/core/src/test/org/apache/solr/cloud/CollectionsAPIDistributedZkTest.java Mon Aug 19 21:31:34 2013
@@ -17,12 +17,39 @@ package org.apache.solr.cloud;
  * limitations under the License.
  */
 
+import static org.apache.solr.cloud.OverseerCollectionProcessor.REPLICATION_FACTOR;
+
+import java.io.File;
+import java.io.IOException;
+import java.lang.management.ManagementFactory;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.concurrent.CompletionService;
+import java.util.concurrent.ExecutorCompletionService;
+import java.util.concurrent.Future;
+import java.util.concurrent.SynchronousQueue;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+
+import javax.management.MBeanServer;
+import javax.management.MBeanServerFactory;
+import javax.management.ObjectName;
+
 import org.apache.lucene.util.Constants;
 import org.apache.lucene.util.LuceneTestCase.Slow;
 import org.apache.lucene.util._TestUtil;
 import org.apache.solr.SolrTestCaseJ4;
 import org.apache.solr.client.solrj.SolrQuery;
 import org.apache.solr.client.solrj.SolrServerException;
+import org.apache.solr.client.solrj.embedded.JettySolrRunner;
 import org.apache.solr.client.solrj.impl.CloudSolrServer;
 import org.apache.solr.client.solrj.impl.HttpSolrServer;
 import org.apache.solr.client.solrj.impl.HttpSolrServer.RemoteSolrException;
@@ -46,8 +73,10 @@ import org.apache.solr.common.params.Mod
 import org.apache.solr.common.util.NamedList;
 import org.apache.solr.common.util.SimpleOrderedMap;
 import org.apache.solr.common.util.StrUtils;
+import org.apache.solr.core.CoreContainer;
 import org.apache.solr.core.SolrCore;
 import org.apache.solr.core.SolrInfoMBean.Category;
+import org.apache.solr.core.SolrResourceLoader;
 import org.apache.solr.servlet.SolrDispatchFilter;
 import org.apache.solr.update.DirectUpdateHandler2;
 import org.apache.solr.update.SolrCmdDistributor.Request;
@@ -55,32 +84,6 @@ import org.apache.solr.util.DefaultSolrT
 import org.junit.Before;
 import org.junit.BeforeClass;
 
-import javax.management.MBeanServer;
-import javax.management.MBeanServerFactory;
-import javax.management.ObjectName;
-
-import java.io.File;
-import java.io.IOException;
-import java.lang.management.ManagementFactory;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
-import java.util.concurrent.CompletionService;
-import java.util.concurrent.ExecutorCompletionService;
-import java.util.concurrent.Future;
-import java.util.concurrent.SynchronousQueue;
-import java.util.concurrent.ThreadPoolExecutor;
-import java.util.concurrent.TimeUnit;
-
-import static org.apache.solr.cloud.OverseerCollectionProcessor.REPLICATION_FACTOR;
-
 /**
  * Tests the Cloud Collections API.
  */
@@ -500,6 +503,8 @@ public class CollectionsAPIDistributedZk
       waitForRecoveriesToFinish("awholynewcollection_" + j, zkStateReader, false);
     }
     
+    checkInstanceDirs(jettys.get(0)); 
+    
     List<String> collectionNameList = new ArrayList<String>();
     collectionNameList.addAll(collectionInfos.keySet());
     String collectionName = collectionNameList.get(random().nextInt(collectionNameList.size()));
@@ -658,6 +663,24 @@ public class CollectionsAPIDistributedZk
     checkNoTwoShardsUseTheSameIndexDir();
   }
 
+  private void checkInstanceDirs(JettySolrRunner jetty) {
+    CoreContainer cores = ((SolrDispatchFilter) jetty.getDispatchFilter()
+        .getFilter()).getCores();
+    Collection<SolrCore> theCores = cores.getCores();
+    for (SolrCore core : theCores) {
+      // look for core props file
+      assertTrue("Could not find expected core.properties file",
+          new File((String) core.getStatistics().get("instanceDir"),
+              "core.properties").exists());
+      
+      assertEquals(
+          SolrResourceLoader.normalizeDir(jetty.getSolrHome() + File.separator
+              + core.getName()),
+          SolrResourceLoader.normalizeDir((String) core.getStatistics().get(
+              "instanceDir")));
+    }
+  }
+
   private boolean waitForReloads(String collectionName, Map<String,Long> urlToTimeBefore) throws SolrServerException, IOException {
     
     

Modified: lucene/dev/branches/lucene5178/solr/core/src/test/org/apache/solr/cloud/ZkCLITest.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene5178/solr/core/src/test/org/apache/solr/cloud/ZkCLITest.java?rev=1515615&r1=1515614&r2=1515615&view=diff
==============================================================================
--- lucene/dev/branches/lucene5178/solr/core/src/test/org/apache/solr/cloud/ZkCLITest.java (original)
+++ lucene/dev/branches/lucene5178/solr/core/src/test/org/apache/solr/cloud/ZkCLITest.java Mon Aug 19 21:31:34 2013
@@ -18,10 +18,14 @@ package org.apache.solr.cloud;
  */
 
 import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.InputStream;
 import java.util.Collection;
 import java.util.List;
 
 import org.apache.commons.io.FileUtils;
+import org.apache.commons.io.IOUtils;
 import org.apache.commons.io.filefilter.RegexFileFilter;
 import org.apache.commons.io.filefilter.TrueFileFilter;
 import org.apache.solr.SolrTestCaseJ4;
@@ -50,7 +54,8 @@ public class ZkCLITest extends SolrTestC
   private String solrHome;
 
   private SolrZkClient zkClient;
-  
+
+  protected static final String SOLR_HOME = SolrTestCaseJ4.TEST_HOME();
   
   @BeforeClass
   public static void beforeClass() {
@@ -141,7 +146,7 @@ public class ZkCLITest extends SolrTestC
 
   @Test
   public void testPut() throws Exception {
-    // test bootstrap_conf
+    // test put
     String data = "my data";
     String[] args = new String[] {"-zkhost", zkServer.getZkAddress(), "-cmd",
         "put", "/data.txt", data};
@@ -151,7 +156,41 @@ public class ZkCLITest extends SolrTestC
 
     assertArrayEquals(zkClient.getData("/data.txt", null, null, true), data.getBytes("UTF-8"));
   }
-  
+
+  @Test
+  public void testPutFile() throws Exception {
+    // test put file
+    String[] args = new String[] {"-zkhost", zkServer.getZkAddress(), "-cmd",
+        "putfile", "/solr.xml", SOLR_HOME + File.separator + "solr-stress-new.xml"};
+    ZkCLI.main(args);
+
+    String fromZk = new String(zkClient.getData("/solr.xml", null, null, true), "UTF-8");
+    File locFile = new File(SOLR_HOME + File.separator + "solr-stress-new.xml");
+    InputStream is = new FileInputStream(locFile);
+    String fromLoc;
+    try {
+      fromLoc = new String(IOUtils.toByteArray(is), "UTF-8");
+    } finally {
+      IOUtils.closeQuietly(is);
+    }
+    assertEquals("Should get back what we put in ZK", fromZk, fromLoc);
+  }
+
+  @Test
+  public void testPutFileNotExists() throws Exception {
+    // test put file
+    String[] args = new String[] {"-zkhost", zkServer.getZkAddress(), "-cmd",
+        "putfile", "/solr.xml", SOLR_HOME + File.separator + "not-there.xml"};
+    try {
+      ZkCLI.main(args);
+      fail("Should have had a file not found exception");
+    } catch (FileNotFoundException fne) {
+      String msg = fne.getMessage();
+      assertTrue("Didn't find expected error message containing 'not-there.xml' in " + msg,
+          msg.indexOf("not-there.xml") != -1);
+    }
+  }
+
   @Test
   public void testList() throws Exception {
     zkClient.makePath("/test", true);

Modified: lucene/dev/branches/lucene5178/solr/core/src/test/org/apache/solr/core/TestLazyCores.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene5178/solr/core/src/test/org/apache/solr/core/TestLazyCores.java?rev=1515615&r1=1515614&r2=1515615&view=diff
==============================================================================
--- lucene/dev/branches/lucene5178/solr/core/src/test/org/apache/solr/core/TestLazyCores.java (original)
+++ lucene/dev/branches/lucene5178/solr/core/src/test/org/apache/solr/core/TestLazyCores.java Mon Aug 19 21:31:34 2013
@@ -69,7 +69,7 @@ public class TestLazyCores extends SolrT
     FileUtils.write(solrXml, LOTS_SOLR_XML, IOUtils.CHARSET_UTF_8.toString());
     ConfigSolrXmlOld config = (ConfigSolrXmlOld) ConfigSolr.fromFile(loader, solrXml);
 
-    CoresLocator locator = new SolrXMLCoresLocator.NonPersistingLocator(solrXml, LOTS_SOLR_XML, config);
+    CoresLocator locator = new SolrXMLCoresLocator.NonPersistingLocator(LOTS_SOLR_XML, config);
 
 
     final CoreContainer cores = new CoreContainer(loader, config, locator);

Modified: lucene/dev/branches/lucene5178/solr/core/src/test/org/apache/solr/core/TestSolrXmlPersistor.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene5178/solr/core/src/test/org/apache/solr/core/TestSolrXmlPersistor.java?rev=1515615&r1=1515614&r2=1515615&view=diff
==============================================================================
--- lucene/dev/branches/lucene5178/solr/core/src/test/org/apache/solr/core/TestSolrXmlPersistor.java (original)
+++ lucene/dev/branches/lucene5178/solr/core/src/test/org/apache/solr/core/TestSolrXmlPersistor.java Mon Aug 19 21:31:34 2013
@@ -35,7 +35,7 @@ public class TestSolrXmlPersistor {
 
     final String solrxml = "<solr><cores adminHandler=\"/admin\"/></solr>";
 
-    SolrXMLCoresLocator persistor = new SolrXMLCoresLocator(new File("testfile.xml"), solrxml, null);
+    SolrXMLCoresLocator persistor = new SolrXMLCoresLocator(solrxml, null);
     assertEquals(persistor.buildSolrXML(EMPTY_CD_LIST),
         "<solr><cores adminHandler=\"/admin\"></cores></solr>");
 
@@ -45,7 +45,7 @@ public class TestSolrXmlPersistor {
   public void emptyCoresTagIsPersisted() {
     final String solrxml = "<solr><cores adminHandler=\"/admin\"></cores></solr>";
 
-    SolrXMLCoresLocator persistor = new SolrXMLCoresLocator(new File("testfile.xml"), solrxml, null);
+    SolrXMLCoresLocator persistor = new SolrXMLCoresLocator(solrxml, null);
     assertEquals(persistor.buildSolrXML(EMPTY_CD_LIST), "<solr><cores adminHandler=\"/admin\"></cores></solr>");
   }
 
@@ -53,7 +53,7 @@ public class TestSolrXmlPersistor {
   public void emptySolrXmlIsPersisted() {
     final String solrxml = "<solr></solr>";
 
-    SolrXMLCoresLocator persistor = new SolrXMLCoresLocator(new File("testfile.xml"), solrxml, null);
+    SolrXMLCoresLocator persistor = new SolrXMLCoresLocator(solrxml, null);
     assertEquals(persistor.buildSolrXML(EMPTY_CD_LIST), "<solr><cores></cores></solr>");
   }
 
@@ -68,7 +68,7 @@ public class TestSolrXmlPersistor {
     final CoreDescriptor cd = new CoreDescriptor(cc, "testcore", "instance/dir/");
     List<CoreDescriptor> cds = ImmutableList.of(cd);
 
-    SolrXMLCoresLocator persistor = new SolrXMLCoresLocator(new File("testfile.xml"), solrxml, null);
+    SolrXMLCoresLocator persistor = new SolrXMLCoresLocator(solrxml, null);
     assertEquals(persistor.buildSolrXML(cds),
           "<solr><cores>" + SolrXMLCoresLocator.NEWLINE
         + "    <core name=\"testcore\" instanceDir=\"instance/dir/\"/>" + SolrXMLCoresLocator.NEWLINE
@@ -89,7 +89,7 @@ public class TestSolrXmlPersistor {
           "</cores>" +
         "</solr>";
 
-    SolrXMLCoresLocator locator = new SolrXMLCoresLocator(new File("testfile.xml"), solrxml, null);
+    SolrXMLCoresLocator locator = new SolrXMLCoresLocator(solrxml, null);
     assertTrue(locator.getTemplate().contains("{{CORES_PLACEHOLDER}}"));
     assertTrue(locator.getTemplate().contains("<shardHandlerFactory "));
     assertTrue(locator.getTemplate().contains("${socketTimeout:500}"));
@@ -107,15 +107,14 @@ public class TestSolrXmlPersistor {
           "</cores>" +
         "</solr>";
 
-    SolrXMLCoresLocator locator = new SolrXMLCoresLocator(new File("testfile.xml"), solrxml, null);
+    SolrXMLCoresLocator locator = new SolrXMLCoresLocator(solrxml, null);
     assertTrue(locator.getTemplate().contains("{{CORES_PLACEHOLDER}}"));
     assertTrue(locator.getTemplate().contains("<shardHandlerFactory "));
   }
 
   @Test
   public void complexXmlIsParsed() {
-    SolrXMLCoresLocator locator = new SolrXMLCoresLocator(new File("testfile.xml"),
-                                        TestSolrXmlPersistence.SOLR_XML_LOTS_SYSVARS, null);
+    SolrXMLCoresLocator locator = new SolrXMLCoresLocator(TestSolrXmlPersistence.SOLR_XML_LOTS_SYSVARS, null);
     assertTrue(locator.getTemplate().contains("{{CORES_PLACEHOLDER}}"));
   }
 

Modified: lucene/dev/branches/lucene5178/solr/core/src/test/org/apache/solr/handler/component/QueryElevationComponentTest.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene5178/solr/core/src/test/org/apache/solr/handler/component/QueryElevationComponentTest.java?rev=1515615&r1=1515614&r2=1515615&view=diff
==============================================================================
--- lucene/dev/branches/lucene5178/solr/core/src/test/org/apache/solr/handler/component/QueryElevationComponentTest.java (original)
+++ lucene/dev/branches/lucene5178/solr/core/src/test/org/apache/solr/handler/component/QueryElevationComponentTest.java Mon Aug 19 21:31:34 2013
@@ -22,6 +22,7 @@ import org.apache.lucene.util.BytesRef;
 import org.apache.lucene.util.IOUtils;
 import org.apache.solr.SolrTestCaseJ4;
 import org.apache.solr.common.params.CommonParams;
+import org.apache.solr.common.params.GroupParams;
 import org.apache.solr.common.params.MapSolrParams;
 import org.apache.solr.common.params.QueryElevationParams;
 import org.apache.solr.util.FileUtils;
@@ -106,6 +107,208 @@ public class QueryElevationComponentTest
   }
 
   @Test
+  public void testGroupedQuery() throws Exception {
+    try {
+      init("schema11.xml");
+      clearIndex();
+      assertU(commit());
+      assertU(adoc("id", "1", "text", "XXXX XXXX", "str_s", "a"));
+      assertU(adoc("id", "2", "text", "XXXX AAAA", "str_s", "b"));
+      assertU(adoc("id", "3", "text", "ZZZZ", "str_s", "c"));
+      assertU(adoc("id", "4", "text", "XXXX ZZZZ", "str_s", "d"));
+      assertU(adoc("id", "5", "text", "ZZZZ ZZZZ", "str_s", "e"));
+      assertU(adoc("id", "6", "text", "AAAA AAAA AAAA", "str_s", "f"));
+      assertU(adoc("id", "7", "text", "AAAA AAAA ZZZZ", "str_s", "g"));
+      assertU(adoc("id", "8", "text", "XXXX", "str_s", "h"));
+      assertU(adoc("id", "9", "text", "YYYY ZZZZ", "str_s", "i"));
+      
+      assertU(adoc("id", "22", "text", "XXXX ZZZZ AAAA", "str_s", "b"));
+      assertU(adoc("id", "66", "text", "XXXX ZZZZ AAAA", "str_s", "f"));
+      assertU(adoc("id", "77", "text", "XXXX ZZZZ AAAA", "str_s", "g"));
+     
+      assertU(commit());
+
+      final String groups = "//arr[@name='groups']";
+
+      assertQ("non-elevated group query", 
+              req(CommonParams.Q, "AAAA", 
+                  CommonParams.QT, "/elevate",
+                  GroupParams.GROUP_FIELD, "str_s", 
+                  GroupParams.GROUP, "true",
+                  GroupParams.GROUP_TOTAL_COUNT, "true", 
+                  GroupParams.GROUP_LIMIT, "100", 
+                  QueryElevationParams.ENABLE, "false",
+                  CommonParams.FL, "id, score, [elevated]")
+              , "//*[@name='ngroups'][.='3']"
+              , "//*[@name='matches'][.='6']"
+
+              , groups +"/lst[1]//doc[1]/float[@name='id'][.='6.0']"
+              , groups +"/lst[1]//doc[1]/bool[@name='[elevated]'][.='false']"
+              , groups +"/lst[1]//doc[2]/float[@name='id'][.='66.0']"
+              , groups +"/lst[1]//doc[2]/bool[@name='[elevated]'][.='false']"
+
+              , groups +"/lst[2]//doc[1]/float[@name='id'][.='7.0']"
+              , groups +"/lst[2]//doc[1]/bool[@name='[elevated]'][.='false']"
+              , groups +"/lst[2]//doc[2]/float[@name='id'][.='77.0']"
+              , groups +"/lst[2]//doc[2]/bool[@name='[elevated]'][.='false']"
+
+              , groups +"/lst[3]//doc[1]/float[@name='id'][.='2.0']"
+              , groups +"/lst[3]//doc[1]/bool[@name='[elevated]'][.='false']"
+              , groups +"/lst[3]//doc[2]/float[@name='id'][.='22.0']"
+              , groups +"/lst[3]//doc[2]/bool[@name='[elevated]'][.='false']"
+              );
+
+      assertQ("elevated group query", 
+              req(CommonParams.Q, "AAAA", 
+                  CommonParams.QT, "/elevate",
+                  GroupParams.GROUP_FIELD, "str_s", 
+                  GroupParams.GROUP, "true",
+                  GroupParams.GROUP_TOTAL_COUNT, "true",
+                  GroupParams.GROUP_LIMIT, "100", 
+                  CommonParams.FL, "id, score, [elevated]")
+              , "//*[@name='ngroups'][.='3']"
+              , "//*[@name='matches'][.='6']"
+
+              , groups +"/lst[1]//doc[1]/float[@name='id'][.='7.0']"
+              , groups +"/lst[1]//doc[1]/bool[@name='[elevated]'][.='true']"
+              , groups +"/lst[1]//doc[2]/float[@name='id'][.='77.0']"
+              , groups +"/lst[1]//doc[2]/bool[@name='[elevated]'][.='false']"
+
+              , groups +"/lst[2]//doc[1]/float[@name='id'][.='6.0']"
+              , groups +"/lst[2]//doc[1]/bool[@name='[elevated]'][.='false']"
+              , groups +"/lst[2]//doc[2]/float[@name='id'][.='66.0']"
+              , groups +"/lst[2]//doc[2]/bool[@name='[elevated]'][.='false']"
+
+              , groups +"/lst[3]//doc[1]/float[@name='id'][.='2.0']"
+              , groups +"/lst[3]//doc[1]/bool[@name='[elevated]'][.='false']"
+              , groups +"/lst[3]//doc[2]/float[@name='id'][.='22.0']"
+              , groups +"/lst[3]//doc[2]/bool[@name='[elevated]'][.='false']"
+              );
+
+      assertQ("non-elevated because sorted group query", 
+              req(CommonParams.Q, "AAAA", 
+                  CommonParams.QT, "/elevate",
+                  CommonParams.SORT, "id asc",
+                  GroupParams.GROUP_FIELD, "str_s", 
+                  GroupParams.GROUP, "true",
+                  GroupParams.GROUP_TOTAL_COUNT, "true", 
+                  GroupParams.GROUP_LIMIT, "100", 
+                  CommonParams.FL, "id, score, [elevated]")
+              , "//*[@name='ngroups'][.='3']"
+              , "//*[@name='matches'][.='6']"
+
+              , groups +"/lst[1]//doc[1]/float[@name='id'][.='2.0']"
+              , groups +"/lst[1]//doc[1]/bool[@name='[elevated]'][.='false']"
+              , groups +"/lst[1]//doc[2]/float[@name='id'][.='22.0']"
+              , groups +"/lst[1]//doc[2]/bool[@name='[elevated]'][.='false']"
+
+              , groups +"/lst[2]//doc[1]/float[@name='id'][.='6.0']"
+              , groups +"/lst[2]//doc[1]/bool[@name='[elevated]'][.='false']"
+              , groups +"/lst[2]//doc[2]/float[@name='id'][.='66.0']"
+              , groups +"/lst[2]//doc[2]/bool[@name='[elevated]'][.='false']"
+
+              , groups +"/lst[3]//doc[1]/float[@name='id'][.='7.0']"
+              , groups +"/lst[3]//doc[1]/bool[@name='[elevated]'][.='true']"
+              , groups +"/lst[3]//doc[2]/float[@name='id'][.='77.0']"
+              , groups +"/lst[3]//doc[2]/bool[@name='[elevated]'][.='false']"
+              );
+
+      assertQ("force-elevated sorted group query", 
+              req(CommonParams.Q, "AAAA", 
+                  CommonParams.QT, "/elevate",
+                  CommonParams.SORT, "id asc",
+                  QueryElevationParams.FORCE_ELEVATION, "true", 
+                  GroupParams.GROUP_FIELD, "str_s", 
+                  GroupParams.GROUP, "true",
+                  GroupParams.GROUP_TOTAL_COUNT, "true", 
+                  GroupParams.GROUP_LIMIT, "100", 
+                  CommonParams.FL, "id, score, [elevated]")
+              , "//*[@name='ngroups'][.='3']"
+              , "//*[@name='matches'][.='6']"
+
+              , groups +"/lst[1]//doc[1]/float[@name='id'][.='7.0']"
+              , groups +"/lst[1]//doc[1]/bool[@name='[elevated]'][.='true']"
+              , groups +"/lst[1]//doc[2]/float[@name='id'][.='77.0']"
+              , groups +"/lst[1]//doc[2]/bool[@name='[elevated]'][.='false']"
+
+              , groups +"/lst[2]//doc[1]/float[@name='id'][.='2.0']"
+              , groups +"/lst[2]//doc[1]/bool[@name='[elevated]'][.='false']"
+              , groups +"/lst[2]//doc[2]/float[@name='id'][.='22.0']"
+              , groups +"/lst[2]//doc[2]/bool[@name='[elevated]'][.='false']"
+
+              , groups +"/lst[3]//doc[1]/float[@name='id'][.='6.0']"
+              , groups +"/lst[3]//doc[1]/bool[@name='[elevated]'][.='false']"
+              , groups +"/lst[3]//doc[2]/float[@name='id'][.='66.0']"
+              , groups +"/lst[3]//doc[2]/bool[@name='[elevated]'][.='false']"
+              );
+
+
+      assertQ("non-elevated because of sort within group query", 
+              req(CommonParams.Q, "AAAA", 
+                  CommonParams.QT, "/elevate",
+                  CommonParams.SORT, "id asc",
+                  GroupParams.GROUP_SORT, "id desc", 
+                  GroupParams.GROUP_FIELD, "str_s", 
+                  GroupParams.GROUP, "true",
+                  GroupParams.GROUP_TOTAL_COUNT, "true", 
+                  GroupParams.GROUP_LIMIT, "100", 
+                  CommonParams.FL, "id, score, [elevated]")
+              , "//*[@name='ngroups'][.='3']"
+              , "//*[@name='matches'][.='6']"
+
+              , groups +"/lst[1]//doc[1]/float[@name='id'][.='22.0']"
+              , groups +"/lst[1]//doc[1]/bool[@name='[elevated]'][.='false']"
+              , groups +"/lst[1]//doc[2]/float[@name='id'][.='2.0']"
+              , groups +"/lst[1]//doc[2]/bool[@name='[elevated]'][.='false']"
+
+              , groups +"/lst[2]//doc[1]/float[@name='id'][.='66.0']"
+              , groups +"/lst[2]//doc[1]/bool[@name='[elevated]'][.='false']"
+              , groups +"/lst[2]//doc[2]/float[@name='id'][.='6.0']"
+              , groups +"/lst[2]//doc[2]/bool[@name='[elevated]'][.='false']"
+
+              , groups +"/lst[3]//doc[1]/float[@name='id'][.='77.0']"
+              , groups +"/lst[3]//doc[1]/bool[@name='[elevated]'][.='false']"
+              , groups +"/lst[3]//doc[2]/float[@name='id'][.='7.0']"
+              , groups +"/lst[3]//doc[2]/bool[@name='[elevated]'][.='true']"
+              );
+
+
+      assertQ("force elevated sort within sorted group query", 
+              req(CommonParams.Q, "AAAA", 
+                  CommonParams.QT, "/elevate",
+                  CommonParams.SORT, "id asc",
+                  GroupParams.GROUP_SORT, "id desc", 
+                  QueryElevationParams.FORCE_ELEVATION, "true", 
+                  GroupParams.GROUP_FIELD, "str_s", 
+                  GroupParams.GROUP, "true",
+                  GroupParams.GROUP_TOTAL_COUNT, "true", 
+                  GroupParams.GROUP_LIMIT, "100", 
+                  CommonParams.FL, "id, score, [elevated]")
+              , "//*[@name='ngroups'][.='3']"
+              , "//*[@name='matches'][.='6']"
+
+              , groups +"/lst[1]//doc[1]/float[@name='id'][.='7.0']"
+              , groups +"/lst[1]//doc[1]/bool[@name='[elevated]'][.='true']"
+              , groups +"/lst[1]//doc[2]/float[@name='id'][.='77.0']"
+              , groups +"/lst[1]//doc[2]/bool[@name='[elevated]'][.='false']"
+
+              , groups +"/lst[2]//doc[1]/float[@name='id'][.='22.0']"
+              , groups +"/lst[2]//doc[1]/bool[@name='[elevated]'][.='false']"
+              , groups +"/lst[2]//doc[2]/float[@name='id'][.='2.0']"
+              , groups +"/lst[2]//doc[2]/bool[@name='[elevated]'][.='false']"
+
+              , groups +"/lst[3]//doc[1]/float[@name='id'][.='66.0']"
+              , groups +"/lst[3]//doc[1]/bool[@name='[elevated]'][.='false']"
+              , groups +"/lst[3]//doc[2]/float[@name='id'][.='6.0']"
+              , groups +"/lst[3]//doc[2]/bool[@name='[elevated]'][.='false']"
+              );
+
+    } finally {
+      delete();
+    }
+  }
+
+  @Test
   public void testTrieFieldType() throws Exception {
     try {
       init("schema.xml");

Modified: lucene/dev/branches/lucene5178/solr/core/src/test/org/apache/solr/search/join/BJQParserTest.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene5178/solr/core/src/test/org/apache/solr/search/join/BJQParserTest.java?rev=1515615&r1=1515614&r2=1515615&view=diff
==============================================================================
--- lucene/dev/branches/lucene5178/solr/core/src/test/org/apache/solr/search/join/BJQParserTest.java (original)
+++ lucene/dev/branches/lucene5178/solr/core/src/test/org/apache/solr/search/join/BJQParserTest.java Mon Aug 19 21:31:34 2013
@@ -25,6 +25,7 @@ import org.apache.solr.search.SolrCache;
 import org.apache.solr.search.SyntaxError;
 import org.junit.BeforeClass;
 import org.junit.Test;
+import org.junit.Ignore;
 
 import java.io.IOException;
 import java.util.ArrayList;
@@ -49,13 +50,21 @@ public class BJQParserTest extends SolrT
     int i = 0;
     List<List<String[]>> blocks = createBlocks();
     for (List<String[]> block : blocks) {
+      List<XmlDoc> updBlock = new ArrayList<>();
+      
       for (String[] doc : block) {
         String[] idDoc = Arrays.copyOf(doc,doc.length+2);
         idDoc[doc.length]="id";
         idDoc[doc.length+1]=Integer.toString(i);
-        assertU(add(doc(idDoc)));
+        updBlock.add(doc(idDoc));
         i++;
       }
+      //got xmls for every doc. now nest all into the last one
+      XmlDoc parentDoc = updBlock.get(updBlock.size()-1);
+      parentDoc.xml = parentDoc.xml.replace("</doc>", 
+          updBlock.subList(0, updBlock.size()-1).toString().replaceAll("[\\[\\]]","")+"</doc>");
+      assertU(add(parentDoc));
+      
       if (random().nextBoolean()) {
         assertU(commit());
         // force empty segment (actually, this will no longer create an empty segment, only a new segments_n)
@@ -184,6 +193,7 @@ public class BJQParserTest extends SolrT
   }
   
   @Test
+  @Ignore("SOLR-5168")
   public void testGrandChildren() throws IOException {
     assertQ(
         req("q", "{!parent which=$parentfilter v=$children}", "children",

Modified: lucene/dev/branches/lucene5178/solr/test-framework/src/java/org/apache/solr/cloud/AbstractFullDistribZkTestBase.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene5178/solr/test-framework/src/java/org/apache/solr/cloud/AbstractFullDistribZkTestBase.java?rev=1515615&r1=1515614&r2=1515615&view=diff
==============================================================================
--- lucene/dev/branches/lucene5178/solr/test-framework/src/java/org/apache/solr/cloud/AbstractFullDistribZkTestBase.java (original)
+++ lucene/dev/branches/lucene5178/solr/test-framework/src/java/org/apache/solr/cloud/AbstractFullDistribZkTestBase.java Mon Aug 19 21:31:34 2013
@@ -17,8 +17,10 @@ package org.apache.solr.cloud;
  * limitations under the License.
  */
 
+import org.apache.commons.io.FilenameUtils;
 import org.apache.http.params.CoreConnectionPNames;
 import org.apache.lucene.util.LuceneTestCase.Slow;
+import org.apache.solr.SolrTestCaseJ4;
 import org.apache.solr.client.solrj.SolrQuery;
 import org.apache.solr.client.solrj.SolrRequest;
 import org.apache.solr.client.solrj.SolrServer;
@@ -44,6 +46,7 @@ import org.apache.solr.common.params.Col
 import org.apache.solr.common.params.ModifiableSolrParams;
 import org.apache.solr.common.params.SolrParams;
 import org.apache.solr.common.util.StrUtils;
+import org.apache.solr.core.SolrResourceLoader;
 import org.junit.After;
 import org.junit.AfterClass;
 import org.junit.Before;
@@ -455,14 +458,45 @@ public abstract class AbstractFullDistri
   }
   
   public JettySolrRunner createJetty(File solrHome, String dataDir, String shardList, String solrConfigOverride, String schemaOverride) throws Exception {
-
-    JettySolrRunner jetty = new JettySolrRunner(solrHome.getAbsolutePath(), context, 0, solrConfigOverride, schemaOverride, false, getExtraServlets());
+    // randomly test a relative solr.home path
+    if (random().nextBoolean()) {
+      solrHome = getRelativeSolrHomePath(solrHome);
+    }
+    
+    JettySolrRunner jetty = new JettySolrRunner(solrHome.getPath(), context, 0, solrConfigOverride, schemaOverride, false, getExtraServlets());
     jetty.setShards(shardList);
     jetty.setDataDir(getDataDir(dataDir));
     jetty.start();
     
     return jetty;
   }
+
+  private File getRelativeSolrHomePath(File solrHome) {
+    String path = SolrResourceLoader.normalizeDir(new File(".").getAbsolutePath());
+    String base = new File(solrHome.getPath()).getAbsolutePath();
+    
+    if (base.startsWith("."));
+    base.replaceFirst("\\.", new File(".").getName());
+    
+    if (path.endsWith(File.separator + ".")) {
+      path = path.substring(0, path.length() - 2);
+    }
+    
+    int splits = path.split("\\" + File.separator).length;
+    
+    StringBuilder p = new StringBuilder();
+    for (int i = 0; i < splits - 2; i++) {
+      p.append(".." + File.separator);
+    }   
+    
+    String prefix = FilenameUtils.getPrefix(path);
+    if (base.startsWith(prefix)) {
+      base = base.substring(prefix.length());
+    }
+
+    solrHome = new File(p.toString() + base);
+    return solrHome;
+  }
   
   protected void updateMappingsFromZk(List<JettySolrRunner> jettys,
       List<SolrServer> clients) throws Exception {

Modified: lucene/dev/branches/lucene5178/solr/test-framework/src/java/org/apache/solr/util/RandomMergePolicy.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene5178/solr/test-framework/src/java/org/apache/solr/util/RandomMergePolicy.java?rev=1515615&r1=1515614&r2=1515615&view=diff
==============================================================================
--- lucene/dev/branches/lucene5178/solr/test-framework/src/java/org/apache/solr/util/RandomMergePolicy.java (original)
+++ lucene/dev/branches/lucene5178/solr/test-framework/src/java/org/apache/solr/util/RandomMergePolicy.java Mon Aug 19 21:31:34 2013
@@ -21,6 +21,9 @@ import org.apache.lucene.index.*;
 import org.apache.lucene.index.MergePolicy.MergeSpecification;
 import org.apache.lucene.util.LuceneTestCase;
 
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
 import java.util.Map;
 import java.io.IOException;
 
@@ -32,6 +35,8 @@ import java.io.IOException;
  */
 public final class RandomMergePolicy extends MergePolicy {
 
+  public static Logger log = LoggerFactory.getLogger(RandomMergePolicy.class);
+  
   /** 
    * Not private so tests can inspect it, 
    * Not final so it can be set on clone
@@ -45,6 +50,8 @@ public final class RandomMergePolicy ext
     super(inner.getNoCFSRatio(), 
           (long) (inner.getMaxCFSSegmentSizeMB() * 1024 * 1024));
     this.inner = inner;
+    log.info("RandomMergePolicy wrapping {}: {}",
+             inner.getClass(), inner);
   }
 
   public RandomMergePolicy clone() {

Modified: lucene/dev/branches/lucene5178/solr/webapp/web/admin.html
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene5178/solr/webapp/web/admin.html?rev=1515615&r1=1515614&r2=1515615&view=diff
==============================================================================
--- lucene/dev/branches/lucene5178/solr/webapp/web/admin.html (original)
+++ lucene/dev/branches/lucene5178/solr/webapp/web/admin.html Mon Aug 19 21:31:34 2013
@@ -41,6 +41,8 @@ limitations under the License.
   <link rel="stylesheet" type="text/css" href="css/styles/schema-browser.css?_=${version}">
   <link rel="stylesheet" type="text/css" href="css/styles/threads.css?_=${version}">
   <link rel="stylesheet" type="text/css" href="css/chosen.css?_=${version}">
+
+  <meta http-equiv="x-ua-compatible" content="IE=9">
     
   <script type="text/javascript">
     

Modified: lucene/dev/branches/lucene5178/solr/webapp/web/js/scripts/app.js
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene5178/solr/webapp/web/js/scripts/app.js?rev=1515615&r1=1515614&r2=1515615&view=diff
==============================================================================
--- lucene/dev/branches/lucene5178/solr/webapp/web/js/scripts/app.js (original)
+++ lucene/dev/branches/lucene5178/solr/webapp/web/js/scripts/app.js Mon Aug 19 21:31:34 2013
@@ -552,7 +552,7 @@ var solr_admin = function( app_config )
       json_str = JSON.stringify( JSON.parse( json_str ), undefined, 2 );
     }
 
-    return json_str;
+    return json_str.esc();
   };
 
   this.format_number = function format_number( number )