|
@@ -26,15 +26,18 @@ import org.elasticsearch.cluster.block.ClusterBlockException;
|
|
import org.elasticsearch.cluster.block.ClusterBlockLevel;
|
|
import org.elasticsearch.cluster.block.ClusterBlockLevel;
|
|
import org.elasticsearch.cluster.metadata.ComponentTemplate;
|
|
import org.elasticsearch.cluster.metadata.ComponentTemplate;
|
|
import org.elasticsearch.cluster.metadata.ComposableIndexTemplate;
|
|
import org.elasticsearch.cluster.metadata.ComposableIndexTemplate;
|
|
|
|
+import org.elasticsearch.cluster.metadata.DataStream;
|
|
import org.elasticsearch.cluster.metadata.ProjectId;
|
|
import org.elasticsearch.cluster.metadata.ProjectId;
|
|
import org.elasticsearch.cluster.metadata.ProjectMetadata;
|
|
import org.elasticsearch.cluster.metadata.ProjectMetadata;
|
|
import org.elasticsearch.cluster.project.ProjectResolver;
|
|
import org.elasticsearch.cluster.project.ProjectResolver;
|
|
import org.elasticsearch.cluster.service.ClusterService;
|
|
import org.elasticsearch.cluster.service.ClusterService;
|
|
import org.elasticsearch.common.io.stream.Writeable;
|
|
import org.elasticsearch.common.io.stream.Writeable;
|
|
|
|
+import org.elasticsearch.common.streams.StreamType;
|
|
import org.elasticsearch.common.util.concurrent.EsExecutors;
|
|
import org.elasticsearch.common.util.concurrent.EsExecutors;
|
|
import org.elasticsearch.core.Assertions;
|
|
import org.elasticsearch.core.Assertions;
|
|
import org.elasticsearch.core.Releasable;
|
|
import org.elasticsearch.core.Releasable;
|
|
import org.elasticsearch.core.TimeValue;
|
|
import org.elasticsearch.core.TimeValue;
|
|
|
|
+import org.elasticsearch.features.FeatureService;
|
|
import org.elasticsearch.index.IndexingPressure;
|
|
import org.elasticsearch.index.IndexingPressure;
|
|
import org.elasticsearch.indices.SystemIndices;
|
|
import org.elasticsearch.indices.SystemIndices;
|
|
import org.elasticsearch.ingest.IngestService;
|
|
import org.elasticsearch.ingest.IngestService;
|
|
@@ -69,6 +72,7 @@ public abstract class TransportAbstractBulkAction extends HandledTransportAction
|
|
protected final Executor coordinationExecutor;
|
|
protected final Executor coordinationExecutor;
|
|
protected final Executor systemCoordinationExecutor;
|
|
protected final Executor systemCoordinationExecutor;
|
|
private final ActionType<BulkResponse> bulkAction;
|
|
private final ActionType<BulkResponse> bulkAction;
|
|
|
|
+ protected final FeatureService featureService;
|
|
|
|
|
|
public TransportAbstractBulkAction(
|
|
public TransportAbstractBulkAction(
|
|
ActionType<BulkResponse> action,
|
|
ActionType<BulkResponse> action,
|
|
@@ -81,7 +85,8 @@ public abstract class TransportAbstractBulkAction extends HandledTransportAction
|
|
IndexingPressure indexingPressure,
|
|
IndexingPressure indexingPressure,
|
|
SystemIndices systemIndices,
|
|
SystemIndices systemIndices,
|
|
ProjectResolver projectResolver,
|
|
ProjectResolver projectResolver,
|
|
- LongSupplier relativeTimeNanosProvider
|
|
|
|
|
|
+ LongSupplier relativeTimeNanosProvider,
|
|
|
|
+ FeatureService featureService
|
|
) {
|
|
) {
|
|
super(action.name(), transportService, actionFilters, requestReader, EsExecutors.DIRECT_EXECUTOR_SERVICE);
|
|
super(action.name(), transportService, actionFilters, requestReader, EsExecutors.DIRECT_EXECUTOR_SERVICE);
|
|
this.threadPool = threadPool;
|
|
this.threadPool = threadPool;
|
|
@@ -93,6 +98,7 @@ public abstract class TransportAbstractBulkAction extends HandledTransportAction
|
|
this.coordinationExecutor = threadPool.executor(ThreadPool.Names.WRITE_COORDINATION);
|
|
this.coordinationExecutor = threadPool.executor(ThreadPool.Names.WRITE_COORDINATION);
|
|
this.systemCoordinationExecutor = threadPool.executor(ThreadPool.Names.SYSTEM_WRITE_COORDINATION);
|
|
this.systemCoordinationExecutor = threadPool.executor(ThreadPool.Names.SYSTEM_WRITE_COORDINATION);
|
|
this.ingestForwarder = new IngestActionForwarder(transportService);
|
|
this.ingestForwarder = new IngestActionForwarder(transportService);
|
|
|
|
+ this.featureService = featureService;
|
|
clusterService.addStateApplier(this.ingestForwarder);
|
|
clusterService.addStateApplier(this.ingestForwarder);
|
|
this.relativeTimeNanosProvider = relativeTimeNanosProvider;
|
|
this.relativeTimeNanosProvider = relativeTimeNanosProvider;
|
|
this.bulkAction = action;
|
|
this.bulkAction = action;
|
|
@@ -396,8 +402,47 @@ public abstract class TransportAbstractBulkAction extends HandledTransportAction
|
|
ActionListener<BulkResponse> listener
|
|
ActionListener<BulkResponse> listener
|
|
) throws IOException {
|
|
) throws IOException {
|
|
final long relativeStartTimeNanos = relativeTimeNanos();
|
|
final long relativeStartTimeNanos = relativeTimeNanos();
|
|
- if (applyPipelines(task, bulkRequest, executor, listener) == false) {
|
|
|
|
- doInternalExecute(task, bulkRequest, executor, listener, relativeStartTimeNanos);
|
|
|
|
|
|
+
|
|
|
|
+ // Validate child stream writes before processing pipelines
|
|
|
|
+ ProjectMetadata projectMetadata = projectResolver.getProjectMetadata(clusterService.state());
|
|
|
|
+ BulkRequestModifier bulkRequestModifier = new BulkRequestModifier(bulkRequest);
|
|
|
|
+
|
|
|
|
+ DocWriteRequest<?> req;
|
|
|
|
+ int i = -1;
|
|
|
|
+ while (bulkRequestModifier.hasNext()) {
|
|
|
|
+ req = bulkRequestModifier.next();
|
|
|
|
+ i++;
|
|
|
|
+
|
|
|
|
+ for (StreamType streamType : StreamType.getEnabledStreamTypesForProject(projectMetadata)) {
|
|
|
|
+ if (req instanceof IndexRequest ir && streamType.matchesStreamPrefix(req.index()) && ir.isPipelineResolved() == false) {
|
|
|
|
+ IllegalArgumentException e = new IllegalArgumentException(
|
|
|
|
+ "Direct writes to child streams are prohibited. Index directly into the ["
|
|
|
|
+ + streamType.getStreamName()
|
|
|
|
+ + "] stream instead"
|
|
|
|
+ );
|
|
|
|
+ Boolean failureStoreEnabled = resolveFailureStore(req.index(), projectMetadata, threadPool.absoluteTimeInMillis());
|
|
|
|
+
|
|
|
|
+ if (featureService.clusterHasFeature(clusterService.state(), DataStream.DATA_STREAM_FAILURE_STORE_FEATURE)) {
|
|
|
|
+ if (Boolean.TRUE.equals(failureStoreEnabled)) {
|
|
|
|
+ bulkRequestModifier.markItemForFailureStore(i, req.index(), e);
|
|
|
|
+ } else if (Boolean.FALSE.equals(failureStoreEnabled)) {
|
|
|
|
+ bulkRequestModifier.markItemAsFailed(i, e, IndexDocFailureStoreStatus.NOT_ENABLED);
|
|
|
|
+ } else {
|
|
|
|
+ bulkRequestModifier.markItemAsFailed(i, e, IndexDocFailureStoreStatus.NOT_APPLICABLE_OR_UNKNOWN);
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ bulkRequestModifier.markItemAsFailed(i, e, IndexDocFailureStoreStatus.NOT_APPLICABLE_OR_UNKNOWN);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ var wrappedListener = bulkRequestModifier.wrapActionListenerIfNeeded(listener);
|
|
|
|
+
|
|
|
|
+ if (applyPipelines(task, bulkRequestModifier.getBulkRequest(), executor, wrappedListener) == false) {
|
|
|
|
+ doInternalExecute(task, bulkRequestModifier.getBulkRequest(), executor, wrappedListener, relativeStartTimeNanos);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|