-
Notifications
You must be signed in to change notification settings - Fork 25.6k
Fix and add a test for failure store with Incremental bulk #115866
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 10 commits
9bd52a0
9b2117d
dd01919
ce2d154
3af8970
05e4d7d
4d0ddc6
4fda9c2
e06a1f7
33d5b34
ebbdced
ce489d1
38639e4
915a1da
46255d4
aa60e1c
6590580
17bfbdd
594ed59
2eb6f72
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||
---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,283 @@ | ||||||||
/* | ||||||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||||||||
* or more contributor license agreements. Licensed under the "Elastic License | ||||||||
* 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side | ||||||||
* Public License v 1"; you may not use this file except in compliance with, at | ||||||||
* your election, the "Elastic License 2.0", the "GNU Affero General Public | ||||||||
* License v3.0 only", or the "Server Side Public License, v 1". | ||||||||
*/ | ||||||||
|
||||||||
package org.elasticsearch.datastreams; | ||||||||
|
||||||||
import org.elasticsearch.action.DocWriteRequest; | ||||||||
import org.elasticsearch.action.admin.indices.template.put.TransportPutComposableIndexTemplateAction; | ||||||||
import org.elasticsearch.action.bulk.BulkItemResponse; | ||||||||
import org.elasticsearch.action.bulk.BulkResponse; | ||||||||
import org.elasticsearch.action.bulk.FailureStoreMetrics; | ||||||||
import org.elasticsearch.action.bulk.IncrementalBulkService; | ||||||||
import org.elasticsearch.action.datastreams.CreateDataStreamAction; | ||||||||
import org.elasticsearch.action.datastreams.GetDataStreamAction; | ||||||||
import org.elasticsearch.action.index.IndexRequest; | ||||||||
import org.elasticsearch.action.support.PlainActionFuture; | ||||||||
import org.elasticsearch.cluster.metadata.ComposableIndexTemplate; | ||||||||
import org.elasticsearch.cluster.metadata.Template; | ||||||||
import org.elasticsearch.common.compress.CompressedXContent; | ||||||||
import org.elasticsearch.common.settings.Settings; | ||||||||
import org.elasticsearch.common.util.concurrent.EsRejectedExecutionException; | ||||||||
import org.elasticsearch.core.AbstractRefCounted; | ||||||||
import org.elasticsearch.core.Releasable; | ||||||||
import org.elasticsearch.core.Strings; | ||||||||
import org.elasticsearch.index.Index; | ||||||||
import org.elasticsearch.index.IndexService; | ||||||||
import org.elasticsearch.index.IndexingPressure; | ||||||||
import org.elasticsearch.index.mapper.DateFieldMapper; | ||||||||
import org.elasticsearch.index.mapper.extras.MapperExtrasPlugin; | ||||||||
import org.elasticsearch.index.shard.IndexShard; | ||||||||
import org.elasticsearch.index.shard.ShardId; | ||||||||
import org.elasticsearch.indices.IndicesService; | ||||||||
import org.elasticsearch.plugins.Plugin; | ||||||||
import org.elasticsearch.plugins.PluginsService; | ||||||||
import org.elasticsearch.telemetry.Measurement; | ||||||||
import org.elasticsearch.telemetry.TestTelemetryPlugin; | ||||||||
import org.elasticsearch.test.ESIntegTestCase; | ||||||||
import org.elasticsearch.xcontent.XContentType; | ||||||||
|
||||||||
import java.io.IOException; | ||||||||
import java.util.ArrayList; | ||||||||
import java.util.Collection; | ||||||||
import java.util.HashMap; | ||||||||
import java.util.List; | ||||||||
import java.util.Map; | ||||||||
import java.util.concurrent.atomic.AtomicBoolean; | ||||||||
import java.util.concurrent.atomic.AtomicLong; | ||||||||
import java.util.function.Consumer; | ||||||||
|
||||||||
import static org.elasticsearch.cluster.metadata.DataStreamTestHelper.backingIndexEqualTo; | ||||||||
import static org.elasticsearch.cluster.metadata.MetadataIndexTemplateService.DEFAULT_TIMESTAMP_FIELD; | ||||||||
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked; | ||||||||
import static org.hamcrest.Matchers.equalTo; | ||||||||
import static org.hamcrest.Matchers.instanceOf; | ||||||||
|
||||||||
public class FailureStoreMetricsWithIncrementalBulkIT extends ESIntegTestCase { | ||||||||
|
||||||||
private static final List<String> METRICS = List.of( | ||||||||
FailureStoreMetrics.METRIC_TOTAL, | ||||||||
FailureStoreMetrics.METRIC_FAILURE_STORE, | ||||||||
FailureStoreMetrics.METRIC_REJECTED | ||||||||
); | ||||||||
|
||||||||
private String dataStream = "data-stream-incremental"; | ||||||||
private String template = "template-incremental"; | ||||||||
|
||||||||
@Override | ||||||||
protected Collection<Class<? extends Plugin>> nodePlugins() { | ||||||||
return List.of(DataStreamsPlugin.class, TestTelemetryPlugin.class, MapperExtrasPlugin.class); | ||||||||
} | ||||||||
|
||||||||
@Override | ||||||||
protected Settings nodeSettings(int nodeOrdinal, Settings otherSettings) { | ||||||||
return Settings.builder() | ||||||||
.put(super.nodeSettings(nodeOrdinal, otherSettings)) | ||||||||
.put(IndexingPressure.SPLIT_BULK_LOW_WATERMARK.getKey(), "512B") | ||||||||
.put(IndexingPressure.SPLIT_BULK_LOW_WATERMARK_SIZE.getKey(), "2048B") | ||||||||
.put(IndexingPressure.SPLIT_BULK_HIGH_WATERMARK.getKey(), "2KB") | ||||||||
.put(IndexingPressure.SPLIT_BULK_HIGH_WATERMARK_SIZE.getKey(), "1024B") | ||||||||
.build(); | ||||||||
} | ||||||||
|
||||||||
public void testShortCircuitFailure() throws Exception { | ||||||||
putComposableIndexTemplate(true); | ||||||||
createDataStream(); | ||||||||
|
||||||||
String coordinatingOnlyNode = internalCluster().startCoordinatingOnlyNode(Settings.EMPTY); | ||||||||
|
||||||||
AbstractRefCounted refCounted = AbstractRefCounted.of(() -> {}); | ||||||||
IncrementalBulkService incrementalBulkService = internalCluster().getInstance(IncrementalBulkService.class, coordinatingOnlyNode); | ||||||||
IncrementalBulkService.Handler handler = incrementalBulkService.newBulkRequest(); | ||||||||
|
||||||||
AtomicBoolean nextRequested = new AtomicBoolean(true); | ||||||||
AtomicLong hits = new AtomicLong(0); | ||||||||
while (nextRequested.get()) { | ||||||||
nextRequested.set(false); | ||||||||
refCounted.incRef(); | ||||||||
handler.addItems(List.of(indexRequest(dataStream)), refCounted::decRef, () -> nextRequested.set(true)); | ||||||||
hits.incrementAndGet(); | ||||||||
} | ||||||||
assertBusy(() -> assertTrue(nextRequested.get())); | ||||||||
var measurements = collectTelemetry(); | ||||||||
assertMeasurements(measurements.get(FailureStoreMetrics.METRIC_TOTAL), (int) hits.get(), dataStream); | ||||||||
assertEquals(0, measurements.get(FailureStoreMetrics.METRIC_FAILURE_STORE).size()); | ||||||||
assertEquals(0, measurements.get(FailureStoreMetrics.METRIC_REJECTED).size()); | ||||||||
|
||||||||
GetDataStreamAction.Request getDataStreamRequest = new GetDataStreamAction.Request(TEST_REQUEST_TIMEOUT, new String[] { "*" }); | ||||||||
GetDataStreamAction.Response getDataStreamResponse = client().execute(GetDataStreamAction.INSTANCE, getDataStreamRequest) | ||||||||
.actionGet(); | ||||||||
assertThat(getDataStreamResponse.getDataStreams().size(), equalTo(1)); | ||||||||
assertThat(getDataStreamResponse.getDataStreams().get(0).getDataStream().getName(), equalTo(dataStream)); | ||||||||
assertThat(getDataStreamResponse.getDataStreams().get(0).getDataStream().getIndices().size(), equalTo(1)); | ||||||||
String backingIndex = getDataStreamResponse.getDataStreams().get(0).getDataStream().getIndices().get(0).getName(); | ||||||||
assertThat(backingIndex, backingIndexEqualTo(dataStream, 1)); | ||||||||
|
||||||||
String node = findShard(resolveIndex(backingIndex), 0); | ||||||||
IndexingPressure primaryPressure = internalCluster().getInstance(IndexingPressure.class, node); | ||||||||
long memoryLimit = primaryPressure.stats().getMemoryLimit(); | ||||||||
long primaryRejections = primaryPressure.stats().getPrimaryRejections(); | ||||||||
try (Releasable releasable = primaryPressure.markPrimaryOperationStarted(10, memoryLimit, false)) { | ||||||||
while (primaryPressure.stats().getPrimaryRejections() == primaryRejections) { | ||||||||
while (nextRequested.get()) { | ||||||||
nextRequested.set(false); | ||||||||
refCounted.incRef(); | ||||||||
List<DocWriteRequest<?>> requests = new ArrayList<>(); | ||||||||
for (int i = 0; i < 20; ++i) { | ||||||||
requests.add(indexRequest(dataStream)); | ||||||||
} | ||||||||
handler.addItems(requests, refCounted::decRef, () -> nextRequested.set(true)); | ||||||||
} | ||||||||
assertBusy(() -> assertTrue(nextRequested.get())); | ||||||||
} | ||||||||
} | ||||||||
|
||||||||
while (nextRequested.get()) { | ||||||||
nextRequested.set(false); | ||||||||
refCounted.incRef(); | ||||||||
handler.addItems(List.of(indexRequest(dataStream)), refCounted::decRef, () -> nextRequested.set(true)); | ||||||||
} | ||||||||
|
||||||||
assertBusy(() -> assertTrue(nextRequested.get())); | ||||||||
|
||||||||
PlainActionFuture<BulkResponse> future = new PlainActionFuture<>(); | ||||||||
handler.lastItems(List.of(indexRequest(dataStream)), refCounted::decRef, future); | ||||||||
|
||||||||
BulkResponse bulkResponse = safeGet(future); | ||||||||
|
||||||||
/* The datastream should have a failure store associated with it now */ | ||||||||
getDataStreamRequest = new GetDataStreamAction.Request(TEST_REQUEST_TIMEOUT, new String[] { "*" }); | ||||||||
getDataStreamResponse = client().execute(GetDataStreamAction.INSTANCE, getDataStreamRequest).actionGet(); | ||||||||
Index failureStoreIndex = getDataStreamResponse.getDataStreams().get(0).getDataStream().getFailureStoreWriteIndex(); | ||||||||
String failureStoreIndexName = failureStoreIndex.getName(); | ||||||||
String failure_node = findShard(resolveIndex(failureStoreIndexName), 0); | ||||||||
boolean shardsOnDifferentNodes = node.equals(failure_node) == false; | ||||||||
|
||||||||
for (int i = 0; i < hits.get(); ++i) { | ||||||||
assertFalse(bulkResponse.getItems()[i].isFailed()); | ||||||||
assertTrue(bulkResponse.getItems()[i].getFailureStoreStatus().getLabel().equalsIgnoreCase("NOT_APPLICABLE_OR_UNKNOWN")); | ||||||||
} | ||||||||
|
||||||||
int docs_redirected_to_fs = 0; | ||||||||
|
||||||||
int docs_in_fs = 0; | ||||||||
|
||||||||
for (int i = (int) hits.get(); i < bulkResponse.getItems().length; ++i) { | ||||||||
BulkItemResponse item = bulkResponse.getItems()[i]; | ||||||||
if (item.isFailed()) { | ||||||||
|
if (isFailureStoreRequest == false | |
&& failureStoreCandidate.isFailureStoreEnabled() | |
&& error instanceof VersionConflictEngineException == false) { |
If you agree I think it's worth the effort because right now the assertions are much more complex than they need to be. I could also give it a go if you want and we can ask @jbaiera to review. Would you feel more comfortable with that approach?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could we convert them these to constants? They look like they are.