Skip to content
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

[Zen2] Write manifest file #35049

Merged
merged 61 commits into from
Nov 19, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
61 commits
Select commit Hold shift + click to select a range
76474dc
[Zen2] Write manifest file
Oct 29, 2018
39e4686
Merge branch 'zen2' into 'zen2_manifest'
Oct 30, 2018
421caa1
Fix code review issues
Oct 31, 2018
5dcb6f5
MetaState -> Manifest
Nov 7, 2018
25e7c52
Change order of ParseField in manifest
Nov 7, 2018
6440a90
Rename globalGeneration and indexGenerations
Nov 7, 2018
aba2e40
writeAndCleanup method
Nov 7, 2018
b6ca5d9
s/of/if
Nov 7, 2018
9d482ad
s/state id/generation id
Nov 7, 2018
23c3ca6
s/zen 1/manifest-less
Nov 7, 2018
3e090b4
ManifestTest: move, reformat, use eq&hash utils, enrich mutation
Nov 7, 2018
988ed6d
fileToCorrupt = file
Nov 7, 2018
87f6ae9
Fix tests: FullClusterRestart callback
Nov 7, 2018
b1eb33e
indices typo fix
Nov 7, 2018
f5cd21f
MetaStateServiceTests refactoring
Nov 7, 2018
1c11360
GatewayMetaState and MetaStateService bug fix
Nov 7, 2018
a2c7226
Manipulation -> parsing/generation
Nov 9, 2018
96029ba
Add TODO to GatewayMetaState
Nov 9, 2018
db6da11
Do not write non-upgraded metadata on the startup
Nov 9, 2018
541c393
isDataOrMasterNode
Nov 9, 2018
b5775cf
Load manifest only on data node, create a method for it
Nov 9, 2018
625d2bf
Remove "Storage is not dirty"
Nov 9, 2018
b6872a8
Inline perform cleanup
Nov 9, 2018
2f1f7f7
Add index name to IOException
Nov 9, 2018
75045f0
Used by tests javadoc
Nov 9, 2018
466ad6f
Rename tests
Nov 9, 2018
4aacfce
Ignore missing global metadata if there is no manifest file
Nov 9, 2018
7ff091e
Empty manifest instead of null
Nov 9, 2018
f57067d
Remove unused import
Nov 9, 2018
3de2060
isEmpty fix
Nov 12, 2018
14aff80
happens-before -> single thread comment
Nov 12, 2018
6b1accb
Make globalStateGeneration final
Nov 12, 2018
0e0ec1c
Remove WriteStateException handling
Nov 12, 2018
f463893
loadManifest -> loadManifestOrEmpty
Nov 12, 2018
c6ea279
Fix bug with missing global generation
Nov 12, 2018
95f3aa1
metaState -> manifest rename, and tests for loading empty manifest
Nov 12, 2018
ffd25a6
Revert "Fix tests: FullClusterRestart callback"
Nov 12, 2018
f21ddf9
fullRestart should call onNodeStopped callback, before re-creating nodes
Nov 12, 2018
f1ff732
Fix broken meta tests
Nov 12, 2018
fb3fc72
write method should perform cleanup if it fails, s/stateId/generationId
Nov 12, 2018
20c9813
GatewayMetaState perform cleanup if apply state fails
Nov 12, 2018
f369096
Merge branch 'zen2' into zen2_manifest
Nov 12, 2018
fb56acc
Remove unused import
Nov 12, 2018
bbab85a
Always cleanup old state on rollback, even if prev gen is missing
Nov 13, 2018
a6dddc8
Allow subclasses to override formats used in MetaStateService
Nov 13, 2018
a3865f6
Do not use loadManifestOrEmpty in loadFullState
Nov 13, 2018
7936cc4
Add random atomicity test for Transaction
Nov 13, 2018
ae1951e
randomMetaData -> randomMetaDataForTx, where is already randomMetaData
Nov 13, 2018
326be60
write should not perform cleanup at all, writeAndCleanup should always
Nov 13, 2018
982e853
Use writeManifestAndCleanup, reorder rollbackActions before write
Nov 13, 2018
4113830
Transaction -> AtomicClusterStateWriter
Nov 13, 2018
0e63bdc
Fix style
Nov 13, 2018
0bc5ab5
Do not cleanup non-referenced IMD in case of rollback
Nov 13, 2018
17bb22a
Revert "fullRestart should call onNodeStopped callback, before re-cre…
Nov 14, 2018
a5de8ad
Merge branch zen2 into zen2_manifest
Nov 14, 2018
c7fb593
getPrefix package private
Nov 15, 2018
736bde5
Add final modifiers
Nov 15, 2018
2577b38
s/re-write/upgrade
Nov 15, 2018
8b0ff4c
typo dangling
Nov 15, 2018
21cec41
Rename test
Nov 15, 2018
f00c74f
Merge zen2 into zen2_manifest
Nov 16, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
197 changes: 197 additions & 0 deletions server/src/main/java/org/elasticsearch/cluster/metadata/Manifest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

package org.elasticsearch.cluster.metadata;

import org.elasticsearch.common.ParseField;
import org.elasticsearch.common.xcontent.ConstructingObjectParser;
import org.elasticsearch.common.xcontent.ObjectParser;
import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.ToXContentFragment;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.gateway.MetaDataStateFormat;
import org.elasticsearch.index.Index;

import java.io.IOException;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
* This class represents the manifest file, which is the entry point for reading meta data from disk.
* Metadata consists of global metadata and index metadata.
* When new version of metadata is written it's assigned some generation long value.
* Global metadata generation could be obtained by calling {@link #getGlobalGeneration()}.
* Index metadata generation could be obtained by calling {@link #getIndexGenerations()}.
*/
public class Manifest implements ToXContentFragment {
private static final long MISSING_GLOBAL_GENERATION = -1;

private final long globalGeneration;
private final Map<Index, Long> indexGenerations;

public Manifest(long globalGeneration, Map<Index, Long> indexGenerations) {
this.globalGeneration = globalGeneration;
this.indexGenerations = indexGenerations;
}

/**
* Returns global metadata generation.
*/
public long getGlobalGeneration() {
return globalGeneration;
}

/**
* Returns map from {@link Index} to index metadata generation.
*/
public Map<Index, Long> getIndexGenerations() {
return indexGenerations;
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Manifest manifest = (Manifest) o;
return globalGeneration == manifest.globalGeneration &&
Objects.equals(indexGenerations, manifest.indexGenerations);
}

@Override
public int hashCode() {
return Objects.hash(globalGeneration, indexGenerations);
}

private static final String MANIFEST_FILE_PREFIX = "manifest-";
private static final ToXContent.Params MANIFEST_FORMAT_PARAMS = new ToXContent.MapParams(Collections.singletonMap("binary", "true"));

public static final MetaDataStateFormat<Manifest> FORMAT = new MetaDataStateFormat<Manifest>(MANIFEST_FILE_PREFIX) {

@Override
public void toXContent(XContentBuilder builder, Manifest state) throws IOException {
state.toXContent(builder, MANIFEST_FORMAT_PARAMS);
}

@Override
public Manifest fromXContent(XContentParser parser) throws IOException {
return Manifest.fromXContent(parser);
}
};


/*
* Code below this comment is for XContent parsing/generation
*/

private static final ParseField GENERATION_PARSE_FIELD = new ParseField("generation");
private static final ParseField INDEX_GENERATIONS_PARSE_FIELD = new ParseField("index_generations");

@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
builder.field(GENERATION_PARSE_FIELD.getPreferredName(), globalGeneration);
builder.array(INDEX_GENERATIONS_PARSE_FIELD.getPreferredName(), indexEntryList().toArray());
return builder;
}

private List<IndexEntry> indexEntryList() {
return indexGenerations.entrySet().stream().
map(entry -> new IndexEntry(entry.getKey(), entry.getValue())).
collect(Collectors.toList());
}

private static long generation(Object[] generationAndListOfIndexEntries) {
return (Long) generationAndListOfIndexEntries[0];
}

private static Map<Index, Long> indices(Object[] generationAndListOfIndexEntries) {
List<IndexEntry> listOfIndices = (List<IndexEntry>) generationAndListOfIndexEntries[1];
return listOfIndices.stream().collect(Collectors.toMap(IndexEntry::getIndex, IndexEntry::getGeneration));
}

private static final ConstructingObjectParser<Manifest, Void> PARSER = new ConstructingObjectParser<>(
"manifest",
generationAndListOfIndexEntries ->
new Manifest(generation(generationAndListOfIndexEntries), indices(generationAndListOfIndexEntries)));

static {
PARSER.declareLong(ConstructingObjectParser.constructorArg(), GENERATION_PARSE_FIELD);
PARSER.declareObjectArray(ConstructingObjectParser.constructorArg(), IndexEntry.INDEX_ENTRY_PARSER, INDEX_GENERATIONS_PARSE_FIELD);
}

public static Manifest fromXContent(XContentParser parser) throws IOException {
return PARSER.parse(parser, null);
}

public boolean isEmpty() {
return globalGeneration == MISSING_GLOBAL_GENERATION && indexGenerations.isEmpty();
}

public static Manifest empty() {
return new Manifest(MISSING_GLOBAL_GENERATION, Collections.emptyMap());
}

public boolean isGlobalGenerationMissing() {
return globalGeneration == MISSING_GLOBAL_GENERATION;
}

private static final class IndexEntry implements ToXContentFragment {
private static final ParseField INDEX_GENERATION_PARSE_FIELD = new ParseField("generation");
private static final ParseField INDEX_PARSE_FIELD = new ParseField("index");

static final ConstructingObjectParser<IndexEntry, Void> INDEX_ENTRY_PARSER = new ConstructingObjectParser<>(
"indexEntry",
indexAndGeneration -> new IndexEntry((Index) indexAndGeneration[0], (long) indexAndGeneration[1]));

static {
INDEX_ENTRY_PARSER.declareField(ConstructingObjectParser.constructorArg(),
Index::fromXContent, INDEX_PARSE_FIELD, ObjectParser.ValueType.OBJECT);
INDEX_ENTRY_PARSER.declareLong(ConstructingObjectParser.constructorArg(), INDEX_GENERATION_PARSE_FIELD);
}

private final long generation;
private final Index index;

IndexEntry(Index index, long generation) {
this.index = index;
this.generation = generation;
}

public long getGeneration() {
return generation;
}

public Index getIndex() {
return index;
}

@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject();
builder.field(INDEX_PARSE_FIELD.getPreferredName(), index);
builder.field(GENERATION_PARSE_FIELD.getPreferredName(), generation);
builder.endObject();
return builder;
}
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -390,7 +390,7 @@ private static NodeMetaData loadOrCreateNodeMetaData(Settings settings, Logger l
metaData = new NodeMetaData(generateNodeId(settings));
}
// we write again to make sure all paths have the latest state file
NodeMetaData.FORMAT.write(metaData, paths);
NodeMetaData.FORMAT.writeAndCleanup(metaData, paths);
return metaData;
}

Expand Down
Loading