org.apache.hadoop.hdfs.protocol.LayoutVersion Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of hadoop-apache Show documentation
Show all versions of hadoop-apache Show documentation
Shaded version of Apache Hadoop for Presto
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF 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.apache.hadoop.hdfs.protocol;
import java.util.Comparator;
import java.util.Map;
import java.util.SortedSet;
import java.util.TreeSet;
import org.apache.hadoop.classification.InterfaceAudience;
/**
* This class tracks changes in the layout version of HDFS.
*
* Layout version is changed for following reasons:
*
* - The layout of how namenode or datanode stores information
* on disk changes.
* - A new operation code is added to the editlog.
* - Modification such as format of a record, content of a record
* in editlog or fsimage.
*
*
* How to update layout version:
* When a change requires new layout version, please add an entry into
* {@link Feature} with a short enum name, new layout version and description
* of the change. Please see {@link Feature} for further details.
*
*/
@InterfaceAudience.Private
public class LayoutVersion {
/**
* Version in which HDFS-2991 was fixed. This bug caused OP_ADD to
* sometimes be skipped for append() calls. If we see such a case when
* loading the edits, but the version is known to have that bug, we
* workaround the issue. Otherwise we should consider it a corruption
* and bail.
*/
public static final int BUGFIX_HDFS_2991_VERSION = -40;
/**
* The interface to be implemented by NameNode and DataNode layout features
*/
public interface LayoutFeature {
public FeatureInfo getInfo();
}
/**
* Enums for features that change the layout version before rolling
* upgrade is supported.
*
* To add a new layout version:
*
* - Define a new enum constant with a short enum name, the new layout version
* and description of the added feature.
* - When adding a layout version with an ancestor that is not same as
* its immediate predecessor, use the constructor where a specific ancestor
* can be passed.
*
*
*/
public enum Feature implements LayoutFeature {
NAMESPACE_QUOTA(-16, "Support for namespace quotas"),
FILE_ACCESS_TIME(-17, "Support for access time on files"),
DISKSPACE_QUOTA(-18, "Support for disk space quotas"),
STICKY_BIT(-19, "Support for sticky bits"),
APPEND_RBW_DIR(-20, "Datanode has \"rbw\" subdirectory for append"),
ATOMIC_RENAME(-21, "Support for atomic rename"),
CONCAT(-22, "Support for concat operation"),
SYMLINKS(-23, "Support for symbolic links"),
DELEGATION_TOKEN(-24, "Support for delegation tokens for security"),
FSIMAGE_COMPRESSION(-25, "Support for fsimage compression"),
FSIMAGE_CHECKSUM(-26, "Support checksum for fsimage"),
REMOVE_REL13_DISK_LAYOUT_SUPPORT(-27, "Remove support for 0.13 disk layout"),
EDITS_CHECKSUM(-28, "Support checksum for editlog"),
UNUSED(-29, "Skipped version"),
FSIMAGE_NAME_OPTIMIZATION(-30, "Store only last part of path in fsimage"),
RESERVED_REL20_203(-31, -19, "Reserved for release 0.20.203", true,
DELEGATION_TOKEN),
RESERVED_REL20_204(-32, -31, "Reserved for release 0.20.204", true),
RESERVED_REL22(-33, -27, "Reserved for release 0.22", true),
RESERVED_REL23(-34, -30, "Reserved for release 0.23", true),
FEDERATION(-35, "Support for namenode federation"),
LEASE_REASSIGNMENT(-36, "Support for persisting lease holder reassignment"),
STORED_TXIDS(-37, "Transaction IDs are stored in edits log and image files"),
TXID_BASED_LAYOUT(-38, "File names in NN Storage are based on transaction IDs"),
EDITLOG_OP_OPTIMIZATION(-39,
"Use LongWritable and ShortWritable directly instead of ArrayWritable of UTF8"),
OPTIMIZE_PERSIST_BLOCKS(-40,
"Serialize block lists with delta-encoded variable length ints, " +
"add OP_UPDATE_BLOCKS"),
RESERVED_REL1_2_0(-41, -32, "Reserved for release 1.2.0", true, CONCAT),
ADD_INODE_ID(-42, -40, "Assign a unique inode id for each inode", false),
SNAPSHOT(-43, "Support for snapshot feature"),
RESERVED_REL1_3_0(-44, -41, "Reserved for release 1.3.0", true,
ADD_INODE_ID, SNAPSHOT, FSIMAGE_NAME_OPTIMIZATION),
OPTIMIZE_SNAPSHOT_INODES(-45, -43,
"Reduce snapshot inode memory footprint", false),
SEQUENTIAL_BLOCK_ID(-46, "Allocate block IDs sequentially and store " +
"block IDs in the edits log and image files"),
EDITLOG_SUPPORT_RETRYCACHE(-47, "Record ClientId and CallId in editlog to "
+ "enable rebuilding retry cache in case of HA failover"),
EDITLOG_ADD_BLOCK(-48, "Add new editlog that only records allocation of "
+ "the new block instead of the entire block list"),
ADD_DATANODE_AND_STORAGE_UUIDS(-49, "Replace StorageID with DatanodeUuid."
+ " Use distinct StorageUuid per storage directory."),
ADD_LAYOUT_FLAGS(-50, "Add support for layout flags."),
CACHING(-51, "Support for cache pools and path-based caching"),
// Hadoop 2.4.0
PROTOBUF_FORMAT(-52, "Use protobuf to serialize FSImage"),
EXTENDED_ACL(-53, "Extended ACL"),
RESERVED_REL2_4_0(-54, -51, "Reserved for release 2.4.0", true,
PROTOBUF_FORMAT, EXTENDED_ACL);
private final FeatureInfo info;
/**
* Feature that is added at layout version {@code lv} - 1.
* @param lv new layout version with the addition of this feature
* @param description description of the feature
*/
Feature(final int lv, final String description) {
this(lv, lv + 1, description, false);
}
/**
* Feature that is added at layout version {@code ancestoryLV}.
* @param lv new layout version with the addition of this feature
* @param ancestorLV layout version from which the new lv is derived from.
* @param description description of the feature
* @param reserved true when this is a layout version reserved for previous
* version
* @param features set of features that are to be enabled for this version
*/
Feature(final int lv, final int ancestorLV, final String description,
boolean reserved, Feature... features) {
info = new FeatureInfo(lv, ancestorLV, description, reserved, features);
}
@Override
public FeatureInfo getInfo() {
return info;
}
}
/** Feature information. */
public static class FeatureInfo {
private final int lv;
private final int ancestorLV;
private final Integer minCompatLV;
private final String description;
private final boolean reserved;
private final LayoutFeature[] specialFeatures;
public FeatureInfo(final int lv, final int ancestorLV, final String description,
boolean reserved, LayoutFeature... specialFeatures) {
this(lv, ancestorLV, null, description, reserved, specialFeatures);
}
public FeatureInfo(final int lv, final int ancestorLV, Integer minCompatLV,
final String description, boolean reserved,
LayoutFeature... specialFeatures) {
this.lv = lv;
this.ancestorLV = ancestorLV;
this.minCompatLV = minCompatLV;
this.description = description;
this.reserved = reserved;
this.specialFeatures = specialFeatures;
}
/**
* Accessor method for feature layout version
* @return int lv value
*/
public int getLayoutVersion() {
return lv;
}
/**
* Accessor method for feature ancestor layout version
* @return int ancestor LV value
*/
public int getAncestorLayoutVersion() {
return ancestorLV;
}
/**
* Accessor method for feature minimum compatible layout version. If the
* feature does not define a minimum compatible layout version, then this
* method returns the feature's own layout version. This would indicate
* that the feature cannot provide compatibility with any prior layout
* version.
*
* @return int minimum compatible LV value
*/
public int getMinimumCompatibleLayoutVersion() {
return minCompatLV != null ? minCompatLV : lv;
}
/**
* Accessor method for feature description
* @return String feature description
*/
public String getDescription() {
return description;
}
public boolean isReservedForOldRelease() {
return reserved;
}
public LayoutFeature[] getSpecialFeatures() {
return specialFeatures;
}
}
static class LayoutFeatureComparator implements Comparator {
@Override
public int compare(LayoutFeature arg0, LayoutFeature arg1) {
return arg0.getInfo().getLayoutVersion()
- arg1.getInfo().getLayoutVersion();
}
}
public static void updateMap(Map> map,
LayoutFeature[] features) {
// Go through all the enum constants and build a map of
// LayoutVersion <-> Set of all supported features in that LayoutVersion
SortedSet existingFeatures = new TreeSet(
new LayoutFeatureComparator());
for (SortedSet s : map.values()) {
existingFeatures.addAll(s);
}
LayoutFeature prevF = existingFeatures.isEmpty() ? null :
existingFeatures.first();
for (LayoutFeature f : features) {
final FeatureInfo info = f.getInfo();
int minCompatLV = info.getMinimumCompatibleLayoutVersion();
if (prevF != null &&
minCompatLV > prevF.getInfo().getMinimumCompatibleLayoutVersion()) {
throw new AssertionError(String.format(
"Features must be listed in order of minimum compatible layout " +
"version. Check features %s and %s.", prevF, f));
}
prevF = f;
SortedSet ancestorSet = map.get(info.getAncestorLayoutVersion());
if (ancestorSet == null) {
// Empty set
ancestorSet = new TreeSet(new LayoutFeatureComparator());
map.put(info.getAncestorLayoutVersion(), ancestorSet);
}
SortedSet featureSet = new TreeSet(ancestorSet);
if (info.getSpecialFeatures() != null) {
for (LayoutFeature specialFeature : info.getSpecialFeatures()) {
featureSet.add(specialFeature);
}
}
featureSet.add(f);
map.put(info.getLayoutVersion(), featureSet);
}
}
/**
* Gets formatted string that describes {@link LayoutVersion} information.
*/
public String getString(Map> map,
LayoutFeature[] values) {
final StringBuilder buf = new StringBuilder();
buf.append("Feature List:\n");
for (LayoutFeature f : values) {
final FeatureInfo info = f.getInfo();
buf.append(f).append(" introduced in layout version ")
.append(info.getLayoutVersion()).append(" (")
.append(info.getDescription()).append(")\n");
}
buf.append("\n\nLayoutVersion and supported features:\n");
for (LayoutFeature f : values) {
final FeatureInfo info = f.getInfo();
buf.append(info.getLayoutVersion()).append(": ")
.append(map.get(info.getLayoutVersion())).append("\n");
}
return buf.toString();
}
/**
* Returns true if a given feature is supported in the given layout version
* @param map layout feature map
* @param f Feature
* @param lv LayoutVersion
* @return true if {@code f} is supported in layout version {@code lv}
*/
public static boolean supports(Map> map,
final LayoutFeature f, final int lv) {
final SortedSet set = map.get(lv);
return set != null && set.contains(f);
}
/**
* Get the current layout version
*/
public static int getCurrentLayoutVersion(LayoutFeature[] features) {
return getLastNonReservedFeature(features).getInfo().getLayoutVersion();
}
/**
* Gets the minimum compatible layout version.
*
* @param features all features to check
* @return minimum compatible layout version
*/
public static int getMinimumCompatibleLayoutVersion(
LayoutFeature[] features) {
return getLastNonReservedFeature(features).getInfo()
.getMinimumCompatibleLayoutVersion();
}
static LayoutFeature getLastNonReservedFeature(LayoutFeature[] features) {
for (int i = features.length -1; i >= 0; i--) {
final FeatureInfo info = features[i].getInfo();
if (!info.isReservedForOldRelease()) {
return features[i];
}
}
throw new AssertionError("All layout versions are reserved.");
}
}