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