|
@@ -46,6 +46,7 @@ import static org.hamcrest.Matchers.equalTo;
|
|
|
import static org.hamcrest.Matchers.is;
|
|
|
import static org.hamcrest.Matchers.lessThanOrEqualTo;
|
|
|
import static org.mockito.ArgumentMatchers.any;
|
|
|
+import static org.mockito.ArgumentMatchers.anyLong;
|
|
|
import static org.mockito.Mockito.doAnswer;
|
|
|
import static org.mockito.Mockito.mock;
|
|
|
import static org.mockito.Mockito.times;
|
|
@@ -74,12 +75,14 @@ public class ThreadPoolMergeSchedulerTests extends ESTestCase {
|
|
|
nodeEnvironment = newNodeEnvironment(settings);
|
|
|
ThreadPoolMergeExecutorService threadPoolMergeExecutorService = ThreadPoolMergeExecutorServiceTests
|
|
|
.getThreadPoolMergeExecutorService(threadPoolTaskQueue.getThreadPool(), settings, nodeEnvironment);
|
|
|
+ var mergeMetrics = mock(MergeMetrics.class);
|
|
|
try (
|
|
|
ThreadPoolMergeScheduler threadPoolMergeScheduler = new ThreadPoolMergeScheduler(
|
|
|
new ShardId("index", "_na_", 1),
|
|
|
IndexSettingsModule.newIndexSettings("index", Settings.EMPTY),
|
|
|
threadPoolMergeExecutorService,
|
|
|
- merge -> 0
|
|
|
+ merge -> 0,
|
|
|
+ mergeMetrics
|
|
|
)
|
|
|
) {
|
|
|
List<OneMerge> executedMergesList = new ArrayList<>();
|
|
@@ -97,9 +100,19 @@ public class ThreadPoolMergeSchedulerTests extends ESTestCase {
|
|
|
return null;
|
|
|
}).when(mergeSource).merge(any(OneMerge.class));
|
|
|
threadPoolMergeScheduler.merge(mergeSource, randomFrom(MergeTrigger.values()));
|
|
|
+
|
|
|
+ // verify queued byte metric is recorded for each merge
|
|
|
+ verify(mergeMetrics, times(i + 1)).incrementQueuedMergeBytes(any(), anyLong());
|
|
|
}
|
|
|
+
|
|
|
threadPoolTaskQueue.runAllTasks();
|
|
|
assertThat(executedMergesList.size(), is(mergeCount));
|
|
|
+
|
|
|
+ // verify metrics are reported for each merge
|
|
|
+ verify(mergeMetrics, times(mergeCount)).moveQueuedMergeBytesToRunning(any(), anyLong());
|
|
|
+ verify(mergeMetrics, times(mergeCount)).decrementRunningMergeBytes(any());
|
|
|
+ verify(mergeMetrics, times(mergeCount)).markMergeMetrics(any(), anyLong(), anyLong());
|
|
|
+
|
|
|
// assert merges are executed in ascending size order
|
|
|
for (int i = 1; i < mergeCount; i++) {
|
|
|
assertThat(
|
|
@@ -113,6 +126,7 @@ public class ThreadPoolMergeSchedulerTests extends ESTestCase {
|
|
|
|
|
|
public void testSimpleMergeTaskBacklogging() {
|
|
|
int mergeExecutorThreadCount = randomIntBetween(1, 5);
|
|
|
+ var mergeMetrics = mock(MergeMetrics.class);
|
|
|
Settings mergeSchedulerSettings = Settings.builder()
|
|
|
.put(MergeSchedulerConfig.MAX_THREAD_COUNT_SETTING.getKey(), mergeExecutorThreadCount)
|
|
|
.build();
|
|
@@ -122,7 +136,8 @@ public class ThreadPoolMergeSchedulerTests extends ESTestCase {
|
|
|
new ShardId("index", "_na_", 1),
|
|
|
IndexSettingsModule.newIndexSettings("index", mergeSchedulerSettings),
|
|
|
threadPoolMergeExecutorService,
|
|
|
- merge -> 0
|
|
|
+ merge -> 0,
|
|
|
+ mergeMetrics
|
|
|
);
|
|
|
// more merge tasks than merge threads
|
|
|
int mergeCount = mergeExecutorThreadCount + randomIntBetween(1, 5);
|
|
@@ -143,6 +158,9 @@ public class ThreadPoolMergeSchedulerTests extends ESTestCase {
|
|
|
}
|
|
|
assertThat(threadPoolMergeScheduler.getRunningMergeTasks().size(), is(mergeExecutorThreadCount));
|
|
|
assertThat(threadPoolMergeScheduler.getBackloggedMergeTasks().size(), is(mergeCount - mergeExecutorThreadCount));
|
|
|
+
|
|
|
+ // verify no metrics are recorded as no merges have been queued or executed through the merge scheduler
|
|
|
+ verifyNoInteractions(mergeMetrics);
|
|
|
}
|
|
|
|
|
|
public void testSimpleMergeTaskReEnqueueingBySize() {
|
|
@@ -156,7 +174,8 @@ public class ThreadPoolMergeSchedulerTests extends ESTestCase {
|
|
|
new ShardId("index", "_na_", 1),
|
|
|
IndexSettingsModule.newIndexSettings("index", mergeSchedulerSettings),
|
|
|
threadPoolMergeExecutorService,
|
|
|
- merge -> 0
|
|
|
+ merge -> 0,
|
|
|
+ MergeMetrics.NOOP
|
|
|
);
|
|
|
// sort backlogged merges by size
|
|
|
PriorityQueue<MergeTask> backloggedMergeTasks = new PriorityQueue<>(
|
|
@@ -388,7 +407,8 @@ public class ThreadPoolMergeSchedulerTests extends ESTestCase {
|
|
|
new ShardId("index", "_na_", 1),
|
|
|
IndexSettingsModule.newIndexSettings("index", settings),
|
|
|
threadPoolMergeExecutorService,
|
|
|
- merge -> 0
|
|
|
+ merge -> 0,
|
|
|
+ MergeMetrics.NOOP
|
|
|
)
|
|
|
) {
|
|
|
MergeSource mergeSource = mock(MergeSource.class);
|
|
@@ -454,6 +474,7 @@ public class ThreadPoolMergeSchedulerTests extends ESTestCase {
|
|
|
// disable fs available disk space feature for this test
|
|
|
.put(ThreadPoolMergeExecutorService.INDICES_MERGE_DISK_CHECK_INTERVAL_SETTING.getKey(), "0s")
|
|
|
.build();
|
|
|
+ var mergeMetrics = mock(MergeMetrics.class);
|
|
|
nodeEnvironment = newNodeEnvironment(settings);
|
|
|
try (TestThreadPool testThreadPool = new TestThreadPool("test", settings)) {
|
|
|
ThreadPoolMergeExecutorService threadPoolMergeExecutorService = ThreadPoolMergeExecutorServiceTests
|
|
@@ -465,7 +486,8 @@ public class ThreadPoolMergeSchedulerTests extends ESTestCase {
|
|
|
new ShardId("index", "_na_", 1),
|
|
|
IndexSettingsModule.newIndexSettings("index", settings),
|
|
|
threadPoolMergeExecutorService,
|
|
|
- merge -> 0
|
|
|
+ merge -> 0,
|
|
|
+ mergeMetrics
|
|
|
)
|
|
|
) {
|
|
|
// at least 1 extra merge than there are concurrently allowed
|
|
@@ -485,7 +507,11 @@ public class ThreadPoolMergeSchedulerTests extends ESTestCase {
|
|
|
return null;
|
|
|
}).when(mergeSource).merge(any(OneMerge.class));
|
|
|
threadPoolMergeScheduler.merge(mergeSource, randomFrom(MergeTrigger.values()));
|
|
|
+
|
|
|
+ // verify queued byte metric is recorded for each merge
|
|
|
+ verify(mergeMetrics, times(i + 1)).incrementQueuedMergeBytes(any(), anyLong());
|
|
|
}
|
|
|
+
|
|
|
for (int completedMergesCount = 0; completedMergesCount < mergeCount
|
|
|
- mergeSchedulerMaxThreadCount; completedMergesCount++) {
|
|
|
int finalCompletedMergesCount = completedMergesCount;
|
|
@@ -530,6 +556,11 @@ public class ThreadPoolMergeSchedulerTests extends ESTestCase {
|
|
|
runMergeSemaphore.release();
|
|
|
}
|
|
|
assertBusy(() -> assertTrue(threadPoolMergeExecutorService.allDone()));
|
|
|
+
|
|
|
+ // verify metrics are recorded for each merge
|
|
|
+ verify(mergeMetrics, times(mergeCount)).moveQueuedMergeBytesToRunning(any(), anyLong());
|
|
|
+ verify(mergeMetrics, times(mergeCount)).decrementRunningMergeBytes(any());
|
|
|
+ verify(mergeMetrics, times(mergeCount)).markMergeMetrics(any(), anyLong(), anyLong());
|
|
|
}
|
|
|
}
|
|
|
}
|
|
@@ -553,7 +584,8 @@ public class ThreadPoolMergeSchedulerTests extends ESTestCase {
|
|
|
new ShardId("index", "_na_", 1),
|
|
|
IndexSettingsModule.newIndexSettings("index", settings),
|
|
|
threadPoolMergeExecutorService,
|
|
|
- merge -> 0
|
|
|
+ merge -> 0,
|
|
|
+ MergeMetrics.NOOP
|
|
|
)
|
|
|
) {
|
|
|
CountDownLatch mergeDoneLatch = new CountDownLatch(1);
|
|
@@ -626,7 +658,8 @@ public class ThreadPoolMergeSchedulerTests extends ESTestCase {
|
|
|
new ShardId("index", "_na_", 1),
|
|
|
indexSettings,
|
|
|
threadPoolMergeExecutorService,
|
|
|
- merge -> 0
|
|
|
+ merge -> 0,
|
|
|
+ MergeMetrics.NOOP
|
|
|
)
|
|
|
) {
|
|
|
threadPoolMergeScheduler.merge(mergeSource, randomFrom(MergeTrigger.values()));
|
|
@@ -656,7 +689,8 @@ public class ThreadPoolMergeSchedulerTests extends ESTestCase {
|
|
|
new ShardId("index", "_na_", 1),
|
|
|
indexSettings,
|
|
|
threadPoolMergeExecutorService,
|
|
|
- merge -> 0
|
|
|
+ merge -> 0,
|
|
|
+ MergeMetrics.NOOP
|
|
|
)
|
|
|
) {
|
|
|
threadPoolMergeScheduler.merge(mergeSource, randomFrom(MergeTrigger.values()));
|
|
@@ -673,7 +707,8 @@ public class ThreadPoolMergeSchedulerTests extends ESTestCase {
|
|
|
new ShardId("index", "_na_", 1),
|
|
|
indexSettings,
|
|
|
threadPoolMergeExecutorService,
|
|
|
- merge -> 0
|
|
|
+ merge -> 0,
|
|
|
+ MergeMetrics.NOOP
|
|
|
)
|
|
|
) {
|
|
|
// merge submitted upon closing
|
|
@@ -690,7 +725,8 @@ public class ThreadPoolMergeSchedulerTests extends ESTestCase {
|
|
|
new ShardId("index", "_na_", 1),
|
|
|
indexSettings,
|
|
|
threadPoolMergeExecutorService,
|
|
|
- merge -> 0
|
|
|
+ merge -> 0,
|
|
|
+ MergeMetrics.NOOP
|
|
|
)
|
|
|
) {
|
|
|
// merge submitted upon closing
|
|
@@ -705,29 +741,63 @@ public class ThreadPoolMergeSchedulerTests extends ESTestCase {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- public void testMergeSchedulerAbortsMergeWhenShouldSkipMergeIsTrue() {
|
|
|
- ThreadPoolMergeExecutorService threadPoolMergeExecutorService = mock(ThreadPoolMergeExecutorService.class);
|
|
|
- // build a scheduler that always returns true for shouldSkipMerge
|
|
|
- ThreadPoolMergeScheduler threadPoolMergeScheduler = new ThreadPoolMergeScheduler(
|
|
|
- new ShardId("index", "_na_", 1),
|
|
|
- IndexSettingsModule.newIndexSettings("index", Settings.builder().build()),
|
|
|
- threadPoolMergeExecutorService,
|
|
|
- merge -> 0
|
|
|
+ public void testMergeSchedulerAbortsMergeWhenShouldSkipMergeIsTrue() throws IOException {
|
|
|
+ DeterministicTaskQueue threadPoolTaskQueue = new DeterministicTaskQueue();
|
|
|
+ Settings settings = Settings.builder()
|
|
|
+ // disable fs available disk space feature for this test
|
|
|
+ .put(ThreadPoolMergeExecutorService.INDICES_MERGE_DISK_CHECK_INTERVAL_SETTING.getKey(), "0s")
|
|
|
+ .build();
|
|
|
+ nodeEnvironment = newNodeEnvironment(settings);
|
|
|
+ ThreadPoolMergeExecutorService threadPoolMergeExecutorService = ThreadPoolMergeExecutorServiceTests
|
|
|
+ .getThreadPoolMergeExecutorService(threadPoolTaskQueue.getThreadPool(), settings, nodeEnvironment);
|
|
|
+ var mergeMetrics = mock(MergeMetrics.class);
|
|
|
+ try (
|
|
|
+ // build a scheduler that always returns true for shouldSkipMerge
|
|
|
+ ThreadPoolMergeScheduler threadPoolMergeScheduler = new ThreadPoolMergeScheduler(
|
|
|
+ new ShardId("index", "_na_", 1),
|
|
|
+ IndexSettingsModule.newIndexSettings("index", Settings.EMPTY),
|
|
|
+ threadPoolMergeExecutorService,
|
|
|
+ merge -> 0,
|
|
|
+ mergeMetrics
|
|
|
+ ) {
|
|
|
+ @Override
|
|
|
+ protected boolean shouldSkipMerge() {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ }
|
|
|
) {
|
|
|
- @Override
|
|
|
- protected boolean shouldSkipMerge() {
|
|
|
- return true;
|
|
|
+ int mergeCount = randomIntBetween(2, 10);
|
|
|
+ for (int i = 0; i < mergeCount; i++) {
|
|
|
+ MergeSource mergeSource = mock(MergeSource.class);
|
|
|
+ OneMerge oneMerge = mock(OneMerge.class);
|
|
|
+ when(oneMerge.getStoreMergeInfo()).thenReturn(getNewMergeInfo(randomLongBetween(1L, 10L)));
|
|
|
+ when(oneMerge.getMergeProgress()).thenReturn(new MergePolicy.OneMergeProgress());
|
|
|
+ when(mergeSource.getNextMerge()).thenReturn(oneMerge, (OneMerge) null);
|
|
|
+
|
|
|
+ // create the merge task
|
|
|
+ MergeTask mergeTask = threadPoolMergeScheduler.newMergeTask(mergeSource, oneMerge, randomFrom(MergeTrigger.values()));
|
|
|
+
|
|
|
+ // verify that calling schedule on the merge task indicates the merge should be aborted
|
|
|
+ Schedule schedule = threadPoolMergeScheduler.schedule(mergeTask);
|
|
|
+ assertThat(schedule, is(Schedule.ABORT));
|
|
|
+
|
|
|
+ // run the merge through the scheduler
|
|
|
+ threadPoolMergeScheduler.merge(mergeSource, randomFrom(MergeTrigger.values()));
|
|
|
+
|
|
|
+ // verify queued merge byte metrics are still recorded for each merge
|
|
|
+ verify(mergeMetrics, times(i + 1)).incrementQueuedMergeBytes(any(), anyLong());
|
|
|
}
|
|
|
- };
|
|
|
- MergeSource mergeSource = mock(MergeSource.class);
|
|
|
- OneMerge oneMerge = mock(OneMerge.class);
|
|
|
- when(oneMerge.getStoreMergeInfo()).thenReturn(getNewMergeInfo(randomLongBetween(1L, 10L)));
|
|
|
- when(oneMerge.getMergeProgress()).thenReturn(new MergePolicy.OneMergeProgress());
|
|
|
- when(mergeSource.getNextMerge()).thenReturn(oneMerge, (OneMerge) null);
|
|
|
- MergeTask mergeTask = threadPoolMergeScheduler.newMergeTask(mergeSource, oneMerge, randomFrom(MergeTrigger.values()));
|
|
|
- // verify that calling schedule on the merge task indicates the merge should be aborted
|
|
|
- Schedule schedule = threadPoolMergeScheduler.schedule(mergeTask);
|
|
|
- assertThat(schedule, is(Schedule.ABORT));
|
|
|
+
|
|
|
+ // run all merges; they should all be aborted
|
|
|
+ threadPoolTaskQueue.runAllTasks();
|
|
|
+
|
|
|
+ // verify queued bytes metrics are moved to running and decremented
|
|
|
+ verify(mergeMetrics, times(mergeCount)).moveQueuedMergeBytesToRunning(any(), anyLong());
|
|
|
+ verify(mergeMetrics, times(mergeCount)).decrementRunningMergeBytes(any());
|
|
|
+
|
|
|
+ // verify we did not mark the merges as merged
|
|
|
+ verify(mergeMetrics, times(0)).markMergeMetrics(any(), anyLong(), anyLong());
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
private static MergeInfo getNewMergeInfo(long estimatedMergeBytes) {
|
|
@@ -746,7 +816,7 @@ public class ThreadPoolMergeSchedulerTests extends ESTestCase {
|
|
|
IndexSettings indexSettings,
|
|
|
ThreadPoolMergeExecutorService threadPoolMergeExecutorService
|
|
|
) {
|
|
|
- super(shardId, indexSettings, threadPoolMergeExecutorService, merge -> 0);
|
|
|
+ super(shardId, indexSettings, threadPoolMergeExecutorService, merge -> 0, MergeMetrics.NOOP);
|
|
|
}
|
|
|
|
|
|
@Override
|