Move ML Optimistic Concurrency Control to Seq No (#38278)
This commit moves the usage of internal versioning for CAS operations to use sequence numbers and primary terms Relates to #36148 Relates to #10708
This commit is contained in:
parent
1d82a6d9f9
commit
ff13a43144
|
@ -514,7 +514,7 @@ public class TransportOpenJobAction extends TransportMasterNodeAction<OpenJobAct
|
||||||
private void clearJobFinishedTime(String jobId, ActionListener<AcknowledgedResponse> listener) {
|
private void clearJobFinishedTime(String jobId, ActionListener<AcknowledgedResponse> listener) {
|
||||||
JobUpdate update = new JobUpdate.Builder(jobId).setClearFinishTime(true).build();
|
JobUpdate update = new JobUpdate.Builder(jobId).setClearFinishTime(true).build();
|
||||||
|
|
||||||
jobConfigProvider.updateJob(jobId, update, null, ActionListener.wrap(
|
jobConfigProvider.updateJob(jobId, update, null, clusterService.state().nodes().getMinNodeVersion(), ActionListener.wrap(
|
||||||
job -> listener.onResponse(new AcknowledgedResponse(true)),
|
job -> listener.onResponse(new AcknowledgedResponse(true)),
|
||||||
e -> {
|
e -> {
|
||||||
logger.error("[" + jobId + "] Failed to clear finished_time", e);
|
logger.error("[" + jobId + "] Failed to clear finished_time", e);
|
||||||
|
|
|
@ -87,7 +87,7 @@ public class TransportUpdateDatafeedAction extends TransportMasterNodeAction<Upd
|
||||||
|
|
||||||
CheckedConsumer<Boolean, Exception> updateConsumer = ok -> {
|
CheckedConsumer<Boolean, Exception> updateConsumer = ok -> {
|
||||||
datafeedConfigProvider.updateDatefeedConfig(request.getUpdate().getId(), request.getUpdate(), headers,
|
datafeedConfigProvider.updateDatefeedConfig(request.getUpdate().getId(), request.getUpdate(), headers,
|
||||||
jobConfigProvider::validateDatafeedJob,
|
jobConfigProvider::validateDatafeedJob, clusterService.state().nodes().getMinNodeVersion(),
|
||||||
ActionListener.wrap(
|
ActionListener.wrap(
|
||||||
updatedConfig -> listener.onResponse(new PutDatafeedAction.Response(updatedConfig)),
|
updatedConfig -> listener.onResponse(new PutDatafeedAction.Response(updatedConfig)),
|
||||||
listener::onFailure
|
listener::onFailure
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
package org.elasticsearch.xpack.ml.action;
|
package org.elasticsearch.xpack.ml.action;
|
||||||
|
|
||||||
import org.elasticsearch.ResourceNotFoundException;
|
import org.elasticsearch.ResourceNotFoundException;
|
||||||
|
import org.elasticsearch.Version;
|
||||||
import org.elasticsearch.action.ActionListener;
|
import org.elasticsearch.action.ActionListener;
|
||||||
import org.elasticsearch.action.get.GetAction;
|
import org.elasticsearch.action.get.GetAction;
|
||||||
import org.elasticsearch.action.get.GetRequest;
|
import org.elasticsearch.action.get.GetRequest;
|
||||||
|
@ -17,6 +18,7 @@ import org.elasticsearch.action.support.ActionFilters;
|
||||||
import org.elasticsearch.action.support.HandledTransportAction;
|
import org.elasticsearch.action.support.HandledTransportAction;
|
||||||
import org.elasticsearch.action.support.WriteRequest;
|
import org.elasticsearch.action.support.WriteRequest;
|
||||||
import org.elasticsearch.client.Client;
|
import org.elasticsearch.client.Client;
|
||||||
|
import org.elasticsearch.cluster.service.ClusterService;
|
||||||
import org.elasticsearch.common.bytes.BytesReference;
|
import org.elasticsearch.common.bytes.BytesReference;
|
||||||
import org.elasticsearch.common.inject.Inject;
|
import org.elasticsearch.common.inject.Inject;
|
||||||
import org.elasticsearch.common.xcontent.LoggingDeprecationHandler;
|
import org.elasticsearch.common.xcontent.LoggingDeprecationHandler;
|
||||||
|
@ -52,14 +54,16 @@ public class TransportUpdateFilterAction extends HandledTransportAction<UpdateFi
|
||||||
|
|
||||||
private final Client client;
|
private final Client client;
|
||||||
private final JobManager jobManager;
|
private final JobManager jobManager;
|
||||||
|
private final ClusterService clusterService;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public TransportUpdateFilterAction(TransportService transportService, ActionFilters actionFilters, Client client,
|
public TransportUpdateFilterAction(TransportService transportService, ActionFilters actionFilters, Client client,
|
||||||
JobManager jobManager) {
|
JobManager jobManager, ClusterService clusterService) {
|
||||||
super(UpdateFilterAction.NAME, transportService, actionFilters,
|
super(UpdateFilterAction.NAME, transportService, actionFilters,
|
||||||
(Supplier<UpdateFilterAction.Request>) UpdateFilterAction.Request::new);
|
(Supplier<UpdateFilterAction.Request>) UpdateFilterAction.Request::new);
|
||||||
this.client = client;
|
this.client = client;
|
||||||
this.jobManager = jobManager;
|
this.jobManager = jobManager;
|
||||||
|
this.clusterService = clusterService;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -95,13 +99,20 @@ public class TransportUpdateFilterAction extends HandledTransportAction<UpdateFi
|
||||||
}
|
}
|
||||||
|
|
||||||
MlFilter updatedFilter = MlFilter.builder(filter.getId()).setDescription(description).setItems(items).build();
|
MlFilter updatedFilter = MlFilter.builder(filter.getId()).setDescription(description).setItems(items).build();
|
||||||
indexUpdatedFilter(updatedFilter, filterWithVersion.version, request, listener);
|
indexUpdatedFilter(
|
||||||
|
updatedFilter, filterWithVersion.version, filterWithVersion.seqNo, filterWithVersion.primaryTerm, request, listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void indexUpdatedFilter(MlFilter filter, long version, UpdateFilterAction.Request request,
|
private void indexUpdatedFilter(MlFilter filter, final long version, final long seqNo, final long primaryTerm,
|
||||||
|
UpdateFilterAction.Request request,
|
||||||
ActionListener<PutFilterAction.Response> listener) {
|
ActionListener<PutFilterAction.Response> listener) {
|
||||||
IndexRequest indexRequest = new IndexRequest(MlMetaIndex.INDEX_NAME, MlMetaIndex.TYPE, filter.documentId());
|
IndexRequest indexRequest = new IndexRequest(MlMetaIndex.INDEX_NAME, MlMetaIndex.TYPE, filter.documentId());
|
||||||
indexRequest.version(version);
|
if (clusterService.state().nodes().getMinNodeVersion().onOrAfter(Version.V_6_7_0)) {
|
||||||
|
indexRequest.setIfSeqNo(seqNo);
|
||||||
|
indexRequest.setIfPrimaryTerm(primaryTerm);
|
||||||
|
} else {
|
||||||
|
indexRequest.version(version);
|
||||||
|
}
|
||||||
indexRequest.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE);
|
indexRequest.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE);
|
||||||
|
|
||||||
try (XContentBuilder builder = XContentFactory.jsonBuilder()) {
|
try (XContentBuilder builder = XContentFactory.jsonBuilder()) {
|
||||||
|
@ -146,7 +157,7 @@ public class TransportUpdateFilterAction extends HandledTransportAction<UpdateFi
|
||||||
XContentParser parser = XContentFactory.xContent(XContentType.JSON)
|
XContentParser parser = XContentFactory.xContent(XContentType.JSON)
|
||||||
.createParser(NamedXContentRegistry.EMPTY, LoggingDeprecationHandler.INSTANCE, stream)) {
|
.createParser(NamedXContentRegistry.EMPTY, LoggingDeprecationHandler.INSTANCE, stream)) {
|
||||||
MlFilter filter = MlFilter.LENIENT_PARSER.apply(parser, null).build();
|
MlFilter filter = MlFilter.LENIENT_PARSER.apply(parser, null).build();
|
||||||
listener.onResponse(new FilterWithVersion(filter, getDocResponse.getVersion()));
|
listener.onResponse(new FilterWithVersion(filter, getDocResponse));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
this.onFailure(new ResourceNotFoundException(Messages.getMessage(Messages.FILTER_NOT_FOUND, filterId)));
|
this.onFailure(new ResourceNotFoundException(Messages.getMessage(Messages.FILTER_NOT_FOUND, filterId)));
|
||||||
|
@ -167,10 +178,15 @@ public class TransportUpdateFilterAction extends HandledTransportAction<UpdateFi
|
||||||
|
|
||||||
private final MlFilter filter;
|
private final MlFilter filter;
|
||||||
private final long version;
|
private final long version;
|
||||||
|
private final long seqNo;
|
||||||
|
private final long primaryTerm;
|
||||||
|
|
||||||
private FilterWithVersion(MlFilter filter, long version) {
|
private FilterWithVersion(MlFilter filter, GetResponse getDocResponse) {
|
||||||
this.filter = filter;
|
this.filter = filter;
|
||||||
this.version = version;
|
this.version = getDocResponse.getVersion();
|
||||||
|
this.seqNo = getDocResponse.getSeqNo();
|
||||||
|
this.primaryTerm = getDocResponse.getPrimaryTerm();
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ package org.elasticsearch.xpack.ml.datafeed.persistence;
|
||||||
import org.apache.logging.log4j.LogManager;
|
import org.apache.logging.log4j.LogManager;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
import org.elasticsearch.ElasticsearchParseException;
|
import org.elasticsearch.ElasticsearchParseException;
|
||||||
|
import org.elasticsearch.Version;
|
||||||
import org.elasticsearch.action.ActionListener;
|
import org.elasticsearch.action.ActionListener;
|
||||||
import org.elasticsearch.action.DocWriteRequest;
|
import org.elasticsearch.action.DocWriteRequest;
|
||||||
import org.elasticsearch.action.DocWriteResponse;
|
import org.elasticsearch.action.DocWriteResponse;
|
||||||
|
@ -19,6 +20,7 @@ import org.elasticsearch.action.get.GetRequest;
|
||||||
import org.elasticsearch.action.get.GetResponse;
|
import org.elasticsearch.action.get.GetResponse;
|
||||||
import org.elasticsearch.action.index.IndexAction;
|
import org.elasticsearch.action.index.IndexAction;
|
||||||
import org.elasticsearch.action.index.IndexRequest;
|
import org.elasticsearch.action.index.IndexRequest;
|
||||||
|
import org.elasticsearch.action.index.IndexRequestBuilder;
|
||||||
import org.elasticsearch.action.index.IndexResponse;
|
import org.elasticsearch.action.index.IndexResponse;
|
||||||
import org.elasticsearch.action.search.SearchRequest;
|
import org.elasticsearch.action.search.SearchRequest;
|
||||||
import org.elasticsearch.action.search.SearchResponse;
|
import org.elasticsearch.action.search.SearchResponse;
|
||||||
|
@ -262,10 +264,12 @@ public class DatafeedConfigProvider {
|
||||||
* @param headers Datafeed headers applied with the update
|
* @param headers Datafeed headers applied with the update
|
||||||
* @param validator BiConsumer that accepts the updated config and can perform
|
* @param validator BiConsumer that accepts the updated config and can perform
|
||||||
* extra validations. {@code validator} must call the passed listener
|
* extra validations. {@code validator} must call the passed listener
|
||||||
|
* @param minClusterNodeVersion minimum version of nodes in cluster
|
||||||
* @param updatedConfigListener Updated datafeed config listener
|
* @param updatedConfigListener Updated datafeed config listener
|
||||||
*/
|
*/
|
||||||
public void updateDatefeedConfig(String datafeedId, DatafeedUpdate update, Map<String, String> headers,
|
public void updateDatefeedConfig(String datafeedId, DatafeedUpdate update, Map<String, String> headers,
|
||||||
BiConsumer<DatafeedConfig, ActionListener<Boolean>> validator,
|
BiConsumer<DatafeedConfig, ActionListener<Boolean>> validator,
|
||||||
|
Version minClusterNodeVersion,
|
||||||
ActionListener<DatafeedConfig> updatedConfigListener) {
|
ActionListener<DatafeedConfig> updatedConfigListener) {
|
||||||
GetRequest getRequest = new GetRequest(AnomalyDetectorsIndex.configIndexName(),
|
GetRequest getRequest = new GetRequest(AnomalyDetectorsIndex.configIndexName(),
|
||||||
ElasticsearchMappings.DOC_TYPE, DatafeedConfig.documentId(datafeedId));
|
ElasticsearchMappings.DOC_TYPE, DatafeedConfig.documentId(datafeedId));
|
||||||
|
@ -277,7 +281,9 @@ public class DatafeedConfigProvider {
|
||||||
updatedConfigListener.onFailure(ExceptionsHelper.missingDatafeedException(datafeedId));
|
updatedConfigListener.onFailure(ExceptionsHelper.missingDatafeedException(datafeedId));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
long version = getResponse.getVersion();
|
final long version = getResponse.getVersion();
|
||||||
|
final long seqNo = getResponse.getSeqNo();
|
||||||
|
final long primaryTerm = getResponse.getPrimaryTerm();
|
||||||
BytesReference source = getResponse.getSourceAsBytesRef();
|
BytesReference source = getResponse.getSourceAsBytesRef();
|
||||||
DatafeedConfig.Builder configBuilder;
|
DatafeedConfig.Builder configBuilder;
|
||||||
try {
|
try {
|
||||||
|
@ -298,7 +304,7 @@ public class DatafeedConfigProvider {
|
||||||
|
|
||||||
ActionListener<Boolean> validatedListener = ActionListener.wrap(
|
ActionListener<Boolean> validatedListener = ActionListener.wrap(
|
||||||
ok -> {
|
ok -> {
|
||||||
indexUpdatedConfig(updatedConfig, version, ActionListener.wrap(
|
indexUpdatedConfig(updatedConfig, version, seqNo, primaryTerm, minClusterNodeVersion, ActionListener.wrap(
|
||||||
indexResponse -> {
|
indexResponse -> {
|
||||||
assert indexResponse.getResult() == DocWriteResponse.Result.UPDATED;
|
assert indexResponse.getResult() == DocWriteResponse.Result.UPDATED;
|
||||||
updatedConfigListener.onResponse(updatedConfig);
|
updatedConfigListener.onResponse(updatedConfig);
|
||||||
|
@ -318,17 +324,23 @@ public class DatafeedConfigProvider {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void indexUpdatedConfig(DatafeedConfig updatedConfig, long version, ActionListener<IndexResponse> listener) {
|
private void indexUpdatedConfig(DatafeedConfig updatedConfig, long version, long seqNo, long primaryTerm,
|
||||||
|
Version minClusterNodeVersion, ActionListener<IndexResponse> listener) {
|
||||||
try (XContentBuilder builder = XContentFactory.jsonBuilder()) {
|
try (XContentBuilder builder = XContentFactory.jsonBuilder()) {
|
||||||
XContentBuilder updatedSource = updatedConfig.toXContent(builder, new ToXContent.MapParams(TO_XCONTENT_PARAMS));
|
XContentBuilder updatedSource = updatedConfig.toXContent(builder, new ToXContent.MapParams(TO_XCONTENT_PARAMS));
|
||||||
IndexRequest indexRequest = client.prepareIndex(AnomalyDetectorsIndex.configIndexName(),
|
IndexRequestBuilder indexRequest = client.prepareIndex(AnomalyDetectorsIndex.configIndexName(),
|
||||||
ElasticsearchMappings.DOC_TYPE, DatafeedConfig.documentId(updatedConfig.getId()))
|
ElasticsearchMappings.DOC_TYPE, DatafeedConfig.documentId(updatedConfig.getId()))
|
||||||
.setSource(updatedSource)
|
.setSource(updatedSource)
|
||||||
.setVersion(version)
|
.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE);
|
||||||
.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE)
|
|
||||||
.request();
|
|
||||||
|
|
||||||
executeAsyncWithOrigin(client, ML_ORIGIN, IndexAction.INSTANCE, indexRequest, listener);
|
if (minClusterNodeVersion.onOrAfter(Version.V_6_7_0)) {
|
||||||
|
indexRequest.setIfSeqNo(seqNo);
|
||||||
|
indexRequest.setIfPrimaryTerm(primaryTerm);
|
||||||
|
} else {
|
||||||
|
indexRequest.setVersion(version);
|
||||||
|
}
|
||||||
|
|
||||||
|
executeAsyncWithOrigin(client, ML_ORIGIN, IndexAction.INSTANCE, indexRequest.request(), listener);
|
||||||
|
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
listener.onFailure(
|
listener.onFailure(
|
||||||
|
|
|
@ -333,7 +333,7 @@ public class JobManager {
|
||||||
|
|
||||||
Runnable doUpdate = () -> {
|
Runnable doUpdate = () -> {
|
||||||
jobConfigProvider.updateJobWithValidation(request.getJobId(), request.getJobUpdate(), maxModelMemoryLimit,
|
jobConfigProvider.updateJobWithValidation(request.getJobId(), request.getJobUpdate(), maxModelMemoryLimit,
|
||||||
this::validate, ActionListener.wrap(
|
this::validate, clusterService.state().nodes().getMinNodeVersion(), ActionListener.wrap(
|
||||||
updatedJob -> postJobUpdate(request, updatedJob, actionListener),
|
updatedJob -> postJobUpdate(request, updatedJob, actionListener),
|
||||||
actionListener::onFailure
|
actionListener::onFailure
|
||||||
));
|
));
|
||||||
|
@ -603,8 +603,8 @@ public class JobManager {
|
||||||
.setModelSnapshotId(modelSnapshot.getSnapshotId())
|
.setModelSnapshotId(modelSnapshot.getSnapshotId())
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
jobConfigProvider.updateJob(request.getJobId(), update, maxModelMemoryLimit, ActionListener.wrap(
|
jobConfigProvider.updateJob(request.getJobId(), update, maxModelMemoryLimit, clusterService.state().nodes().getMinNodeVersion(),
|
||||||
job -> {
|
ActionListener.wrap(job -> {
|
||||||
auditor.info(request.getJobId(),
|
auditor.info(request.getJobId(),
|
||||||
Messages.getMessage(Messages.JOB_AUDIT_REVERTED, modelSnapshot.getDescription()));
|
Messages.getMessage(Messages.JOB_AUDIT_REVERTED, modelSnapshot.getDescription()));
|
||||||
updateHandler.accept(Boolean.TRUE);
|
updateHandler.accept(Boolean.TRUE);
|
||||||
|
|
|
@ -10,6 +10,7 @@ import org.apache.logging.log4j.Logger;
|
||||||
import org.apache.lucene.search.join.ScoreMode;
|
import org.apache.lucene.search.join.ScoreMode;
|
||||||
import org.elasticsearch.ElasticsearchException;
|
import org.elasticsearch.ElasticsearchException;
|
||||||
import org.elasticsearch.ElasticsearchParseException;
|
import org.elasticsearch.ElasticsearchParseException;
|
||||||
|
import org.elasticsearch.Version;
|
||||||
import org.elasticsearch.action.ActionListener;
|
import org.elasticsearch.action.ActionListener;
|
||||||
import org.elasticsearch.action.DocWriteRequest;
|
import org.elasticsearch.action.DocWriteRequest;
|
||||||
import org.elasticsearch.action.DocWriteResponse;
|
import org.elasticsearch.action.DocWriteResponse;
|
||||||
|
@ -21,6 +22,7 @@ import org.elasticsearch.action.get.GetRequest;
|
||||||
import org.elasticsearch.action.get.GetResponse;
|
import org.elasticsearch.action.get.GetResponse;
|
||||||
import org.elasticsearch.action.index.IndexAction;
|
import org.elasticsearch.action.index.IndexAction;
|
||||||
import org.elasticsearch.action.index.IndexRequest;
|
import org.elasticsearch.action.index.IndexRequest;
|
||||||
|
import org.elasticsearch.action.index.IndexRequestBuilder;
|
||||||
import org.elasticsearch.action.index.IndexResponse;
|
import org.elasticsearch.action.index.IndexResponse;
|
||||||
import org.elasticsearch.action.search.SearchRequest;
|
import org.elasticsearch.action.search.SearchRequest;
|
||||||
import org.elasticsearch.action.search.SearchResponse;
|
import org.elasticsearch.action.search.SearchResponse;
|
||||||
|
@ -225,9 +227,12 @@ public class JobConfigProvider {
|
||||||
* @param maxModelMemoryLimit The maximum model memory allowed. This can be {@code null}
|
* @param maxModelMemoryLimit The maximum model memory allowed. This can be {@code null}
|
||||||
* if the job's {@link org.elasticsearch.xpack.core.ml.job.config.AnalysisLimits}
|
* if the job's {@link org.elasticsearch.xpack.core.ml.job.config.AnalysisLimits}
|
||||||
* are not changed.
|
* are not changed.
|
||||||
|
* @param minClusterNodeVersion the minimum version of nodes in the cluster
|
||||||
* @param updatedJobListener Updated job listener
|
* @param updatedJobListener Updated job listener
|
||||||
*/
|
*/
|
||||||
public void updateJob(String jobId, JobUpdate update, ByteSizeValue maxModelMemoryLimit, ActionListener<Job> updatedJobListener) {
|
public void updateJob(String jobId, JobUpdate update, ByteSizeValue maxModelMemoryLimit,
|
||||||
|
Version minClusterNodeVersion,
|
||||||
|
ActionListener<Job> updatedJobListener) {
|
||||||
GetRequest getRequest = new GetRequest(AnomalyDetectorsIndex.configIndexName(),
|
GetRequest getRequest = new GetRequest(AnomalyDetectorsIndex.configIndexName(),
|
||||||
ElasticsearchMappings.DOC_TYPE, Job.documentId(jobId));
|
ElasticsearchMappings.DOC_TYPE, Job.documentId(jobId));
|
||||||
|
|
||||||
|
@ -239,7 +244,9 @@ public class JobConfigProvider {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
long version = getResponse.getVersion();
|
final long version = getResponse.getVersion();
|
||||||
|
final long seqNo = getResponse.getSeqNo();
|
||||||
|
final long primaryTerm = getResponse.getPrimaryTerm();
|
||||||
BytesReference source = getResponse.getSourceAsBytesRef();
|
BytesReference source = getResponse.getSourceAsBytesRef();
|
||||||
Job.Builder jobBuilder;
|
Job.Builder jobBuilder;
|
||||||
try {
|
try {
|
||||||
|
@ -259,7 +266,7 @@ public class JobConfigProvider {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
indexUpdatedJob(updatedJob, version, updatedJobListener);
|
indexUpdatedJob(updatedJob, version, seqNo, primaryTerm, minClusterNodeVersion, updatedJobListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -280,17 +287,18 @@ public class JobConfigProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Similar to {@link #updateJob(String, JobUpdate, ByteSizeValue, ActionListener)} but
|
* Similar to {@link #updateJob(String, JobUpdate, ByteSizeValue, Version, ActionListener)} but
|
||||||
* with an extra validation step which is called before the updated is applied.
|
* with an extra validation step which is called before the updated is applied.
|
||||||
*
|
*
|
||||||
* @param jobId The Id of the job to update
|
* @param jobId The Id of the job to update
|
||||||
* @param update The job update
|
* @param update The job update
|
||||||
* @param maxModelMemoryLimit The maximum model memory allowed
|
* @param maxModelMemoryLimit The maximum model memory allowed
|
||||||
* @param validator The job update validator
|
* @param validator The job update validator
|
||||||
|
* @param minClusterNodeVersion the minimum version of a node ifn the cluster
|
||||||
* @param updatedJobListener Updated job listener
|
* @param updatedJobListener Updated job listener
|
||||||
*/
|
*/
|
||||||
public void updateJobWithValidation(String jobId, JobUpdate update, ByteSizeValue maxModelMemoryLimit,
|
public void updateJobWithValidation(String jobId, JobUpdate update, ByteSizeValue maxModelMemoryLimit,
|
||||||
UpdateValidator validator, ActionListener<Job> updatedJobListener) {
|
UpdateValidator validator, Version minClusterNodeVersion, ActionListener<Job> updatedJobListener) {
|
||||||
GetRequest getRequest = new GetRequest(AnomalyDetectorsIndex.configIndexName(),
|
GetRequest getRequest = new GetRequest(AnomalyDetectorsIndex.configIndexName(),
|
||||||
ElasticsearchMappings.DOC_TYPE, Job.documentId(jobId));
|
ElasticsearchMappings.DOC_TYPE, Job.documentId(jobId));
|
||||||
|
|
||||||
|
@ -302,7 +310,9 @@ public class JobConfigProvider {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
long version = getResponse.getVersion();
|
final long version = getResponse.getVersion();
|
||||||
|
final long seqNo = getResponse.getSeqNo();
|
||||||
|
final long primaryTerm = getResponse.getPrimaryTerm();
|
||||||
BytesReference source = getResponse.getSourceAsBytesRef();
|
BytesReference source = getResponse.getSourceAsBytesRef();
|
||||||
Job originalJob;
|
Job originalJob;
|
||||||
try {
|
try {
|
||||||
|
@ -324,7 +334,7 @@ public class JobConfigProvider {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
indexUpdatedJob(updatedJob, version, updatedJobListener);
|
indexUpdatedJob(updatedJob, version, seqNo, primaryTerm, minClusterNodeVersion, updatedJobListener);
|
||||||
},
|
},
|
||||||
updatedJobListener::onFailure
|
updatedJobListener::onFailure
|
||||||
));
|
));
|
||||||
|
@ -337,17 +347,22 @@ public class JobConfigProvider {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void indexUpdatedJob(Job updatedJob, long version, ActionListener<Job> updatedJobListener) {
|
private void indexUpdatedJob(Job updatedJob, long version, long seqNo, long primaryTerm, Version minClusterNodeVersion,
|
||||||
|
ActionListener<Job> updatedJobListener) {
|
||||||
try (XContentBuilder builder = XContentFactory.jsonBuilder()) {
|
try (XContentBuilder builder = XContentFactory.jsonBuilder()) {
|
||||||
XContentBuilder updatedSource = updatedJob.toXContent(builder, ToXContent.EMPTY_PARAMS);
|
XContentBuilder updatedSource = updatedJob.toXContent(builder, ToXContent.EMPTY_PARAMS);
|
||||||
IndexRequest indexRequest = client.prepareIndex(AnomalyDetectorsIndex.configIndexName(),
|
IndexRequestBuilder indexRequest = client.prepareIndex(AnomalyDetectorsIndex.configIndexName(),
|
||||||
ElasticsearchMappings.DOC_TYPE, Job.documentId(updatedJob.getId()))
|
ElasticsearchMappings.DOC_TYPE, Job.documentId(updatedJob.getId()))
|
||||||
.setSource(updatedSource)
|
.setSource(updatedSource)
|
||||||
.setVersion(version)
|
.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE);
|
||||||
.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE)
|
if (minClusterNodeVersion.onOrAfter(Version.V_6_7_0)) {
|
||||||
.request();
|
indexRequest.setIfSeqNo(seqNo);
|
||||||
|
indexRequest.setIfPrimaryTerm(primaryTerm);
|
||||||
|
} else {
|
||||||
|
indexRequest.setVersion(version);
|
||||||
|
}
|
||||||
|
|
||||||
executeAsyncWithOrigin(client, ML_ORIGIN, IndexAction.INSTANCE, indexRequest, ActionListener.wrap(
|
executeAsyncWithOrigin(client, ML_ORIGIN, IndexAction.INSTANCE, indexRequest.request(), ActionListener.wrap(
|
||||||
indexResponse -> {
|
indexResponse -> {
|
||||||
assert indexResponse.getResult() == DocWriteResponse.Result.UPDATED;
|
assert indexResponse.getResult() == DocWriteResponse.Result.UPDATED;
|
||||||
updatedJobListener.onResponse(updatedJob);
|
updatedJobListener.onResponse(updatedJob);
|
||||||
|
|
|
@ -7,6 +7,7 @@ package org.elasticsearch.xpack.ml.integration;
|
||||||
|
|
||||||
import org.elasticsearch.ResourceAlreadyExistsException;
|
import org.elasticsearch.ResourceAlreadyExistsException;
|
||||||
import org.elasticsearch.ResourceNotFoundException;
|
import org.elasticsearch.ResourceNotFoundException;
|
||||||
|
import org.elasticsearch.Version;
|
||||||
import org.elasticsearch.action.ActionListener;
|
import org.elasticsearch.action.ActionListener;
|
||||||
import org.elasticsearch.action.DocWriteResponse;
|
import org.elasticsearch.action.DocWriteResponse;
|
||||||
import org.elasticsearch.action.delete.DeleteResponse;
|
import org.elasticsearch.action.delete.DeleteResponse;
|
||||||
|
@ -86,7 +87,7 @@ public class DatafeedConfigProviderIT extends MlSingleNodeTestCase {
|
||||||
AtomicReference<DatafeedConfig> configHolder = new AtomicReference<>();
|
AtomicReference<DatafeedConfig> configHolder = new AtomicReference<>();
|
||||||
blockingCall(actionListener ->
|
blockingCall(actionListener ->
|
||||||
datafeedConfigProvider.updateDatefeedConfig(datafeedId, update.build(), updateHeaders,
|
datafeedConfigProvider.updateDatefeedConfig(datafeedId, update.build(), updateHeaders,
|
||||||
(updatedConfig, listener) -> listener.onResponse(Boolean.TRUE), actionListener),
|
(updatedConfig, listener) -> listener.onResponse(Boolean.TRUE), Version.CURRENT, actionListener),
|
||||||
configHolder, exceptionHolder);
|
configHolder, exceptionHolder);
|
||||||
assertNull(exceptionHolder.get());
|
assertNull(exceptionHolder.get());
|
||||||
assertThat(configHolder.get().getIndices(), equalTo(updateIndices));
|
assertThat(configHolder.get().getIndices(), equalTo(updateIndices));
|
||||||
|
@ -167,7 +168,7 @@ public class DatafeedConfigProviderIT extends MlSingleNodeTestCase {
|
||||||
AtomicReference<DatafeedConfig> configHolder = new AtomicReference<>();
|
AtomicReference<DatafeedConfig> configHolder = new AtomicReference<>();
|
||||||
blockingCall(actionListener ->
|
blockingCall(actionListener ->
|
||||||
datafeedConfigProvider.updateDatefeedConfig(datafeedId, update.build(), Collections.emptyMap(),
|
datafeedConfigProvider.updateDatefeedConfig(datafeedId, update.build(), Collections.emptyMap(),
|
||||||
(updatedConfig, listener) -> listener.onResponse(Boolean.TRUE), actionListener),
|
(updatedConfig, listener) -> listener.onResponse(Boolean.TRUE), Version.CURRENT, actionListener),
|
||||||
configHolder, exceptionHolder);
|
configHolder, exceptionHolder);
|
||||||
assertNull(configHolder.get());
|
assertNull(configHolder.get());
|
||||||
assertNotNull(exceptionHolder.get());
|
assertNotNull(exceptionHolder.get());
|
||||||
|
@ -193,7 +194,7 @@ public class DatafeedConfigProviderIT extends MlSingleNodeTestCase {
|
||||||
AtomicReference<Exception> exceptionHolder = new AtomicReference<>();
|
AtomicReference<Exception> exceptionHolder = new AtomicReference<>();
|
||||||
blockingCall(actionListener ->
|
blockingCall(actionListener ->
|
||||||
datafeedConfigProvider.updateDatefeedConfig(datafeedId, update.build(), Collections.emptyMap(),
|
datafeedConfigProvider.updateDatefeedConfig(datafeedId, update.build(), Collections.emptyMap(),
|
||||||
validateErrorFunction, actionListener),
|
validateErrorFunction, Version.CURRENT, actionListener),
|
||||||
configHolder, exceptionHolder);
|
configHolder, exceptionHolder);
|
||||||
|
|
||||||
assertNull(configHolder.get());
|
assertNull(configHolder.get());
|
||||||
|
|
|
@ -8,6 +8,7 @@ package org.elasticsearch.xpack.ml.integration;
|
||||||
import org.elasticsearch.ElasticsearchStatusException;
|
import org.elasticsearch.ElasticsearchStatusException;
|
||||||
import org.elasticsearch.ResourceAlreadyExistsException;
|
import org.elasticsearch.ResourceAlreadyExistsException;
|
||||||
import org.elasticsearch.ResourceNotFoundException;
|
import org.elasticsearch.ResourceNotFoundException;
|
||||||
|
import org.elasticsearch.Version;
|
||||||
import org.elasticsearch.action.DocWriteResponse;
|
import org.elasticsearch.action.DocWriteResponse;
|
||||||
import org.elasticsearch.action.delete.DeleteResponse;
|
import org.elasticsearch.action.delete.DeleteResponse;
|
||||||
import org.elasticsearch.action.index.IndexResponse;
|
import org.elasticsearch.action.index.IndexResponse;
|
||||||
|
@ -147,8 +148,8 @@ public class JobConfigProviderIT extends MlSingleNodeTestCase {
|
||||||
JobUpdate jobUpdate = new JobUpdate.Builder(jobId).setDescription("This job has been updated").build();
|
JobUpdate jobUpdate = new JobUpdate.Builder(jobId).setDescription("This job has been updated").build();
|
||||||
|
|
||||||
AtomicReference<Job> updateJobResponseHolder = new AtomicReference<>();
|
AtomicReference<Job> updateJobResponseHolder = new AtomicReference<>();
|
||||||
blockingCall(actionListener -> jobConfigProvider.updateJob(jobId, jobUpdate, new ByteSizeValue(32), actionListener),
|
blockingCall(actionListener -> jobConfigProvider.updateJob
|
||||||
updateJobResponseHolder, exceptionHolder);
|
(jobId, jobUpdate, new ByteSizeValue(32), Version.CURRENT, actionListener), updateJobResponseHolder, exceptionHolder);
|
||||||
assertNull(exceptionHolder.get());
|
assertNull(exceptionHolder.get());
|
||||||
assertEquals("This job has been updated", updateJobResponseHolder.get().getDescription());
|
assertEquals("This job has been updated", updateJobResponseHolder.get().getDescription());
|
||||||
|
|
||||||
|
@ -205,8 +206,8 @@ public class JobConfigProviderIT extends MlSingleNodeTestCase {
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
AtomicReference<Job> updateJobResponseHolder = new AtomicReference<>();
|
AtomicReference<Job> updateJobResponseHolder = new AtomicReference<>();
|
||||||
blockingCall(actionListener -> jobConfigProvider.updateJob(jobId, invalidUpdate, new ByteSizeValue(32), actionListener),
|
blockingCall(actionListener -> jobConfigProvider.updateJob(jobId, invalidUpdate, new ByteSizeValue(32), Version.CURRENT,
|
||||||
updateJobResponseHolder, exceptionHolder);
|
actionListener), updateJobResponseHolder, exceptionHolder);
|
||||||
assertNull(updateJobResponseHolder.get());
|
assertNull(updateJobResponseHolder.get());
|
||||||
assertNotNull(exceptionHolder.get());
|
assertNotNull(exceptionHolder.get());
|
||||||
assertThat(exceptionHolder.get(), instanceOf(ElasticsearchStatusException.class));
|
assertThat(exceptionHolder.get(), instanceOf(ElasticsearchStatusException.class));
|
||||||
|
@ -229,9 +230,8 @@ public class JobConfigProviderIT extends MlSingleNodeTestCase {
|
||||||
AtomicReference<Exception> exceptionHolder = new AtomicReference<>();
|
AtomicReference<Exception> exceptionHolder = new AtomicReference<>();
|
||||||
AtomicReference<Job> updateJobResponseHolder = new AtomicReference<>();
|
AtomicReference<Job> updateJobResponseHolder = new AtomicReference<>();
|
||||||
// update with the no-op validator
|
// update with the no-op validator
|
||||||
blockingCall(actionListener ->
|
blockingCall(actionListener -> jobConfigProvider.updateJobWithValidation(
|
||||||
jobConfigProvider.updateJobWithValidation(jobId, jobUpdate, new ByteSizeValue(32), validator, actionListener),
|
jobId, jobUpdate, new ByteSizeValue(32), validator, Version.CURRENT, actionListener), updateJobResponseHolder, exceptionHolder);
|
||||||
updateJobResponseHolder, exceptionHolder);
|
|
||||||
|
|
||||||
assertNull(exceptionHolder.get());
|
assertNull(exceptionHolder.get());
|
||||||
assertNotNull(updateJobResponseHolder.get());
|
assertNotNull(updateJobResponseHolder.get());
|
||||||
|
@ -244,7 +244,7 @@ public class JobConfigProviderIT extends MlSingleNodeTestCase {
|
||||||
updateJobResponseHolder.set(null);
|
updateJobResponseHolder.set(null);
|
||||||
// Update with a validator that errors
|
// Update with a validator that errors
|
||||||
blockingCall(actionListener -> jobConfigProvider.updateJobWithValidation(jobId, jobUpdate, new ByteSizeValue(32),
|
blockingCall(actionListener -> jobConfigProvider.updateJobWithValidation(jobId, jobUpdate, new ByteSizeValue(32),
|
||||||
validatorWithAnError, actionListener),
|
validatorWithAnError, Version.CURRENT, actionListener),
|
||||||
updateJobResponseHolder, exceptionHolder);
|
updateJobResponseHolder, exceptionHolder);
|
||||||
|
|
||||||
assertNull(updateJobResponseHolder.get());
|
assertNull(updateJobResponseHolder.get());
|
||||||
|
|
Loading…
Reference in New Issue