Skip to content

Commit 09cd077

Browse files
committed
Fix IndexMetaData loads after rollover (#33394)
When we rollover and index we write the conditions of the rollover that the old index met into the old index. Loading this index metadata requires a working `NamedXContentRegistry` that has been populated with parsers from the rollover infrastructure. We had a few loads that didn't use a working `NamedXContentRegistry` and so would fail if they ever encountered an index that had been rolled over. Here are the locations of the loads and how I fixed them: * IndexFolderUpgrader - removed entirely. It existed to support opening indices made in Elasticsearch 2.x. Since we only need this change as far back as 6.4.1 which will supports reading from indices created as far back as 5.0.0 we should be good here. * TransportNodesListGatewayStartedShards - wired the `NamedXContentRegistry` into place. * TransportNodesListShardStoreMetaData - wired the `NamedXContentRegistry` into place. * OldIndexUtils - removed entirely. It existed to support the zip based index backwards compatibility tests which we've since replaced with code that actually runs old versions of Elasticsearch. In addition to fixing the actual problem I added full cluster restart integration tests for rollover which would have caught this problem and I added an extra assertion to IndexMetaData's deserialization code which will trip if we try to deserialize and index's metadata without a fully formed `NamedXContentRegistry`. It won't catch if use the *wrong* `NamedXContentRegistry` but it is better than nothing. Closes #33316
1 parent 8bb3fa3 commit 09cd077

File tree

7 files changed

+71
-413
lines changed

7 files changed

+71
-413
lines changed

qa/full-cluster-restart/src/test/java/org/elasticsearch/upgrades/FullClusterRestartIT.java

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -490,6 +490,62 @@ public void testShrinkAfterUpgrade() throws IOException {
490490
}
491491
}
492492

493+
/**
494+
* Test upgrading after a rollover. Specifically:
495+
* <ol>
496+
* <li>Create an index with a write alias
497+
* <li>Write some documents to the write alias
498+
* <li>Roll over the index
499+
* <li>Make sure the document count is correct
500+
* <li>Upgrade
501+
* <li>Write some more documents to the write alias
502+
* <li>Make sure the document count is correct
503+
* </ol>
504+
*/
505+
public void testRollover() throws IOException {
506+
if (runningAgainstOldCluster) {
507+
Request createIndex = new Request("PUT", "/" + index + "-000001");
508+
createIndex.setJsonEntity("{"
509+
+ " \"aliases\": {"
510+
+ " \"" + index + "_write\": {}"
511+
+ " }"
512+
+ "}");
513+
client().performRequest(createIndex);
514+
}
515+
516+
int bulkCount = 10;
517+
StringBuilder bulk = new StringBuilder();
518+
for (int i = 0; i < bulkCount; i++) {
519+
bulk.append("{\"index\":{}}\n");
520+
bulk.append("{\"test\":\"test\"}\n");
521+
}
522+
Request bulkRequest = new Request("POST", "/" + index + "_write/doc/_bulk");
523+
bulkRequest.setJsonEntity(bulk.toString());
524+
bulkRequest.addParameter("refresh", "");
525+
assertThat(EntityUtils.toString(client().performRequest(bulkRequest).getEntity()), containsString("\"errors\":false"));
526+
527+
if (runningAgainstOldCluster) {
528+
Request rolloverRequest = new Request("POST", "/" + index + "_write/_rollover");
529+
rolloverRequest.setJsonEntity("{"
530+
+ " \"conditions\": {"
531+
+ " \"max_docs\": 5"
532+
+ " }"
533+
+ "}");
534+
client().performRequest(rolloverRequest);
535+
536+
assertThat(EntityUtils.toString(client().performRequest(new Request("GET", "/_cat/indices?v")).getEntity()),
537+
containsString("testrollover-000002"));
538+
}
539+
540+
Request countRequest = new Request("POST", "/" + index + "-*/_search");
541+
countRequest.addParameter("size", "0");
542+
Map<String, Object> count = entityAsMap(client().performRequest(countRequest));
543+
assertNoFailures(count);
544+
545+
int expectedCount = bulkCount + (runningAgainstOldCluster ? 0 : bulkCount);
546+
assertEquals(expectedCount, (int) XContentMapValues.extractValue("hits.total", count));
547+
}
548+
493549
void assertBasicSearchWorks(int count) throws IOException {
494550
logger.info("--> testing basic search");
495551
{
@@ -963,7 +1019,7 @@ private void checkSnapshot(String snapshotName, int count, Version tookOnVersion
9631019
Request writeToRestoredRequest = new Request("POST", "/restored_" + index + "/doc/_bulk");
9641020
writeToRestoredRequest.addParameter("refresh", "true");
9651021
writeToRestoredRequest.setJsonEntity(bulk.toString());
966-
client().performRequest(writeToRestoredRequest);
1022+
assertThat(EntityUtils.toString(client().performRequest(writeToRestoredRequest).getEntity()), containsString("\"errors\":false"));
9671023

9681024
// And count to make sure the add worked
9691025
// Make sure search finds all documents

server/src/main/java/org/elasticsearch/cluster/metadata/IndexMetaData.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
import org.elasticsearch.common.settings.Setting;
4646
import org.elasticsearch.common.settings.Setting.Property;
4747
import org.elasticsearch.common.settings.Settings;
48+
import org.elasticsearch.common.xcontent.NamedXContentRegistry;
4849
import org.elasticsearch.common.xcontent.ToXContent;
4950
import org.elasticsearch.common.xcontent.ToXContentFragment;
5051
import org.elasticsearch.common.xcontent.XContentBuilder;
@@ -1355,6 +1356,8 @@ public void toXContent(XContentBuilder builder, IndexMetaData state) throws IOEx
13551356

13561357
@Override
13571358
public IndexMetaData fromXContent(XContentParser parser) throws IOException {
1359+
assert parser.getXContentRegistry() != NamedXContentRegistry.EMPTY
1360+
: "loading index metadata requires a working named xcontent registry";
13581361
return Builder.fromXContent(parser);
13591362
}
13601363
};

server/src/main/java/org/elasticsearch/common/util/IndexFolderUpgrader.java

Lines changed: 0 additions & 134 deletions
This file was deleted.

server/src/main/java/org/elasticsearch/gateway/GatewayMetaState.java

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@
3535
import org.elasticsearch.common.component.AbstractComponent;
3636
import org.elasticsearch.common.settings.Settings;
3737
import org.elasticsearch.common.unit.TimeValue;
38-
import org.elasticsearch.common.util.IndexFolderUpgrader;
3938
import org.elasticsearch.env.NodeEnvironment;
4039
import org.elasticsearch.index.Index;
4140
import org.elasticsearch.plugins.MetaDataUpgrader;
@@ -84,7 +83,6 @@ public GatewayMetaState(Settings settings, NodeEnvironment nodeEnv, MetaStateSer
8483
if (DiscoveryNode.isMasterNode(settings) || DiscoveryNode.isDataNode(settings)) {
8584
try {
8685
ensureNoPre019State();
87-
IndexFolderUpgrader.upgradeIndicesIfNeeded(settings, nodeEnv);
8886
final MetaData metaData = metaStateService.loadFullState();
8987
final MetaData upgradedMetaData = upgradeMetaData(metaData, metaDataIndexUpgradeService, metaDataUpgrader);
9088
// We finished global state validation and successfully checked all indices for backward compatibility

server/src/main/java/org/elasticsearch/gateway/TransportNodesListGatewayStartedShards.java

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -70,18 +70,21 @@ public class TransportNodesListGatewayStartedShards extends
7070
public static final String ACTION_NAME = "internal:gateway/local/started_shards";
7171
private final NodeEnvironment nodeEnv;
7272
private final IndicesService indicesService;
73+
private final NamedXContentRegistry namedXContentRegistry;
7374

7475
@Inject
7576
public TransportNodesListGatewayStartedShards(Settings settings, ThreadPool threadPool,
7677
ClusterService clusterService, TransportService transportService,
7778
ActionFilters actionFilters,
7879
IndexNameExpressionResolver indexNameExpressionResolver,
79-
NodeEnvironment env, IndicesService indicesService) {
80+
NodeEnvironment env, IndicesService indicesService,
81+
NamedXContentRegistry namedXContentRegistry) {
8082
super(settings, ACTION_NAME, threadPool, clusterService, transportService, actionFilters,
8183
indexNameExpressionResolver, Request::new, NodeRequest::new, ThreadPool.Names.FETCH_SHARD_STARTED,
8284
NodeGatewayStartedShards.class);
8385
this.nodeEnv = env;
8486
this.indicesService = indicesService;
87+
this.namedXContentRegistry = namedXContentRegistry;
8588
}
8689

8790
@Override
@@ -116,15 +119,15 @@ protected NodeGatewayStartedShards nodeOperation(NodeRequest request) {
116119
try {
117120
final ShardId shardId = request.getShardId();
118121
logger.trace("{} loading local shard state info", shardId);
119-
ShardStateMetaData shardStateMetaData = ShardStateMetaData.FORMAT.loadLatestState(logger, NamedXContentRegistry.EMPTY,
122+
ShardStateMetaData shardStateMetaData = ShardStateMetaData.FORMAT.loadLatestState(logger, namedXContentRegistry,
120123
nodeEnv.availableShardPaths(request.shardId));
121124
if (shardStateMetaData != null) {
122125
IndexMetaData metaData = clusterService.state().metaData().index(shardId.getIndex());
123126
if (metaData == null) {
124127
// we may send this requests while processing the cluster state that recovered the index
125128
// sometimes the request comes in before the local node processed that cluster state
126129
// in such cases we can load it from disk
127-
metaData = IndexMetaData.FORMAT.loadLatestState(logger, NamedXContentRegistry.EMPTY,
130+
metaData = IndexMetaData.FORMAT.loadLatestState(logger, namedXContentRegistry,
128131
nodeEnv.indexPaths(shardId.getIndex()));
129132
}
130133
if (metaData == null) {

server/src/main/java/org/elasticsearch/indices/store/TransportNodesListShardStoreMetaData.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -68,18 +68,20 @@ public class TransportNodesListShardStoreMetaData extends TransportNodesAction<T
6868
public static final String ACTION_NAME = "internal:cluster/nodes/indices/shard/store";
6969

7070
private final IndicesService indicesService;
71-
7271
private final NodeEnvironment nodeEnv;
72+
private final NamedXContentRegistry namedXContentRegistry;
7373

7474
@Inject
7575
public TransportNodesListShardStoreMetaData(Settings settings, ThreadPool threadPool,
7676
ClusterService clusterService, TransportService transportService,
7777
IndicesService indicesService, NodeEnvironment nodeEnv, ActionFilters actionFilters,
78-
IndexNameExpressionResolver indexNameExpressionResolver) {
78+
IndexNameExpressionResolver indexNameExpressionResolver,
79+
NamedXContentRegistry namedXContentRegistry) {
7980
super(settings, ACTION_NAME, threadPool, clusterService, transportService, actionFilters, indexNameExpressionResolver,
8081
Request::new, NodeRequest::new, ThreadPool.Names.FETCH_SHARD_STORE, NodeStoreFilesMetaData.class);
8182
this.indicesService = indicesService;
8283
this.nodeEnv = nodeEnv;
84+
this.namedXContentRegistry = namedXContentRegistry;
8385
}
8486

8587
@Override
@@ -131,7 +133,7 @@ private StoreFilesMetaData listStoreMetaData(ShardId shardId) throws IOException
131133
// we may send this requests while processing the cluster state that recovered the index
132134
// sometimes the request comes in before the local node processed that cluster state
133135
// in such cases we can load it from disk
134-
metaData = IndexMetaData.FORMAT.loadLatestState(logger, NamedXContentRegistry.EMPTY,
136+
metaData = IndexMetaData.FORMAT.loadLatestState(logger, namedXContentRegistry,
135137
nodeEnv.indexPaths(shardId.getIndex()));
136138
}
137139
if (metaData == null) {

0 commit comments

Comments
 (0)