[ILM] make alias swapping atomic (#35972)
In the current implementation, there is a time between the ShrinkStep and the ShrinkSetAliasStep that both the source and target indices will be present with the same aliases. This means that queries to during this time will query both and return duplicates. This fixes that scenario by moving the alias inheritance to the same aliases update request as is done in ShrinkSetAliasStep
This commit is contained in:
parent
ba3ee98943
commit
fa5f551b80
|
@ -9,6 +9,7 @@ import org.elasticsearch.action.ActionListener;
|
||||||
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest;
|
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest;
|
||||||
import org.elasticsearch.client.Client;
|
import org.elasticsearch.client.Client;
|
||||||
import org.elasticsearch.cluster.ClusterState;
|
import org.elasticsearch.cluster.ClusterState;
|
||||||
|
import org.elasticsearch.cluster.metadata.AliasMetaData;
|
||||||
import org.elasticsearch.cluster.metadata.IndexMetaData;
|
import org.elasticsearch.cluster.metadata.IndexMetaData;
|
||||||
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
@ -36,11 +37,20 @@ public class ShrinkSetAliasStep extends AsyncActionStep {
|
||||||
String index = indexMetaData.getIndex().getName();
|
String index = indexMetaData.getIndex().getName();
|
||||||
// get target shrink index
|
// get target shrink index
|
||||||
String targetIndexName = shrunkIndexPrefix + index;
|
String targetIndexName = shrunkIndexPrefix + index;
|
||||||
|
|
||||||
IndicesAliasesRequest aliasesRequest = new IndicesAliasesRequest()
|
IndicesAliasesRequest aliasesRequest = new IndicesAliasesRequest()
|
||||||
.addAliasAction(IndicesAliasesRequest.AliasActions.removeIndex().index(index))
|
.addAliasAction(IndicesAliasesRequest.AliasActions.removeIndex().index(index))
|
||||||
.addAliasAction(IndicesAliasesRequest.AliasActions.add().index(targetIndexName).alias(index));
|
.addAliasAction(IndicesAliasesRequest.AliasActions.add().index(targetIndexName).alias(index));
|
||||||
|
// copy over other aliases from original index
|
||||||
|
indexMetaData.getAliases().values().spliterator().forEachRemaining(aliasMetaDataObjectCursor -> {
|
||||||
|
AliasMetaData aliasMetaDataToAdd = aliasMetaDataObjectCursor.value;
|
||||||
|
// inherit all alias properties except `is_write_index`
|
||||||
|
aliasesRequest.addAliasAction(IndicesAliasesRequest.AliasActions.add()
|
||||||
|
.index(targetIndexName).alias(aliasMetaDataToAdd.alias())
|
||||||
|
.indexRouting(aliasMetaDataToAdd.indexRouting())
|
||||||
|
.searchRouting(aliasMetaDataToAdd.searchRouting())
|
||||||
|
.filter(aliasMetaDataToAdd.filter() == null ? null : aliasMetaDataToAdd.filter().string())
|
||||||
|
.writeIndex(null));
|
||||||
|
});
|
||||||
getClient().admin().indices().aliases(aliasesRequest, ActionListener.wrap(response ->
|
getClient().admin().indices().aliases(aliasesRequest, ActionListener.wrap(response ->
|
||||||
listener.onResponse(true), listener::onFailure));
|
listener.onResponse(true), listener::onFailure));
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
package org.elasticsearch.xpack.core.indexlifecycle;
|
package org.elasticsearch.xpack.core.indexlifecycle;
|
||||||
|
|
||||||
import org.elasticsearch.action.ActionListener;
|
import org.elasticsearch.action.ActionListener;
|
||||||
import org.elasticsearch.action.admin.indices.alias.Alias;
|
|
||||||
import org.elasticsearch.action.admin.indices.shrink.ResizeRequest;
|
import org.elasticsearch.action.admin.indices.shrink.ResizeRequest;
|
||||||
import org.elasticsearch.client.Client;
|
import org.elasticsearch.client.Client;
|
||||||
import org.elasticsearch.cluster.ClusterState;
|
import org.elasticsearch.cluster.ClusterState;
|
||||||
|
@ -58,13 +57,9 @@ public class ShrinkStep extends AsyncActionStep {
|
||||||
|
|
||||||
String shrunkenIndexName = shrunkIndexPrefix + indexMetaData.getIndex().getName();
|
String shrunkenIndexName = shrunkIndexPrefix + indexMetaData.getIndex().getName();
|
||||||
ResizeRequest resizeRequest = new ResizeRequest(shrunkenIndexName, indexMetaData.getIndex().getName());
|
ResizeRequest resizeRequest = new ResizeRequest(shrunkenIndexName, indexMetaData.getIndex().getName());
|
||||||
indexMetaData.getAliases().values().spliterator().forEachRemaining(aliasMetaDataObjectCursor -> {
|
|
||||||
resizeRequest.getTargetIndexRequest().alias(new Alias(aliasMetaDataObjectCursor.value.alias()));
|
|
||||||
});
|
|
||||||
resizeRequest.getTargetIndexRequest().settings(relevantTargetSettings);
|
resizeRequest.getTargetIndexRequest().settings(relevantTargetSettings);
|
||||||
|
|
||||||
getClient().admin().indices().resizeIndex(resizeRequest, ActionListener.wrap(response -> {
|
getClient().admin().indices().resizeIndex(resizeRequest, ActionListener.wrap(response -> {
|
||||||
// TODO(talevy): when is this not acknowledged?
|
|
||||||
listener.onResponse(response.isAcknowledged());
|
listener.onResponse(response.isAcknowledged());
|
||||||
}, listener::onFailure));
|
}, listener::onFailure));
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,7 @@ import org.elasticsearch.action.support.master.AcknowledgedResponse;
|
||||||
import org.elasticsearch.client.AdminClient;
|
import org.elasticsearch.client.AdminClient;
|
||||||
import org.elasticsearch.client.Client;
|
import org.elasticsearch.client.Client;
|
||||||
import org.elasticsearch.client.IndicesAdminClient;
|
import org.elasticsearch.client.IndicesAdminClient;
|
||||||
|
import org.elasticsearch.cluster.metadata.AliasMetaData;
|
||||||
import org.elasticsearch.cluster.metadata.IndexMetaData;
|
import org.elasticsearch.cluster.metadata.IndexMetaData;
|
||||||
import org.elasticsearch.xpack.core.indexlifecycle.AsyncActionStep.Listener;
|
import org.elasticsearch.xpack.core.indexlifecycle.AsyncActionStep.Listener;
|
||||||
import org.elasticsearch.xpack.core.indexlifecycle.Step.StepKey;
|
import org.elasticsearch.xpack.core.indexlifecycle.Step.StepKey;
|
||||||
|
@ -71,15 +72,33 @@ public class ShrinkSetAliasStepTests extends AbstractStepTestCase<ShrinkSetAlias
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testPerformAction() {
|
public void testPerformAction() {
|
||||||
IndexMetaData indexMetaData = IndexMetaData.builder(randomAlphaOfLength(10)).settings(settings(Version.CURRENT))
|
IndexMetaData.Builder indexMetaDataBuilder = IndexMetaData.builder(randomAlphaOfLength(10)).settings(settings(Version.CURRENT))
|
||||||
.numberOfShards(randomIntBetween(1, 5)).numberOfReplicas(randomIntBetween(0, 5)).build();
|
.numberOfShards(randomIntBetween(1, 5)).numberOfReplicas(randomIntBetween(0, 5));
|
||||||
|
AliasMetaData.Builder aliasBuilder = AliasMetaData.builder(randomAlphaOfLengthBetween(3, 10));
|
||||||
|
if (randomBoolean()) {
|
||||||
|
aliasBuilder.routing(randomAlphaOfLengthBetween(3, 10));
|
||||||
|
}
|
||||||
|
if (randomBoolean()) {
|
||||||
|
aliasBuilder.searchRouting(randomAlphaOfLengthBetween(3, 10));
|
||||||
|
}
|
||||||
|
if (randomBoolean()) {
|
||||||
|
aliasBuilder.indexRouting(randomAlphaOfLengthBetween(3, 10));
|
||||||
|
}
|
||||||
|
String aliasMetaDataFilter = randomBoolean() ? null : "{\"term\":{\"year\":2016}}";
|
||||||
|
aliasBuilder.filter(aliasMetaDataFilter);
|
||||||
|
aliasBuilder.writeIndex(randomBoolean());
|
||||||
|
AliasMetaData aliasMetaData = aliasBuilder.build();
|
||||||
|
IndexMetaData indexMetaData = indexMetaDataBuilder.putAlias(aliasMetaData).build();
|
||||||
ShrinkSetAliasStep step = createRandomInstance();
|
ShrinkSetAliasStep step = createRandomInstance();
|
||||||
|
|
||||||
String sourceIndex = indexMetaData.getIndex().getName();
|
String sourceIndex = indexMetaData.getIndex().getName();
|
||||||
String shrunkenIndex = step.getShrunkIndexPrefix() + sourceIndex;
|
String shrunkenIndex = step.getShrunkIndexPrefix() + sourceIndex;
|
||||||
List<AliasActions> expectedAliasActions = Arrays.asList(
|
List<AliasActions> expectedAliasActions = Arrays.asList(
|
||||||
IndicesAliasesRequest.AliasActions.removeIndex().index(sourceIndex),
|
IndicesAliasesRequest.AliasActions.removeIndex().index(sourceIndex),
|
||||||
IndicesAliasesRequest.AliasActions.add().index(shrunkenIndex).alias(sourceIndex));
|
IndicesAliasesRequest.AliasActions.add().index(shrunkenIndex).alias(sourceIndex),
|
||||||
|
IndicesAliasesRequest.AliasActions.add().index(shrunkenIndex).alias(aliasMetaData.alias())
|
||||||
|
.searchRouting(aliasMetaData.searchRouting()).indexRouting(aliasMetaData.indexRouting())
|
||||||
|
.filter(aliasMetaDataFilter).writeIndex(null));
|
||||||
AdminClient adminClient = Mockito.mock(AdminClient.class);
|
AdminClient adminClient = Mockito.mock(AdminClient.class);
|
||||||
IndicesAdminClient indicesClient = Mockito.mock(IndicesAdminClient.class);
|
IndicesAdminClient indicesClient = Mockito.mock(IndicesAdminClient.class);
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,6 @@ package org.elasticsearch.xpack.core.indexlifecycle;
|
||||||
import org.apache.lucene.util.SetOnce;
|
import org.apache.lucene.util.SetOnce;
|
||||||
import org.elasticsearch.Version;
|
import org.elasticsearch.Version;
|
||||||
import org.elasticsearch.action.ActionListener;
|
import org.elasticsearch.action.ActionListener;
|
||||||
import org.elasticsearch.action.admin.indices.alias.Alias;
|
|
||||||
import org.elasticsearch.action.admin.indices.rollover.RolloverResponse;
|
import org.elasticsearch.action.admin.indices.rollover.RolloverResponse;
|
||||||
import org.elasticsearch.action.admin.indices.shrink.ResizeRequest;
|
import org.elasticsearch.action.admin.indices.shrink.ResizeRequest;
|
||||||
import org.elasticsearch.action.admin.indices.shrink.ResizeResponse;
|
import org.elasticsearch.action.admin.indices.shrink.ResizeResponse;
|
||||||
|
@ -112,7 +111,7 @@ public class ShrinkStepTests extends AbstractStepTestCase<ShrinkStep> {
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
ActionListener<ResizeResponse> listener = (ActionListener<ResizeResponse>) invocation.getArguments()[1];
|
ActionListener<ResizeResponse> listener = (ActionListener<ResizeResponse>) invocation.getArguments()[1];
|
||||||
assertThat(request.getSourceIndex(), equalTo(sourceIndexMetaData.getIndex().getName()));
|
assertThat(request.getSourceIndex(), equalTo(sourceIndexMetaData.getIndex().getName()));
|
||||||
assertThat(request.getTargetIndexRequest().aliases(), equalTo(Collections.singleton(new Alias("my_alias"))));
|
assertThat(request.getTargetIndexRequest().aliases(), equalTo(Collections.emptySet()));
|
||||||
assertThat(request.getTargetIndexRequest().settings(), equalTo(Settings.builder()
|
assertThat(request.getTargetIndexRequest().settings(), equalTo(Settings.builder()
|
||||||
.put(IndexMetaData.SETTING_NUMBER_OF_SHARDS, step.getNumberOfShards())
|
.put(IndexMetaData.SETTING_NUMBER_OF_SHARDS, step.getNumberOfShards())
|
||||||
.put(IndexMetaData.SETTING_NUMBER_OF_REPLICAS, sourceIndexMetaData.getNumberOfReplicas())
|
.put(IndexMetaData.SETTING_NUMBER_OF_REPLICAS, sourceIndexMetaData.getNumberOfReplicas())
|
||||||
|
|
Loading…
Reference in New Issue