Skip to content

Commit f468120

Browse files
SOLR-17261: Allow cores to load without a timeout (#2431)
ExecutorUtil once again has the ability to wait for an ExecutorService to terminate without a timeout.
1 parent b7d4ef8 commit f468120

File tree

3 files changed

+55
-2
lines changed

3 files changed

+55
-2
lines changed

solr/CHANGES.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,8 @@ Bug Fixes
115115
---------------------
116116
* SOLR-12813: subqueries should respect basic auth. (Rudy Seitz via Eric Pugh)
117117

118+
* SOLR-17261: Remove unintended timeout of 60 seconds for core loading. (Houston Putman)
119+
118120
Dependency Upgrades
119121
---------------------
120122
(No changes)

solr/core/src/java/org/apache/solr/core/CoreContainer.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1081,9 +1081,9 @@ private void loadInternal() {
10811081
} finally {
10821082
if (asyncSolrCoreLoad) {
10831083
coreContainerWorkExecutor.submit(
1084-
() -> ExecutorUtil.shutdownAndAwaitTermination(coreLoadExecutor));
1084+
() -> ExecutorUtil.shutdownAndAwaitTerminationForever(coreLoadExecutor));
10851085
} else {
1086-
ExecutorUtil.shutdownAndAwaitTermination(coreLoadExecutor);
1086+
ExecutorUtil.shutdownAndAwaitTerminationForever(coreLoadExecutor);
10871087
}
10881088
}
10891089

solr/solrj/src/java/org/apache/solr/common/util/ExecutorUtil.java

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,18 +106,48 @@ public static boolean isTerminated(ExecutorService pool) {
106106
}
107107
}
108108

109+
/**
110+
* Shutdown the {@link ExecutorService} and wait for 60 seconds for the threads to complete. More
111+
* detail on the waiting can be found in {@link #awaitTermination(ExecutorService)}.
112+
*
113+
* @param pool The ExecutorService to shutdown and wait on
114+
*/
109115
public static void shutdownAndAwaitTermination(ExecutorService pool) {
110116
if (pool == null) return;
111117
pool.shutdown(); // Disable new tasks from being submitted
112118
awaitTermination(pool);
113119
}
114120

121+
/**
122+
* Shutdown the {@link ExecutorService} and wait forever for the threads to complete. More detail
123+
* on the waiting can be found in {@link #awaitTerminationForever(ExecutorService)}.
124+
*
125+
* <p>This should likely not be used in {@code close()} methods, as we want to timebound when
126+
* shutting down. However, sometimes {@link ExecutorService}s are used to submit a list of tasks
127+
* and awaiting termination is akin to waiting on the list of {@link Future}s to complete. In that
128+
* case, this method should be used as there is no inherent time bound to waiting on those tasks
129+
* to complete.
130+
*
131+
* @param pool The ExecutorService to shutdown and wait on
132+
*/
133+
public static void shutdownAndAwaitTerminationForever(ExecutorService pool) {
134+
if (pool == null) return;
135+
pool.shutdown(); // Disable new tasks from being submitted
136+
awaitTerminationForever(pool);
137+
}
138+
115139
public static void shutdownNowAndAwaitTermination(ExecutorService pool) {
116140
if (pool == null) return;
117141
pool.shutdownNow(); // Disable new tasks from being submitted; interrupt existing tasks
118142
awaitTermination(pool);
119143
}
120144

145+
/**
146+
* Await the termination of an {@link ExecutorService} for a default of 60 seconds, then force
147+
* shutdown the remaining threads and wait another 60 seconds.
148+
*
149+
* @param pool the ExecutorService to wait on
150+
*/
121151
public static void awaitTermination(ExecutorService pool) {
122152
awaitTermination(pool, 60, TimeUnit.SECONDS);
123153
}
@@ -143,6 +173,27 @@ static void awaitTermination(ExecutorService pool, long timeout, TimeUnit unit)
143173
}
144174
}
145175

176+
/**
177+
* Await the termination of an {@link ExecutorService} until all threads are complete, or until we
178+
* are interrupted, at which point the {@link ExecutorService} will be interrupted as well.
179+
*
180+
* @param pool the ExecutorService to wait on
181+
*/
182+
public static void awaitTerminationForever(ExecutorService pool) {
183+
boolean shutdown = false;
184+
try {
185+
while (!shutdown) {
186+
// Wait a while for existing tasks to terminate
187+
shutdown = pool.awaitTermination(60, TimeUnit.SECONDS);
188+
}
189+
} catch (InterruptedException e) {
190+
// Force cancel if current thread also interrupted
191+
pool.shutdownNow();
192+
// Preserve interrupt status
193+
Thread.currentThread().interrupt();
194+
}
195+
}
196+
146197
/** See {@link java.util.concurrent.Executors#newFixedThreadPool(int, ThreadFactory)} */
147198
public static ExecutorService newMDCAwareFixedThreadPool(
148199
int nThreads, ThreadFactory threadFactory) {

0 commit comments

Comments
 (0)