-
Notifications
You must be signed in to change notification settings - Fork 24.8k
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
Create first backing index when creating data stream #54467
Changes from 6 commits
0ae87c5
806acc4
078dae1
1284b2b
df1bf05
47e6b88
0bd4bd4
6c1856f
fe2849d
9c9a42c
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 | ||||
---|---|---|---|---|---|---|
|
@@ -24,6 +24,7 @@ | |||||
import org.elasticsearch.action.ActionRequestValidationException; | ||||||
import org.elasticsearch.action.ActionType; | ||||||
import org.elasticsearch.action.ValidateActions; | ||||||
import org.elasticsearch.action.admin.indices.create.CreateIndexClusterStateUpdateRequest; | ||||||
import org.elasticsearch.action.support.ActionFilters; | ||||||
import org.elasticsearch.action.support.master.AcknowledgedResponse; | ||||||
import org.elasticsearch.action.support.master.MasterNodeRequest; | ||||||
|
@@ -33,6 +34,7 @@ | |||||
import org.elasticsearch.cluster.block.ClusterBlockException; | ||||||
import org.elasticsearch.cluster.block.ClusterBlockLevel; | ||||||
import org.elasticsearch.cluster.metadata.DataStream; | ||||||
import org.elasticsearch.cluster.metadata.IndexMetadata; | ||||||
import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver; | ||||||
import org.elasticsearch.cluster.metadata.Metadata; | ||||||
import org.elasticsearch.cluster.metadata.MetadataCreateIndexService; | ||||||
|
@@ -42,13 +44,14 @@ | |||||
import org.elasticsearch.common.inject.Inject; | ||||||
import org.elasticsearch.common.io.stream.StreamInput; | ||||||
import org.elasticsearch.common.io.stream.StreamOutput; | ||||||
import org.elasticsearch.common.settings.Settings; | ||||||
import org.elasticsearch.common.unit.TimeValue; | ||||||
import org.elasticsearch.tasks.Task; | ||||||
import org.elasticsearch.threadpool.ThreadPool; | ||||||
import org.elasticsearch.transport.TransportService; | ||||||
|
||||||
import java.io.IOException; | ||||||
import java.util.Collections; | ||||||
import java.util.List; | ||||||
import java.util.Objects; | ||||||
|
||||||
public class CreateDataStreamAction extends ActionType<AcknowledgedResponse> { | ||||||
|
@@ -117,10 +120,14 @@ public int hashCode() { | |||||
|
||||||
public static class TransportAction extends TransportMasterNodeAction<Request, AcknowledgedResponse> { | ||||||
|
||||||
private final MetadataCreateIndexService metadataCreateIndexService; | ||||||
|
||||||
@Inject | ||||||
public TransportAction(TransportService transportService, ClusterService clusterService, ThreadPool threadPool, | ||||||
ActionFilters actionFilters, IndexNameExpressionResolver indexNameExpressionResolver) { | ||||||
ActionFilters actionFilters, IndexNameExpressionResolver indexNameExpressionResolver, | ||||||
MetadataCreateIndexService metaDataCreateIndexService) { | ||||||
super(NAME, transportService, clusterService, threadPool, actionFilters, Request::new, indexNameExpressionResolver); | ||||||
this.metadataCreateIndexService = metaDataCreateIndexService; | ||||||
} | ||||||
|
||||||
@Override | ||||||
|
@@ -151,7 +158,7 @@ public void onFailure(String source, Exception e) { | |||||
|
||||||
@Override | ||||||
public ClusterState execute(ClusterState currentState) throws Exception { | ||||||
return createDataStream(currentState, request); | ||||||
return createDataStream(metadataCreateIndexService, currentState, request); | ||||||
} | ||||||
|
||||||
@Override | ||||||
|
@@ -161,16 +168,26 @@ public void clusterStateProcessed(String source, ClusterState oldState, ClusterS | |||||
}); | ||||||
} | ||||||
|
||||||
static ClusterState createDataStream(ClusterState currentState, Request request) { | ||||||
static ClusterState createDataStream(MetadataCreateIndexService metadataCreateIndexService, | ||||||
ClusterState currentState, | ||||||
Request request) throws Exception { | ||||||
if (currentState.metadata().dataStreams().containsKey(request.name)) { | ||||||
throw new IllegalArgumentException("data_stream [" + request.name + "] already exists"); | ||||||
} | ||||||
|
||||||
MetadataCreateIndexService.validateIndexOrAliasName(request.name, | ||||||
(s1, s2) -> new IllegalArgumentException("data_stream [" + s1 + "] " + s2)); | ||||||
|
||||||
String firstBackingIndexName = request.name + "-000001"; | ||||||
CreateIndexClusterStateUpdateRequest createIndexRequest = | ||||||
martijnvg marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
new CreateIndexClusterStateUpdateRequest("initialize_data_stream", firstBackingIndexName, firstBackingIndexName) | ||||||
.settings(Settings.builder().put("index.hidden", true).build()); | ||||||
currentState = metadataCreateIndexService.applyCreateIndexRequest(currentState, createIndexRequest, false); | ||||||
IndexMetadata firstBackingIndex = currentState.metadata().index(firstBackingIndexName); | ||||||
assert firstBackingIndex != null; | ||||||
|
||||||
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. It would be good to add:
Suggested change
since that is guaranteed to fail tests (the NPE occurring further down could be swallowed). |
||||||
Metadata.Builder builder = Metadata.builder(currentState.metadata()).put( | ||||||
new DataStream(request.name, request.timestampFieldName, Collections.emptyList())); | ||||||
new DataStream(request.name, request.timestampFieldName, List.of(firstBackingIndex.getIndex()))); | ||||||
logger.info("adding data stream [{}]", request.name); | ||||||
return ClusterState.builder(currentState).metadata(builder).build(); | ||||||
} | ||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -56,7 +56,7 @@ public interface IndexAbstraction { | |
|
||
/** | ||
* A write index is a dedicated concrete index, that accepts all the new documents that belong to an index abstraction. | ||
* | ||
* <p> | ||
* A write index may also be a regular concrete index of a index abstraction and may therefore also be returned | ||
* by {@link #getIndices()}. An index abstraction may also not have a dedicated write index. | ||
* | ||
|
@@ -87,7 +87,9 @@ enum Type { | |
* An alias typically refers to many concrete indices and | ||
* may have a write index. | ||
*/ | ||
ALIAS("alias"); | ||
ALIAS("alias"), | ||
|
||
DATA_STREAM("data_stream"); | ||
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. maybe add some java doc here? |
||
|
||
private final String displayName; | ||
|
||
|
@@ -181,7 +183,7 @@ public boolean isHidden() { | |
|
||
/** | ||
* Returns the unique alias metadata per concrete index. | ||
* | ||
* <p> | ||
* (note that although alias can point to the same concrete indices, each alias reference may have its own routing | ||
* and filters) | ||
*/ | ||
|
@@ -233,7 +235,7 @@ public void computeAndValidateAliasProperties() { | |
|
||
// Validate hidden status | ||
final Map<Boolean, List<IndexMetadata>> groupedByHiddenStatus = referenceIndexMetadatas.stream() | ||
.collect(Collectors.groupingBy(idxMeta -> Boolean.TRUE.equals(idxMeta.getAliases().get(aliasName).isHidden()))); | ||
.collect(Collectors.groupingBy(idxMeta -> Boolean.TRUE.equals(idxMeta.getAliases().get(aliasName).isHidden()))); | ||
if (isNonEmpty(groupedByHiddenStatus.get(true)) && isNonEmpty(groupedByHiddenStatus.get(false))) { | ||
List<String> hiddenOn = groupedByHiddenStatus.get(true).stream() | ||
.map(idx -> idx.getIndex().getName()).collect(Collectors.toList()); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -18,20 +18,26 @@ | |
*/ | ||
package org.elasticsearch.action.admin.indices.datastream; | ||
|
||
import org.elasticsearch.Version; | ||
import org.elasticsearch.action.ActionRequestValidationException; | ||
import org.elasticsearch.action.admin.indices.create.CreateIndexClusterStateUpdateRequest; | ||
import org.elasticsearch.action.admin.indices.datastream.CreateDataStreamAction.Request; | ||
import org.elasticsearch.cluster.ClusterName; | ||
import org.elasticsearch.cluster.ClusterState; | ||
import org.elasticsearch.cluster.metadata.DataStream; | ||
import org.elasticsearch.cluster.metadata.IndexMetadata; | ||
import org.elasticsearch.cluster.metadata.Metadata; | ||
import org.elasticsearch.cluster.metadata.MetadataCreateIndexService; | ||
import org.elasticsearch.common.io.stream.Writeable; | ||
import org.elasticsearch.common.settings.Settings; | ||
import org.elasticsearch.test.AbstractWireSerializingTestCase; | ||
|
||
import java.util.Collections; | ||
import java.util.Map; | ||
|
||
import static org.hamcrest.Matchers.containsString; | ||
import static org.hamcrest.Matchers.equalTo; | ||
import static org.hamcrest.Matchers.notNullValue; | ||
|
||
public class CreateDataStreamRequestTests extends AbstractWireSerializingTestCase<Request> { | ||
|
||
|
@@ -62,33 +68,60 @@ public void testValidateRequestWithoutTimestampField() { | |
assertThat(e.validationErrors().get(0), containsString("timestamp field name is missing")); | ||
} | ||
|
||
public void testCreateDataStream() { | ||
public void testCreateDataStream() throws Exception { | ||
final MetadataCreateIndexService metadataCreateIndexService = new MockMetadataCreateIndexService(); | ||
final String dataStreamName = "my-data-stream"; | ||
ClusterState cs = ClusterState.builder(new ClusterName("_name")).build(); | ||
CreateDataStreamAction.Request req = new CreateDataStreamAction.Request(dataStreamName); | ||
ClusterState newState = CreateDataStreamAction.TransportAction.createDataStream(cs, req); | ||
ClusterState newState = CreateDataStreamAction.TransportAction.createDataStream(metadataCreateIndexService, cs, req); | ||
assertThat(newState.metadata().dataStreams().size(), equalTo(1)); | ||
assertThat(newState.metadata().dataStreams().get(dataStreamName).getName(), equalTo(dataStreamName)); | ||
assertThat(newState.metadata().index(dataStreamName + "-000001"), notNullValue()); | ||
assertThat(newState.metadata().index(dataStreamName + "-000001").getSettings().get("index.hidden"), equalTo("true")); | ||
} | ||
|
||
public void testCreateDuplicateDataStream() { | ||
final MetadataCreateIndexService metadataCreateIndexService = new MockMetadataCreateIndexService(); | ||
final String dataStreamName = "my-data-stream"; | ||
DataStream existingDataStream = new DataStream(dataStreamName, "timestamp", Collections.emptyList()); | ||
ClusterState cs = ClusterState.builder(new ClusterName("_name")) | ||
.metadata(Metadata.builder().dataStreams(Map.of(dataStreamName, existingDataStream)).build()).build(); | ||
CreateDataStreamAction.Request req = new CreateDataStreamAction.Request(dataStreamName); | ||
|
||
IllegalArgumentException e = expectThrows(IllegalArgumentException.class, | ||
() -> CreateDataStreamAction.TransportAction.createDataStream(cs, req)); | ||
() -> CreateDataStreamAction.TransportAction.createDataStream(metadataCreateIndexService, cs, req)); | ||
assertThat(e.getMessage(), containsString("data_stream [" + dataStreamName + "] already exists")); | ||
} | ||
|
||
public void testCreateDataStreamWithInvalidName() { | ||
final MetadataCreateIndexService metadataCreateIndexService = new MockMetadataCreateIndexService(); | ||
final String dataStreamName = "_My-da#ta- ,stream-"; | ||
ClusterState cs = ClusterState.builder(new ClusterName("_name")).build(); | ||
CreateDataStreamAction.Request req = new CreateDataStreamAction.Request(dataStreamName); | ||
IllegalArgumentException e = expectThrows(IllegalArgumentException.class, | ||
() -> CreateDataStreamAction.TransportAction.createDataStream(cs, req)); | ||
() -> CreateDataStreamAction.TransportAction.createDataStream(metadataCreateIndexService, cs, req)); | ||
assertThat(e.getMessage(), containsString("must not contain the following characters")); | ||
} | ||
|
||
private static class MockMetadataCreateIndexService extends MetadataCreateIndexService { | ||
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. maybe instead of mock class use: |
||
|
||
MockMetadataCreateIndexService() { | ||
super(null, null, null, null, null, null, null, null, null, null, false); | ||
} | ||
|
||
@Override | ||
public ClusterState applyCreateIndexRequest(ClusterState currentState, CreateIndexClusterStateUpdateRequest request, | ||
boolean silent) throws Exception { | ||
Metadata.Builder b = Metadata.builder(currentState.metadata()) | ||
.put(IndexMetadata.builder(request.index()) | ||
.settings(Settings.builder() | ||
.put(IndexMetadata.SETTING_VERSION_CREATED, Version.CURRENT) | ||
.put(request.settings()) | ||
.build()) | ||
.numberOfShards(1) | ||
.numberOfReplicas(1) | ||
.build(), false); | ||
return ClusterState.builder(currentState).metadata(b.build()).build(); | ||
} | ||
} | ||
} |
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.
Can also the index name be checked here inside the indices array field?
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.
@martijnvg, it looks like the format of the backing indices response changed when the data stream's
indices
member was changed fromList<String>
toList<Index>
. It now looks like this:Is that ok?
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.
Yes, this is intended. We can add this assert:
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.
never mind my comment, you already made this change :)