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.io.PrintStream;
021    import java.text.SimpleDateFormat;
022    import java.util.Comparator;
023    import java.util.Date;
024    
025    import org.apache.hadoop.fs.Path;
026    import org.apache.hadoop.fs.permission.FsPermission;
027    import org.apache.hadoop.hdfs.DFSUtil;
028    
029    /**
030     * Metadata about a snapshottable directory
031     */
032    public class SnapshottableDirectoryStatus {
033      /** Compare the statuses by full paths. */
034      public static final Comparator<SnapshottableDirectoryStatus> COMPARATOR
035          = new Comparator<SnapshottableDirectoryStatus>() {
036        @Override
037        public int compare(SnapshottableDirectoryStatus left,
038                           SnapshottableDirectoryStatus right) {
039          int d = DFSUtil.compareBytes(left.parentFullPath, right.parentFullPath);
040          return d != 0? d
041              : DFSUtil.compareBytes(left.dirStatus.getLocalNameInBytes(),
042                  right.dirStatus.getLocalNameInBytes());
043        }
044      };
045    
046      /** Basic information of the snapshottable directory */
047      private HdfsFileStatus dirStatus;
048      
049      /** Number of snapshots that have been taken*/
050      private int snapshotNumber;
051      
052      /** Number of snapshots allowed. */
053      private int snapshotQuota;
054      
055      /** Full path of the parent. */
056      private byte[] parentFullPath;
057      
058      public SnapshottableDirectoryStatus(long modification_time, long access_time,
059          FsPermission permission, String owner, String group, byte[] localName,
060          long inodeId, int childrenNum,
061          int snapshotNumber, int snapshotQuota, byte[] parentFullPath) {
062        this.dirStatus = new HdfsFileStatus(0, true, 0, 0, modification_time,
063            access_time, permission, owner, group, null, localName, inodeId,
064            childrenNum);
065        this.snapshotNumber = snapshotNumber;
066        this.snapshotQuota = snapshotQuota;
067        this.parentFullPath = parentFullPath;
068      }
069    
070      /**
071       * @return Number of snapshots that have been taken for the directory
072       */
073      public int getSnapshotNumber() {
074        return snapshotNumber;
075      }
076    
077      /**
078       * @return Number of snapshots allowed for the directory
079       */
080      public int getSnapshotQuota() {
081        return snapshotQuota;
082      }
083      
084      /**
085       * @return Full path of the parent
086       */
087      public byte[] getParentFullPath() {
088        return parentFullPath;
089      }
090    
091      /**
092       * @return The basic information of the directory
093       */
094      public HdfsFileStatus getDirStatus() {
095        return dirStatus;
096      }
097      
098      /**
099       * @return Full path of the file
100       */
101      public Path getFullPath() {
102        String parentFullPathStr = 
103            (parentFullPath == null || parentFullPath.length == 0) ? 
104                null : DFSUtil.bytes2String(parentFullPath);
105        if (parentFullPathStr == null
106            && dirStatus.getLocalNameInBytes().length == 0) {
107          // root
108          return new Path("/");
109        } else {
110          return parentFullPathStr == null ? new Path(dirStatus.getLocalName())
111              : new Path(parentFullPathStr, dirStatus.getLocalName());
112        }
113      }
114      
115      /**
116       * Print a list of {@link SnapshottableDirectoryStatus} out to a given stream.
117       * @param stats The list of {@link SnapshottableDirectoryStatus}
118       * @param out The given stream for printing.
119       */
120      public static void print(SnapshottableDirectoryStatus[] stats, 
121          PrintStream out) {
122        if (stats == null || stats.length == 0) {
123          out.println();
124          return;
125        }
126        int maxRepl = 0, maxLen = 0, maxOwner = 0, maxGroup = 0;
127        int maxSnapshotNum = 0, maxSnapshotQuota = 0;
128        for (SnapshottableDirectoryStatus status : stats) {
129          maxRepl = maxLength(maxRepl, status.dirStatus.getReplication());
130          maxLen = maxLength(maxLen, status.dirStatus.getLen());
131          maxOwner = maxLength(maxOwner, status.dirStatus.getOwner());
132          maxGroup = maxLength(maxGroup, status.dirStatus.getGroup());
133          maxSnapshotNum = maxLength(maxSnapshotNum, status.snapshotNumber);
134          maxSnapshotQuota = maxLength(maxSnapshotQuota, status.snapshotQuota);
135        }
136        
137        StringBuilder fmt = new StringBuilder();
138        fmt.append("%s%s "); // permission string
139        fmt.append("%"  + maxRepl  + "s ");
140        fmt.append((maxOwner > 0) ? "%-" + maxOwner + "s " : "%s");
141        fmt.append((maxGroup > 0) ? "%-" + maxGroup + "s " : "%s");
142        fmt.append("%"  + maxLen   + "s ");
143        fmt.append("%s "); // mod time
144        fmt.append("%"  + maxSnapshotNum  + "s ");
145        fmt.append("%"  + maxSnapshotQuota  + "s ");
146        fmt.append("%s"); // path
147        
148        String lineFormat = fmt.toString();
149        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm");
150             
151        for (SnapshottableDirectoryStatus status : stats) {
152          String line = String.format(lineFormat, "d", 
153              status.dirStatus.getPermission(),
154              status.dirStatus.getReplication(),
155              status.dirStatus.getOwner(),
156              status.dirStatus.getGroup(),
157              String.valueOf(status.dirStatus.getLen()),
158              dateFormat.format(new Date(status.dirStatus.getModificationTime())),
159              status.snapshotNumber, status.snapshotQuota, 
160              status.getFullPath().toString()
161          );
162          out.println(line);
163        }
164      }
165    
166      private static int maxLength(int n, Object value) {
167        return Math.max(n, String.valueOf(value).length());
168      }
169    }