|
|
@@ -23,13 +23,14 @@ import com.google.common.collect.Lists;
|
|
|
import com.google.common.collect.Maps;
|
|
|
import com.google.common.collect.Sets;
|
|
|
import org.elasticsearch.action.admin.indices.mapping.delete.DeleteMappingClusterStateUpdateRequest;
|
|
|
-import org.elasticsearch.action.support.master.MasterNodeOperationRequest;
|
|
|
-import org.elasticsearch.cluster.*;
|
|
|
+import org.elasticsearch.action.admin.indices.mapping.put.PutMappingClusterStateUpdateRequest;
|
|
|
+import org.elasticsearch.cluster.AckedClusterStateUpdateTask;
|
|
|
+import org.elasticsearch.cluster.ClusterService;
|
|
|
+import org.elasticsearch.cluster.ClusterState;
|
|
|
+import org.elasticsearch.cluster.ClusterStateUpdateTask;
|
|
|
import org.elasticsearch.cluster.ack.ClusterStateUpdateListener;
|
|
|
import org.elasticsearch.cluster.ack.ClusterStateUpdateResponse;
|
|
|
-import org.elasticsearch.cluster.action.index.NodeMappingCreatedAction;
|
|
|
import org.elasticsearch.cluster.node.DiscoveryNode;
|
|
|
-import org.elasticsearch.cluster.routing.IndexRoutingTable;
|
|
|
import org.elasticsearch.common.Nullable;
|
|
|
import org.elasticsearch.common.Priority;
|
|
|
import org.elasticsearch.common.component.AbstractComponent;
|
|
|
@@ -38,7 +39,6 @@ import org.elasticsearch.common.inject.Inject;
|
|
|
import org.elasticsearch.common.settings.Settings;
|
|
|
import org.elasticsearch.common.unit.TimeValue;
|
|
|
import org.elasticsearch.common.util.concurrent.ConcurrentCollections;
|
|
|
-import org.elasticsearch.common.util.concurrent.CountDown;
|
|
|
import org.elasticsearch.index.Index;
|
|
|
import org.elasticsearch.index.mapper.DocumentMapper;
|
|
|
import org.elasticsearch.index.mapper.MapperService;
|
|
|
@@ -57,7 +57,7 @@ import static com.google.common.collect.Maps.newHashMap;
|
|
|
import static org.elasticsearch.index.mapper.DocumentMapper.MergeFlags.mergeFlags;
|
|
|
|
|
|
/**
|
|
|
- *
|
|
|
+ * Service responsible for submitting mapping changes
|
|
|
*/
|
|
|
public class MetaDataMappingService extends AbstractComponent {
|
|
|
|
|
|
@@ -65,16 +65,13 @@ public class MetaDataMappingService extends AbstractComponent {
|
|
|
|
|
|
private final IndicesService indicesService;
|
|
|
|
|
|
- private final NodeMappingCreatedAction mappingCreatedAction;
|
|
|
-
|
|
|
private final BlockingQueue<MappingTask> refreshOrUpdateQueue = ConcurrentCollections.newBlockingQueue();
|
|
|
|
|
|
@Inject
|
|
|
- public MetaDataMappingService(Settings settings, ClusterService clusterService, IndicesService indicesService, NodeMappingCreatedAction mappingCreatedAction) {
|
|
|
+ public MetaDataMappingService(Settings settings, ClusterService clusterService, IndicesService indicesService) {
|
|
|
super(settings);
|
|
|
this.clusterService = clusterService;
|
|
|
this.indicesService = indicesService;
|
|
|
- this.mappingCreatedAction = mappingCreatedAction;
|
|
|
}
|
|
|
|
|
|
static class MappingTask {
|
|
|
@@ -99,9 +96,9 @@ public class MetaDataMappingService extends AbstractComponent {
|
|
|
static class UpdateTask extends MappingTask {
|
|
|
final String type;
|
|
|
final CompressedString mappingSource;
|
|
|
- final Listener listener;
|
|
|
+ final ClusterStateUpdateListener listener;
|
|
|
|
|
|
- UpdateTask(String index, String indexUUID, String type, CompressedString mappingSource, Listener listener) {
|
|
|
+ UpdateTask(String index, String indexUUID, String type, CompressedString mappingSource, ClusterStateUpdateListener listener) {
|
|
|
super(index, indexUUID);
|
|
|
this.type = type;
|
|
|
this.mappingSource = mappingSource;
|
|
|
@@ -247,7 +244,7 @@ public class MetaDataMappingService extends AbstractComponent {
|
|
|
}
|
|
|
for (Object task : tasks) {
|
|
|
if (task instanceof UpdateTask) {
|
|
|
- ((UpdateTask) task).listener.onResponse(new Response(true));
|
|
|
+ ((UpdateTask) task).listener.onResponse(new ClusterStateUpdateResponse(true));
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
@@ -277,7 +274,7 @@ public class MetaDataMappingService extends AbstractComponent {
|
|
|
});
|
|
|
}
|
|
|
|
|
|
- public void updateMapping(final String index, final String indexUUID, final String type, final CompressedString mappingSource, final Listener listener) {
|
|
|
+ public void updateMapping(final String index, final String indexUUID, final String type, final CompressedString mappingSource, final ClusterStateUpdateListener listener) {
|
|
|
refreshOrUpdateQueue.add(new UpdateTask(index, indexUUID, type, mappingSource, listener));
|
|
|
clusterService.submitStateUpdateTask("update-mapping [" + index + "][" + type + "]", Priority.HIGH, new ClusterStateUpdateTask() {
|
|
|
@Override
|
|
|
@@ -362,15 +359,33 @@ public class MetaDataMappingService extends AbstractComponent {
|
|
|
});
|
|
|
}
|
|
|
|
|
|
- public void putMapping(final PutRequest request, final Listener listener) {
|
|
|
+ public void putMapping(final PutMappingClusterStateUpdateRequest request, final ClusterStateUpdateListener listener) {
|
|
|
|
|
|
- clusterService.submitStateUpdateTask("put-mapping [" + request.mappingType + "]", Priority.HIGH, new TimeoutClusterStateUpdateTask() {
|
|
|
+ clusterService.submitStateUpdateTask("put-mapping [" + request.type() + "]", Priority.HIGH, new AckedClusterStateUpdateTask() {
|
|
|
|
|
|
- CountDownListener countDownListener; // used to count ack responses before confirming operation is complete
|
|
|
+ @Override
|
|
|
+ public boolean mustAck(DiscoveryNode discoveryNode) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void onAllNodesAcked(@Nullable Throwable t) {
|
|
|
+ listener.onResponse(new ClusterStateUpdateResponse(true));
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void onAckTimeout() {
|
|
|
+ listener.onResponse(new ClusterStateUpdateResponse(false));
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public TimeValue ackTimeout() {
|
|
|
+ return request.ackTimeout();
|
|
|
+ }
|
|
|
|
|
|
@Override
|
|
|
public TimeValue timeout() {
|
|
|
- return request.masterTimeout;
|
|
|
+ return request.masterNodeTimeout();
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
@@ -382,17 +397,17 @@ public class MetaDataMappingService extends AbstractComponent {
|
|
|
public ClusterState execute(final ClusterState currentState) throws Exception {
|
|
|
List<String> indicesToClose = Lists.newArrayList();
|
|
|
try {
|
|
|
- if (request.indices.length == 0) {
|
|
|
+ if (request.indices().length == 0) {
|
|
|
throw new IndexMissingException(new Index("_all"));
|
|
|
}
|
|
|
- for (String index : request.indices) {
|
|
|
+ for (String index : request.indices()) {
|
|
|
if (!currentState.metaData().hasIndex(index)) {
|
|
|
throw new IndexMissingException(new Index(index));
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// pre create indices here and add mappings to them so we can merge the mappings here if needed
|
|
|
- for (String index : request.indices) {
|
|
|
+ for (String index : request.indices()) {
|
|
|
if (indicesService.hasIndex(index)) {
|
|
|
continue;
|
|
|
}
|
|
|
@@ -404,29 +419,29 @@ public class MetaDataMappingService extends AbstractComponent {
|
|
|
indexService.mapperService().merge(MapperService.DEFAULT_MAPPING, indexMetaData.mappings().get(MapperService.DEFAULT_MAPPING).source(), false);
|
|
|
}
|
|
|
// only add the current relevant mapping (if exists)
|
|
|
- if (indexMetaData.mappings().containsKey(request.mappingType)) {
|
|
|
- indexService.mapperService().merge(request.mappingType, indexMetaData.mappings().get(request.mappingType).source(), false);
|
|
|
+ if (indexMetaData.mappings().containsKey(request.type())) {
|
|
|
+ indexService.mapperService().merge(request.type(), indexMetaData.mappings().get(request.type()).source(), false);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
Map<String, DocumentMapper> newMappers = newHashMap();
|
|
|
Map<String, DocumentMapper> existingMappers = newHashMap();
|
|
|
- for (String index : request.indices) {
|
|
|
+ for (String index : request.indices()) {
|
|
|
IndexService indexService = indicesService.indexService(index);
|
|
|
if (indexService != null) {
|
|
|
// try and parse it (no need to add it here) so we can bail early in case of parsing exception
|
|
|
DocumentMapper newMapper;
|
|
|
- DocumentMapper existingMapper = indexService.mapperService().documentMapper(request.mappingType);
|
|
|
- if (MapperService.DEFAULT_MAPPING.equals(request.mappingType)) {
|
|
|
+ DocumentMapper existingMapper = indexService.mapperService().documentMapper(request.type());
|
|
|
+ if (MapperService.DEFAULT_MAPPING.equals(request.type())) {
|
|
|
// _default_ types do not go through merging, but we do test the new settings. Also don't apply the old default
|
|
|
- newMapper = indexService.mapperService().parse(request.mappingType, new CompressedString(request.mappingSource), false);
|
|
|
+ newMapper = indexService.mapperService().parse(request.type(), new CompressedString(request.source()), false);
|
|
|
} else {
|
|
|
- newMapper = indexService.mapperService().parse(request.mappingType, new CompressedString(request.mappingSource));
|
|
|
+ newMapper = indexService.mapperService().parse(request.type(), new CompressedString(request.source()));
|
|
|
if (existingMapper != null) {
|
|
|
// first, simulate
|
|
|
DocumentMapper.MergeResult mergeResult = existingMapper.merge(newMapper, mergeFlags().simulate(true));
|
|
|
// if we have conflicts, and we are not supposed to ignore them, throw an exception
|
|
|
- if (!request.ignoreConflicts && mergeResult.hasConflicts()) {
|
|
|
+ if (!request.ignoreConflicts() && mergeResult.hasConflicts()) {
|
|
|
throw new MergeMappingException(mergeResult.conflicts());
|
|
|
}
|
|
|
}
|
|
|
@@ -442,7 +457,7 @@ public class MetaDataMappingService extends AbstractComponent {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- String mappingType = request.mappingType;
|
|
|
+ String mappingType = request.type();
|
|
|
if (mappingType == null) {
|
|
|
mappingType = newMappers.values().iterator().next().type();
|
|
|
} else if (!mappingType.equals(newMappers.values().iterator().next().type())) {
|
|
|
@@ -489,12 +504,11 @@ public class MetaDataMappingService extends AbstractComponent {
|
|
|
|
|
|
if (mappings.isEmpty()) {
|
|
|
// no changes, return
|
|
|
- listener.onResponse(new Response(true));
|
|
|
return currentState;
|
|
|
}
|
|
|
|
|
|
MetaData.Builder builder = MetaData.builder(currentState.metaData());
|
|
|
- for (String indexName : request.indices) {
|
|
|
+ for (String indexName : request.indices()) {
|
|
|
IndexMetaData indexMetaData = currentState.metaData().index(indexName);
|
|
|
if (indexMetaData == null) {
|
|
|
throw new IndexMissingException(new Index(indexName));
|
|
|
@@ -505,26 +519,7 @@ public class MetaDataMappingService extends AbstractComponent {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- ClusterState updatedState = ClusterState.builder(currentState).metaData(builder).build();
|
|
|
-
|
|
|
- int counter = 1; // we want to wait on the master node to apply it on its cluster state
|
|
|
- // also wait for nodes that actually have the index created on them to apply the mappings internally
|
|
|
- for (String index : request.indices) {
|
|
|
- IndexRoutingTable indexRoutingTable = updatedState.routingTable().index(index);
|
|
|
- if (indexRoutingTable != null) {
|
|
|
- counter += indexRoutingTable.numberOfNodesShardsAreAllocatedOn(updatedState.nodes().masterNodeId());
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- logger.debug("Expecting {} mapping created responses for other nodes", counter - 1);
|
|
|
-
|
|
|
- // TODO: adding one to the version is based on knowledge on how the parent class will increment the version
|
|
|
- // move this to the base class or add another callback before publishing the new cluster state so we
|
|
|
- // capture its version.
|
|
|
- countDownListener = new CountDownListener(counter, currentState.version() + 1, listener);
|
|
|
- mappingCreatedAction.add(countDownListener, request.timeout);
|
|
|
-
|
|
|
- return updatedState;
|
|
|
+ return ClusterState.builder(currentState).metaData(builder).build();
|
|
|
} finally {
|
|
|
for (String index : indicesToClose) {
|
|
|
indicesService.removeIndex(index, "created for mapping processing");
|
|
|
@@ -534,107 +529,8 @@ public class MetaDataMappingService extends AbstractComponent {
|
|
|
|
|
|
@Override
|
|
|
public void clusterStateProcessed(String source, ClusterState oldState, ClusterState newState) {
|
|
|
- if (countDownListener != null) {
|
|
|
- // the master has applied it on its cluster state
|
|
|
- countDownListener.decrementCounter();
|
|
|
- }
|
|
|
- }
|
|
|
- });
|
|
|
- }
|
|
|
-
|
|
|
- public static interface Listener {
|
|
|
-
|
|
|
- void onResponse(Response response);
|
|
|
-
|
|
|
- void onFailure(Throwable t);
|
|
|
- }
|
|
|
|
|
|
- public static class PutRequest {
|
|
|
-
|
|
|
- final String[] indices;
|
|
|
-
|
|
|
- final String mappingType;
|
|
|
-
|
|
|
- final String mappingSource;
|
|
|
-
|
|
|
- boolean ignoreConflicts = false;
|
|
|
-
|
|
|
- TimeValue timeout = TimeValue.timeValueSeconds(10);
|
|
|
- TimeValue masterTimeout = MasterNodeOperationRequest.DEFAULT_MASTER_NODE_TIMEOUT;
|
|
|
-
|
|
|
- public PutRequest(String[] indices, String mappingType, String mappingSource) {
|
|
|
- this.indices = indices;
|
|
|
- this.mappingType = mappingType;
|
|
|
- this.mappingSource = mappingSource;
|
|
|
- }
|
|
|
-
|
|
|
- public PutRequest ignoreConflicts(boolean ignoreConflicts) {
|
|
|
- this.ignoreConflicts = ignoreConflicts;
|
|
|
- return this;
|
|
|
- }
|
|
|
-
|
|
|
- public PutRequest timeout(TimeValue timeout) {
|
|
|
- this.timeout = timeout;
|
|
|
- return this;
|
|
|
- }
|
|
|
-
|
|
|
- public PutRequest masterTimeout(TimeValue masterTimeout) {
|
|
|
- this.masterTimeout = masterTimeout;
|
|
|
- return this;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- public static class Response {
|
|
|
- private final boolean acknowledged;
|
|
|
-
|
|
|
- public Response(boolean acknowledged) {
|
|
|
- this.acknowledged = acknowledged;
|
|
|
- }
|
|
|
-
|
|
|
- public boolean acknowledged() {
|
|
|
- return acknowledged;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- private class CountDownListener implements NodeMappingCreatedAction.Listener {
|
|
|
-
|
|
|
- private final CountDown countDown;
|
|
|
- private final Listener listener;
|
|
|
- private final long minClusterStateVersion;
|
|
|
-
|
|
|
- /**
|
|
|
- * @param countDown initial counter value
|
|
|
- * @param minClusterStateVersion the minimum cluster state version for which accept responses
|
|
|
- * @param listener listener to call when counter reaches 0.
|
|
|
- */
|
|
|
- public CountDownListener(int countDown, long minClusterStateVersion, Listener listener) {
|
|
|
- this.countDown = new CountDown(countDown);
|
|
|
- this.listener = listener;
|
|
|
- this.minClusterStateVersion = minClusterStateVersion;
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public void onNodeMappingCreated(NodeMappingCreatedAction.NodeMappingCreatedResponse response) {
|
|
|
- if (response.clusterStateVersion() < minClusterStateVersion) {
|
|
|
- return;
|
|
|
}
|
|
|
- decrementCounter();
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- public void decrementCounter() {
|
|
|
- if (countDown.countDown()) {
|
|
|
- mappingCreatedAction.remove(this);
|
|
|
- listener.onResponse(new Response(true));
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public void onTimeout() {
|
|
|
- if (countDown.fastForward()) {
|
|
|
- mappingCreatedAction.remove(this);
|
|
|
- listener.onResponse(new Response(false));
|
|
|
- }
|
|
|
- }
|
|
|
+ });
|
|
|
}
|
|
|
}
|