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
111 final int lv;
112 final int ancestorLV;
113 final String description;
114 final boolean reserved;
115 final Feature[] specialFeatures;
116
117 /**
118 * Feature that is added at layout version {@code lv} - 1.
119 * @param lv new layout version with the addition of this feature
120 * @param description description of the feature
121 */
122 Feature(final int lv, final String description) {
123 this(lv, lv + 1, description, false);
124 }
125
126 /**
127 * Feature that is added at layout version {@code ancestoryLV}.
128 * @param lv new layout version with the addition of this feature
129 * @param ancestorLV layout version from which the new lv is derived from.
130 * @param description description of the feature
131 * @param reserved true when this is a layout version reserved for previous
132 * verions
133 * @param features set of features that are to be enabled for this version
134 */
135 Feature(final int lv, final int ancestorLV, final String description,
136 boolean reserved, Feature... features) {
137 this.lv = lv;
138 this.ancestorLV = ancestorLV;
139 this.description = description;
140 this.reserved = reserved;
141 specialFeatures = features;
142 }
143
144 /**
145 * Accessor method for feature layout version
146 * @return int lv value
147 */
148 public int getLayoutVersion() {
149 return lv;
150 }
151
152 /**
153 * Accessor method for feature ancestor layout version
154 * @return int ancestor LV value
155 */
156 public int getAncestorLayoutVersion() {
157 return ancestorLV;
158 }
159
160 /**
161 * Accessor method for feature description
162 * @return String feature description
163 */
164 public String getDescription() {
165 return description;
166 }
167
168 public boolean isReservedForOldRelease() {
169 return reserved;
170 }
171 }
172
173 // Build layout version and corresponding feature matrix
174 static final Map<Integer, EnumSet<Feature>>map =
175 new HashMap<Integer, EnumSet<Feature>>();
176
177 // Static initialization
178 static {
179 initMap();
180 }
181
182 /**
183 * Initialize the map of a layout version and EnumSet of {@link Feature}s
184 * supported.
185 */
186 private static void initMap() {
187 // Go through all the enum constants and build a map of
188 // LayoutVersion <-> EnumSet of all supported features in that LayoutVersion
189 for (Feature f : Feature.values()) {
190 EnumSet<Feature> ancestorSet = map.get(f.ancestorLV);
191 if (ancestorSet == null) {
192 ancestorSet = EnumSet.noneOf(Feature.class); // Empty enum set
193 map.put(f.ancestorLV, ancestorSet);
194 }
195 EnumSet<Feature> featureSet = EnumSet.copyOf(ancestorSet);
196 if (f.specialFeatures != null) {
197 for (Feature specialFeature : f.specialFeatures) {
198 featureSet.add(specialFeature);
199 }
200 }
201 featureSet.add(f);
202 map.put(f.lv, featureSet);
203 }
204 }
205
206 /**
207 * Gets formatted string that describes {@link LayoutVersion} information.
208 */
209 public static String getString() {
210 final StringBuilder buf = new StringBuilder();
211 buf.append("Feature List:\n");
212 for (Feature f : Feature.values()) {
213 buf.append(f).append(" introduced in layout version ")
214 .append(f.lv).append(" (").
215 append(f.description).append(")\n");
216 }
217
218 buf.append("\n\nLayoutVersion and supported features:\n");
219 for (Feature f : Feature.values()) {
220 buf.append(f.lv).append(": ").append(map.get(f.lv))
221 .append("\n");
222 }
223 return buf.toString();
224 }
225
226 /**
227 * Returns true if a given feature is supported in the given layout version
228 * @param f Feature
229 * @param lv LayoutVersion
230 * @return true if {@code f} is supported in layout version {@code lv}
231 */
232 public static boolean supports(final Feature f, final int lv) {
233 final EnumSet<Feature> set = map.get(lv);
234 return set != null && set.contains(f);
235 }
236
237 /**
238 * Get the current layout version
239 */
240 public static int getCurrentLayoutVersion() {
241 Feature[] values = Feature.values();
242 for (int i = values.length -1; i >= 0; i--) {
243 if (!values[i].isReservedForOldRelease()) {
244 return values[i].lv;
245 }
246 }
247 throw new AssertionError("All layout versions are reserved.");
248 }
249 }