diff --git a/build.gradle b/build.gradle
index b612fe2bf58..f10d8a1c23e 100644
--- a/build.gradle
+++ b/build.gradle
@@ -23,7 +23,7 @@ plugins {
id "com.palantir.consistent-versions" version "2.11.0"
id "org.owasp.dependencycheck" version "8.0.1"
id 'ca.cutterslade.analyze' version "1.9.0"
- id 'de.thetaphi.forbiddenapis' version '3.5' apply false
+ id 'de.thetaphi.forbiddenapis' version '3.6' apply false
id "de.undercouch.download" version "5.2.0" apply false
id "net.ltgt.errorprone" version "3.0.1" apply false
id 'com.diffplug.spotless' version "6.5.2" apply false
diff --git a/gradle/validation/error-prone.gradle b/gradle/validation/error-prone.gradle
index 9c80fea0c47..d2800242425 100644
--- a/gradle/validation/error-prone.gradle
+++ b/gradle/validation/error-prone.gradle
@@ -85,6 +85,7 @@ allprojects { prj ->
// '-Xep:AutoValueConstructorOrderChecker:OFF', // we don't use autovalue
'-Xep:BadAnnotationImplementation:ERROR',
'-Xep:BadShiftAmount:ERROR',
+ '-Xep:BanClassLoader:ERROR',
'-Xep:BanJNDI:ERROR', // todo - implement with forbidden APIs instead?
'-Xep:BoxedPrimitiveEquality:ERROR',
// '-Xep:BundleDeserializationCast:OFF', // we don't use android
@@ -104,6 +105,7 @@ allprojects { prj ->
'-Xep:DangerousLiteralNull:ERROR',
'-Xep:DeadException:ERROR',
'-Xep:DeadThread:ERROR',
+ '-Xep:DereferenceWithNullBranch:ERROR',
'-Xep:DiscardedPostfixExpression:ERROR',
// '-Xep:DoNotCall:OFF', // we don't use this annotation
'-Xep:DoNotMock:ERROR',
@@ -262,6 +264,7 @@ allprojects { prj ->
'-Xep:AssertThrowsMultipleStatements:WARN',
'-Xep:AssertionFailureIgnored:WARN',
'-Xep:AssistedInjectAndInjectOnSameConstructor:WARN',
+ '-Xep:AttemptedNegativeZero:WARN',
// '-Xep:AutoValueFinalMethods:OFF', // we don't use autovalue
// '-Xep:AutoValueImmutableFields:OFF', // we don't use autovalue
// '-Xep:AutoValueSubclassLeaked:OFF', // we don't use autovalue
@@ -284,6 +287,7 @@ allprojects { prj ->
'-Xep:ClassCanBeStatic:WARN',
'-Xep:ClassNewInstance:WARN',
// '-Xep:CloseableProvides:OFF', // we don't use this annotation
+ '-Xep:ClosingStandardOutputStreams:WARN',
'-Xep:CollectionUndefinedEquality:WARN',
'-Xep:CollectorShouldNotUseState:WARN',
'-Xep:ComparableAndComparator:WARN',
@@ -299,6 +303,7 @@ allprojects { prj ->
// '-Xep:DoNotCallSuggester:OFF', // we don't use this annotation
// '-Xep:DoNotClaimAnnotations:OFF', // we don't use this annotation
// '-Xep:DoNotMockAutoValue:OFF', // we don't use autovalue
+ // '-Xep:DoNotUseRuleChain:OFF', // todo could be fixed but not easy
// '-Xep:DoubleCheckedLocking:OFF', // todo check if useful or comment why not
'-Xep:EmptyBlockTag:WARN',
// '-Xep:EmptyCatch:OFF', // todo check if useful or comment why not - might be handled by ECJ?
@@ -325,6 +330,7 @@ allprojects { prj ->
// '-Xep:FutureReturnValueIgnored:OFF', // todo there are problems that should be fixed
'-Xep:GetClassOnEnum:WARN',
'-Xep:HidingField:WARN',
+ '-Xep:ICCProfileGetInstance:WARN',
'-Xep:IdentityHashMapUsage:WARN',
// '-Xep:ImmutableAnnotationChecker:OFF', // we don't use this annotation
'-Xep:ImmutableEnumChecker:WARN',
@@ -343,6 +349,7 @@ allprojects { prj ->
// '-Xep:InlineMeInliner:OFF', // we don't use this annotation
// '-Xep:InlineMeSuggester:OFF', // We don't use this annotation
// '-Xep:InputStreamSlowMultibyteRead:OFF', // todo check if useful or comment why not
+ '-Xep:InlineTrivialConstant:WARN',
'-Xep:InstanceOfAndCastMatchWrongType:WARN',
'-Xep:IntLongMath:WARN',
// '-Xep:InvalidBlockTag:OFF', // this is needed for tags like lucene.internal
@@ -379,6 +386,7 @@ allprojects { prj ->
'-Xep:LiteEnumValueOf:WARN',
'-Xep:LiteProtoToString:WARN',
'-Xep:LockNotBeforeTry:WARN',
+ '-Xep:LockOnNonEnclosingClassLiteral:WARN',
'-Xep:LogicalAssignment:WARN',
'-Xep:LongDoubleConversion:WARN',
'-Xep:LongFloatConversion:WARN',
@@ -390,25 +398,32 @@ allprojects { prj ->
'-Xep:MissingFail:WARN',
'-Xep:MissingImplementsComparable:WARN',
'-Xep:MissingOverride:WARN',
+ // '-Xep:MissingRefasterAnnotation:OFF', // don't use Refaster
// '-Xep:MissingSummary:OFF', // style preference that we don't want to enforce
// '-Xep:MixedMutabilityReturnType:OFF', // todo check if useful or comment why not
'-Xep:MockNotUsedInProduction:WARN',
'-Xep:ModifiedButNotUsed:WARN',
'-Xep:ModifyCollectionInEnhancedForLoop:WARN',
'-Xep:ModifySourceCollectionInStream:WARN',
+ '-Xep:MultimapKeys:WARN',
'-Xep:MultipleParallelOrSequentialCalls:WARN',
'-Xep:MultipleUnaryOperatorsInMethodCall:WARN',
+ // '-Xep:MutableGuiceModule:OFF', // we don't use guice
'-Xep:MutablePublicArray:WARN',
+ '-Xep:NamedLikeContextualKeyword:WARN',
'-Xep:NarrowCalculation:WARN',
'-Xep:NarrowingCompoundAssignment:WARN',
// '-Xep:NegativeCharLiteral:OFF', // todo check if useful or comment why not
'-Xep:NestedInstanceOfConditions:WARN',
'-Xep:NewFileSystem:WARN',
+ //'-Xep:NonApiType:OFF', // todo could be fixed but lots of changes
// '-Xep:NonAtomicVolatileUpdate:OFF', // todo check if useful or comment why not
'-Xep:NonCanonicalType:WARN',
'-Xep:NonOverridingEquals:WARN',
+ '-Xep:NotJavadoc:WARN',
'-Xep:NullOptional:WARN',
// '-Xep:NullableConstructor:OFF', // we don't use this annotation
+ '-Xep:NullableOptional:WARN',
// '-Xep:NullablePrimitive:OFF', // we don't use this annotation
// '-Xep:NullablePrimitiveArray:OFF', // we don't use this annotation
// '-Xep:NullableVoid:OFF', // we don't use this annotation
@@ -420,9 +435,10 @@ allprojects { prj ->
'-Xep:OptionalNotPresent:WARN',
'-Xep:OrphanedFormatString:WARN',
// '-Xep:OutlineNone:OFF', // we don't use gwt
+ '-Xep:OverridingMethodInconsistentArgumentNamesChecker:WARN',
'-Xep:OverrideThrowableToString:WARN',
'-Xep:Overrides:WARN',
- '-Xep:OverridesGuiceInjectableMethod:WARN',
+ // '-Xep:OverridesGuiceInjectableMethod:OFF', // we don't use guice
'-Xep:ParameterName:WARN',
'-Xep:PreconditionsCheckNotNullRepeated:WARN',
'-Xep:PrimitiveAtomicReference:WARN',
@@ -434,6 +450,7 @@ allprojects { prj ->
'-Xep:ReachabilityFenceUsage:WARN',
'-Xep:ReferenceEquality:WARN',
'-Xep:RethrowReflectiveOperationExceptionAsLinkageError:WARN',
+ '-Xep:ReturnAtTheEndOfVoidFunction:WARN',
'-Xep:ReturnFromVoid:WARN',
'-Xep:RobolectricShadowDirectlyOn:WARN',
'-Xep:RxReturnValueIgnored:WARN',
@@ -446,6 +463,7 @@ allprojects { prj ->
'-Xep:StaticMockMember:WARN',
// '-Xep:StreamResourceLeak:OFF', // todo check if useful or comment why not
'-Xep:StreamToIterable:WARN',
+ // '-Xep:StringCaseLocaleUsage:OFF', // we have forbiddenapis for that
// '-Xep:StringSplitter:OFF', // todo check if useful or comment why not - might be able to use forbidden-apis for this?
// '-Xep:SwigMemoryLeak:OFF', // we don't use swig
// '-Xep:SynchronizeOnNonFinalField:OFF', // todo check if useful or comment why not
@@ -457,6 +475,7 @@ allprojects { prj ->
'-Xep:ToStringReturnsNull:WARN',
// '-Xep:TruthAssertExpected:OFF', // we don't use truth
// '-Xep:TruthConstantAsserts:OFF', // we don't use truth
+ // '-Xep:TruthContainsExactlyElementsInUsage:OFF', // we don't use truth
// '-Xep:TruthGetOrDefault:OFF', // we don't use truth
// '-Xep:TruthIncompatibleType:OFF', // we don't use truth
'-Xep:TypeEquals:WARN',
@@ -468,11 +487,14 @@ allprojects { prj ->
'-Xep:UnescapedEntity:WARN',
// '-Xep:UnicodeEscape:OFF', // can't enable since Lucene/Solr tests use unicode a bunch
// '-Xep:UnnecessaryAssignment:OFF', // we don't use these annotations
+ '-Xep:UnnecessaryAsync:WARN',
'-Xep:UnnecessaryLambda:WARN',
'-Xep:UnnecessaryLongToIntConversion:WARN',
'-Xep:UnnecessaryMethodInvocationMatcher:WARN',
'-Xep:UnnecessaryMethodReference:WARN',
// '-Xep:UnnecessaryParentheses:OFF', // style preference that we don't want to enforce
+ '-Xep:UnnecessaryStringBuilder:WARN',
+ // '-Xep:UnnecessaryTestMethodPrefix:OFF', // style preference that we don't want to enforce
// '-Xep:UnqualifiedYield:OFF', // javac takes care
'-Xep:UnrecognisedJavadocTag:WARN',
'-Xep:UnsafeFinalization:WARN',
diff --git a/solr/CHANGES.txt b/solr/CHANGES.txt
index c8a3a1dd63c..d9e18452386 100644
--- a/solr/CHANGES.txt
+++ b/solr/CHANGES.txt
@@ -72,6 +72,10 @@ New Features
* SOLR-16954: Make Circuit Breakers available for Update Requests (janhoy, Christine Poerschke, Pierre Salagnac)
+* SOLR-15056: A new Circuit breaker for percentage of CPU utilization is added. The former "CPU" circuit breaker
+ is now more correctly named LoadAverageCircuitBreaker as it trips on system load average which is not a percentage.
+ Users of legacy CircuitBreakerManager are not affected by this change. (Walter Underwood, janhoy, Christine Poerschke, Atri Sharma)
+
* SOLR-15771: bin/auth creates reasonable roles and permissions for security: 'search', 'index', 'admin', and 'superadmin' and assigns user superadmin role. (Eric Pugh, janhoy)
* SOLR-15367: Convert "rid" functionality into a default Tracer (Alex Deparvu, David Smiley)
@@ -109,6 +113,8 @@ Improvements
* SOLR-15474: Make Circuit breakers individually pluggable (Atri Sharma, Christine Poerschke, janhoy)
+* SOLR-16982: Trip Circuit Breakers only for external requests (janhoy, Christine Poerschke)
+
* SOLR-16927: Allow SolrClientCache clients to use Jetty HTTP2 clients (Alex Deparvu, David Smiley)
* SOLR-16896, SOLR-16897: Add support of OAuth 2.0/OIDC 'code with PKCE' flow (Lamine Idjeraoui, janhoy, Kevin Risden, Anshum Gupta)
@@ -123,6 +129,8 @@ Improvements
* SOLR-16970: SOLR_OPTS is now able to override options set by the Solr control scripts, "bin/solr" and "bin/solr.cmd". (Houston Putman)
+* SOLR-16968: The MemoryCircuitBreaker now uses average heap usage over the last 30 seconds (janhoy, Christine Poerschke)
+
* SOLR-14886: Suppress stack traces in query response (Isabelle Giguere via Alex Deparvu)
* SOLR-16461: `/solr/coreName/replication?command=backup` now has a v2 equivalent, available at
@@ -134,6 +142,11 @@ Improvements
* SOLR-15440: The Learning To Rank FieldValueFeature now uses DocValues when docValues=true and stored=true are combined. (Christine Poerschke, Tom Gilke)
+* SOLR-16959: Make the internal CoresLocator implementation configurable in solr.xml (Vincent Primault via David Smiley)
+
+* SOLR-16967: Some ConfigSet operations formerly required that solrconfig.xml exist but should not have because
+ the name of the file is configurable when creating cores / collections. (David Smiley)
+
Optimizations
---------------------
@@ -141,6 +154,9 @@ Optimizations
* SOLR-16265: reduce memory usage of ContentWriter based requests in Http2SolrClient (Alex Deparvu, Kevin Risden, David Smiley)
+* SOLR-16989: Optimize and consolidate reuse of DocValues iterators for value retrieval (Michael Gibney)
+
+* SOLR-17004: ZkStateReader waitForState should check clusterState before using watchers (Kevin Risden)
Bug Fixes
---------------------
@@ -192,11 +208,36 @@ Bug Fixes
* SOLR-16971: RealTimeGet with Composite router throws NPE (Alex Deparvu)
+* SOLR-16931: ReRankScaler explain breaks with debug=true and in distributed mode (Joel Bernstein)
+
+* SOLR-16983: Fixed a bug that could cause some usages of SolrStream to fail to close InputStreams from the server.
+ Also fixed the usage of ObjectReleaseTracker in SolrTestCaseJ4 to catch these kinds of bugs (hossman)
+
+* SOLR-16925: Fix indentation for JacksonJsonWriter (Houston Putman)
+
+* SOLR-16701: Fix race condition on PRS enabled collection deletion (Patson Luk)
+
+* SOLR-16991: Concurrent requests failing JWT authentication in Admin UI intermittently (Lamine Idjeraoui, janhoy)
+
+* SOLR-16997: OTEL configurator NPE when SOLR_HOST not set (janhoy)
+
+* PR#1963: Fix the admin UI green core-size graph on nodes screen (janhoy)
+
+* SOLR-16980: Connect to SOLR standalone with basic authentication (Alex Deparvu)
+
+* SOLR-16992: Non-reproducible StreamingTest failures -- suggests CloudSolrStream concurency race condition (Alex Deparvu, hossman)
+
+* SOLR-16644: Fixing the entropy warning threshold using scaling based on poolsize (Raghavan Muthuregunathan)
+
Dependency Upgrades
---------------------
* PR#1846: Update io.opentelemetry to 1.29.0 (Alex Deparvu)
+* SOLR-16985: Upgrade Lucene to 9.8.0 (Alex Deparvu, Christine Poerschke)
+
+* PR#1971: Update forbiddenapis to 3.6 to support Java 21/22 and commons-io up to 2.14.0 (Uwe Schindler)
+
Other Changes
---------------------
@@ -214,6 +255,10 @@ Other Changes
* SOLR-16979: BATS integration tests now start solr instances on a randomly selected port (janhoy)
+* SOLR-16978: Be case insensitive when parsing booleans from text (Tomás Fernández Löbbe)
+
+* SOLR-16960: Tests should sometimes run with a Tracer (not no-op) (Alex Deparvu)
+
================== 9.3.0 ==================
Upgrade Notes
@@ -376,6 +421,9 @@ Improvements
* SOLR-16878: Use Log4J JUL manager when starting Java. This is necessary for Lucene logs to be included with Solr logs. (Houston Putman, Uwe Schindler)
+* SOLR-16397: Reload core v2 endpoints have been updated to be more REST-ful.
+ RELOAD is now available at `POST /api/cores/coreName/reload` (Sanjay Dutt via Jason Gerlowski)
+
Optimizations
---------------------
diff --git a/solr/bin/solr b/solr/bin/solr
index cc72f621094..101fde35a51 100644
--- a/solr/bin/solr
+++ b/solr/bin/solr
@@ -1915,12 +1915,26 @@ function start_solr() {
-jar start.jar "${SOLR_JETTY_CONFIG[@]}" $SOLR_JETTY_ADDL_CONFIG \
1>"$SOLR_LOGS_DIR/solr-$SOLR_PORT-console.log" 2>&1 & echo $! > "$SOLR_PID_DIR/solr-$SOLR_PORT.pid"
- # check if /proc/sys/kernel/random/entropy_avail exists then check output of cat /proc/sys/kernel/random/entropy_avail to see if less than 300
- if [[ -f /proc/sys/kernel/random/entropy_avail ]] && (( $(cat /proc/sys/kernel/random/entropy_avail) < 300)); then
- echo "Warning: Available entropy is low. As a result, use of the UUIDField, SSL, or any other features that require"
- echo "RNG might not work properly. To check for the amount of available entropy, use 'cat /proc/sys/kernel/random/entropy_avail'."
- echo ""
+ # Get the current entropy available
+ entropy_avail=$(cat /proc/sys/kernel/random/entropy_avail)
+
+ # Get the pool size
+ pool_size=$(cat /proc/sys/kernel/random/poolsize)
+
+ # Check if entropy is available and pool size is non-zero
+ if [[ $entropy_avail -gt 0 && $pool_size -ne 0 ]]; then
+ # Compute the ratio of entropy available to pool size
+ ratio=$(awk -v ea="$entropy_avail" -v ps="$pool_size" 'BEGIN {print (ea/ps)*100}')
+
+ # Check if the ratio is less than 25%
+ if (( $(echo "$ratio < 25" | bc -l) )); then
+ echo "Warning: Available entropy is low. As a result, use of the UUIDField, SSL, or any other features that require"
+ echo "RNG might not work properly. To check for the amount of available entropy, use 'cat /proc/sys/kernel/random/entropy_avail'."
+ fi
+ else
+ echo "Error: Either no entropy is available or the pool size is zero."
fi
+
# no lsof on cygwin though
if lsof -v 2>&1 | grep -q revision; then
echo -n "Waiting up to $SOLR_START_WAIT seconds to see Solr running on port $SOLR_PORT"
diff --git a/solr/core/src/java/org/apache/solr/cli/SimplePostTool.java b/solr/core/src/java/org/apache/solr/cli/SimplePostTool.java
index 40153c27be0..35842eb1c38 100644
--- a/solr/core/src/java/org/apache/solr/cli/SimplePostTool.java
+++ b/solr/core/src/java/org/apache/solr/cli/SimplePostTool.java
@@ -426,7 +426,6 @@ private void doWebMode() {
} catch (MalformedURLException e) {
fatal("Wrong URL trying to append /extract to " + solrUrl);
}
- return;
}
private void doStdinMode() {
diff --git a/solr/core/src/java/org/apache/solr/cloud/ZkConfigSetService.java b/solr/core/src/java/org/apache/solr/cloud/ZkConfigSetService.java
index 5f83f88c8eb..1718edbf56a 100644
--- a/solr/core/src/java/org/apache/solr/cloud/ZkConfigSetService.java
+++ b/solr/core/src/java/org/apache/solr/cloud/ZkConfigSetService.java
@@ -139,10 +139,7 @@ public String configSetName(CoreDescriptor cd) {
@Override
public boolean checkConfigExists(String configName) throws IOException {
try {
- Boolean existsSolrConfigXml =
- zkClient.exists(CONFIGS_ZKNODE + "/" + configName + "/solrconfig.xml", true);
- if (existsSolrConfigXml == null) return false;
- return existsSolrConfigXml;
+ return zkClient.exists(CONFIGS_ZKNODE + "/" + configName, true);
} catch (KeeperException | InterruptedException e) {
throw new IOException(
"Error checking whether config exists", SolrZkClient.checkInterrupted(e));
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 b35cbbef058..cdf90bdc7a4 100644
--- a/solr/core/src/java/org/apache/solr/core/CoreContainer.java
+++ b/solr/core/src/java/org/apache/solr/core/CoreContainer.java
@@ -26,7 +26,6 @@
import static org.apache.solr.common.params.CommonParams.METRICS_PATH;
import static org.apache.solr.common.params.CommonParams.ZK_PATH;
import static org.apache.solr.common.params.CommonParams.ZK_STATUS_PATH;
-import static org.apache.solr.core.CorePropertiesLocator.PROPERTIES_FILENAME;
import static org.apache.solr.security.AuthenticationPlugin.AUTHENTICATION_PLUGIN_PROP;
import com.github.benmanes.caffeine.cache.Interner;
@@ -377,21 +376,24 @@ public CoreContainer(Path solrHome, Properties properties) {
* @see #load()
*/
public CoreContainer(NodeConfig config) {
- this(config, new CorePropertiesLocator(config.getCoreRootDirectory()));
+ this(config, CoresLocator.instantiate(config));
}
public CoreContainer(NodeConfig config, boolean asyncSolrCoreLoad) {
- this(config, new CorePropertiesLocator(config.getCoreRootDirectory()), asyncSolrCoreLoad);
+ this(config, CoresLocator.instantiate(config), asyncSolrCoreLoad);
}
/**
- * Create a new CoreContainer using the given configuration and locator. The container's cores are
- * not loaded.
+ * Create a new CoreContainer using the given configuration and locator.
+ *
+ *
The container's cores are not loaded. This constructor should be used only in tests, as it
+ * overrides {@link CoresLocator}'s instantiation process.
*
* @param config a ConfigSolr representation of this container's configuration
* @param locator a CoresLocator
* @see #load()
*/
+ @VisibleForTesting
public CoreContainer(NodeConfig config, CoresLocator locator) {
this(config, locator, false);
}
@@ -1945,9 +1947,7 @@ private CoreDescriptor reloadCoreDescriptor(CoreDescriptor oldDesc) {
return null;
}
- CorePropertiesLocator cpl = new CorePropertiesLocator(null);
- CoreDescriptor ret =
- cpl.buildCoreDescriptor(oldDesc.getInstanceDir().resolve(PROPERTIES_FILENAME), this);
+ CoreDescriptor ret = getCoresLocator().reload(oldDesc, 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
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 be3da5c3447..c060fc5d3cd 100644
--- a/solr/core/src/java/org/apache/solr/core/CorePropertiesLocator.java
+++ b/solr/core/src/java/org/apache/solr/core/CorePropertiesLocator.java
@@ -16,6 +16,7 @@
*/
package org.apache.solr.core;
+import com.google.common.annotations.VisibleForTesting;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
@@ -51,6 +52,11 @@ public class CorePropertiesLocator implements CoresLocator {
private final Path rootDirectory;
+ public CorePropertiesLocator(NodeConfig nodeConfig) {
+ this(nodeConfig.getCoreRootDirectory());
+ }
+
+ @VisibleForTesting
public CorePropertiesLocator(Path coreDiscoveryRoot) {
this.rootDirectory = coreDiscoveryRoot;
log.debug("Config-defined core root directory: {}", this.rootDirectory);
@@ -193,6 +199,11 @@ public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOExce
return cds;
}
+ @Override
+ public CoreDescriptor reload(CoreDescriptor cd, CoreContainer cc) {
+ return buildCoreDescriptor(cd.getInstanceDir().resolve(PROPERTIES_FILENAME), cc);
+ }
+
protected CoreDescriptor buildCoreDescriptor(Path propertiesFile, CoreContainer cc) {
if (Files.notExists(propertiesFile)) {
// This can happen in tests, see CoreContainer#reloadCoreDescriptor
diff --git a/solr/core/src/java/org/apache/solr/core/CoresLocator.java b/solr/core/src/java/org/apache/solr/core/CoresLocator.java
index 10eac005230..3321e057860 100644
--- a/solr/core/src/java/org/apache/solr/core/CoresLocator.java
+++ b/solr/core/src/java/org/apache/solr/core/CoresLocator.java
@@ -27,7 +27,7 @@ public interface CoresLocator {
* @param cc the CoreContainer
* @param coreDescriptors CoreDescriptors to persist
*/
- public void create(CoreContainer cc, CoreDescriptor... coreDescriptors);
+ void create(CoreContainer cc, CoreDescriptor... coreDescriptors);
/**
* Ensure that the core definitions from the passed in CoreDescriptors will persist across
@@ -36,7 +36,7 @@ public interface CoresLocator {
* @param cc the CoreContainer
* @param coreDescriptors CoreDescriptors to persist
*/
- public void persist(CoreContainer cc, CoreDescriptor... coreDescriptors);
+ void persist(CoreContainer cc, CoreDescriptor... coreDescriptors);
/**
* Ensure that the core definitions from the passed in CoreDescriptors are not available for
@@ -45,7 +45,7 @@ public interface CoresLocator {
* @param cc the CoreContainer
* @param coreDescriptors CoreDescriptors of the cores to remove
*/
- public void delete(CoreContainer cc, CoreDescriptor... coreDescriptors);
+ void delete(CoreContainer cc, CoreDescriptor... coreDescriptors);
/**
* Persist the new name of a renamed core
@@ -54,7 +54,7 @@ public interface CoresLocator {
* @param oldCD the CoreDescriptor of the core before renaming
* @param newCD the CoreDescriptor of the core after renaming
*/
- public void rename(CoreContainer cc, CoreDescriptor oldCD, CoreDescriptor newCD);
+ void rename(CoreContainer cc, CoreDescriptor oldCD, CoreDescriptor newCD);
/**
* Swap two core definitions
@@ -63,7 +63,7 @@ public interface CoresLocator {
* @param cd1 the core descriptor of the first core, after swapping
* @param cd2 the core descriptor of the second core, after swapping
*/
- public void swap(CoreContainer cc, CoreDescriptor cd1, CoreDescriptor cd2);
+ void swap(CoreContainer cc, CoreDescriptor cd1, CoreDescriptor cd2);
/**
* Load all the CoreDescriptors from persistence store
@@ -71,5 +71,31 @@ public interface CoresLocator {
* @param cc the CoreContainer
* @return a list of all CoreDescriptors found
*/
- public List discover(CoreContainer cc);
+ List discover(CoreContainer cc);
+
+ /**
+ * Reload a core descriptor.
+ *
+ * @param cd the old core descriptor
+ * @param cc the CoreContainer
+ * @return a new core descriptor
+ */
+ CoreDescriptor reload(CoreDescriptor cd, CoreContainer cc);
+
+ /**
+ * Returns a new instance of {@link CoresLocator}, depending on provided config.
+ *
+ * @param nodeConfig Solr configuration.
+ */
+ static CoresLocator instantiate(NodeConfig nodeConfig) {
+ final String coresLocatorClass = nodeConfig.getCoresLocatorClass();
+ return nodeConfig
+ .getSolrResourceLoader()
+ .newInstance(
+ coresLocatorClass,
+ CoresLocator.class,
+ null,
+ new Class>[] {NodeConfig.class},
+ new Object[] {nodeConfig});
+ }
}
diff --git a/solr/core/src/java/org/apache/solr/core/FileSystemConfigSetService.java b/solr/core/src/java/org/apache/solr/core/FileSystemConfigSetService.java
index 5ada2f99cfb..7631edc9809 100644
--- a/solr/core/src/java/org/apache/solr/core/FileSystemConfigSetService.java
+++ b/solr/core/src/java/org/apache/solr/core/FileSystemConfigSetService.java
@@ -80,8 +80,7 @@ public String configSetName(CoreDescriptor cd) {
@Override
public boolean checkConfigExists(String configName) throws IOException {
- Path solrConfigXmlFile = getConfigDir(configName).resolve("solrconfig.xml");
- return Files.exists(solrConfigXmlFile);
+ return Files.exists(getConfigDir(configName));
}
@Override
diff --git a/solr/core/src/java/org/apache/solr/core/NodeConfig.java b/solr/core/src/java/org/apache/solr/core/NodeConfig.java
index 9177889f447..387fe3beafb 100644
--- a/solr/core/src/java/org/apache/solr/core/NodeConfig.java
+++ b/solr/core/src/java/org/apache/solr/core/NodeConfig.java
@@ -56,6 +56,7 @@ public class NodeConfig {
private final String nodeName;
private final Path coreRootDirectory;
+ private final String coresLocatorClass;
private final Path solrDataHome;
@@ -125,6 +126,7 @@ public class NodeConfig {
private NodeConfig(
String nodeName,
Path coreRootDirectory,
+ String coresLocatorClass,
Path solrDataHome,
Integer booleanQueryMaxClauseCount,
Path configSetBaseDirectory,
@@ -162,6 +164,7 @@ private NodeConfig(
// all Path params here are absolute and normalized.
this.nodeName = nodeName;
this.coreRootDirectory = coreRootDirectory;
+ this.coresLocatorClass = coresLocatorClass;
this.solrDataHome = solrDataHome;
this.booleanQueryMaxClauseCount = booleanQueryMaxClauseCount;
this.configSetBaseDirectory = configSetBaseDirectory;
@@ -271,6 +274,10 @@ public Path getCoreRootDirectory() {
return coreRootDirectory;
}
+ public String getCoresLocatorClass() {
+ return this.coresLocatorClass;
+ }
+
/** Absolute. */
public Path getSolrDataHome() {
return solrDataHome;
@@ -592,6 +599,7 @@ public static class NodeConfigBuilder {
// all Path fields here are absolute and normalized.
private SolrResourceLoader loader;
private Path coreRootDirectory;
+ private String coresLocatorClass = DEFAULT_CORESLOCATORCLASS;
private Path solrDataHome;
private Integer booleanQueryMaxClauseCount;
private Path configSetBaseDirectory;
@@ -632,6 +640,8 @@ public static class NodeConfigBuilder {
// No:of core load threads in cloud mode is set to a default of 8
public static final int DEFAULT_CORE_LOAD_THREADS_IN_CLOUD = 8;
+ private static final String DEFAULT_CORESLOCATORCLASS =
+ "org.apache.solr.core.CorePropertiesLocator";
private static final String DEFAULT_ADMINHANDLERCLASS =
"org.apache.solr.handler.admin.CoreAdminHandler";
private static final String DEFAULT_INFOHANDLERCLASS =
@@ -671,6 +681,11 @@ public NodeConfigBuilder setCoreRootDirectory(String coreRootDirectory) {
return this;
}
+ public NodeConfigBuilder setCoresLocatorClass(String coresLocatorClass) {
+ this.coresLocatorClass = coresLocatorClass;
+ return this;
+ }
+
public NodeConfigBuilder setSolrDataHome(String solrDataHomeString) {
// keep it null unless explicitly set to non-empty value
if (solrDataHomeString != null && !solrDataHomeString.isEmpty()) {
@@ -755,8 +770,8 @@ public NodeConfigBuilder setReplayUpdatesThreads(int replayUpdatesThreads) {
this.replayUpdatesThreads = replayUpdatesThreads;
return this;
}
-
// Remove in Solr 10.0
+
@Deprecated
public NodeConfigBuilder setTransientCacheSize(int transientCacheSize) {
this.transientCacheSize = transientCacheSize;
@@ -886,6 +901,7 @@ public NodeConfig build() {
return new NodeConfig(
nodeName,
coreRootDirectory,
+ coresLocatorClass,
solrDataHome,
booleanQueryMaxClauseCount,
configSetBaseDirectory,
diff --git a/solr/core/src/java/org/apache/solr/core/SchemaCodecFactory.java b/solr/core/src/java/org/apache/solr/core/SchemaCodecFactory.java
index 8615e0a32ef..2b2933b0f86 100644
--- a/solr/core/src/java/org/apache/solr/core/SchemaCodecFactory.java
+++ b/solr/core/src/java/org/apache/solr/core/SchemaCodecFactory.java
@@ -16,16 +16,21 @@
*/
package org.apache.solr.core;
+import java.io.IOException;
import java.lang.invoke.MethodHandles;
import java.util.Arrays;
import java.util.Locale;
import org.apache.lucene.codecs.Codec;
import org.apache.lucene.codecs.DocValuesFormat;
import org.apache.lucene.codecs.KnnVectorsFormat;
+import org.apache.lucene.codecs.KnnVectorsReader;
+import org.apache.lucene.codecs.KnnVectorsWriter;
import org.apache.lucene.codecs.PostingsFormat;
import org.apache.lucene.codecs.lucene95.Lucene95Codec;
import org.apache.lucene.codecs.lucene95.Lucene95Codec.Mode;
import org.apache.lucene.codecs.lucene95.Lucene95HnswVectorsFormat;
+import org.apache.lucene.index.SegmentReadState;
+import org.apache.lucene.index.SegmentWriteState;
import org.apache.solr.common.SolrException;
import org.apache.solr.common.SolrException.ErrorCode;
import org.apache.solr.common.util.NamedList;
@@ -127,7 +132,8 @@ public KnnVectorsFormat getKnnVectorsFormatForField(String field) {
if (DenseVectorField.HNSW_ALGORITHM.equals(knnAlgorithm)) {
int maxConn = vectorType.getHnswMaxConn();
int beamWidth = vectorType.getHnswBeamWidth();
- return new Lucene95HnswVectorsFormat(maxConn, beamWidth);
+ var delegate = new Lucene95HnswVectorsFormat(maxConn, beamWidth);
+ return new SolrDelegatingKnnVectorsFormat(delegate, vectorType.getDimension());
} else {
throw new SolrException(
ErrorCode.SERVER_ERROR, knnAlgorithm + " KNN algorithm is not supported");
@@ -145,4 +151,34 @@ public Codec getCodec() {
assert core != null : "inform must be called first";
return codec;
}
+
+ /**
+ * This class exists because Lucene95HnswVectorsFormat's getMaxDimensions method is final and we
+ * need to workaround that constraint to allow more than the default number of dimensions
+ */
+ private static final class SolrDelegatingKnnVectorsFormat extends KnnVectorsFormat {
+ private final KnnVectorsFormat delegate;
+ private final int maxDimensions;
+
+ public SolrDelegatingKnnVectorsFormat(KnnVectorsFormat delegate, int maxDimensions) {
+ super(delegate.getName());
+ this.delegate = delegate;
+ this.maxDimensions = maxDimensions;
+ }
+
+ @Override
+ public KnnVectorsWriter fieldsWriter(SegmentWriteState state) throws IOException {
+ return delegate.fieldsWriter(state);
+ }
+
+ @Override
+ public KnnVectorsReader fieldsReader(SegmentReadState state) throws IOException {
+ return delegate.fieldsReader(state);
+ }
+
+ @Override
+ public int getMaxDimensions(String fieldName) {
+ return maxDimensions;
+ }
+ }
}
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 944d4684016..cb741cc97b6 100644
--- a/solr/core/src/java/org/apache/solr/core/SolrCore.java
+++ b/solr/core/src/java/org/apache/solr/core/SolrCore.java
@@ -1088,9 +1088,6 @@ private SolrCore(
solrMetricsContext = coreMetricManager.getSolrMetricsContext();
this.coreMetricManager.loadReporters();
- // init pluggable circuit breakers
- initPlugins(null, CircuitBreaker.class);
-
if (updateHandler == null) {
directoryFactory = initDirectoryFactory();
recoveryStrategyBuilder = initRecoveryStrategyBuilder();
@@ -1115,6 +1112,9 @@ private SolrCore(
// initialize core metrics
initializeMetrics(solrMetricsContext, null);
+ // init pluggable circuit breakers, after metrics because some circuit breakers use metrics
+ initPlugins(null, CircuitBreaker.class);
+
SolrFieldCacheBean solrFieldCacheBean = new SolrFieldCacheBean();
// this is registered at the CONTAINER level because it's not core-specific - for now we
// also register it here for back-compat
@@ -1764,6 +1764,17 @@ private void doClose() {
ExecutorUtil.shutdownAndAwaitTermination(coreAsyncTaskExecutor);
+ // Close circuit breakers that may have background threads, before metrics because some circuit
+ // breakers use metrics
+ try {
+ getCircuitBreakerRegistry().close();
+ } catch (Throwable e) {
+ log.error("Exception closing circuit breakers", e);
+ if (e instanceof Error) {
+ throw (Error) e;
+ }
+ }
+
// stop reporting metrics
try {
coreMetricManager.close();
@@ -3041,10 +3052,10 @@ public PluginBag getResponseWriters() {
try {
m.put(
"xlsx",
- (QueryResponseWriter)
- Class.forName("org.apache.solr.handler.extraction.XLSXResponseWriter")
- .getConstructor()
- .newInstance());
+ Class.forName("org.apache.solr.handler.extraction.XLSXResponseWriter")
+ .asSubclass(QueryResponseWriter.class)
+ .getDeclaredConstructor()
+ .newInstance());
} catch (Exception e) {
// don't worry; extraction module not in class path
}
diff --git a/solr/core/src/java/org/apache/solr/core/SolrXmlConfig.java b/solr/core/src/java/org/apache/solr/core/SolrXmlConfig.java
index df0645c8f69..cba8a277504 100644
--- a/solr/core/src/java/org/apache/solr/core/SolrXmlConfig.java
+++ b/solr/core/src/java/org/apache/solr/core/SolrXmlConfig.java
@@ -348,6 +348,9 @@ private static NodeConfig fillSolrSection(NodeConfig.NodeConfigBuilder builder,
case "configSetService":
builder.setConfigSetServiceClass(it.txt());
break;
+ case "coresLocator":
+ builder.setCoresLocatorClass(it.txt());
+ break;
case "coreRootDirectory":
builder.setCoreRootDirectory(it.txt());
break;
diff --git a/solr/core/src/java/org/apache/solr/handler/ContentStreamHandlerBase.java b/solr/core/src/java/org/apache/solr/handler/ContentStreamHandlerBase.java
index fb40af3c081..f28a7a6a6de 100644
--- a/solr/core/src/java/org/apache/solr/handler/ContentStreamHandlerBase.java
+++ b/solr/core/src/java/org/apache/solr/handler/ContentStreamHandlerBase.java
@@ -19,6 +19,7 @@
import static org.apache.solr.common.params.CommonParams.FAILURE;
import static org.apache.solr.common.params.CommonParams.STATUS;
+import java.lang.invoke.MethodHandles;
import java.util.List;
import org.apache.solr.client.solrj.SolrRequest.SolrRequestType;
import org.apache.solr.common.SolrException;
@@ -33,6 +34,8 @@
import org.apache.solr.update.processor.UpdateRequestProcessorChain;
import org.apache.solr.util.circuitbreaker.CircuitBreaker;
import org.apache.solr.util.circuitbreaker.CircuitBreakerRegistry;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
/**
* Shares common code between various handlers that manipulate {@link
@@ -40,6 +43,8 @@
*/
public abstract class ContentStreamHandlerBase extends RequestHandlerBase {
+ private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
+
@Override
public void init(NamedList> args) {
super.init(args);
@@ -119,6 +124,12 @@ public void handleRequestBody(SolrQueryRequest req, SolrQueryResponse rsp) throw
* @return true if circuit breakers are tripped, false otherwise.
*/
protected boolean checkCircuitBreakers(SolrQueryRequest req, SolrQueryResponse rsp) {
+ if (isInternalShardRequest(req)) {
+ if (log.isTraceEnabled()) {
+ log.trace("Internal request, skipping circuit breaker check");
+ }
+ return false;
+ }
CircuitBreakerRegistry circuitBreakerRegistry = req.getCore().getCircuitBreakerRegistry();
if (circuitBreakerRegistry.isEnabled(SolrRequestType.UPDATE)) {
List trippedCircuitBreakers =
diff --git a/solr/core/src/java/org/apache/solr/handler/ReplicationHandler.java b/solr/core/src/java/org/apache/solr/handler/ReplicationHandler.java
index ab40ff02543..096f81ee492 100644
--- a/solr/core/src/java/org/apache/solr/handler/ReplicationHandler.java
+++ b/solr/core/src/java/org/apache/solr/handler/ReplicationHandler.java
@@ -1804,11 +1804,10 @@ private static Long readIntervalNs(String interval) {
public static final String LEADER_URL = "leaderUrl";
- @Deprecated
/**
- * @deprecated: Only used for backwards compatibility. Use {@link #LEADER_URL}
+ * @deprecated Only used for backwards compatibility. Use {@link #LEADER_URL}
*/
- public static final String LEGACY_LEADER_URL = "masterUrl";
+ @Deprecated public static final String LEGACY_LEADER_URL = "masterUrl";
public static final String FETCH_FROM_LEADER = "fetchFromLeader";
@@ -1817,11 +1816,11 @@ private static Long readIntervalNs(String interval) {
// loss
public static final String SKIP_COMMIT_ON_LEADER_VERSION_ZERO = "skipCommitOnLeaderVersionZero";
- @Deprecated
/**
- * @deprecated: Only used for backwards compatibility. Use {@link
+ * @deprecated Only used for backwards compatibility. Use {@link
* #SKIP_COMMIT_ON_LEADER_VERSION_ZERO}
*/
+ @Deprecated
public static final String LEGACY_SKIP_COMMIT_ON_LEADER_VERSION_ZERO =
"skipCommitOnMasterVersionZero";
diff --git a/solr/core/src/java/org/apache/solr/handler/RequestHandlerBase.java b/solr/core/src/java/org/apache/solr/handler/RequestHandlerBase.java
index 3a3c89f2b8a..2c53eb26625 100644
--- a/solr/core/src/java/org/apache/solr/handler/RequestHandlerBase.java
+++ b/solr/core/src/java/org/apache/solr/handler/RequestHandlerBase.java
@@ -28,6 +28,7 @@
import org.apache.solr.api.ApiBag;
import org.apache.solr.api.ApiSupport;
import org.apache.solr.common.SolrException;
+import org.apache.solr.common.params.ShardParams;
import org.apache.solr.common.params.SolrParams;
import org.apache.solr.common.util.NamedList;
import org.apache.solr.common.util.SuppressForbidden;
@@ -44,6 +45,7 @@
import org.apache.solr.response.SolrQueryResponse;
import org.apache.solr.search.SyntaxError;
import org.apache.solr.security.PermissionNameProvider;
+import org.apache.solr.update.processor.DistributedUpdateProcessor;
import org.apache.solr.util.SolrPluginUtils;
import org.apache.solr.util.TestInjection;
import org.slf4j.Logger;
@@ -343,4 +345,16 @@ public Collection getApis() {
return Collections.singleton(
new ApiBag.ReqHandlerToApi(this, ApiBag.constructSpec(pluginInfo)));
}
+
+ /**
+ * Checks whether the given request is an internal request to a shard. We rely on the fact that an
+ * internal search request to a shard contains the param "isShard", and an internal update request
+ * to a shard contains the param "distrib.from".
+ *
+ * @return true if request is internal
+ */
+ public static boolean isInternalShardRequest(SolrQueryRequest req) {
+ return req.getParams().get(DistributedUpdateProcessor.DISTRIB_FROM) != null
+ || "true".equals(req.getParams().get(ShardParams.IS_SHARD));
+ }
}
diff --git a/solr/core/src/java/org/apache/solr/handler/admin/CoreAdminHandler.java b/solr/core/src/java/org/apache/solr/handler/admin/CoreAdminHandler.java
index 8ee1bf3254a..d928282df5c 100644
--- a/solr/core/src/java/org/apache/solr/handler/admin/CoreAdminHandler.java
+++ b/solr/core/src/java/org/apache/solr/handler/admin/CoreAdminHandler.java
@@ -383,7 +383,6 @@ public Collection getApis() {
apis.addAll(AnnotatedApi.getApis(new CreateCoreAPI(this)));
apis.addAll(AnnotatedApi.getApis(new RejoinLeaderElectionAPI(this)));
apis.addAll(AnnotatedApi.getApis(new OverseerOperationAPI(this)));
- apis.addAll(AnnotatedApi.getApis(new ReloadCoreAPI(this)));
apis.addAll(AnnotatedApi.getApis(new SwapCoresAPI(this)));
apis.addAll(AnnotatedApi.getApis(new RenameCoreAPI(this)));
apis.addAll(AnnotatedApi.getApis(new UnloadCoreAPI(this)));
@@ -403,7 +402,11 @@ public Collection getApis() {
@Override
public Collection> getJerseyResources() {
return List.of(
- CoreSnapshotAPI.class, InstallCoreDataAPI.class, BackupCoreAPI.class, RestoreCoreAPI.class);
+ CoreSnapshotAPI.class,
+ InstallCoreDataAPI.class,
+ BackupCoreAPI.class,
+ RestoreCoreAPI.class,
+ ReloadCoreAPI.class);
}
public interface CoreAdminOp {
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 31251759c76..987c79d376b 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
@@ -58,6 +58,7 @@
import java.nio.file.Path;
import java.util.Locale;
import java.util.Map;
+import org.apache.solr.client.api.model.SolrJerseyResponse;
import org.apache.solr.cloud.ZkController;
import org.apache.solr.common.SolrException;
import org.apache.solr.common.SolrException.ErrorCode;
@@ -72,6 +73,7 @@
import org.apache.solr.core.SolrCore;
import org.apache.solr.handler.admin.CoreAdminHandler.CoreAdminOp;
import org.apache.solr.handler.admin.api.CoreSnapshotAPI;
+import org.apache.solr.handler.admin.api.ReloadCoreAPI;
import org.apache.solr.handler.api.V2ApiUtils;
import org.apache.solr.search.SolrIndexSearcher;
import org.apache.solr.update.UpdateLog;
@@ -133,7 +135,13 @@ public enum CoreAdminOperation implements CoreAdminOp {
SolrParams params = it.req.getParams();
String cname = params.required().get(CoreAdminParams.CORE);
- it.handler.coreContainer.reload(cname);
+ ReloadCoreAPI reloadCoreAPI =
+ new ReloadCoreAPI(
+ it.req, it.rsp, it.handler.coreContainer, it.handler.getCoreAdminAsyncTracker());
+ ReloadCoreAPI.ReloadCoreRequestBody reloadCoreRequestBody =
+ new ReloadCoreAPI.ReloadCoreRequestBody();
+ SolrJerseyResponse response = reloadCoreAPI.reloadCore(cname, reloadCoreRequestBody);
+ V2ApiUtils.squashIntoSolrResponseWithoutHeader(it.rsp, response);
}),
STATUS_OP(STATUS, new StatusOp()),
SWAP_OP(
diff --git a/solr/core/src/java/org/apache/solr/handler/admin/PrepRecoveryOp.java b/solr/core/src/java/org/apache/solr/handler/admin/PrepRecoveryOp.java
index df9453d3da6..d56dbb6506f 100644
--- a/solr/core/src/java/org/apache/solr/handler/admin/PrepRecoveryOp.java
+++ b/solr/core/src/java/org/apache/solr/handler/admin/PrepRecoveryOp.java
@@ -20,7 +20,6 @@
import java.lang.invoke.MethodHandles;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
-import java.util.concurrent.atomic.AtomicReference;
import org.apache.solr.cloud.CloudDescriptor;
import org.apache.solr.cloud.ZkController.NotInClusterStateException;
import org.apache.solr.cloud.ZkShardTerms;
@@ -75,7 +74,6 @@ public void execute(CallInfo it) throws Exception {
collectionName = core.getCoreDescriptor().getCloudDescriptor().getCollectionName();
cloudDescriptor = core.getCoreDescriptor().getCloudDescriptor();
}
- AtomicReference errorMessage = new AtomicReference<>();
try {
coreContainer
.getZkController()
@@ -201,9 +199,8 @@ public void execute(CallInfo it) throws Exception {
return false;
});
} catch (TimeoutException | InterruptedException e) {
- String error = errorMessage.get();
- if (error == null) error = "Timeout waiting for collection state.";
- throw new NotInClusterStateException(ErrorCode.SERVER_ERROR, error);
+ throw new NotInClusterStateException(
+ ErrorCode.SERVER_ERROR, "Timeout waiting for collection state.");
}
}
}
diff --git a/solr/core/src/java/org/apache/solr/handler/admin/api/ReloadCoreAPI.java b/solr/core/src/java/org/apache/solr/handler/admin/api/ReloadCoreAPI.java
index e330d713340..b0252b83fa9 100644
--- a/solr/core/src/java/org/apache/solr/handler/admin/api/ReloadCoreAPI.java
+++ b/solr/core/src/java/org/apache/solr/handler/admin/api/ReloadCoreAPI.java
@@ -17,52 +17,69 @@
package org.apache.solr.handler.admin.api;
-import static org.apache.solr.client.solrj.SolrRequest.METHOD.POST;
-import static org.apache.solr.common.params.CommonParams.ACTION;
-import static org.apache.solr.handler.ClusterAPI.wrapParams;
+import static org.apache.solr.client.solrj.impl.BinaryResponseParser.BINARY_CONTENT_TYPE_V2;
import static org.apache.solr.security.PermissionNameProvider.Name.CORE_EDIT_PERM;
-import java.util.HashMap;
-import java.util.Locale;
-import java.util.Map;
-import org.apache.solr.api.Command;
-import org.apache.solr.api.EndPoint;
-import org.apache.solr.api.PayloadObj;
-import org.apache.solr.common.params.CoreAdminParams;
-import org.apache.solr.common.util.ReflectMapWriter;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.media.Schema;
+import io.swagger.v3.oas.annotations.parameters.RequestBody;
+import javax.inject.Inject;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import org.apache.solr.client.api.model.SolrJerseyResponse;
+import org.apache.solr.core.CoreContainer;
import org.apache.solr.handler.admin.CoreAdminHandler;
+import org.apache.solr.jersey.JacksonReflectMapWriter;
+import org.apache.solr.jersey.PermissionName;
+import org.apache.solr.request.SolrQueryRequest;
+import org.apache.solr.response.SolrQueryResponse;
/**
* V2 API for reloading an individual core.
*
- *
The new API (POST /v2/cores/coreName {'reload': {...}}) is equivalent to the v1
- * /admin/cores?action=reload command.
- *
- * @see ReloadCorePayload
+ *
The new API (POST /v2/cores/coreName/reload is analogous to the v1 /admin/cores?action=RELOAD
+ * command.
*/
-@EndPoint(
- path = {"/cores/{core}"},
- method = POST,
- permission = CORE_EDIT_PERM)
-public class ReloadCoreAPI {
- private static final String V2_RELOAD_CORE_CMD = "reload";
-
- private final CoreAdminHandler coreHandler;
+@Path("/cores/{coreName}/reload")
+public class ReloadCoreAPI extends CoreAdminAPIBase {
- public ReloadCoreAPI(CoreAdminHandler coreHandler) {
- this.coreHandler = coreHandler;
+ @Inject
+ public ReloadCoreAPI(
+ SolrQueryRequest solrQueryRequest,
+ SolrQueryResponse solrQueryResponse,
+ CoreContainer coreContainer,
+ CoreAdminHandler.CoreAdminAsyncTracker coreAdminAsyncTracker) {
+ super(coreContainer, coreAdminAsyncTracker, solrQueryRequest, solrQueryResponse);
}
- @Command(name = V2_RELOAD_CORE_CMD)
- public void reloadCore(PayloadObj obj) throws Exception {
- final String coreName = obj.getRequest().getPathTemplateValues().get(CoreAdminParams.CORE);
-
- final Map v1Params = new HashMap<>();
- v1Params.put(ACTION, CoreAdminParams.CoreAdminAction.RELOAD.name().toLowerCase(Locale.ROOT));
- v1Params.put(CoreAdminParams.CORE, coreName);
-
- coreHandler.handleRequestBody(wrapParams(obj.getRequest(), v1Params), obj.getResponse());
+ @POST
+ @Produces({"application/json", "application/xml", BINARY_CONTENT_TYPE_V2})
+ @PermissionName(CORE_EDIT_PERM)
+ public SolrJerseyResponse reloadCore(
+ @Parameter(description = "The name of the core to reload.", required = true)
+ @PathParam("coreName")
+ String coreName,
+ @Schema(description = "Additional parameters for reloading the core") @RequestBody
+ ReloadCoreAPI.ReloadCoreRequestBody reloadCoreRequestBody)
+ throws Exception {
+ SolrJerseyResponse solrJerseyResponse = instantiateJerseyResponse(SolrJerseyResponse.class);
+ return handlePotentiallyAsynchronousTask(
+ solrJerseyResponse,
+ coreName,
+ (reloadCoreRequestBody == null) ? null : reloadCoreRequestBody.async,
+ "reload",
+ () -> {
+ coreContainer.reload(coreName);
+ return solrJerseyResponse;
+ });
}
- public static class ReloadCorePayload implements ReflectMapWriter {}
+ public static class ReloadCoreRequestBody implements JacksonReflectMapWriter {
+ @Schema(description = "Request ID to track this action which will be processed asynchronously.")
+ @JsonProperty("async")
+ public String async;
+ }
}
diff --git a/solr/core/src/java/org/apache/solr/handler/component/FieldFacetStats.java b/solr/core/src/java/org/apache/solr/handler/component/FieldFacetStats.java
index 8c0201be2d0..2b0926ba2ee 100644
--- a/solr/core/src/java/org/apache/solr/handler/component/FieldFacetStats.java
+++ b/solr/core/src/java/org/apache/solr/handler/component/FieldFacetStats.java
@@ -190,6 +190,5 @@ public void accumulateMissing() throws IOException {
}
}
}
- return;
}
}
diff --git a/solr/core/src/java/org/apache/solr/handler/component/QueryElevationComponent.java b/solr/core/src/java/org/apache/solr/handler/component/QueryElevationComponent.java
index 3d5b7eb28af..61816a7c5f1 100644
--- a/solr/core/src/java/org/apache/solr/handler/component/QueryElevationComponent.java
+++ b/solr/core/src/java/org/apache/solr/handler/component/QueryElevationComponent.java
@@ -329,8 +329,7 @@ protected ElevationProvider handleConfigLoadingException(E
*
* @return The cached or loaded {@link ElevationProvider}.
*/
- @VisibleForTesting
- ElevationProvider getElevationProvider(IndexReader reader, SolrCore core) {
+ protected ElevationProvider getElevationProvider(IndexReader reader, SolrCore core) {
synchronized (LOCK) {
if (cacheElevationProvider != null && Objects.equals(cacheIndexReader.get(), reader)) {
return cacheElevationProvider; // cache hit !
@@ -377,7 +376,8 @@ protected long getConfigVersion(SolrCore core) {
*
* @return The loaded {@link ElevationProvider}; not null.
*/
- private ElevationProvider loadElevationProvider(SolrCore core) throws IOException, SAXException {
+ protected ElevationProvider loadElevationProvider(SolrCore core)
+ throws IOException, SAXException {
Document xmlDocument;
try {
xmlDocument = SafeXMLParsing.parseConfigXML(log, core.getResourceLoader(), configFileName);
diff --git a/solr/core/src/java/org/apache/solr/handler/component/RealTimeGetComponent.java b/solr/core/src/java/org/apache/solr/handler/component/RealTimeGetComponent.java
index 7944f4840ce..a34cd99d8be 100644
--- a/solr/core/src/java/org/apache/solr/handler/component/RealTimeGetComponent.java
+++ b/solr/core/src/java/org/apache/solr/handler/component/RealTimeGetComponent.java
@@ -81,6 +81,7 @@
import org.apache.solr.schema.IndexSchema;
import org.apache.solr.schema.SchemaField;
import org.apache.solr.search.DocList;
+import org.apache.solr.search.DocValuesIteratorCache;
import org.apache.solr.search.QueryUtils;
import org.apache.solr.search.ReturnFields;
import org.apache.solr.search.SolrDocumentFetcher;
@@ -238,6 +239,7 @@ public void process(ResponseBuilder rb) throws IOException {
boolean opennedRealtimeSearcher = false;
BytesRefBuilder idBytes = new BytesRefBuilder();
+ DocValuesIteratorCache reuseDvIters = null;
for (String idStr : reqIds.allIds) {
fieldType.readableToIndexed(idStr, idBytes);
// if _route_ is passed, id is a child doc. TODO remove in SOLR-15064
@@ -348,7 +350,11 @@ public void process(ResponseBuilder rb) throws IOException {
searcherInfo.getSearcher().doc(docid, rsp.getReturnFields().getLuceneFieldNames());
SolrDocument doc = toSolrDoc(luceneDocument, core.getLatestSchema());
SolrDocumentFetcher docFetcher = searcherInfo.getSearcher().getDocFetcher();
- docFetcher.decorateDocValueFields(doc, docid, docFetcher.getNonStoredDVs(true));
+ if (reuseDvIters == null) {
+ reuseDvIters = new DocValuesIteratorCache(searcherInfo.getSearcher());
+ }
+ docFetcher.decorateDocValueFields(
+ doc, docid, docFetcher.getNonStoredDVs(true), reuseDvIters);
if (null != transformer) {
if (null == resultContext) {
// either first pass, or we've re-opened searcher - either way now we setContext
@@ -575,7 +581,11 @@ private static SolrDocument mergePartialDocWithFullDocFromIndex(
if (!doc.containsKey(VERSION_FIELD)) {
searcher
.getDocFetcher()
- .decorateDocValueFields(doc, docid, Collections.singleton(VERSION_FIELD));
+ .decorateDocValueFields(
+ doc,
+ docid,
+ Collections.singleton(VERSION_FIELD),
+ new DocValuesIteratorCache(searcher, false));
}
long docVersion = (long) doc.getFirstValue(VERSION_FIELD);
diff --git a/solr/core/src/java/org/apache/solr/handler/component/SearchHandler.java b/solr/core/src/java/org/apache/solr/handler/component/SearchHandler.java
index 995e6a3c684..744d6093222 100644
--- a/solr/core/src/java/org/apache/solr/handler/component/SearchHandler.java
+++ b/solr/core/src/java/org/apache/solr/handler/component/SearchHandler.java
@@ -357,6 +357,12 @@ protected ResponseBuilder newResponseBuilder(
*/
protected boolean checkCircuitBreakers(
SolrQueryRequest req, SolrQueryResponse rsp, ResponseBuilder rb) {
+ if (isInternalShardRequest(req)) {
+ if (log.isTraceEnabled()) {
+ log.trace("Internal request, skipping circuit breaker check");
+ }
+ return false;
+ }
final RTimerTree timer = rb.isDebug() ? req.getRequestTimer() : null;
final CircuitBreakerRegistry circuitBreakerRegistry = req.getCore().getCircuitBreakerRegistry();
diff --git a/solr/core/src/java/org/apache/solr/handler/export/BoolFieldWriter.java b/solr/core/src/java/org/apache/solr/handler/export/BoolFieldWriter.java
index fbeccdc4c0d..cf32497b5d7 100644
--- a/solr/core/src/java/org/apache/solr/handler/export/BoolFieldWriter.java
+++ b/solr/core/src/java/org/apache/solr/handler/export/BoolFieldWriter.java
@@ -21,10 +21,14 @@
import org.apache.lucene.util.BytesRef;
import org.apache.solr.common.MapWriter;
import org.apache.solr.schema.FieldType;
+import org.apache.solr.search.DocValuesIteratorCache;
class BoolFieldWriter extends StringFieldWriter {
- public BoolFieldWriter(String field, FieldType fieldType) {
- super(field, fieldType);
+ public BoolFieldWriter(
+ String field,
+ FieldType fieldType,
+ DocValuesIteratorCache.FieldDocValuesSupplier docValuesCache) {
+ super(field, fieldType, docValuesCache);
}
@Override
diff --git a/solr/core/src/java/org/apache/solr/handler/export/DateFieldWriter.java b/solr/core/src/java/org/apache/solr/handler/export/DateFieldWriter.java
index c86f0eacac1..7e32e98d5b8 100644
--- a/solr/core/src/java/org/apache/solr/handler/export/DateFieldWriter.java
+++ b/solr/core/src/java/org/apache/solr/handler/export/DateFieldWriter.java
@@ -17,58 +17,19 @@
package org.apache.solr.handler.export;
-import com.carrotsearch.hppc.IntObjectHashMap;
import java.io.IOException;
import java.util.Date;
-import org.apache.lucene.index.DocValues;
-import org.apache.lucene.index.LeafReaderContext;
-import org.apache.lucene.index.NumericDocValues;
import org.apache.solr.common.MapWriter;
+import org.apache.solr.search.DocValuesIteratorCache;
-class DateFieldWriter extends FieldWriter {
- private String field;
- private IntObjectHashMap docValuesCache = new IntObjectHashMap<>();
-
- public DateFieldWriter(String field) {
- this.field = field;
+class DateFieldWriter extends LongFieldWriter {
+ public DateFieldWriter(
+ String field, DocValuesIteratorCache.FieldDocValuesSupplier docValuesCache) {
+ super(field, docValuesCache);
}
@Override
- public boolean write(
- SortDoc sortDoc, LeafReaderContext readerContext, MapWriter.EntryWriter ew, int fieldIndex)
- throws IOException {
- Long val;
- SortValue sortValue = sortDoc.getSortValue(this.field);
- if (sortValue != null) {
- if (sortValue.isPresent()) {
- val = (long) sortValue.getCurrentValue();
- } else { // empty-value
- return false;
- }
- } else {
- // field is not part of 'sort' param, but part of 'fl' param
- int readerOrd = readerContext.ord;
- NumericDocValues vals = null;
- if (docValuesCache.containsKey(readerOrd)) {
- NumericDocValues numericDocValues = docValuesCache.get(readerOrd);
- if (numericDocValues.docID() < sortDoc.docId) {
- // We have not advanced beyond the current docId so we can use this docValues.
- vals = numericDocValues;
- }
- }
-
- if (vals == null) {
- vals = DocValues.getNumeric(readerContext.reader(), this.field);
- docValuesCache.put(readerOrd, vals);
- }
-
- if (vals.advance(sortDoc.docId) == sortDoc.docId) {
- val = vals.longValue();
- } else {
- return false;
- }
- }
- ew.put(this.field, new Date(val));
- return true;
+ protected void doWrite(MapWriter.EntryWriter ew, long val) throws IOException {
+ ew.put(field, new Date(val));
}
}
diff --git a/solr/core/src/java/org/apache/solr/handler/export/DoubleFieldWriter.java b/solr/core/src/java/org/apache/solr/handler/export/DoubleFieldWriter.java
index 50cbdddb385..e439560894b 100644
--- a/solr/core/src/java/org/apache/solr/handler/export/DoubleFieldWriter.java
+++ b/solr/core/src/java/org/apache/solr/handler/export/DoubleFieldWriter.java
@@ -17,57 +17,46 @@
package org.apache.solr.handler.export;
-import com.carrotsearch.hppc.IntObjectHashMap;
import java.io.IOException;
-import org.apache.lucene.index.DocValues;
import org.apache.lucene.index.LeafReaderContext;
import org.apache.lucene.index.NumericDocValues;
import org.apache.solr.common.MapWriter;
+import org.apache.solr.search.DocValuesIteratorCache;
class DoubleFieldWriter extends FieldWriter {
- private String field;
- private IntObjectHashMap docValuesCache = new IntObjectHashMap<>();
+ private final String field;
+ private final DocValuesIteratorCache.FieldDocValuesSupplier docValuesCache;
- public DoubleFieldWriter(String field) {
+ public DoubleFieldWriter(
+ String field, DocValuesIteratorCache.FieldDocValuesSupplier docValuesCache) {
this.field = field;
+ this.docValuesCache = docValuesCache;
}
@Override
public boolean write(
SortDoc sortDoc, LeafReaderContext readerContext, MapWriter.EntryWriter ew, int fieldIndex)
throws IOException {
+ double val;
SortValue sortValue = sortDoc.getSortValue(this.field);
if (sortValue != null) {
if (sortValue.isPresent()) {
- double val = (double) sortValue.getCurrentValue();
- ew.put(this.field, val);
- return true;
+ val = (double) sortValue.getCurrentValue();
} else { // empty-value
return false;
}
} else {
// field is not part of 'sort' param, but part of 'fl' param
- int readerOrd = readerContext.ord;
- NumericDocValues vals = null;
- if (docValuesCache.containsKey(readerOrd)) {
- NumericDocValues numericDocValues = docValuesCache.get(readerOrd);
- if (numericDocValues.docID() < sortDoc.docId) {
- // We have not advanced beyond the current docId so we can use this docValues.
- vals = numericDocValues;
- }
- }
-
- if (vals == null) {
- vals = DocValues.getNumeric(readerContext.reader(), this.field);
- docValuesCache.put(readerOrd, vals);
- }
- if (vals.advance(sortDoc.docId) == sortDoc.docId) {
- long val = vals.longValue();
- ew.put(this.field, Double.longBitsToDouble(val));
- return true;
+ NumericDocValues vals =
+ docValuesCache.getNumericDocValues(
+ sortDoc.docId, readerContext.reader(), readerContext.ord);
+ if (vals != null) {
+ val = Double.longBitsToDouble(vals.longValue());
} else {
return false;
}
}
+ ew.put(this.field, val);
+ return true;
}
}
diff --git a/solr/core/src/java/org/apache/solr/handler/export/ExportWriter.java b/solr/core/src/java/org/apache/solr/handler/export/ExportWriter.java
index 8f38c94942e..51ba5551b69 100644
--- a/solr/core/src/java/org/apache/solr/handler/export/ExportWriter.java
+++ b/solr/core/src/java/org/apache/solr/handler/export/ExportWriter.java
@@ -74,6 +74,7 @@
import org.apache.solr.schema.SchemaField;
import org.apache.solr.schema.SortableTextField;
import org.apache.solr.schema.StrField;
+import org.apache.solr.search.DocValuesIteratorCache;
import org.apache.solr.search.SolrIndexSearcher;
import org.apache.solr.search.SortSpec;
import org.apache.solr.search.SyntaxError;
@@ -99,6 +100,14 @@ public class ExportWriter implements SolrCore.RawWriter, Closeable {
public static final int DEFAULT_BATCH_SIZE = 30000;
public static final int DEFAULT_QUEUE_SIZE = 150000;
+ private static final FieldWriter EMPTY_FIELD_WRITER =
+ new FieldWriter() {
+ @Override
+ public boolean write(
+ SortDoc sortDoc, LeafReaderContext readerContext, EntryWriter out, int fieldIndex) {
+ return false;
+ }
+ };
private OutputStreamWriter respWriter;
final SolrQueryRequest req;
@@ -480,6 +489,7 @@ public FieldWriter[] getFieldWriters(String[] fields, SolrIndexSearcher searcher
throws IOException {
IndexSchema schema = searcher.getSchema();
FieldWriter[] writers = new FieldWriter[fields.length];
+ DocValuesIteratorCache dvIterCache = new DocValuesIteratorCache(searcher, false);
for (int i = 0; i < fields.length; i++) {
String field = fields[i];
SchemaField schemaField = null;
@@ -501,47 +511,51 @@ public FieldWriter[] getFieldWriters(String[] fields, SolrIndexSearcher searcher
schemaField + " Must have useDocValuesAsStored='true' to be used with export writer");
}
- if (fieldType instanceof IntValueFieldType) {
+ DocValuesIteratorCache.FieldDocValuesSupplier docValuesCache = dvIterCache.getSupplier(field);
+
+ if (docValuesCache == null) {
+ writers[i] = EMPTY_FIELD_WRITER;
+ } else if (fieldType instanceof IntValueFieldType) {
if (multiValued) {
- writers[i] = new MultiFieldWriter(field, fieldType, schemaField, true);
+ writers[i] = new MultiFieldWriter(field, fieldType, schemaField, true, docValuesCache);
} else {
- writers[i] = new IntFieldWriter(field);
+ writers[i] = new IntFieldWriter(field, docValuesCache);
}
} else if (fieldType instanceof LongValueFieldType) {
if (multiValued) {
- writers[i] = new MultiFieldWriter(field, fieldType, schemaField, true);
+ writers[i] = new MultiFieldWriter(field, fieldType, schemaField, true, docValuesCache);
} else {
- writers[i] = new LongFieldWriter(field);
+ writers[i] = new LongFieldWriter(field, docValuesCache);
}
} else if (fieldType instanceof FloatValueFieldType) {
if (multiValued) {
- writers[i] = new MultiFieldWriter(field, fieldType, schemaField, true);
+ writers[i] = new MultiFieldWriter(field, fieldType, schemaField, true, docValuesCache);
} else {
- writers[i] = new FloatFieldWriter(field);
+ writers[i] = new FloatFieldWriter(field, docValuesCache);
}
} else if (fieldType instanceof DoubleValueFieldType) {
if (multiValued) {
- writers[i] = new MultiFieldWriter(field, fieldType, schemaField, true);
+ writers[i] = new MultiFieldWriter(field, fieldType, schemaField, true, docValuesCache);
} else {
- writers[i] = new DoubleFieldWriter(field);
+ writers[i] = new DoubleFieldWriter(field, docValuesCache);
}
} else if (fieldType instanceof StrField || fieldType instanceof SortableTextField) {
if (multiValued) {
- writers[i] = new MultiFieldWriter(field, fieldType, schemaField, false);
+ writers[i] = new MultiFieldWriter(field, fieldType, schemaField, false, docValuesCache);
} else {
- writers[i] = new StringFieldWriter(field, fieldType);
+ writers[i] = new StringFieldWriter(field, fieldType, docValuesCache);
}
} else if (fieldType instanceof DateValueFieldType) {
if (multiValued) {
- writers[i] = new MultiFieldWriter(field, fieldType, schemaField, false);
+ writers[i] = new MultiFieldWriter(field, fieldType, schemaField, false, docValuesCache);
} else {
- writers[i] = new DateFieldWriter(field);
+ writers[i] = new DateFieldWriter(field, docValuesCache);
}
} else if (fieldType instanceof BoolField) {
if (multiValued) {
- writers[i] = new MultiFieldWriter(field, fieldType, schemaField, true);
+ writers[i] = new MultiFieldWriter(field, fieldType, schemaField, true, docValuesCache);
} else {
- writers[i] = new BoolFieldWriter(field, fieldType);
+ writers[i] = new BoolFieldWriter(field, fieldType, docValuesCache);
}
} else {
throw new IOException(
diff --git a/solr/core/src/java/org/apache/solr/handler/export/FloatFieldWriter.java b/solr/core/src/java/org/apache/solr/handler/export/FloatFieldWriter.java
index 48bd9d632ed..a60c14e6b0a 100644
--- a/solr/core/src/java/org/apache/solr/handler/export/FloatFieldWriter.java
+++ b/solr/core/src/java/org/apache/solr/handler/export/FloatFieldWriter.java
@@ -17,58 +17,46 @@
package org.apache.solr.handler.export;
-import com.carrotsearch.hppc.IntObjectHashMap;
import java.io.IOException;
-import org.apache.lucene.index.DocValues;
import org.apache.lucene.index.LeafReaderContext;
import org.apache.lucene.index.NumericDocValues;
import org.apache.solr.common.MapWriter;
+import org.apache.solr.search.DocValuesIteratorCache;
class FloatFieldWriter extends FieldWriter {
- private String field;
- private IntObjectHashMap docValuesCache = new IntObjectHashMap<>();
+ private final String field;
+ private final DocValuesIteratorCache.FieldDocValuesSupplier docValuesCache;
- public FloatFieldWriter(String field) {
+ public FloatFieldWriter(
+ String field, DocValuesIteratorCache.FieldDocValuesSupplier docValuesCache) {
this.field = field;
+ this.docValuesCache = docValuesCache;
}
@Override
public boolean write(
SortDoc sortDoc, LeafReaderContext readerContext, MapWriter.EntryWriter ew, int fieldIndex)
throws IOException {
+ float val;
SortValue sortValue = sortDoc.getSortValue(this.field);
if (sortValue != null) {
if (sortValue.isPresent()) {
- float val = (float) sortValue.getCurrentValue();
- ew.put(this.field, val);
- return true;
+ val = (float) sortValue.getCurrentValue();
} else { // empty-value
return false;
}
} else {
// field is not part of 'sort' param, but part of 'fl' param
- int readerOrd = readerContext.ord;
- NumericDocValues vals = null;
- if (docValuesCache.containsKey(readerOrd)) {
- NumericDocValues numericDocValues = docValuesCache.get(readerOrd);
- if (numericDocValues.docID() < sortDoc.docId) {
- // We have not advanced beyond the current docId so we can use this docValues.
- vals = numericDocValues;
- }
- }
-
- if (vals == null) {
- vals = DocValues.getNumeric(readerContext.reader(), this.field);
- docValuesCache.put(readerOrd, vals);
- }
-
- if (vals.advance(sortDoc.docId) == sortDoc.docId) {
- int val = (int) vals.longValue();
- ew.put(this.field, Float.intBitsToFloat(val));
- return true;
+ NumericDocValues vals =
+ docValuesCache.getNumericDocValues(
+ sortDoc.docId, readerContext.reader(), readerContext.ord);
+ if (vals != null) {
+ val = Float.intBitsToFloat((int) vals.longValue());
} else {
return false;
}
}
+ ew.put(this.field, val);
+ return true;
}
}
diff --git a/solr/core/src/java/org/apache/solr/handler/export/IntFieldWriter.java b/solr/core/src/java/org/apache/solr/handler/export/IntFieldWriter.java
index 1ecef85f21b..bf0396d4ab8 100644
--- a/solr/core/src/java/org/apache/solr/handler/export/IntFieldWriter.java
+++ b/solr/core/src/java/org/apache/solr/handler/export/IntFieldWriter.java
@@ -17,19 +17,20 @@
package org.apache.solr.handler.export;
-import com.carrotsearch.hppc.IntObjectHashMap;
import java.io.IOException;
-import org.apache.lucene.index.DocValues;
import org.apache.lucene.index.LeafReaderContext;
import org.apache.lucene.index.NumericDocValues;
import org.apache.solr.common.MapWriter;
+import org.apache.solr.search.DocValuesIteratorCache;
class IntFieldWriter extends FieldWriter {
- private String field;
- private IntObjectHashMap docValuesCache = new IntObjectHashMap<>();
+ private final String field;
+ private final DocValuesIteratorCache.FieldDocValuesSupplier docValuesCache;
- public IntFieldWriter(String field) {
+ public IntFieldWriter(
+ String field, DocValuesIteratorCache.FieldDocValuesSupplier docValuesCache) {
this.field = field;
+ this.docValuesCache = docValuesCache;
}
@Override
@@ -46,22 +47,10 @@ public boolean write(
}
} else {
// field is not part of 'sort' param, but part of 'fl' param
- int readerOrd = readerContext.ord;
- NumericDocValues vals = null;
- if (docValuesCache.containsKey(readerOrd)) {
- NumericDocValues numericDocValues = docValuesCache.get(readerOrd);
- if (numericDocValues.docID() < sortDoc.docId) {
- // We have not advanced beyond the current docId so we can use this docValues.
- vals = numericDocValues;
- }
- }
-
- if (vals == null) {
- vals = DocValues.getNumeric(readerContext.reader(), this.field);
- docValuesCache.put(readerOrd, vals);
- }
-
- if (vals.advance(sortDoc.docId) == sortDoc.docId) {
+ NumericDocValues vals =
+ docValuesCache.getNumericDocValues(
+ sortDoc.docId, readerContext.reader(), readerContext.ord);
+ if (vals != null) {
val = (int) vals.longValue();
} else {
return false;
diff --git a/solr/core/src/java/org/apache/solr/handler/export/LongFieldWriter.java b/solr/core/src/java/org/apache/solr/handler/export/LongFieldWriter.java
index 9c18a72bd6d..7961549477c 100644
--- a/solr/core/src/java/org/apache/solr/handler/export/LongFieldWriter.java
+++ b/solr/core/src/java/org/apache/solr/handler/export/LongFieldWriter.java
@@ -17,20 +17,21 @@
package org.apache.solr.handler.export;
-import com.carrotsearch.hppc.IntObjectHashMap;
import java.io.IOException;
-import org.apache.lucene.index.DocValues;
import org.apache.lucene.index.LeafReaderContext;
import org.apache.lucene.index.NumericDocValues;
import org.apache.solr.common.MapWriter;
+import org.apache.solr.search.DocValuesIteratorCache;
class LongFieldWriter extends FieldWriter {
- private String field;
+ protected final String field;
- private IntObjectHashMap docValuesCache = new IntObjectHashMap<>();
+ private final DocValuesIteratorCache.FieldDocValuesSupplier docValuesCache;
- public LongFieldWriter(String field) {
+ public LongFieldWriter(
+ String field, DocValuesIteratorCache.FieldDocValuesSupplier docValuesCache) {
this.field = field;
+ this.docValuesCache = docValuesCache;
}
@Override
@@ -47,28 +48,20 @@ public boolean write(
}
} else {
// field is not part of 'sort' param, but part of 'fl' param
- int readerOrd = readerContext.ord;
- NumericDocValues vals = null;
- if (docValuesCache.containsKey(readerOrd)) {
- NumericDocValues numericDocValues = docValuesCache.get(readerOrd);
- if (numericDocValues.docID() < sortDoc.docId) {
- // We have not advanced beyond the current docId so we can use this docValues.
- vals = numericDocValues;
- }
- }
-
- if (vals == null) {
- vals = DocValues.getNumeric(readerContext.reader(), this.field);
- docValuesCache.put(readerOrd, vals);
- }
-
- if (vals.advance(sortDoc.docId) == sortDoc.docId) {
+ NumericDocValues vals =
+ docValuesCache.getNumericDocValues(
+ sortDoc.docId, readerContext.reader(), readerContext.ord);
+ if (vals != null) {
val = vals.longValue();
} else {
return false;
}
}
- ew.put(field, val);
+ doWrite(ew, val);
return true;
}
+
+ protected void doWrite(MapWriter.EntryWriter ew, long val) throws IOException {
+ ew.put(field, val);
+ }
}
diff --git a/solr/core/src/java/org/apache/solr/handler/export/MultiFieldWriter.java b/solr/core/src/java/org/apache/solr/handler/export/MultiFieldWriter.java
index 86dd8ba82e3..7f5bdee4899 100644
--- a/solr/core/src/java/org/apache/solr/handler/export/MultiFieldWriter.java
+++ b/solr/core/src/java/org/apache/solr/handler/export/MultiFieldWriter.java
@@ -17,11 +17,9 @@
package org.apache.solr.handler.export;
-import com.carrotsearch.hppc.IntObjectHashMap;
import java.io.IOException;
import java.util.Date;
import java.util.function.LongFunction;
-import org.apache.lucene.index.DocValues;
import org.apache.lucene.index.IndexableField;
import org.apache.lucene.index.LeafReaderContext;
import org.apache.lucene.index.SortedNumericDocValues;
@@ -33,18 +31,23 @@
import org.apache.solr.common.MapWriter;
import org.apache.solr.schema.FieldType;
import org.apache.solr.schema.SchemaField;
+import org.apache.solr.search.DocValuesIteratorCache;
class MultiFieldWriter extends FieldWriter {
- private String field;
- private FieldType fieldType;
- private SchemaField schemaField;
- private boolean numeric;
- private CharsRefBuilder cref = new CharsRefBuilder();
+ private final String field;
+ private final FieldType fieldType;
+ private final SchemaField schemaField;
+ private final boolean numeric;
+ private final CharsRefBuilder cref = new CharsRefBuilder();
private final LongFunction