You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by ma...@apache.org on 2021/02/02 21:01:21 UTC

[lucene-solr] branch reference_impl updated: @1307 Small optimizations.

This is an automated email from the ASF dual-hosted git repository.

markrmiller pushed a commit to branch reference_impl
in repository https://gitbox.apache.org/repos/asf/lucene-solr.git


The following commit(s) were added to refs/heads/reference_impl by this push:
     new 61be2e3  @1307 Small optimizations.
61be2e3 is described below

commit 61be2e3567931e66e758a80228ea393a0f920fb5
Author: markrmiller@gmail.com <ma...@gmail.com>
AuthorDate: Tue Feb 2 15:00:22 2021 -0600

    @1307 Small optimizations.
---
 gradle/testing/defaults-tests.gradle               |   2 +-
 .../lucene/index/TestIndexWriterOnJRECrash.java    |  60 +++++-----
 .../java/org/apache/solr/core/CoreContainer.java   |  71 +++++++-----
 .../apache/solr/core/CorePropertiesLocator.java    | 111 ++++++++++---------
 .../src/java/org/apache/solr/core/SolrCore.java    |   4 +-
 .../apache/solr/core/StandardDirectoryFactory.java |   2 +-
 .../repository/LocalFileSystemRepository.java      |  28 ++---
 .../java/org/apache/solr/handler/IndexFetcher.java |   3 +-
 .../solr/handler/admin/CoreAdminOperation.java     | 122 +++++++++++----------
 .../DocumentExpressionDictionaryFactory.java       |  10 +-
 .../org/apache/solr/cloud/SolrCLIZkUtilsTest.java  |  58 ++++++----
 .../uninverting/TestFieldCacheWithThreads.java     |   3 +-
 12 files changed, 262 insertions(+), 212 deletions(-)

diff --git a/gradle/testing/defaults-tests.gradle b/gradle/testing/defaults-tests.gradle
index 351863a..92cd8b2 100644
--- a/gradle/testing/defaults-tests.gradle
+++ b/gradle/testing/defaults-tests.gradle
@@ -107,7 +107,7 @@ allprojects {
       minHeapSize = propertyOrDefault("tests.minheapsize", "512m")
       maxHeapSize = propertyOrDefault("tests.heapsize", "512m")
 
-      jvmArgs Commandline.translateCommandline(propertyOrDefault("tests.jvmargs", "-XX:TieredStopAtLevel=1 -XX:+UseParallelGC -XX:-UseBiasedLocking -Djava.net.preferIPv4Stack=true -DconfigurationFile=log4j2.xml -Dorg.apache.xml.dtm.DTMManager=org.apache.xml.dtm.ref.DTMManagerDefault"));
+      jvmArgs Commandline.translateCommandline(propertyOrDefault("tests.jvmargs", "-XX:TieredStopAtLevel=1 -XX:+UseParallelGC -XX:-UseBiasedLocking -Djava.net.preferIPv4Stack=true -Dzookeeper.jmx.log4j.disable=true -Dlog4j2.disable.jmx=true -DconfigurationFile=log4j2.xml -Dorg.apache.xml.dtm.DTMManager=org.apache.xml.dtm.ref.DTMManagerDefault"));
 
       ignoreFailures = resolvedTestOption("tests.haltonfailure").toBoolean() == false
 
diff --git a/lucene/core/src/test/org/apache/lucene/index/TestIndexWriterOnJRECrash.java b/lucene/core/src/test/org/apache/lucene/index/TestIndexWriterOnJRECrash.java
index 692a90c..a40dfc0 100644
--- a/lucene/core/src/test/org/apache/lucene/index/TestIndexWriterOnJRECrash.java
+++ b/lucene/core/src/test/org/apache/lucene/index/TestIndexWriterOnJRECrash.java
@@ -154,32 +154,7 @@ public class TestIndexWriterOnJRECrash extends TestNRTThreads {
    */
   public boolean checkIndexes(Path path) throws IOException {
     final AtomicBoolean found = new AtomicBoolean();
-    Files.walkFileTree(path, new SimpleFileVisitor<Path>() {
-      @Override
-      public FileVisitResult postVisitDirectory(Path dirPath, IOException exc) throws IOException {
-        if (exc != null) {
-          throw exc;
-        } else {
-          try (BaseDirectoryWrapper dir = newFSDirectory(dirPath)) {
-            dir.setCheckIndexOnClose(false); // don't double-checkindex
-            if (DirectoryReader.indexExists(dir)) {
-              if (VERBOSE) {
-                System.err.println("Checking index: " + dirPath);
-              }
-              // LUCENE-4738: if we crashed while writing first
-              // commit it's possible index will be corrupt (by
-              // design we don't try to be smart about this case
-              // since that too risky):
-              if (SegmentInfos.getLastCommitGeneration(dir) > 1) {
-                TestUtil.checkIndex(dir);
-              }
-              found.set(true);
-            }
-          }
-          return FileVisitResult.CONTINUE;
-        }
-      }
-    });
+    Files.walkFileTree(path, new PathSimpleFileVisitor(found));
     return found.get();
   }
 
@@ -219,4 +194,37 @@ public class TestIndexWriterOnJRECrash extends TestNRTThreads {
     // We couldn't get the JVM to crash for some reason.
     fail();
   }
+
+  private static class PathSimpleFileVisitor extends SimpleFileVisitor<Path> {
+    private final AtomicBoolean found;
+
+    public PathSimpleFileVisitor(AtomicBoolean found) {
+      this.found = found;
+    }
+
+    @Override
+    public FileVisitResult postVisitDirectory(Path dirPath, IOException exc) throws IOException {
+      if (exc != null) {
+        throw exc;
+      } else {
+        try (BaseDirectoryWrapper dir = newFSDirectory(dirPath)) {
+          dir.setCheckIndexOnClose(false); // don't double-checkindex
+          if (DirectoryReader.indexExists(dir)) {
+            if (VERBOSE) {
+              System.err.println("Checking index: " + dirPath);
+            }
+            // LUCENE-4738: if we crashed while writing first
+            // commit it's possible index will be corrupt (by
+            // design we don't try to be smart about this case
+            // since that too risky):
+            if (SegmentInfos.getLastCommitGeneration(dir) > 1) {
+              TestUtil.checkIndex(dir);
+            }
+            found.set(true);
+          }
+        }
+        return FileVisitResult.CONTINUE;
+      }
+    }
+  }
 }
diff --git a/solr/core/src/java/org/apache/solr/core/CoreContainer.java b/solr/core/src/java/org/apache/solr/core/CoreContainer.java
index 84db56c..a86ff0b 100644
--- a/solr/core/src/java/org/apache/solr/core/CoreContainer.java
+++ b/solr/core/src/java/org/apache/solr/core/CoreContainer.java
@@ -145,6 +145,7 @@ import java.util.concurrent.RejectedExecutionException;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
 import java.util.concurrent.locks.ReentrantLock;
+import java.util.function.Consumer;
 
 /**
  * @since solr 1.3
@@ -1611,7 +1612,7 @@ public class CoreContainer implements Closeable {
               try {
                 while (new File(dataDir).exists()) {
                   try {
-                    Files.walk(new File(dataDir).toPath()).sorted(Comparator.reverseOrder()).map(Path::toFile).forEach(File::delete);
+                    Files.walk(new File(dataDir).toPath()).sorted(Comparator.reverseOrder()).forEach(new FileConsumer());
                   } catch (NoSuchFileException e) {
 
                   }
@@ -1720,34 +1721,34 @@ public class CoreContainer implements Closeable {
 
   // ---------------- Core name related methods ---------------
 
-  private CoreDescriptor reloadCoreDescriptor(CoreDescriptor oldDesc) {
-    if (oldDesc == null) {
-      return null;
-    }
-
-    CorePropertiesLocator cpl = new CorePropertiesLocator(null);
-    CoreDescriptor ret = cpl.buildCoreDescriptor(oldDesc.getInstanceDir().resolve(PROPERTIES_FILENAME), this);
-
-    // Ok, this little jewel is all because we still create core descriptors on the fly from lists of properties
-    // in tests particularly. Theoretically, there should be _no_ way to create a CoreDescriptor in the new world
-    // of core discovery without writing the core.properties file out first.
-    //
-    // TODO: remove core.properties from the conf directory in test files, it's in a bad place there anyway.
-    if (ret == null) {
-      oldDesc.loadExtraProperties(); // there may be changes to extra properties that we need to pick up.
-      return oldDesc;
-
-    }
-    // The CloudDescriptor bit here is created in a very convoluted way, requiring access to private methods
-    // in ZkController. When reloading, this behavior is identical to what used to happen where a copy of the old
-    // CoreDescriptor was just re-used.
-
-    if (ret.getCloudDescriptor() != null) {
-      ret.getCloudDescriptor().reload(oldDesc.getCloudDescriptor());
-    }
-
-    return ret;
-  }
+//  private CoreDescriptor reloadCoreDescriptor(CoreDescriptor oldDesc) {
+//    if (oldDesc == null) {
+//      return null;
+//    }
+//
+//    CorePropertiesLocator cpl = new CorePropertiesLocator(null);
+//    CoreDescriptor ret = cpl.buildCoreDescriptor(oldDesc.getInstanceDir().resolve(PROPERTIES_FILENAME), this);
+//
+//    // Ok, this little jewel is all because we still create core descriptors on the fly from lists of properties
+//    // in tests particularly. Theoretically, there should be _no_ way to create a CoreDescriptor in the new world
+//    // of core discovery without writing the core.properties file out first.
+//    //
+//    // TODO: remove core.properties from the conf directory in test files, it's in a bad place there anyway.
+//    if (ret == null) {
+//      oldDesc.loadExtraProperties(); // there may be changes to extra properties that we need to pick up.
+//      return oldDesc;
+//
+//    }
+//    // The CloudDescriptor bit here is created in a very convoluted way, requiring access to private methods
+//    // in ZkController. When reloading, this behavior is identical to what used to happen where a copy of the old
+//    // CoreDescriptor was just re-used.
+//
+//    if (ret.getCloudDescriptor() != null) {
+//      ret.getCloudDescriptor().reload(oldDesc.getCloudDescriptor());
+//    }
+//
+//    return ret;
+//  }
 
   /**
    * Recreates a SolrCore.
@@ -2038,7 +2039,7 @@ public class CoreContainer implements Closeable {
         try {
           while (Files.exists(cd.getInstanceDir())) {
             try {
-              Files.walk(cd.getInstanceDir()).sorted(Comparator.reverseOrder()).map(Path::toFile).forEach(File::delete);
+              Files.walk(cd.getInstanceDir()).sorted(Comparator.reverseOrder()).forEach(new FileConsumer());
             } catch (NoSuchFileException e) {
 
             }
@@ -2364,6 +2365,16 @@ public class CoreContainer implements Closeable {
     }
   }
 
+  public static class FileConsumer implements Consumer<Path> {
+    public void accept(Path file) {
+      try {
+        Files.delete(file);
+      }catch (IOException e) {
+        log.warn("Could not delete file {}", file, e);
+      }
+    }
+  }
+
   private class EmbeddedSolrServer extends org.apache.solr.client.solrj.embedded.EmbeddedSolrServer {
     public EmbeddedSolrServer() {
       super(CoreContainer.this, null);
diff --git a/solr/core/src/java/org/apache/solr/core/CorePropertiesLocator.java b/solr/core/src/java/org/apache/solr/core/CorePropertiesLocator.java
index dafdc78..1ecd6b3 100644
--- a/solr/core/src/java/org/apache/solr/core/CorePropertiesLocator.java
+++ b/solr/core/src/java/org/apache/solr/core/CorePropertiesLocator.java
@@ -134,34 +134,7 @@ public class CorePropertiesLocator implements CoresLocator {
       Set<FileVisitOption> options = new HashSet<>();
       options.add(FileVisitOption.FOLLOW_LINKS);
       final int maxDepth = 256;
-      Files.walkFileTree(this.rootDirectory, options, maxDepth, new SimpleFileVisitor<Path>() {
-        @Override
-        public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
-          if (file.getFileName().toString().equals(PROPERTIES_FILENAME)) {
-            CoreDescriptor cd = buildCoreDescriptor(file, cc);
-            if (cd != null) {
-              if (log.isDebugEnabled()) {
-                log.debug("Found core {} in {}", cd.getName(), cd.getInstanceDir());
-              }
-              cds.add(cd);
-            }
-            return FileVisitResult.SKIP_SIBLINGS;
-          }
-          return FileVisitResult.CONTINUE;
-        }
-
-        @Override
-        public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException {
-          // if we get an error on the root, then fail the whole thing
-          // otherwise, log a warning and continue to try and load other cores
-          if (file.equals(rootDirectory)) {
-            log.error("Error reading core root directory {}: {}", file, exc);
-            throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, "Error reading core root directory");
-          }
-          log.warn("Error visiting {}: {}", file, exc);
-          return FileVisitResult.CONTINUE;
-        }
-      });
+      Files.walkFileTree(this.rootDirectory, options, maxDepth, new PathSimpleFileVisitor(cc, cds, rootDirectory));
     } catch (IOException e) {
       throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, "Couldn't walk file tree under " + this.rootDirectory, e);
     }
@@ -176,28 +149,6 @@ public class CorePropertiesLocator implements CoresLocator {
     return cds;
   }
 
-  protected CoreDescriptor buildCoreDescriptor(Path propertiesFile, CoreContainer cc) {
-
-    Path instanceDir = propertiesFile.getParent();
-    Properties coreProperties = new Properties();
-    try (InputStream fis = Files.newInputStream(propertiesFile)) {
-      coreProperties.load(new InputStreamReader(fis, StandardCharsets.UTF_8));
-      String name = createName(coreProperties, instanceDir);
-      Map<String, String> propMap = new HashMap<>();
-      for (String key : coreProperties.stringPropertyNames()) {
-        propMap.put(key, coreProperties.getProperty(key));
-      }
-      CoreDescriptor ret = new CoreDescriptor(name, instanceDir, propMap, cc.getContainerProperties(), cc.getZkController());
-      ret.loadExtraProperties();
-      return ret;
-    }
-    catch (IOException e) {
-      log.error("Couldn't load core descriptor from {}:", propertiesFile, e);
-      return null;
-    }
-
-  }
-
   protected static String createName(Properties p, Path instanceDir) {
     return p.getProperty(CoreDescriptor.CORE_NAME, instanceDir.getFileName().toString());
   }
@@ -209,4 +160,64 @@ public class CorePropertiesLocator implements CoresLocator {
     return p;
   }
 
+  private static class PathSimpleFileVisitor extends SimpleFileVisitor<Path> {
+    private final CoreContainer cc;
+    private final List<CoreDescriptor> cds;
+    private final Path rootDirectory;
+
+    public PathSimpleFileVisitor(CoreContainer cc, List<CoreDescriptor> cds, Path rootDirectory) {
+      this.cc = cc;
+      this.cds = cds;
+      this.rootDirectory = rootDirectory;
+    }
+
+    @Override
+    public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
+      if (file.getFileName().toString().equals(PROPERTIES_FILENAME)) {
+        CoreDescriptor cd = buildCoreDescriptor(file, cc);
+        if (cd != null) {
+          if (log.isDebugEnabled()) {
+            log.debug("Found core {} in {}", cd.getName(), cd.getInstanceDir());
+          }
+          cds.add(cd);
+        }
+        return FileVisitResult.SKIP_SIBLINGS;
+      }
+      return FileVisitResult.CONTINUE;
+    }
+
+    @Override
+    public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException {
+      // if we get an error on the root, then fail the whole thing
+      // otherwise, log a warning and continue to try and load other cores
+      if (file.equals(rootDirectory)) {
+        log.error("Error reading core root directory {}: {}", file, exc);
+        throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, "Error reading core root directory");
+      }
+      log.warn("Error visiting {}: {}", file, exc);
+      return FileVisitResult.CONTINUE;
+    }
+
+    protected CoreDescriptor buildCoreDescriptor(Path propertiesFile, CoreContainer cc) {
+
+      Path instanceDir = propertiesFile.getParent();
+      Properties coreProperties = new Properties();
+      try (InputStream fis = Files.newInputStream(propertiesFile)) {
+        coreProperties.load(new InputStreamReader(fis, StandardCharsets.UTF_8));
+        String name = createName(coreProperties, instanceDir);
+        Map<String, String> propMap = new HashMap<>();
+        for (String key : coreProperties.stringPropertyNames()) {
+          propMap.put(key, coreProperties.getProperty(key));
+        }
+        CoreDescriptor ret = new CoreDescriptor(name, instanceDir, propMap, cc.getContainerProperties(), cc.getZkController());
+        ret.loadExtraProperties();
+        return ret;
+      }
+      catch (IOException e) {
+        log.error("Couldn't load core descriptor from {}:", propertiesFile, e);
+        return null;
+      }
+
+    }
+  }
 }
diff --git a/solr/core/src/java/org/apache/solr/core/SolrCore.java b/solr/core/src/java/org/apache/solr/core/SolrCore.java
index 2240c50..40fcfb5 100644
--- a/solr/core/src/java/org/apache/solr/core/SolrCore.java
+++ b/solr/core/src/java/org/apache/solr/core/SolrCore.java
@@ -3391,7 +3391,7 @@ public final class SolrCore implements SolrInfoBean, Closeable {
       try {
           while (Files.exists(dataDir)) {
             try {
-              Files.walk(dataDir).sorted(Comparator.reverseOrder()).map(Path::toFile).forEach(File::delete);
+              Files.walk(dataDir).sorted(Comparator.reverseOrder()).forEach(new CoreContainer.FileConsumer());
             } catch (NoSuchFileException e) {
 
             }
@@ -3404,7 +3404,7 @@ public final class SolrCore implements SolrInfoBean, Closeable {
       try {
         while (Files.exists(cd.getInstanceDir())) {
           try {
-            Files.walk(cd.getInstanceDir()).sorted(Comparator.reverseOrder()).map(Path::toFile).forEach(File::delete);
+            Files.walk(cd.getInstanceDir()).sorted(Comparator.reverseOrder()).forEach(new CoreContainer.FileConsumer());
           } catch (NoSuchFileException e) {
 
           }
diff --git a/solr/core/src/java/org/apache/solr/core/StandardDirectoryFactory.java b/solr/core/src/java/org/apache/solr/core/StandardDirectoryFactory.java
index 4be4b56..1a6c341 100644
--- a/solr/core/src/java/org/apache/solr/core/StandardDirectoryFactory.java
+++ b/solr/core/src/java/org/apache/solr/core/StandardDirectoryFactory.java
@@ -111,7 +111,7 @@ public class StandardDirectoryFactory extends CachingDirectoryFactory {
     Path dirFile = Paths.get(cacheValue.path);
     while (Files.exists(dirFile)) {
       try {
-        Files.walk(dirFile).sorted(Comparator.reverseOrder()).map(Path::toFile).forEach(File::delete);
+        Files.walk(dirFile).sorted(Comparator.reverseOrder()).forEach(new CoreContainer.FileConsumer());
       } catch (NoSuchFileException e) {
 
       }
diff --git a/solr/core/src/java/org/apache/solr/core/backup/repository/LocalFileSystemRepository.java b/solr/core/src/java/org/apache/solr/core/backup/repository/LocalFileSystemRepository.java
index 612a61f..345d88c 100644
--- a/solr/core/src/java/org/apache/solr/core/backup/repository/LocalFileSystemRepository.java
+++ b/solr/core/src/java/org/apache/solr/core/backup/repository/LocalFileSystemRepository.java
@@ -96,19 +96,7 @@ public class LocalFileSystemRepository implements BackupRepository {
 
   @Override
   public void deleteDirectory(URI path) throws IOException {
-    Files.walkFileTree(Paths.get(path), new SimpleFileVisitor<Path>() {
-      @Override
-      public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
-        Files.delete(file);
-        return FileVisitResult.CONTINUE;
-      }
-
-      @Override
-      public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
-        Files.delete(dir);
-        return FileVisitResult.CONTINUE;
-      }
-    });
+    Files.walkFileTree(Paths.get(path), new PathSimpleFileVisitor());
   }
 
   @Override
@@ -156,4 +144,18 @@ public class LocalFileSystemRepository implements BackupRepository {
 
   @Override
   public void close() throws IOException {}
+
+  private static class PathSimpleFileVisitor extends SimpleFileVisitor<Path> {
+    @Override
+    public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
+      Files.delete(file);
+      return FileVisitResult.CONTINUE;
+    }
+
+    @Override
+    public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
+      Files.delete(dir);
+      return FileVisitResult.CONTINUE;
+    }
+  }
 }
diff --git a/solr/core/src/java/org/apache/solr/handler/IndexFetcher.java b/solr/core/src/java/org/apache/solr/handler/IndexFetcher.java
index 2f996f3..68c6928 100644
--- a/solr/core/src/java/org/apache/solr/handler/IndexFetcher.java
+++ b/solr/core/src/java/org/apache/solr/handler/IndexFetcher.java
@@ -48,6 +48,7 @@ import org.apache.solr.common.params.ModifiableSolrParams;
 import org.apache.solr.common.util.FastInputStream;
 import org.apache.solr.common.util.NamedList;
 import org.apache.solr.common.util.SuppressForbidden;
+import org.apache.solr.core.CoreContainer;
 import org.apache.solr.core.DirectoryFactory;
 import org.apache.solr.core.DirectoryFactory.DirContext;
 import org.apache.solr.core.IndexDeletionPolicyWrapper;
@@ -1560,7 +1561,7 @@ public class IndexFetcher {
     while (Files.exists(dir.toPath())) {
 
       try {
-        Files.walk(dir.toPath()).sorted(Comparator.reverseOrder()).map(Path::toFile).forEach(File::delete);
+        Files.walk(dir.toPath()).sorted(Comparator.reverseOrder()).forEach(new CoreContainer.FileConsumer());
       } catch (NoSuchFileException e) {
 
       } catch (IOException e) {
diff --git a/solr/core/src/java/org/apache/solr/handler/admin/CoreAdminOperation.java b/solr/core/src/java/org/apache/solr/handler/admin/CoreAdminOperation.java
index 44986b3..7fd50f4 100644
--- a/solr/core/src/java/org/apache/solr/handler/admin/CoreAdminOperation.java
+++ b/solr/core/src/java/org/apache/solr/handler/admin/CoreAdminOperation.java
@@ -74,73 +74,77 @@ import static org.apache.solr.handler.admin.CoreAdminHandler.normalizePath;
 
 enum CoreAdminOperation implements CoreAdminOp {
 
-  CREATE_OP(CREATE, it -> {
-    SolrParams params = it.req.getParams();
-    log().info("core create command {}", params);
-    String coreName = params.required().get(CoreAdminParams.NAME);
-    MDCLoggingContext.setCoreName(coreName);
-    try {
-
-      assert TestInjection.injectRandomDelayInCoreCreation();
-
-      Map<String,String> coreParams = buildCoreParams(params);
-      CoreContainer coreContainer = it.handler.coreContainer;
-      Path instancePath;
+  CREATE_OP(CREATE, new CoreAdminOp() {
+    @Override
+    public void execute(CallInfo it) throws Exception {
+
+      SolrParams params = it.req.getParams();
+      log().info("core create command {}", params);
+      String coreName = params.required().get(CoreAdminParams.NAME);
+      MDCLoggingContext.setCoreName(coreName);
+      try {
+
+        assert TestInjection.injectRandomDelayInCoreCreation();
+
+        Map<String,String> coreParams = buildCoreParams(params);
+        CoreContainer coreContainer = it.handler.coreContainer;
+        Path instancePath;
+
+        // TODO: Should we nuke setting odd instance paths?  They break core discovery, generally
+        String instanceDir = it.req.getParams().get(CoreAdminParams.INSTANCE_DIR);
+        if (instanceDir == null) instanceDir = it.req.getParams().get("property.instanceDir");
+        if (instanceDir != null) {
+          instanceDir = PropertiesUtil.substituteProperty(instanceDir, coreContainer.getContainerProperties(), new HashMap(System.getProperties()));
+          instancePath = coreContainer.getCoreRootDirectory().resolve(instanceDir).normalize();
+        } else {
+          instancePath = coreContainer.getCoreRootDirectory().resolve(coreName);
+        }
 
-      // TODO: Should we nuke setting odd instance paths?  They break core discovery, generally
-      String instanceDir = it.req.getParams().get(CoreAdminParams.INSTANCE_DIR);
-      if (instanceDir == null) instanceDir = it.req.getParams().get("property.instanceDir");
-      if (instanceDir != null) {
-        instanceDir = PropertiesUtil.substituteProperty(instanceDir, coreContainer.getContainerProperties(), new HashMap(System.getProperties()));
-        instancePath = coreContainer.getCoreRootDirectory().resolve(instanceDir).normalize();
-      } else {
-        instancePath = coreContainer.getCoreRootDirectory().resolve(coreName);
-      }
+        boolean newCollection = params.getBool(CoreAdminParams.NEW_COLLECTION, false);
+        if (coreContainer.isShutDown()) {
+          log().warn("Will not create SolrCore, CoreContainer is shutdown");
+          throw new AlreadyClosedException("Will not create SolrCore, CoreContainer is shutdown");
+        }
+        long start = System.nanoTime();
+        coreContainer.create(coreName, instancePath, coreParams, newCollection);
+        log().info("SolrCore {} created in {}ms", coreName, TimeUnit.MILLISECONDS.convert(System.nanoTime() - start, TimeUnit.NANOSECONDS));
 
-      boolean newCollection = params.getBool(CoreAdminParams.NEW_COLLECTION, false);
-      if (coreContainer.isShutDown()) {
-        log().warn("Will not create SolrCore, CoreContainer is shutdown");
-        throw new AlreadyClosedException("Will not create SolrCore, CoreContainer is shutdown");
+        it.rsp.add("core", coreName);
+      } finally {
+        MDCLoggingContext.clear();
       }
-      long start = System.nanoTime();
-      coreContainer.create(coreName, instancePath, coreParams, newCollection);
-      log().info("SolrCore {} created in {}ms", coreName, TimeUnit.MILLISECONDS.convert(System.nanoTime() - start, TimeUnit.NANOSECONDS));
-
-      it.rsp.add("core", coreName);
-    } finally {
-      MDCLoggingContext.clear();
     }
   }),
-  UNLOAD_OP(UNLOAD, it -> {
-    SolrParams params = it.req.getParams();
-    String cname = params.required().get(CoreAdminParams.CORE);
-
-    boolean deleteIndexDir = params.getBool(CoreAdminParams.DELETE_INDEX, true);
-    boolean deleteDataDir = params.getBool(CoreAdminParams.DELETE_DATA_DIR, true);
-    boolean deleteInstanceDir = params.getBool(CoreAdminParams.DELETE_INSTANCE_DIR, true);
-    boolean deleteMetricsHistory = params.getBool(CoreAdminParams.DELETE_METRICS_HISTORY, true);
-    CoreDescriptor cdescr = it.handler.coreContainer.getCoreDescriptor(cname);
-    it.handler.coreContainer.unload(cname, deleteIndexDir, deleteDataDir, deleteInstanceDir);
-    if (deleteMetricsHistory) {
-      MetricsHistoryHandler historyHandler = it.handler.coreContainer.getMetricsHistoryHandler();
-      if (historyHandler != null) {
-        CloudDescriptor cd = cdescr != null ? cdescr.getCloudDescriptor() : null;
-        String registry;
-        if (cd == null) {
-          registry = SolrMetricManager.getRegistryName(SolrInfoBean.Group.core, cname);
-        } else {
-          String replicaName = Utils.parseMetricsReplicaName(cd.getCollectionName(), cname);
-          registry = SolrMetricManager.getRegistryName(SolrInfoBean.Group.core,
-              cd.getCollectionName(),
-              cd.getShardId(),
-              replicaName);
+  UNLOAD_OP(UNLOAD, new CoreAdminOp() {
+    @Override
+    public void execute(CallInfo it) throws Exception {
+      SolrParams params = it.req.getParams();
+      String cname = params.required().get(CoreAdminParams.CORE);
+
+      boolean deleteIndexDir = params.getBool(CoreAdminParams.DELETE_INDEX, true);
+      boolean deleteDataDir = params.getBool(CoreAdminParams.DELETE_DATA_DIR, true);
+      boolean deleteInstanceDir = params.getBool(CoreAdminParams.DELETE_INSTANCE_DIR, true);
+      boolean deleteMetricsHistory = params.getBool(CoreAdminParams.DELETE_METRICS_HISTORY, true);
+      CoreDescriptor cdescr = it.handler.coreContainer.getCoreDescriptor(cname);
+      it.handler.coreContainer.unload(cname, deleteIndexDir, deleteDataDir, deleteInstanceDir);
+      if (deleteMetricsHistory) {
+        MetricsHistoryHandler historyHandler = it.handler.coreContainer.getMetricsHistoryHandler();
+        if (historyHandler != null) {
+          CloudDescriptor cd = cdescr != null ? cdescr.getCloudDescriptor() : null;
+          String registry;
+          if (cd == null) {
+            registry = SolrMetricManager.getRegistryName(SolrInfoBean.Group.core, cname);
+          } else {
+            String replicaName = Utils.parseMetricsReplicaName(cd.getCollectionName(), cname);
+            registry = SolrMetricManager.getRegistryName(SolrInfoBean.Group.core, cd.getCollectionName(), cd.getShardId(), replicaName);
+          }
+          historyHandler.checkSystemCollection();
+          historyHandler.removeHistory(registry);
         }
-        historyHandler.checkSystemCollection();
-        historyHandler.removeHistory(registry);
       }
-    }
 
-    assert TestInjection.injectNonExistentCoreExceptionAfterUnload(cname);
+      assert TestInjection.injectNonExistentCoreExceptionAfterUnload(cname);
+    }
   }),
   RELOAD_OP(RELOAD, it -> {
     SolrParams params = it.req.getParams();
diff --git a/solr/core/src/java/org/apache/solr/spelling/suggest/DocumentExpressionDictionaryFactory.java b/solr/core/src/java/org/apache/solr/spelling/suggest/DocumentExpressionDictionaryFactory.java
index 120c7ce..921b36a 100644
--- a/solr/core/src/java/org/apache/solr/spelling/suggest/DocumentExpressionDictionaryFactory.java
+++ b/solr/core/src/java/org/apache/solr/spelling/suggest/DocumentExpressionDictionaryFactory.java
@@ -48,7 +48,8 @@ public class DocumentExpressionDictionaryFactory extends DictionaryFactory {
   /** Label used to define the name of the
    * sortField used in the {@link #WEIGHT_EXPRESSION} */
   public static final String SORT_FIELD = "sortField";
-  
+  private volatile LongValuesSource fromExp;
+
   @Override
   public Dictionary create(SolrCore core, SolrIndexSearcher searcher) {
     if(params == null) {
@@ -76,9 +77,10 @@ public class DocumentExpressionDictionaryFactory extends DictionaryFactory {
         sortFields.add(getSortField(core, sortFieldName));
       }
     }
-   
-    return new DocumentValueSourceDictionary(searcher.getIndexReader(), field, fromExpression(weightExpression,
-        sortFields), payloadField);
+    if (fromExp == null) {
+      fromExp = fromExpression(weightExpression, sortFields);
+    }
+    return new DocumentValueSourceDictionary(searcher.getIndexReader(), field, fromExp, payloadField);
   }
 
   public LongValuesSource fromExpression(String weightExpression, Set<SortField> sortFields) {
diff --git a/solr/core/src/test/org/apache/solr/cloud/SolrCLIZkUtilsTest.java b/solr/core/src/test/org/apache/solr/cloud/SolrCLIZkUtilsTest.java
index 72fe292..d44eed8 100644
--- a/solr/core/src/test/org/apache/solr/cloud/SolrCLIZkUtilsTest.java
+++ b/solr/core/src/test/org/apache/solr/cloud/SolrCLIZkUtilsTest.java
@@ -725,30 +725,7 @@ public class SolrCLIZkUtilsTest extends SolrCloudTestCase {
   }
 
   void verifyAllFilesAreZNodes(Path fileRoot, String zkRoot) throws IOException {
-    Files.walkFileTree(fileRoot, new SimpleFileVisitor<Path>() {
-      void checkPathOnZk(Path path) {
-        String znode = ZkMaintenanceUtils.createZkNodeName(zkRoot, fileRoot, path);
-        try { // It's easier to catch this exception and fail than catch it everywher eles.
-          assertTrue("Should have found " + znode + " on Zookeeper", zkClient.exists(znode));
-        } catch (Exception e) {
-          fail("Caught unexpected exception " + e.getMessage() + " Znode we were checking " + znode);
-        }
-      }
-
-      @Override
-      public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
-        assertTrue("Path should start at proper place!", file.startsWith(fileRoot));
-        checkPathOnZk(file);
-        return FileVisitResult.CONTINUE;
-      }
-
-      @Override
-      public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
-
-        checkPathOnZk(dir);
-        return FileVisitResult.CONTINUE;
-      }
-    });
+    Files.walkFileTree(fileRoot, new PathSimpleFileVisitor(zkRoot, fileRoot));
   }
 
   // Insure that all znodes in first are in second and vice-versa
@@ -766,4 +743,37 @@ public class SolrCLIZkUtilsTest extends SolrCloudTestCase {
       verifyFirstZNodesInSecond(fNode, sNode);
     }
   }
+
+  private static class PathSimpleFileVisitor extends SimpleFileVisitor<Path> {
+    private final String zkRoot;
+    private final Path fileRoot;
+
+    public PathSimpleFileVisitor(String zkRoot, Path fileRoot) {
+      this.zkRoot = zkRoot;
+      this.fileRoot = fileRoot;
+    }
+
+    void checkPathOnZk(Path path) {
+      String znode = ZkMaintenanceUtils.createZkNodeName(zkRoot, fileRoot, path);
+      try { // It's easier to catch this exception and fail than catch it everywher eles.
+        assertTrue("Should have found " + znode + " on Zookeeper", zkClient.exists(znode));
+      } catch (Exception e) {
+        fail("Caught unexpected exception " + e.getMessage() + " Znode we were checking " + znode);
+      }
+    }
+
+    @Override
+    public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
+      assertTrue("Path should start at proper place!", file.startsWith(fileRoot));
+      checkPathOnZk(file);
+      return FileVisitResult.CONTINUE;
+    }
+
+    @Override
+    public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
+
+      checkPathOnZk(dir);
+      return FileVisitResult.CONTINUE;
+    }
+  }
 }
diff --git a/solr/core/src/test/org/apache/solr/uninverting/TestFieldCacheWithThreads.java b/solr/core/src/test/org/apache/solr/uninverting/TestFieldCacheWithThreads.java
index 58ed45d..9a0b57b 100644
--- a/solr/core/src/test/org/apache/solr/uninverting/TestFieldCacheWithThreads.java
+++ b/solr/core/src/test/org/apache/solr/uninverting/TestFieldCacheWithThreads.java
@@ -147,7 +147,8 @@ public class TestFieldCacheWithThreads extends SolrTestCase {
     r.close();
     dir.close();
   }
-  
+
+  @Nightly // can generate a lot of garbage
   public void test2() throws Exception {
     Random random = random();
     final int NUM_DOCS = TEST_NIGHTLY ? atLeast(100) : 20;