Put Mappings CountDownListener validates cluster state version of incoming change confirmations.
Closes #3508
This commit is contained in:
parent
3eed2625e2
commit
3ac3c7d12c
|
@ -76,6 +76,7 @@ public class NodeMappingCreatedAction extends AbstractComponent {
|
||||||
|
|
||||||
public void nodeMappingCreated(final NodeMappingCreatedResponse response) throws ElasticSearchException {
|
public void nodeMappingCreated(final NodeMappingCreatedResponse response) throws ElasticSearchException {
|
||||||
DiscoveryNodes nodes = clusterService.state().nodes();
|
DiscoveryNodes nodes = clusterService.state().nodes();
|
||||||
|
logger.debug("Sending mapping created for index {}, type {} (cluster state version: {})", response.index, response.type, response.clusterStateVersion);
|
||||||
if (nodes.localNodeMaster()) {
|
if (nodes.localNodeMaster()) {
|
||||||
threadPool.generic().execute(new Runnable() {
|
threadPool.generic().execute(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
|
@ -128,14 +129,16 @@ public class NodeMappingCreatedAction extends AbstractComponent {
|
||||||
private String index;
|
private String index;
|
||||||
private String type;
|
private String type;
|
||||||
private String nodeId;
|
private String nodeId;
|
||||||
|
private long clusterStateVersion;
|
||||||
|
|
||||||
private NodeMappingCreatedResponse() {
|
private NodeMappingCreatedResponse() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public NodeMappingCreatedResponse(String index, String type, String nodeId) {
|
public NodeMappingCreatedResponse(String index, String type, String nodeId, long clusterStateVersion) {
|
||||||
this.index = index;
|
this.index = index;
|
||||||
this.type = type;
|
this.type = type;
|
||||||
this.nodeId = nodeId;
|
this.nodeId = nodeId;
|
||||||
|
this.clusterStateVersion = clusterStateVersion;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String index() {
|
public String index() {
|
||||||
|
@ -150,12 +153,17 @@ public class NodeMappingCreatedAction extends AbstractComponent {
|
||||||
return nodeId;
|
return nodeId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public long clusterStateVersion() {
|
||||||
|
return clusterStateVersion;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void writeTo(StreamOutput out) throws IOException {
|
public void writeTo(StreamOutput out) throws IOException {
|
||||||
super.writeTo(out);
|
super.writeTo(out);
|
||||||
out.writeString(index);
|
out.writeString(index);
|
||||||
out.writeString(type);
|
out.writeString(type);
|
||||||
out.writeString(nodeId);
|
out.writeString(nodeId);
|
||||||
|
out.writeVLong(clusterStateVersion);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -164,6 +172,7 @@ public class NodeMappingCreatedAction extends AbstractComponent {
|
||||||
index = in.readString();
|
index = in.readString();
|
||||||
type = in.readString();
|
type = in.readString();
|
||||||
nodeId = in.readString();
|
nodeId = in.readString();
|
||||||
|
clusterStateVersion = in.readVLong();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -492,7 +492,11 @@ public class MetaDataMappingService extends AbstractComponent {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
countDownListener = new CountDownListener(counter, request.indices, request.mappingType, listener);
|
|
||||||
|
// 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 it's version.
|
||||||
|
countDownListener = new CountDownListener(counter, currentState.version() + 1, listener);
|
||||||
mappingCreatedAction.add(countDownListener, request.timeout);
|
mappingCreatedAction.add(countDownListener, request.timeout);
|
||||||
|
|
||||||
return updatedState;
|
return updatedState;
|
||||||
|
@ -589,22 +593,22 @@ public class MetaDataMappingService extends AbstractComponent {
|
||||||
private final AtomicBoolean notified = new AtomicBoolean();
|
private final AtomicBoolean notified = new AtomicBoolean();
|
||||||
private final AtomicInteger countDown;
|
private final AtomicInteger countDown;
|
||||||
private final Listener listener;
|
private final Listener listener;
|
||||||
private final List<String> indices;
|
private final long minClusterStateVersion;
|
||||||
private final String type;
|
|
||||||
|
|
||||||
public CountDownListener(int countDown, String[] indices, String type, Listener listener) {
|
/**
|
||||||
this.indices = Arrays.asList(indices);
|
* @param countDown initial counter value
|
||||||
this.type = type;
|
* @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 AtomicInteger(countDown);
|
this.countDown = new AtomicInteger(countDown);
|
||||||
this.listener = listener;
|
this.listener = listener;
|
||||||
|
this.minClusterStateVersion = minClusterStateVersion;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onNodeMappingCreated(NodeMappingCreatedAction.NodeMappingCreatedResponse response) {
|
public void onNodeMappingCreated(NodeMappingCreatedAction.NodeMappingCreatedResponse response) {
|
||||||
if (indices.indexOf(response.index()) < 0) {
|
if (response.clusterStateVersion() < minClusterStateVersion) {
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (type != null && !type.equals(response.type())) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
decrementCounter();
|
decrementCounter();
|
||||||
|
|
|
@ -133,8 +133,9 @@ public class IndicesClusterStateService extends AbstractLifecycleComponent<Indic
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void clusterChanged(final ClusterChangedEvent event) {
|
public void clusterChanged(final ClusterChangedEvent event) {
|
||||||
if (!indicesService.changesAllowed())
|
if (!indicesService.changesAllowed()) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!lifecycle.started()) {
|
if (!lifecycle.started()) {
|
||||||
return;
|
return;
|
||||||
|
@ -402,7 +403,8 @@ public class IndicesClusterStateService extends AbstractLifecycleComponent<Indic
|
||||||
logger.debug("[{}] parsed mapping [{}], and got different sources\noriginal:\n{}\nparsed:\n{}", index, mappingType, mappingSource, mapperService.documentMapper(mappingType).mappingSource());
|
logger.debug("[{}] parsed mapping [{}], and got different sources\noriginal:\n{}\nparsed:\n{}", index, mappingType, mappingSource, mapperService.documentMapper(mappingType).mappingSource());
|
||||||
requiresRefresh = true;
|
requiresRefresh = true;
|
||||||
}
|
}
|
||||||
nodeMappingCreatedAction.nodeMappingCreated(new NodeMappingCreatedAction.NodeMappingCreatedResponse(index, mappingType, event.state().nodes().localNodeId()));
|
nodeMappingCreatedAction.nodeMappingCreated(
|
||||||
|
new NodeMappingCreatedAction.NodeMappingCreatedResponse(index, mappingType, event.state().nodes().localNodeId(), event.state().version()));
|
||||||
} else {
|
} else {
|
||||||
DocumentMapper existingMapper = mapperService.documentMapper(mappingType);
|
DocumentMapper existingMapper = mapperService.documentMapper(mappingType);
|
||||||
if (!mappingSource.equals(existingMapper.mappingSource())) {
|
if (!mappingSource.equals(existingMapper.mappingSource())) {
|
||||||
|
@ -417,7 +419,8 @@ public class IndicesClusterStateService extends AbstractLifecycleComponent<Indic
|
||||||
// this might happen when upgrading from 0.15 to 0.16
|
// this might happen when upgrading from 0.15 to 0.16
|
||||||
logger.debug("[{}] parsed mapping [{}], and got different sources\noriginal:\n{}\nparsed:\n{}", index, mappingType, mappingSource, mapperService.documentMapper(mappingType).mappingSource());
|
logger.debug("[{}] parsed mapping [{}], and got different sources\noriginal:\n{}\nparsed:\n{}", index, mappingType, mappingSource, mapperService.documentMapper(mappingType).mappingSource());
|
||||||
}
|
}
|
||||||
nodeMappingCreatedAction.nodeMappingCreated(new NodeMappingCreatedAction.NodeMappingCreatedResponse(index, mappingType, event.state().nodes().localNodeId()));
|
nodeMappingCreatedAction.nodeMappingCreated(
|
||||||
|
new NodeMappingCreatedAction.NodeMappingCreatedResponse(index, mappingType, event.state().nodes().localNodeId(), event.state().version()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
|
@ -486,8 +489,9 @@ public class IndicesClusterStateService extends AbstractLifecycleComponent<Indic
|
||||||
}
|
}
|
||||||
|
|
||||||
private void applyNewOrUpdatedShards(final ClusterChangedEvent event) throws ElasticSearchException {
|
private void applyNewOrUpdatedShards(final ClusterChangedEvent event) throws ElasticSearchException {
|
||||||
if (!indicesService.changesAllowed())
|
if (!indicesService.changesAllowed()) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
RoutingTable routingTable = event.state().routingTable();
|
RoutingTable routingTable = event.state().routingTable();
|
||||||
RoutingNode routingNodes = event.state().readOnlyRoutingNodes().nodesToShards().get(event.state().nodes().localNodeId());
|
RoutingNode routingNodes = event.state().readOnlyRoutingNodes().nodesToShards().get(event.state().nodes().localNodeId());
|
||||||
|
|
|
@ -245,8 +245,6 @@ public class UpdateMappingTests extends AbstractSharedClusterTest {
|
||||||
@Test
|
@Test
|
||||||
public void updateMappingConcurrently() throws Throwable {
|
public void updateMappingConcurrently() throws Throwable {
|
||||||
// Test that we can concurrently update different indexes and types.
|
// Test that we can concurrently update different indexes and types.
|
||||||
// NOTE: concurrently updating the mapping of the same type and index can still return before all (relevant) nodes are updated.
|
|
||||||
// The fix for that tracked on issues #3508
|
|
||||||
int shardNo = Math.max(5, numberOfNodes());
|
int shardNo = Math.max(5, numberOfNodes());
|
||||||
|
|
||||||
prepareCreate("test1").setSettings("index.number_of_shards", shardNo).execute().actionGet();
|
prepareCreate("test1").setSettings("index.number_of_shards", shardNo).execute().actionGet();
|
||||||
|
@ -263,6 +261,7 @@ public class UpdateMappingTests extends AbstractSharedClusterTest {
|
||||||
|
|
||||||
for (int j = 0; j < threads.length; j++) {
|
for (int j = 0; j < threads.length; j++) {
|
||||||
threads[j] = new Thread(new Runnable() {
|
threads[j] = new Thread(new Runnable() {
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
try {
|
try {
|
||||||
|
@ -276,11 +275,12 @@ public class UpdateMappingTests extends AbstractSharedClusterTest {
|
||||||
Client client1 = clientArray.get(i % clientArray.size());
|
Client client1 = clientArray.get(i % clientArray.size());
|
||||||
Client client2 = clientArray.get((i + 1) % clientArray.size());
|
Client client2 = clientArray.get((i + 1) % clientArray.size());
|
||||||
String indexName = i % 2 == 0 ? "test2" : "test1";
|
String indexName = i % 2 == 0 ? "test2" : "test1";
|
||||||
String typeName = Thread.currentThread().getName() + "_" + i;
|
String typeName = "type" + (i % 10);
|
||||||
|
String fieldName = Thread.currentThread().getName() + "_" + i;
|
||||||
|
|
||||||
PutMappingResponse response = client1.admin().indices().preparePutMapping(indexName).setType(typeName).setSource(
|
PutMappingResponse response = client1.admin().indices().preparePutMapping(indexName).setType(typeName).setSource(
|
||||||
JsonXContent.contentBuilder().startObject().startObject(typeName)
|
JsonXContent.contentBuilder().startObject().startObject(typeName)
|
||||||
.startObject("properties").startObject("f").field("type", "string").endObject().endObject()
|
.startObject("properties").startObject(fieldName).field("type", "string").endObject().endObject()
|
||||||
.endObject().endObject()
|
.endObject().endObject()
|
||||||
).get();
|
).get();
|
||||||
|
|
||||||
|
@ -288,6 +288,7 @@ public class UpdateMappingTests extends AbstractSharedClusterTest {
|
||||||
GetMappingsResponse getMappingResponse = client2.admin().indices().prepareGetMappings(indexName).get();
|
GetMappingsResponse getMappingResponse = client2.admin().indices().prepareGetMappings(indexName).get();
|
||||||
Map<String, MappingMetaData> mappings = getMappingResponse.getMappings().get(indexName);
|
Map<String, MappingMetaData> mappings = getMappingResponse.getMappings().get(indexName);
|
||||||
assertThat(mappings.keySet(), Matchers.hasItem(typeName));
|
assertThat(mappings.keySet(), Matchers.hasItem(typeName));
|
||||||
|
assertThat(((Map<String, Object>) mappings.get(typeName).getSourceAsMap().get("properties")).keySet(), Matchers.hasItem(fieldName));
|
||||||
}
|
}
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
threadException[0] = t;
|
threadException[0] = t;
|
||||||
|
|
Loading…
Reference in New Issue