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 */
018package org.apache.hadoop.hdfs.protocol;
019
020import java.util.Comparator;
021import java.util.Map;
022import java.util.SortedSet;
023import java.util.TreeSet;
024
025import org.apache.hadoop.classification.InterfaceAudience;
026
027/**
028 * This class tracks changes in the layout version of HDFS.
029 * 
030 * Layout version is changed for following reasons:
031 * <ol>
032 * <li>The layout of how namenode or datanode stores information 
033 * on disk changes.</li>
034 * <li>A new operation code is added to the editlog.</li>
035 * <li>Modification such as format of a record, content of a record 
036 * in editlog or fsimage.</li>
037 * </ol>
038 * <br>
039 * <b>How to update layout version:<br></b>
040 * When a change requires new layout version, please add an entry into
041 * {@link Feature} with a short enum name, new layout version and description
042 * of the change. Please see {@link Feature} for further details.
043 * <br>
044 */
045@InterfaceAudience.Private
046public class LayoutVersion {
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   * The interface to be implemented by NameNode and DataNode layout features 
058   */
059  public interface LayoutFeature {
060    public FeatureInfo getInfo();
061  }
062
063  /**
064   * Enums for features that change the layout version before rolling
065   * upgrade is supported.
066   * <br><br>
067   * To add a new layout version:
068   * <ul>
069   * <li>Define a new enum constant with a short enum name, the new layout version 
070   * and description of the added feature.</li>
071   * <li>When adding a layout version with an ancestor that is not same as
072   * its immediate predecessor, use the constructor where a specific ancestor
073   * can be passed.
074   * </li>
075   * </ul>
076   */
077  public static enum Feature implements LayoutFeature {
078    NAMESPACE_QUOTA(-16, "Support for namespace quotas"),
079    FILE_ACCESS_TIME(-17, "Support for access time on files"),
080    DISKSPACE_QUOTA(-18, "Support for disk space quotas"),
081    STICKY_BIT(-19, "Support for sticky bits"),
082    APPEND_RBW_DIR(-20, "Datanode has \"rbw\" subdirectory for append"),
083    ATOMIC_RENAME(-21, "Support for atomic rename"),
084    CONCAT(-22, "Support for concat operation"),
085    SYMLINKS(-23, "Support for symbolic links"),
086    DELEGATION_TOKEN(-24, "Support for delegation tokens for security"),
087    FSIMAGE_COMPRESSION(-25, "Support for fsimage compression"),
088    FSIMAGE_CHECKSUM(-26, "Support checksum for fsimage"),
089    REMOVE_REL13_DISK_LAYOUT_SUPPORT(-27, "Remove support for 0.13 disk layout"),
090    EDITS_CHESKUM(-28, "Support checksum for editlog"),
091    UNUSED(-29, "Skipped version"),
092    FSIMAGE_NAME_OPTIMIZATION(-30, "Store only last part of path in fsimage"),
093    RESERVED_REL20_203(-31, -19, "Reserved for release 0.20.203", true,
094        DELEGATION_TOKEN),
095    RESERVED_REL20_204(-32, -31, "Reserved for release 0.20.204", true),
096    RESERVED_REL22(-33, -27, "Reserved for release 0.22", true),
097    RESERVED_REL23(-34, -30, "Reserved for release 0.23", true),
098    FEDERATION(-35, "Support for namenode federation"),
099    LEASE_REASSIGNMENT(-36, "Support for persisting lease holder reassignment"),
100    STORED_TXIDS(-37, "Transaction IDs are stored in edits log and image files"),
101    TXID_BASED_LAYOUT(-38, "File names in NN Storage are based on transaction IDs"), 
102    EDITLOG_OP_OPTIMIZATION(-39,
103        "Use LongWritable and ShortWritable directly instead of ArrayWritable of UTF8"),
104    OPTIMIZE_PERSIST_BLOCKS(-40,
105        "Serialize block lists with delta-encoded variable length ints, " +
106        "add OP_UPDATE_BLOCKS"),
107    RESERVED_REL1_2_0(-41, -32, "Reserved for release 1.2.0", true, CONCAT),
108    ADD_INODE_ID(-42, -40, "Assign a unique inode id for each inode", false),
109    SNAPSHOT(-43, "Support for snapshot feature"),
110    RESERVED_REL1_3_0(-44, -41,
111        "Reserved for release 1.3.0", true, ADD_INODE_ID, SNAPSHOT),
112    OPTIMIZE_SNAPSHOT_INODES(-45, -43,
113        "Reduce snapshot inode memory footprint", false),
114    SEQUENTIAL_BLOCK_ID(-46, "Allocate block IDs sequentially and store " +
115        "block IDs in the edits log and image files"),
116    EDITLOG_SUPPORT_RETRYCACHE(-47, "Record ClientId and CallId in editlog to " 
117        + "enable rebuilding retry cache in case of HA failover"),
118    EDITLOG_ADD_BLOCK(-48, "Add new editlog that only records allocation of "
119        + "the new block instead of the entire block list"),
120    ADD_DATANODE_AND_STORAGE_UUIDS(-49, "Replace StorageID with DatanodeUuid."
121        + " Use distinct StorageUuid per storage directory."),
122    ADD_LAYOUT_FLAGS(-50, "Add support for layout flags."),
123    CACHING(-51, "Support for cache pools and path-based caching"),
124    // Hadoop 2.4.0
125    PROTOBUF_FORMAT(-52, "Use protobuf to serialize FSImage"),
126    EXTENDED_ACL(-53, "Extended ACL"),
127    RESERVED_REL2_4_0(-54, -51, "Reserved for release 2.4.0", true,
128        PROTOBUF_FORMAT, EXTENDED_ACL);
129
130    private final FeatureInfo info;
131
132    /**
133     * Feature that is added at layout version {@code lv} - 1. 
134     * @param lv new layout version with the addition of this feature
135     * @param description description of the feature
136     */
137    Feature(final int lv, final String description) {
138      this(lv, lv + 1, description, false);
139    }
140
141    /**
142     * Feature that is added at layout version {@code ancestoryLV}.
143     * @param lv new layout version with the addition of this feature
144     * @param ancestorLV layout version from which the new lv is derived from.
145     * @param description description of the feature
146     * @param reserved true when this is a layout version reserved for previous
147     *        version
148     * @param features set of features that are to be enabled for this version
149     */
150    Feature(final int lv, final int ancestorLV, final String description,
151        boolean reserved, Feature... features) {
152      info = new FeatureInfo(lv, ancestorLV, description, reserved, features);
153    }
154    
155    @Override
156    public FeatureInfo getInfo() {
157      return info;
158    }
159  }
160  
161  /** Feature information. */
162  public static class FeatureInfo {
163    private final int lv;
164    private final int ancestorLV;
165    private final String description;
166    private final boolean reserved;
167    private final LayoutFeature[] specialFeatures;
168
169    public FeatureInfo(final int lv, final int ancestorLV, final String description,
170        boolean reserved, LayoutFeature... specialFeatures) {
171      this.lv = lv;
172      this.ancestorLV = ancestorLV;
173      this.description = description;
174      this.reserved = reserved;
175      this.specialFeatures = specialFeatures;
176    }
177    
178    /** 
179     * Accessor method for feature layout version 
180     * @return int lv value
181     */
182    public int getLayoutVersion() {
183      return lv;
184    }
185
186    /** 
187     * Accessor method for feature ancestor layout version 
188     * @return int ancestor LV value
189     */
190    public int getAncestorLayoutVersion() {
191      return ancestorLV;
192    }
193
194    /** 
195     * Accessor method for feature description 
196     * @return String feature description 
197     */
198    public String getDescription() {
199      return description;
200    }
201    
202    public boolean isReservedForOldRelease() {
203      return reserved;
204    }
205    
206    public LayoutFeature[] getSpecialFeatures() {
207      return specialFeatures;
208    }
209  }
210
211  static class LayoutFeatureComparator implements Comparator<LayoutFeature> {
212    @Override
213    public int compare(LayoutFeature arg0, LayoutFeature arg1) {
214      return arg0.getInfo().getLayoutVersion()
215          - arg1.getInfo().getLayoutVersion();
216    }
217  }
218 
219  public static void updateMap(Map<Integer, SortedSet<LayoutFeature>> map,
220      LayoutFeature[] features) {
221    // Go through all the enum constants and build a map of
222    // LayoutVersion <-> Set of all supported features in that LayoutVersion
223    for (LayoutFeature f : features) {
224      final FeatureInfo info = f.getInfo();
225      SortedSet<LayoutFeature> ancestorSet = map.get(info.getAncestorLayoutVersion());
226      if (ancestorSet == null) {
227        // Empty set
228        ancestorSet = new TreeSet<LayoutFeature>(new LayoutFeatureComparator());
229        map.put(info.getAncestorLayoutVersion(), ancestorSet);
230      }
231      SortedSet<LayoutFeature> featureSet = new TreeSet<LayoutFeature>(ancestorSet);
232      if (info.getSpecialFeatures() != null) {
233        for (LayoutFeature specialFeature : info.getSpecialFeatures()) {
234          featureSet.add(specialFeature);
235        }
236      }
237      featureSet.add(f);
238      map.put(info.getLayoutVersion(), featureSet);
239    }
240  }
241  
242  /**
243   * Gets formatted string that describes {@link LayoutVersion} information.
244   */
245  public String getString(Map<Integer, SortedSet<LayoutFeature>> map,
246      LayoutFeature[] values) {
247    final StringBuilder buf = new StringBuilder();
248    buf.append("Feature List:\n");
249    for (LayoutFeature f : values) {
250      final FeatureInfo info = f.getInfo();
251      buf.append(f).append(" introduced in layout version ")
252          .append(info.getLayoutVersion()).append(" (")
253          .append(info.getDescription()).append(")\n");
254    }
255
256    buf.append("\n\nLayoutVersion and supported features:\n");
257    for (LayoutFeature f : values) {
258      final FeatureInfo info = f.getInfo();
259      buf.append(info.getLayoutVersion()).append(": ")
260          .append(map.get(info.getLayoutVersion())).append("\n");
261    }
262    return buf.toString();
263  }
264  
265  /**
266   * Returns true if a given feature is supported in the given layout version
267   * @param map layout feature map
268   * @param f Feature
269   * @param lv LayoutVersion
270   * @return true if {@code f} is supported in layout version {@code lv}
271   */
272  public static boolean supports(Map<Integer, SortedSet<LayoutFeature>> map,
273      final LayoutFeature f, final int lv) {
274    final SortedSet<LayoutFeature> set =  map.get(lv);
275    return set != null && set.contains(f);
276  }
277  
278  /**
279   * Get the current layout version
280   */
281  public static int getCurrentLayoutVersion(LayoutFeature[] features) {
282    return getLastNonReservedFeature(features).getInfo().getLayoutVersion();
283  }
284
285  static LayoutFeature getLastNonReservedFeature(LayoutFeature[] features) {
286    for (int i = features.length -1; i >= 0; i--) {
287      final FeatureInfo info = features[i].getInfo();
288      if (!info.isReservedForOldRelease()) {
289        return features[i];
290      }
291    }
292    throw new AssertionError("All layout versions are reserved.");
293  }
294}
295