Skip to content

Commit 9a1afc4

Browse files
committed
Core: Lucene merges must run on target shard during recovery
This does not affect 2.0, where we let Lucene launch merges normally (elastic#8643). In 1.x, every 1 sec (default), we ask Lucene to kick off any new merges, but we unfortunately don't turn that logic on in the target shard until after recovery has finished. This means if you have a large translog, and/or a smallish index buffer, way too many segments can accumulate in the target shard during recovery, making version lookups slower and slower (OI(N^2)) and possibly causing slow recovery issues like elastic#9226. This fix changes IndexShard to launch merges as soon as the shard is created, so merging runs during recovery. Closes elastic#10463
1 parent 4014206 commit 9a1afc4

File tree

1 file changed

+15
-13
lines changed

1 file changed

+15
-13
lines changed

src/main/java/org/elasticsearch/index/shard/service/InternalIndexShard.java

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,16 @@ public InternalIndexShard(ShardId shardId, @IndexSettings Settings indexSettings
202202
logger.debug("state: [CREATED]");
203203

204204
this.checkIndexOnStartup = indexSettings.get("index.shard.check_on_startup", "false");
205+
206+
// since we can do async merging, it will not be called explicitly when indexing (adding / deleting docs), and only when flushing
207+
// so, make sure we periodically call it, this need to be a small enough value so merging will actually
208+
// happen and reduce the number of segments
209+
if (mergeInterval.millis() > 0) {
210+
mergeScheduleFuture = threadPool.schedule(mergeInterval, ThreadPool.Names.SAME, new EngineMerger());
211+
logger.debug("scheduling optimizer / merger every {}", mergeInterval);
212+
} else {
213+
logger.debug("scheduled optimizer / merger disabled");
214+
}
205215
}
206216

207217
public MergeSchedulerProvider mergeScheduler() {
@@ -731,7 +741,7 @@ public InternalIndexShard postRecovery(String reason) throws IndexShardStartedEx
731741
checkIndex(true);
732742
}
733743
engine.start();
734-
startScheduledTasksIfNeeded();
744+
startEngineRefresher();
735745
changeState(IndexShardState.POST_RECOVERY, reason);
736746
}
737747
indicesLifecycle.afterIndexShardPostRecovery(this);
@@ -778,7 +788,7 @@ public void performRecoveryFinalization(boolean withFlush) throws ElasticsearchE
778788
changeState(IndexShardState.POST_RECOVERY, "post recovery");
779789
}
780790
indicesLifecycle.afterIndexShardPostRecovery(this);
781-
startScheduledTasksIfNeeded();
791+
startEngineRefresher();
782792
engine.enableGcDeletes(true);
783793
}
784794

@@ -913,22 +923,13 @@ private void verifyStarted() throws IllegalIndexShardStateException {
913923
}
914924
}
915925

916-
private void startScheduledTasksIfNeeded() {
926+
private void startEngineRefresher() {
917927
if (refreshInterval.millis() > 0) {
918928
refreshScheduledFuture = threadPool.schedule(refreshInterval, ThreadPool.Names.SAME, new EngineRefresher());
919929
logger.debug("scheduling refresher every {}", refreshInterval);
920930
} else {
921931
logger.debug("scheduled refresher disabled");
922932
}
923-
// since we can do async merging, it will not be called explicitly when indexing (adding / deleting docs), and only when flushing
924-
// so, make sure we periodically call it, this need to be a small enough value so mergine will actually
925-
// happen and reduce the number of segments
926-
if (mergeInterval.millis() > 0) {
927-
mergeScheduleFuture = threadPool.schedule(mergeInterval, ThreadPool.Names.SAME, new EngineMerger());
928-
logger.debug("scheduling optimizer / merger every {}", mergeInterval);
929-
} else {
930-
logger.debug("scheduled optimizer / merger disabled");
931-
}
932933
}
933934

934935
private Query filterQueryIfNeeded(Query query, String[] types) {
@@ -1020,7 +1021,8 @@ private void reschedule() {
10201021
class EngineMerger implements Runnable {
10211022
@Override
10221023
public void run() {
1023-
if (!engine().possibleMergeNeeded()) {
1024+
final Engine engine = engine();
1025+
if (engine == null || engine.possibleMergeNeeded() == false) {
10241026
synchronized (mutex) {
10251027
if (state != IndexShardState.CLOSED) {
10261028
mergeScheduleFuture = threadPool.schedule(mergeInterval, ThreadPool.Names.SAME, this);

0 commit comments

Comments
 (0)