/**
* 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 org.apache.hadoop.classification.InterfaceAudience;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.Map;
/**
* This class tracks changes in the layout version of HDFS.
* <p/>
* Layout version is changed for following reasons:
* <ol>
* <li>The layout of how namenode or datanode stores information
* on disk changes.</li>
* <li>A new operation code is added to the editlog.</li>
* <li>Modification such as format of a record, content of a record
* in editlog or fsimage.</li>
* </ol>
* <br>
* <b>How to update layout version:<br></b>
* 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.
* <br>
*/
@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;
/**
* Enums for features that change the layout version.
* <br><br>
* To add a new layout version:
* <ul>
* <li>Define a new enum constant with a short enum name, the new layout
* version
* and description of the added feature.</li>
* <li>When adding a layout version with an ancestor that is not same as
* its immediate predecessor, use the constructor where a spacific ancestor
* can be passed.
* </li>
* </ul>
*/
public static enum Feature {
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_CHESKUM(-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"),
RESERVED_REL20_204(-32, "Reserved for release 0.20.204"),
RESERVED_REL22(-33, -27, "Reserved for release 0.22"),
RESERVED_REL23(-34, -30, "Reserved for release 0.23"),
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");
final int lv;
final int ancestorLV;
final String description;
/**
* Feature that is added at {@code currentLV}.
*
* @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);
}
/**
* Feature that is added at {@code currentLV}.
*
* @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
*/
Feature(final int lv, final int ancestorLV, final String description) {
this.lv = lv;
this.ancestorLV = ancestorLV;
this.description = description;
}
/**
* 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 description
*
* @return String feature description
*/
public String getDescription() {
return description;
}
}
// Build layout version and corresponding feature matrix
static final Map<Integer, EnumSet<Feature>> map =
new HashMap<Integer, EnumSet<Feature>>();
// Static initialization
static {
initMap();
}
/**
* Initialize the map of a layout version and EnumSet of {@link Feature}s
* supported.
*/
private static void initMap() {
// Go through all the enum constants and build a map of
// LayoutVersion <-> EnumSet of all supported features in that LayoutVersion
for (Feature f : Feature.values()) {
EnumSet<Feature> ancestorSet = map.get(f.ancestorLV);
if (ancestorSet == null) {
ancestorSet = EnumSet.noneOf(Feature.class); // Empty enum set
map.put(f.ancestorLV, ancestorSet);
}
EnumSet<Feature> featureSet = EnumSet.copyOf(ancestorSet);
featureSet.add(f);
map.put(f.lv, featureSet);
}
// Special initialization for 0.20.203 and 0.20.204
// to add Feature#DELEGATION_TOKEN
specialInit(Feature.RESERVED_REL20_203.lv, Feature.DELEGATION_TOKEN);
specialInit(Feature.RESERVED_REL20_204.lv, Feature.DELEGATION_TOKEN);
}
private static void specialInit(int lv, Feature f) {
EnumSet<Feature> set = map.get(lv);
set.add(f);
}
/**
* Gets formatted string that describes {@link LayoutVersion} information.
*/
public static String getString() {
final StringBuilder buf = new StringBuilder();
buf.append("Feature List:\n");
for (Feature f : Feature.values()) {
buf.append(f).append(" introduced in layout version ").append(f.lv)
.append(" (").
append(f.description).append(")\n");
}
buf.append("\n\nLayoutVersion and supported features:\n");
for (Feature f : Feature.values()) {
buf.append(f.lv).append(": ").append(map.get(f.lv)).append("\n");
}
return buf.toString();
}
/**
* Returns true if a given feature is supported in the given layout version
*
* @param f
* Feature
* @param lv
* LayoutVersion
* @return true if {@code f} is supported in layout version {@code lv}
*/
public static boolean supports(final Feature f, final int lv) {
final EnumSet<Feature> set = map.get(lv);
return set != null && set.contains(f);
}
/**
* Get the current layout version
*/
public static int getCurrentLayoutVersion() {
Feature[] values = Feature.values();
return values[values.length - 1].lv;
}
}