-
Notifications
You must be signed in to change notification settings - Fork 24.9k
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
ILM: add support for rolling over data streams #57295
Changes from 5 commits
a692663
aae8ce3
ec11c9c
b890e04
6fc0933
1aeedfd
2feb945
308d1b6
91a86cd
9a62405
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 |
---|---|---|
|
@@ -13,6 +13,7 @@ | |
import org.elasticsearch.client.Client; | ||
import org.elasticsearch.cluster.ClusterState; | ||
import org.elasticsearch.cluster.ClusterStateObserver; | ||
import org.elasticsearch.cluster.metadata.IndexAbstraction; | ||
import org.elasticsearch.cluster.metadata.IndexMetadata; | ||
import org.elasticsearch.common.Strings; | ||
|
||
|
@@ -39,38 +40,46 @@ public boolean isRetryable() { | |
@Override | ||
public void performAction(IndexMetadata indexMetadata, ClusterState currentClusterState, | ||
ClusterStateObserver observer, Listener listener) { | ||
boolean indexingComplete = LifecycleSettings.LIFECYCLE_INDEXING_COMPLETE_SETTING.get(indexMetadata.getSettings()); | ||
if (indexingComplete) { | ||
logger.trace(indexMetadata.getIndex() + " has lifecycle complete set, skipping " + RolloverStep.NAME); | ||
listener.onResponse(true); | ||
return; | ||
} | ||
IndexAbstraction indexAbstraction = currentClusterState.metadata().getIndicesLookup().get(indexMetadata.getIndex().getName()); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Super minor, but can you add an assert indexAbstraction != null : "expected the index " + indexName + " to exist in the lookup but it didn't"; after this line? I don't think it's going to happen, but we should check it regardless. Optionally, we could make it a real error also (throw an |
||
final String rolloverTarget; | ||
if (indexAbstraction.getParentDataStream() != null) { | ||
rolloverTarget = indexAbstraction.getParentDataStream().getDataStream().getName(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just to be super paranoid, I think we should handle the case where There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think that can be changed to:
to eliminate the need for another null check. |
||
} else { | ||
boolean indexingComplete = LifecycleSettings.LIFECYCLE_INDEXING_COMPLETE_SETTING.get(indexMetadata.getSettings()); | ||
if (indexingComplete) { | ||
logger.trace(indexMetadata.getIndex() + " has lifecycle complete set, skipping " + RolloverStep.NAME); | ||
listener.onResponse(true); | ||
return; | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should we allow this indexing complete setting regardless of whether the parent data stream exists or not? (in otherwords, moving it before the |
||
|
||
String rolloverAlias = RolloverAction.LIFECYCLE_ROLLOVER_ALIAS_SETTING.get(indexMetadata.getSettings()); | ||
String rolloverAlias = RolloverAction.LIFECYCLE_ROLLOVER_ALIAS_SETTING.get(indexMetadata.getSettings()); | ||
|
||
if (Strings.isNullOrEmpty(rolloverAlias)) { | ||
listener.onFailure(new IllegalArgumentException(String.format(Locale.ROOT, | ||
"setting [%s] for index [%s] is empty or not defined", RolloverAction.LIFECYCLE_ROLLOVER_ALIAS, | ||
indexMetadata.getIndex().getName()))); | ||
return; | ||
} | ||
if (Strings.isNullOrEmpty(rolloverAlias)) { | ||
listener.onFailure(new IllegalArgumentException(String.format(Locale.ROOT, | ||
"setting [%s] for index [%s] is empty or not defined", RolloverAction.LIFECYCLE_ROLLOVER_ALIAS, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this is a chance we can improve this error message (if you agree), maybe something like:
I'm not stuck on the wording, maybe you have a better idea? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Great point, I think the wording sounds good |
||
indexMetadata.getIndex().getName()))); | ||
return; | ||
} | ||
|
||
if (indexMetadata.getRolloverInfos().get(rolloverAlias) != null) { | ||
logger.info("index [{}] was already rolled over for alias [{}], not attempting to roll over again", | ||
indexMetadata.getIndex().getName(), rolloverAlias); | ||
listener.onResponse(true); | ||
return; | ||
} | ||
if (indexMetadata.getRolloverInfos().get(rolloverAlias) != null) { | ||
logger.info("index [{}] was already rolled over for alias [{}], not attempting to roll over again", | ||
indexMetadata.getIndex().getName(), rolloverAlias); | ||
listener.onResponse(true); | ||
return; | ||
} | ||
|
||
if (indexMetadata.getAliases().containsKey(rolloverAlias) == false) { | ||
listener.onFailure(new IllegalArgumentException(String.format(Locale.ROOT, | ||
"%s [%s] does not point to index [%s]", RolloverAction.LIFECYCLE_ROLLOVER_ALIAS, rolloverAlias, | ||
indexMetadata.getIndex().getName()))); | ||
return; | ||
} | ||
|
||
if (indexMetadata.getAliases().containsKey(rolloverAlias) == false) { | ||
listener.onFailure(new IllegalArgumentException(String.format(Locale.ROOT, | ||
"%s [%s] does not point to index [%s]", RolloverAction.LIFECYCLE_ROLLOVER_ALIAS, rolloverAlias, | ||
indexMetadata.getIndex().getName()))); | ||
return; | ||
rolloverTarget = rolloverAlias; | ||
} | ||
|
||
// Calling rollover with no conditions will always roll over the index | ||
RolloverRequest rolloverRequest = new RolloverRequest(rolloverAlias, null) | ||
RolloverRequest rolloverRequest = new RolloverRequest(rolloverTarget, null) | ||
.masterNodeTimeout(getMasterTimeout(currentClusterState)); | ||
// We don't wait for active shards when we perform the rollover because the | ||
// {@link org.elasticsearch.xpack.core.ilm.WaitForActiveShardsStep} step will do so | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,6 +9,7 @@ | |
import org.apache.logging.log4j.Logger; | ||
import org.elasticsearch.action.admin.indices.rollover.RolloverInfo; | ||
import org.elasticsearch.cluster.ClusterState; | ||
import org.elasticsearch.cluster.metadata.IndexAbstraction; | ||
import org.elasticsearch.cluster.metadata.IndexMetadata; | ||
import org.elasticsearch.cluster.metadata.Metadata; | ||
import org.elasticsearch.common.Strings; | ||
|
@@ -52,16 +53,11 @@ public ClusterState performAction(Index index, ClusterState currentState) { | |
// so just use the current time. | ||
newIndexTime = fallbackTimeSupplier.getAsLong(); | ||
} else { | ||
// find the newly created index from the rollover and fetch its index.creation_date | ||
String rolloverAlias = RolloverAction.LIFECYCLE_ROLLOVER_ALIAS_SETTING.get(indexMetadata.getSettings()); | ||
if (Strings.isNullOrEmpty(rolloverAlias)) { | ||
throw new IllegalStateException("setting [" + RolloverAction.LIFECYCLE_ROLLOVER_ALIAS | ||
+ "] is not set on index [" + indexMetadata.getIndex().getName() + "]"); | ||
} | ||
RolloverInfo rolloverInfo = indexMetadata.getRolloverInfos().get(rolloverAlias); | ||
final String rolloverTarget = getRolloverTarget(index, currentState); | ||
RolloverInfo rolloverInfo = indexMetadata.getRolloverInfos().get(rolloverTarget); | ||
if (rolloverInfo == null) { | ||
throw new IllegalStateException("no rollover info found for [" + indexMetadata.getIndex().getName() + "] with alias [" + | ||
rolloverAlias + "], the index has not yet rolled over with that alias"); | ||
throw new IllegalStateException("no rollover info found for [" + indexMetadata.getIndex().getName() + | ||
"] with rollover target [" + rolloverTarget + "], the index has not yet rolled over with that target"); | ||
} | ||
newIndexTime = rolloverInfo.getTime(); | ||
} | ||
|
@@ -76,6 +72,24 @@ public ClusterState performAction(Index index, ClusterState currentState) { | |
.put(newIndexMetadata)).build(); | ||
} | ||
|
||
private String getRolloverTarget(Index index, ClusterState currentState) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this can be a |
||
IndexAbstraction indexAbstraction = currentState.metadata().getIndicesLookup().get(index.getName()); | ||
final String rolloverTarget; | ||
if (indexAbstraction.getParentDataStream() != null) { | ||
rolloverTarget = indexAbstraction.getParentDataStream().getDataStream().getName(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same comment here about There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The underlying |
||
} else { | ||
// find the newly created index from the rollover and fetch its index.creation_date | ||
IndexMetadata indexMetadata = currentState.metadata().index(index); | ||
String rolloverAlias = RolloverAction.LIFECYCLE_ROLLOVER_ALIAS_SETTING.get(indexMetadata.getSettings()); | ||
if (Strings.isNullOrEmpty(rolloverAlias)) { | ||
throw new IllegalStateException("setting [" + RolloverAction.LIFECYCLE_ROLLOVER_ALIAS | ||
+ "] is not set on index [" + indexMetadata.getIndex().getName() + "]"); | ||
} | ||
rolloverTarget = rolloverAlias; | ||
} | ||
return rolloverTarget; | ||
} | ||
|
||
@Override | ||
public int hashCode() { | ||
return super.hashCode(); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,6 +10,7 @@ | |
import org.apache.logging.log4j.Logger; | ||
import org.elasticsearch.action.support.ActiveShardCount; | ||
import org.elasticsearch.cluster.ClusterState; | ||
import org.elasticsearch.cluster.metadata.DataStream; | ||
import org.elasticsearch.cluster.metadata.IndexAbstraction; | ||
import org.elasticsearch.cluster.metadata.IndexMetadata; | ||
import org.elasticsearch.cluster.routing.IndexRoutingTable; | ||
|
@@ -64,43 +65,48 @@ public Result isConditionMet(Index index, ClusterState clusterState) { | |
return new Result(true, new Info(message)); | ||
} | ||
|
||
String rolloverAlias = RolloverAction.LIFECYCLE_ROLLOVER_ALIAS_SETTING.get(originalIndexMeta.getSettings()); | ||
if (Strings.isNullOrEmpty(rolloverAlias)) { | ||
throw new IllegalStateException("setting [" + RolloverAction.LIFECYCLE_ROLLOVER_ALIAS | ||
+ "] is not set on index [" + originalIndexMeta.getIndex().getName() + "]"); | ||
} | ||
|
||
IndexAbstraction indexAbstraction = clusterState.metadata().getIndicesLookup().get(rolloverAlias); | ||
assert indexAbstraction.getType() == IndexAbstraction.Type.ALIAS : rolloverAlias + " must be an alias but it is not"; | ||
|
||
IndexMetadata aliasWriteIndex = indexAbstraction.getWriteIndex(); | ||
IndexAbstraction indexAbstraction = clusterState.metadata().getIndicesLookup().get(index.getName()); | ||
final String rolledIndexName; | ||
final String waitForActiveShardsSettingValue; | ||
if (aliasWriteIndex != null) { | ||
rolledIndexName = aliasWriteIndex.getIndex().getName(); | ||
waitForActiveShardsSettingValue = aliasWriteIndex.getSettings().get("index.write.wait_for_active_shards"); | ||
if (indexAbstraction.getParentDataStream() != null) { | ||
DataStream dataStream = indexAbstraction.getParentDataStream().getDataStream(); | ||
rolledIndexName = DataStream.getBackingIndexName(dataStream.getName(), dataStream.getGeneration()); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Minor: this correctly identifies the data stream's write index under the current implementation of data streams. The There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks for the suggestion, Dan. Pushed a fix to change this. |
||
IndexMetadata rolledIndexMeta = clusterState.metadata().index(rolledIndexName); | ||
if (rolledIndexMeta == null) { | ||
return getErrorResultOnNullMetadata(index); | ||
} | ||
waitForActiveShardsSettingValue = rolledIndexMeta.getSettings().get("index.write.wait_for_active_shards"); | ||
} else { | ||
List<IndexMetadata> indices = indexAbstraction.getIndices(); | ||
int maxIndexCounter = -1; | ||
IndexMetadata rolledIndexMeta = null; | ||
for (IndexMetadata indexMetadata : indices) { | ||
int indexNameCounter = parseIndexNameCounter(indexMetadata.getIndex().getName()); | ||
if (maxIndexCounter < indexNameCounter) { | ||
maxIndexCounter = indexNameCounter; | ||
rolledIndexMeta = indexMetadata; | ||
} | ||
String rolloverAlias = RolloverAction.LIFECYCLE_ROLLOVER_ALIAS_SETTING.get(originalIndexMeta.getSettings()); | ||
if (Strings.isNullOrEmpty(rolloverAlias)) { | ||
throw new IllegalStateException("setting [" + RolloverAction.LIFECYCLE_ROLLOVER_ALIAS | ||
+ "] is not set on index [" + originalIndexMeta.getIndex().getName() + "]"); | ||
} | ||
if (rolledIndexMeta == null) { | ||
String errorMessage = String.format(Locale.ROOT, | ||
"unable to find the index that was rolled over from [%s] as part of lifecycle action [%s]", index.getName(), | ||
getKey().getAction()); | ||
|
||
// Index must have been since deleted | ||
logger.debug(errorMessage); | ||
return new Result(false, new Info(errorMessage)); | ||
IndexAbstraction aliasAbstraction = clusterState.metadata().getIndicesLookup().get(rolloverAlias); | ||
assert aliasAbstraction.getType() == IndexAbstraction.Type.ALIAS : rolloverAlias + " must be an alias but it is not"; | ||
|
||
IndexMetadata aliasWriteIndex = aliasAbstraction.getWriteIndex(); | ||
if (aliasWriteIndex != null) { | ||
rolledIndexName = aliasWriteIndex.getIndex().getName(); | ||
waitForActiveShardsSettingValue = aliasWriteIndex.getSettings().get("index.write.wait_for_active_shards"); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Super minor, but can we use |
||
} else { | ||
List<IndexMetadata> indices = aliasAbstraction.getIndices(); | ||
int maxIndexCounter = -1; | ||
IndexMetadata rolledIndexMeta = null; | ||
for (IndexMetadata indexMetadata : indices) { | ||
int indexNameCounter = parseIndexNameCounter(indexMetadata.getIndex().getName()); | ||
if (maxIndexCounter < indexNameCounter) { | ||
maxIndexCounter = indexNameCounter; | ||
rolledIndexMeta = indexMetadata; | ||
} | ||
} | ||
if (rolledIndexMeta == null) { | ||
return getErrorResultOnNullMetadata(index); | ||
} | ||
rolledIndexName = rolledIndexMeta.getIndex().getName(); | ||
waitForActiveShardsSettingValue = rolledIndexMeta.getSettings().get("index.write.wait_for_active_shards"); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same here about using |
||
} | ||
rolledIndexName = rolledIndexMeta.getIndex().getName(); | ||
waitForActiveShardsSettingValue = rolledIndexMeta.getSettings().get("index.write.wait_for_active_shards"); | ||
} | ||
|
||
ActiveShardCount activeShardCount = ActiveShardCount.parseString(waitForActiveShardsSettingValue); | ||
|
@@ -114,6 +120,16 @@ public Result isConditionMet(Index index, ClusterState clusterState) { | |
return new Result(enoughShardsActive, new ActiveShardsInfo(currentActiveShards, activeShardCount.toString(), enoughShardsActive)); | ||
} | ||
|
||
private Result getErrorResultOnNullMetadata(Index originalIndex) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This can be |
||
String errorMessage = String.format(Locale.ROOT, | ||
"unable to find the index that was rolled over from [%s] as part of lifecycle action [%s]", originalIndex.getName(), | ||
getKey().getAction()); | ||
|
||
// Index must have been since deleted | ||
logger.debug(errorMessage); | ||
return new Result(false, new Info(errorMessage)); | ||
} | ||
|
||
/** | ||
* Parses the number from the rolled over index name. It also supports the date-math format (ie. index name is wrapped in < and >) | ||
* <p> | ||
|
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.
It does seem strange to pass both the
Metadata
and theIndexMetadata
, should we instead passMetadata
andIndex
so it's easy to look up the index metadata?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.
Yeah, fair enough, it felt a bit odd to me too (it equally felt wasteful, in terms of CPU cycles, to re-do the lookup every time though, but given ILM is not so much about low latency I agree it makes sense to change it)