Skip to content

Commit ecfd48b

Browse files
matrivbleskes
andauthored
[Tests] Make testEngineGCDeletesSetting deterministic (#38942) (#39231)
`InternalEngine.resolveDocVersion()` uses `relativeTimeInMillis()` from `ThreadPool` so it needs, the cached time to be advanced. Add a check to ensure that and decrease the `thread_pool.estimated_time_interval` to 1msec to prevent long running times for the test. Fixes: #38874 Co-authored-by: Boaz Leskes <[email protected]>
1 parent 1316825 commit ecfd48b

File tree

3 files changed

+48
-8
lines changed

3 files changed

+48
-8
lines changed

server/src/main/java/org/elasticsearch/threadpool/ThreadPool.java

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,8 @@ public Collection<ExecutorBuilder> builders() {
161161
}
162162

163163
public static Setting<TimeValue> ESTIMATED_TIME_INTERVAL_SETTING =
164-
Setting.timeSetting("thread_pool.estimated_time_interval", TimeValue.timeValueMillis(200), Setting.Property.NodeScope);
164+
Setting.timeSetting("thread_pool.estimated_time_interval",
165+
TimeValue.timeValueMillis(200), TimeValue.ZERO, Setting.Property.NodeScope);
165166

166167
public ThreadPool(final Settings settings, final ExecutorBuilder<?>... customBuilders) {
167168
assert Node.NODE_NAME_SETTING.exists(settings);
@@ -548,22 +549,36 @@ static class CachedTimeThread extends Thread {
548549
/**
549550
* Return the current time used for relative calculations. This is
550551
* {@link System#nanoTime()} truncated to milliseconds.
552+
* <p>
553+
* If {@link ThreadPool#ESTIMATED_TIME_INTERVAL_SETTING} is set to 0
554+
* then the cache is disabled and the method calls {@link System#nanoTime()}
555+
* whenever called. Typically used for testing.
551556
*/
552557
long relativeTimeInMillis() {
553-
return relativeMillis;
558+
if (0 < interval) {
559+
return relativeMillis;
560+
}
561+
return TimeValue.nsecToMSec(System.nanoTime());
554562
}
555563

556564
/**
557565
* Return the current epoch time, used to find absolute time. This is
558566
* a cached version of {@link System#currentTimeMillis()}.
567+
* <p>
568+
* If {@link ThreadPool#ESTIMATED_TIME_INTERVAL_SETTING} is set to 0
569+
* then the cache is disabled and the method calls {@link System#currentTimeMillis()}
570+
* whenever called. Typically used for testing.
559571
*/
560572
long absoluteTimeInMillis() {
561-
return absoluteMillis;
573+
if (0 < interval) {
574+
return absoluteMillis;
575+
}
576+
return System.currentTimeMillis();
562577
}
563578

564579
@Override
565580
public void run() {
566-
while (running) {
581+
while (running && 0 < interval) {
567582
relativeMillis = TimeValue.nsecToMSec(System.nanoTime());
568583
absoluteMillis = System.currentTimeMillis();
569584
try {

server/src/test/java/org/elasticsearch/indices/settings/UpdateSettingsIT.java

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
import org.elasticsearch.indices.IndicesService;
3333
import org.elasticsearch.plugins.Plugin;
3434
import org.elasticsearch.test.ESIntegTestCase;
35+
import org.elasticsearch.threadpool.ThreadPool;
3536

3637
import java.util.Arrays;
3738
import java.util.Collection;
@@ -47,6 +48,7 @@
4748
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertThrows;
4849
import static org.hamcrest.Matchers.containsString;
4950
import static org.hamcrest.Matchers.equalTo;
51+
import static org.hamcrest.Matchers.greaterThan;
5052
import static org.hamcrest.Matchers.nullValue;
5153

5254
public class UpdateSettingsIT extends ESIntegTestCase {
@@ -126,6 +128,16 @@ public List<Setting<?>> getSettings() {
126128
}
127129
}
128130

131+
/**
132+
* Needed by {@link UpdateSettingsIT#testEngineGCDeletesSetting()}
133+
*/
134+
@Override
135+
protected Settings nodeSettings(int nodeOrdinal) {
136+
return Settings.builder().put(super.nodeSettings(nodeOrdinal))
137+
.put("thread_pool.estimated_time_interval", 0)
138+
.build();
139+
}
140+
129141
public void testUpdateDependentClusterSettings() {
130142
IllegalArgumentException iae = expectThrows(IllegalArgumentException.class, () ->
131143
client().admin().cluster().prepareUpdateSettings().setPersistentSettings(Settings.builder()
@@ -435,23 +447,28 @@ public void testOpenCloseUpdateSettings() throws Exception {
435447
assertThat(getSettingsResponse.getSetting("test", "index.final"), nullValue());
436448
}
437449

438-
public void testEngineGCDeletesSetting() throws InterruptedException {
450+
public void testEngineGCDeletesSetting() throws Exception {
439451
createIndex("test");
440452
client().prepareIndex("test", "type", "1").setSource("f", 1).get();
441453
DeleteResponse response = client().prepareDelete("test", "type", "1").get();
442454
long seqNo = response.getSeqNo();
443455
long primaryTerm = response.getPrimaryTerm();
444456
// delete is still in cache this should work
445457
client().prepareIndex("test", "type", "1").setSource("f", 2).setIfSeqNo(seqNo).setIfPrimaryTerm(primaryTerm).get();
446-
client().admin().indices().prepareUpdateSettings("test").setSettings(Settings.builder().put("index.gc_deletes", 0)).get();
458+
assertAcked(client().admin().indices().prepareUpdateSettings("test").setSettings(Settings.builder().put("index.gc_deletes", 0)));
447459

448460
response = client().prepareDelete("test", "type", "1").get();
449461
seqNo = response.getSeqNo();
450-
Thread.sleep(300); // wait for cache time to change TODO: this needs to be solved better. To be discussed.
462+
463+
// Make sure the time has advanced for InternalEngine#resolveDocVersion()
464+
for (ThreadPool threadPool : internalCluster().getInstances(ThreadPool.class)) {
465+
long startTime = threadPool.relativeTimeInMillis();
466+
assertBusy(() -> assertThat(threadPool.relativeTimeInMillis(), greaterThan(startTime)));
467+
}
468+
451469
// delete is should not be in cache
452470
assertThrows(client().prepareIndex("test", "type", "1").setSource("f", 3).setIfSeqNo(seqNo).setIfPrimaryTerm(primaryTerm),
453471
VersionConflictEngineException.class);
454-
455472
}
456473

457474
public void testUpdateSettingsWithBlocks() {

server/src/test/java/org/elasticsearch/threadpool/ThreadPoolTests.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,10 @@
1919

2020
package org.elasticsearch.threadpool;
2121

22+
import org.elasticsearch.common.settings.Settings;
2223
import org.elasticsearch.test.ESTestCase;
2324

25+
import static org.elasticsearch.threadpool.ThreadPool.ESTIMATED_TIME_INTERVAL_SETTING;
2426
import static org.hamcrest.CoreMatchers.equalTo;
2527

2628
public class ThreadPoolTests extends ESTestCase {
@@ -59,4 +61,10 @@ public void testAbsoluteTime() throws Exception {
5961
threadPool.close();
6062
}
6163
}
64+
65+
public void testEstimatedTimeIntervalSettingAcceptsOnlyZeroAndPositiveTime() {
66+
Settings settings = Settings.builder().put("thread_pool.estimated_time_interval", -1).build();
67+
Exception e = expectThrows(IllegalArgumentException.class, () -> ESTIMATED_TIME_INTERVAL_SETTING.get(settings));
68+
assertEquals("failed to parse value [-1] for setting [thread_pool.estimated_time_interval], must be >= [0ms]", e.getMessage());
69+
}
6270
}

0 commit comments

Comments
 (0)