Skip to content

Commit 6c91c8a

Browse files
committed
update search expiration to work in scheduled reaper mode
1 parent e6b05ee commit 6c91c8a

File tree

2 files changed

+29
-64
lines changed

2 files changed

+29
-64
lines changed

modules/elasticsearch/src/main/java/org/elasticsearch/search/SearchService.java

Lines changed: 26 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,6 @@
2727
import org.elasticsearch.common.component.AbstractLifecycleComponent;
2828
import org.elasticsearch.common.inject.Inject;
2929
import org.elasticsearch.common.settings.Settings;
30-
import org.elasticsearch.common.timer.Timeout;
31-
import org.elasticsearch.common.timer.TimerTask;
3230
import org.elasticsearch.common.unit.TimeValue;
3331
import org.elasticsearch.common.util.concurrent.ConcurrentCollections;
3432
import org.elasticsearch.common.util.concurrent.ConcurrentMapLong;
@@ -50,13 +48,14 @@
5048
import org.elasticsearch.search.internal.InternalSearchRequest;
5149
import org.elasticsearch.search.internal.SearchContext;
5250
import org.elasticsearch.search.query.*;
51+
import org.elasticsearch.threadpool.ThreadPool;
5352
import org.elasticsearch.timer.TimerService;
5453

5554
import javax.annotation.Nullable;
5655
import java.io.IOException;
5756
import java.util.HashMap;
5857
import java.util.Map;
59-
import java.util.concurrent.TimeUnit;
58+
import java.util.concurrent.ScheduledFuture;
6059
import java.util.concurrent.atomic.AtomicLong;
6160

6261
import static org.elasticsearch.common.unit.TimeValue.*;
@@ -81,7 +80,9 @@ public class SearchService extends AbstractLifecycleComponent<SearchService> {
8180
private final FetchPhase fetchPhase;
8281

8382

84-
private final TimeValue defaultKeepAlive;
83+
private final long defaultKeepAlive;
84+
85+
private final ScheduledFuture keepAliveReaper;
8586

8687

8788
private final AtomicLong idGenerator = new AtomicLong();
@@ -92,7 +93,7 @@ public class SearchService extends AbstractLifecycleComponent<SearchService> {
9293

9394
private final ImmutableMap<String, SearchParseElement> elementParsers;
9495

95-
@Inject public SearchService(Settings settings, ClusterService clusterService, IndicesService indicesService, IndicesLifecycle indicesLifecycle, TimerService timerService,
96+
@Inject public SearchService(Settings settings, ClusterService clusterService, IndicesService indicesService, IndicesLifecycle indicesLifecycle, ThreadPool threadPool, TimerService timerService,
9697
ScriptService scriptService, DfsPhase dfsPhase, QueryPhase queryPhase, FetchPhase fetchPhase) {
9798
super(settings);
9899
this.clusterService = clusterService;
@@ -103,15 +104,18 @@ public class SearchService extends AbstractLifecycleComponent<SearchService> {
103104
this.queryPhase = queryPhase;
104105
this.fetchPhase = fetchPhase;
105106

107+
TimeValue keepAliveInterval = componentSettings.getAsTime("keep_alive_interval", timeValueMinutes(1));
106108
// we can have 5 minutes here, since we make sure to clean with search requests and when shard/index closes
107-
this.defaultKeepAlive = componentSettings.getAsTime("default_keep_alive", timeValueMinutes(5));
109+
this.defaultKeepAlive = componentSettings.getAsTime("default_keep_alive", timeValueMinutes(5)).millis();
108110

109111
Map<String, SearchParseElement> elementParsers = new HashMap<String, SearchParseElement>();
110112
elementParsers.putAll(dfsPhase.parseElements());
111113
elementParsers.putAll(queryPhase.parseElements());
112114
elementParsers.putAll(fetchPhase.parseElements());
113115
this.elementParsers = ImmutableMap.copyOf(elementParsers);
114116
indicesLifecycle.addListener(indicesLifecycleListener);
117+
118+
this.keepAliveReaper = threadPool.scheduleWithFixedDelay(new Reaper(), keepAliveInterval);
115119
}
116120

117121
@Override protected void doStart() throws ElasticSearchException {
@@ -125,6 +129,7 @@ public class SearchService extends AbstractLifecycleComponent<SearchService> {
125129
}
126130

127131
@Override protected void doClose() throws ElasticSearchException {
132+
keepAliveReaper.cancel(false);
128133
indicesService.indicesLifecycle().removeListener(indicesLifecycleListener);
129134
}
130135

@@ -344,9 +349,9 @@ private SearchContext createContext(InternalSearchRequest request) throws Elasti
344349
fetchPhase.preProcess(context);
345350

346351
// compute the context keep alive
347-
TimeValue keepAlive = defaultKeepAlive;
352+
long keepAlive = defaultKeepAlive;
348353
if (request.scroll() != null && request.scroll().keepAlive() != null) {
349-
keepAlive = request.scroll().keepAlive();
354+
keepAlive = request.scroll().keepAlive().millis();
350355
}
351356
context.keepAlive(keepAlive);
352357
} catch (RuntimeException e) {
@@ -371,18 +376,12 @@ private void freeContext(SearchContext context) {
371376
}
372377

373378
private void contextProcessing(SearchContext context) {
374-
if (context.keepAliveTimeout() != null) {
375-
((KeepAliveTimerTask) context.keepAliveTimeout().getTask()).processing();
376-
}
379+
// disable timeout while executing a search
380+
context.accessed(-1);
377381
}
378382

379383
private void contextProcessedSuccessfully(SearchContext context) {
380-
if (context.keepAliveTimeout() != null) {
381-
((KeepAliveTimerTask) context.keepAliveTimeout().getTask()).doneProcessing();
382-
} else {
383-
context.accessed(timerService.estimatedTimeInMillis());
384-
context.keepAliveTimeout(timerService.newTimeout(new KeepAliveTimerTask(context), context.keepAlive(), TimerService.ExecutionType.DEFAULT));
385-
}
384+
context.accessed(timerService.estimatedTimeInMillis());
386385
}
387386

388387
private void cleanContext(SearchContext context) {
@@ -451,7 +450,7 @@ private void processScroll(InternalScrollSearchRequest request, SearchContext co
451450
context.scroll(request.scroll());
452451
// update the context keep alive based on the new scroll value
453452
if (request.scroll() != null && request.scroll().keepAlive() != null) {
454-
context.keepAlive(request.scroll().keepAlive());
453+
context.keepAlive(request.scroll().keepAlive().millis());
455454
}
456455
}
457456

@@ -466,35 +465,15 @@ class CleanContextOnIndicesLifecycleListener extends IndicesLifecycle.Listener {
466465
}
467466
}
468467

469-
class KeepAliveTimerTask implements TimerTask {
470-
471-
private final SearchContext context;
472-
473-
KeepAliveTimerTask(SearchContext context) {
474-
this.context = context;
475-
}
476-
477-
public void processing() {
478-
context.keepAliveTimeout().cancel();
479-
}
480-
481-
public void doneProcessing() {
482-
context.accessed(timerService.estimatedTimeInMillis());
483-
context.keepAliveTimeout(timerService.newTimeout(this, context.keepAlive(), TimerService.ExecutionType.DEFAULT));
484-
}
485-
486-
@Override public void run(Timeout timeout) throws Exception {
487-
if (timeout.isCancelled()) {
488-
return;
489-
}
490-
long currentTime = timerService.estimatedTimeInMillis();
491-
long nextDelay = context.keepAlive().millis() - (currentTime - context.lastAccessTime());
492-
if (nextDelay <= 0) {
493-
// Time out, free the context (and remove it from the active context)
494-
freeContext(context.id());
495-
} else {
496-
// Read occurred before the timeout - set a new timeout with shorter delay.
497-
context.keepAliveTimeout(timerService.newTimeout(this, nextDelay, TimeUnit.MILLISECONDS, TimerService.ExecutionType.DEFAULT));
468+
class Reaper implements Runnable {
469+
@Override public void run() {
470+
for (SearchContext context : activeContexts.values()) {
471+
if (context.lastAccessTime() == -1) { // its being processed or timeout is disabled
472+
continue;
473+
}
474+
if ((timerService.estimatedTimeInMillis() - context.lastAccessTime() > context.keepAlive())) {
475+
freeContext(context);
476+
}
498477
}
499478
}
500479
}

modules/elasticsearch/src/main/java/org/elasticsearch/search/internal/SearchContext.java

Lines changed: 3 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@
2525
import org.elasticsearch.common.collect.ImmutableList;
2626
import org.elasticsearch.common.collect.Lists;
2727
import org.elasticsearch.common.lease.Releasable;
28-
import org.elasticsearch.common.timer.Timeout;
2928
import org.elasticsearch.common.unit.TimeValue;
3029
import org.elasticsearch.index.cache.field.data.FieldDataCache;
3130
import org.elasticsearch.index.cache.filter.FilterCache;
@@ -130,12 +129,10 @@ public static SearchContext current() {
130129

131130
private boolean queryRewritten;
132131

133-
private volatile TimeValue keepAlive;
132+
private volatile long keepAlive;
134133

135134
private volatile long lastAccessTime;
136135

137-
private volatile Timeout keepAliveTimeout;
138-
139136
public SearchContext(long id, SearchShardTarget shardTarget, int numberOfShards, TimeValue timeout,
140137
String[] types, Engine.Searcher engineSearcher, IndexService indexService, ScriptService scriptService) {
141138
this.id = id;
@@ -161,9 +158,6 @@ public SearchContext(long id, SearchShardTarget shardTarget, int numberOfShards,
161158
// ignore any exception here
162159
}
163160
engineSearcher.release();
164-
if (keepAliveTimeout != null) {
165-
keepAliveTimeout.cancel();
166-
}
167161
return true;
168162
}
169163

@@ -392,22 +386,14 @@ public long lastAccessTime() {
392386
return this.lastAccessTime;
393387
}
394388

395-
public TimeValue keepAlive() {
389+
public long keepAlive() {
396390
return this.keepAlive;
397391
}
398392

399-
public void keepAlive(TimeValue keepAlive) {
393+
public void keepAlive(long keepAlive) {
400394
this.keepAlive = keepAlive;
401395
}
402396

403-
public void keepAliveTimeout(Timeout keepAliveTimeout) {
404-
this.keepAliveTimeout = keepAliveTimeout;
405-
}
406-
407-
public Timeout keepAliveTimeout() {
408-
return this.keepAliveTimeout;
409-
}
410-
411397
public ScriptSearchLookup scriptSearchLookup() {
412398
if (scriptSearchLookup == null) {
413399
scriptSearchLookup = new ScriptSearchLookup(mapperService(), fieldDataCache());

0 commit comments

Comments
 (0)