001 /** 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018 package org.apache.hadoop.hdfs.protocol; 019 020 import java.util.EnumSet; 021 import java.util.HashMap; 022 import java.util.Map; 023 024 import org.apache.hadoop.classification.InterfaceAudience; 025 026 /** 027 * This class tracks changes in the layout version of HDFS. 028 * 029 * Layout version is changed for following reasons: 030 * <ol> 031 * <li>The layout of how namenode or datanode stores information 032 * on disk changes.</li> 033 * <li>A new operation code is added to the editlog.</li> 034 * <li>Modification such as format of a record, content of a record 035 * in editlog or fsimage.</li> 036 * </ol> 037 * <br> 038 * <b>How to update layout version:<br></b> 039 * When a change requires new layout version, please add an entry into 040 * {@link Feature} with a short enum name, new layout version and description 041 * of the change. Please see {@link Feature} for further details. 042 * <br> 043 */ 044 @InterfaceAudience.Private 045 public class LayoutVersion { 046 047 /** 048 * Version in which HDFS-2991 was fixed. This bug caused OP_ADD to 049 * sometimes be skipped for append() calls. If we see such a case when 050 * loading the edits, but the version is known to have that bug, we 051 * workaround the issue. Otherwise we should consider it a corruption 052 * and bail. 053 */ 054 public static final int BUGFIX_HDFS_2991_VERSION = -40; 055 056 /** 057 * Enums for features that change the layout version. 058 * <br><br> 059 * To add a new layout version: 060 * <ul> 061 * <li>Define a new enum constant with a short enum name, the new layout version 062 * and description of the added feature.</li> 063 * <li>When adding a layout version with an ancestor that is not same as 064 * its immediate predecessor, use the constructor where a spacific ancestor 065 * can be passed. 066 * </li> 067 * </ul> 068 */ 069 public static enum Feature { 070 NAMESPACE_QUOTA(-16, "Support for namespace quotas"), 071 FILE_ACCESS_TIME(-17, "Support for access time on files"), 072 DISKSPACE_QUOTA(-18, "Support for disk space quotas"), 073 STICKY_BIT(-19, "Support for sticky bits"), 074 APPEND_RBW_DIR(-20, "Datanode has \"rbw\" subdirectory for append"), 075 ATOMIC_RENAME(-21, "Support for atomic rename"), 076 CONCAT(-22, "Support for concat operation"), 077 SYMLINKS(-23, "Support for symbolic links"), 078 DELEGATION_TOKEN(-24, "Support for delegation tokens for security"), 079 FSIMAGE_COMPRESSION(-25, "Support for fsimage compression"), 080 FSIMAGE_CHECKSUM(-26, "Support checksum for fsimage"), 081 REMOVE_REL13_DISK_LAYOUT_SUPPORT(-27, "Remove support for 0.13 disk layout"), 082 EDITS_CHESKUM(-28, "Support checksum for editlog"), 083 UNUSED(-29, "Skipped version"), 084 FSIMAGE_NAME_OPTIMIZATION(-30, "Store only last part of path in fsimage"), 085 RESERVED_REL20_203(-31, -19, "Reserved for release 0.20.203", true, 086 DELEGATION_TOKEN), 087 RESERVED_REL20_204(-32, -31, "Reserved for release 0.20.204", true), 088 RESERVED_REL22(-33, -27, "Reserved for release 0.22", true), 089 RESERVED_REL23(-34, -30, "Reserved for release 0.23", true), 090 FEDERATION(-35, "Support for namenode federation"), 091 LEASE_REASSIGNMENT(-36, "Support for persisting lease holder reassignment"), 092 STORED_TXIDS(-37, "Transaction IDs are stored in edits log and image files"), 093 TXID_BASED_LAYOUT(-38, "File names in NN Storage are based on transaction IDs"), 094 EDITLOG_OP_OPTIMIZATION(-39, 095 "Use LongWritable and ShortWritable directly instead of ArrayWritable of UTF8"), 096 OPTIMIZE_PERSIST_BLOCKS(-40, 097 "Serialize block lists with delta-encoded variable length ints, " + 098 "add OP_UPDATE_BLOCKS"), 099 RESERVED_REL1_2_0(-41, -32, "Reserved for release 1.2.0", true, CONCAT), 100 ADD_INODE_ID(-42, -40, "Assign a unique inode id for each inode", false), 101 SNAPSHOT(-43, "Support for snapshot feature"), 102 RESERVED_REL1_3_0(-44, -41, 103 "Reserved for release 1.3.0", true, ADD_INODE_ID, SNAPSHOT), 104 OPTIMIZE_SNAPSHOT_INODES(-45, -43, 105 "Reduce snapshot inode memory footprint", false), 106 SEQUENTIAL_BLOCK_ID(-46, "Allocate block IDs sequentially and store " + 107 "block IDs in the edits log and image files"), 108 EDITLOG_SUPPORT_RETRYCACHE(-47, "Record ClientId and CallId in editlog to " 109 + "enable rebuilding retry cache in case of HA failover"), 110 EDITLOG_ADD_BLOCK(-48, "Add new editlog that only records allocation of " 111 + "the new block instead of the entire block list"), 112 ADD_DATANODE_AND_STORAGE_UUIDS(-49, "Replace StorageID with DatanodeUuid." 113 + " Use distinct StorageUuid per storage directory."), 114 ADD_LAYOUT_FLAGS(-50, "Add support for layout flags."), 115 CACHING(-51, "Support for cache pools and path-based caching"); 116 117 final int lv; 118 final int ancestorLV; 119 final String description; 120 final boolean reserved; 121 final Feature[] specialFeatures; 122 123 /** 124 * Feature that is added at layout version {@code lv} - 1. 125 * @param lv new layout version with the addition of this feature 126 * @param description description of the feature 127 */ 128 Feature(final int lv, final String description) { 129 this(lv, lv + 1, description, false); 130 } 131 132 /** 133 * Feature that is added at layout version {@code ancestoryLV}. 134 * @param lv new layout version with the addition of this feature 135 * @param ancestorLV layout version from which the new lv is derived from. 136 * @param description description of the feature 137 * @param reserved true when this is a layout version reserved for previous 138 * verions 139 * @param features set of features that are to be enabled for this version 140 */ 141 Feature(final int lv, final int ancestorLV, final String description, 142 boolean reserved, Feature... features) { 143 this.lv = lv; 144 this.ancestorLV = ancestorLV; 145 this.description = description; 146 this.reserved = reserved; 147 specialFeatures = features; 148 } 149 150 /** 151 * Accessor method for feature layout version 152 * @return int lv value 153 */ 154 public int getLayoutVersion() { 155 return lv; 156 } 157 158 /** 159 * Accessor method for feature ancestor layout version 160 * @return int ancestor LV value 161 */ 162 public int getAncestorLayoutVersion() { 163 return ancestorLV; 164 } 165 166 /** 167 * Accessor method for feature description 168 * @return String feature description 169 */ 170 public String getDescription() { 171 return description; 172 } 173 174 public boolean isReservedForOldRelease() { 175 return reserved; 176 } 177 } 178 179 // Build layout version and corresponding feature matrix 180 static final Map<Integer, EnumSet<Feature>>map = 181 new HashMap<Integer, EnumSet<Feature>>(); 182 183 // Static initialization 184 static { 185 initMap(); 186 } 187 188 /** 189 * Initialize the map of a layout version and EnumSet of {@link Feature}s 190 * supported. 191 */ 192 private static void initMap() { 193 // Go through all the enum constants and build a map of 194 // LayoutVersion <-> EnumSet of all supported features in that LayoutVersion 195 for (Feature f : Feature.values()) { 196 EnumSet<Feature> ancestorSet = map.get(f.ancestorLV); 197 if (ancestorSet == null) { 198 ancestorSet = EnumSet.noneOf(Feature.class); // Empty enum set 199 map.put(f.ancestorLV, ancestorSet); 200 } 201 EnumSet<Feature> featureSet = EnumSet.copyOf(ancestorSet); 202 if (f.specialFeatures != null) { 203 for (Feature specialFeature : f.specialFeatures) { 204 featureSet.add(specialFeature); 205 } 206 } 207 featureSet.add(f); 208 map.put(f.lv, featureSet); 209 } 210 } 211 212 /** 213 * Gets formatted string that describes {@link LayoutVersion} information. 214 */ 215 public static String getString() { 216 final StringBuilder buf = new StringBuilder(); 217 buf.append("Feature List:\n"); 218 for (Feature f : Feature.values()) { 219 buf.append(f).append(" introduced in layout version ") 220 .append(f.lv).append(" ("). 221 append(f.description).append(")\n"); 222 } 223 224 buf.append("\n\nLayoutVersion and supported features:\n"); 225 for (Feature f : Feature.values()) { 226 buf.append(f.lv).append(": ").append(map.get(f.lv)) 227 .append("\n"); 228 } 229 return buf.toString(); 230 } 231 232 /** 233 * Returns true if a given feature is supported in the given layout version 234 * @param f Feature 235 * @param lv LayoutVersion 236 * @return true if {@code f} is supported in layout version {@code lv} 237 */ 238 public static boolean supports(final Feature f, final int lv) { 239 final EnumSet<Feature> set = map.get(lv); 240 return set != null && set.contains(f); 241 } 242 243 /** 244 * Get the current layout version 245 */ 246 public static int getCurrentLayoutVersion() { 247 Feature[] values = Feature.values(); 248 for (int i = values.length -1; i >= 0; i--) { 249 if (!values[i].isReservedForOldRelease()) { 250 return values[i].lv; 251 } 252 } 253 throw new AssertionError("All layout versions are reserved."); 254 } 255 } 256