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.io.PrintStream;
021import java.text.SimpleDateFormat;
022import java.util.Comparator;
023import java.util.Date;
024
025import org.apache.hadoop.fs.Path;
026import org.apache.hadoop.fs.permission.FsPermission;
027import org.apache.hadoop.hdfs.DFSUtil;
028
029/**
030 * Metadata about a snapshottable directory
031 */
032public 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 final HdfsFileStatus dirStatus;
048  
049  /** Number of snapshots that have been taken*/
050  private final int snapshotNumber;
051  
052  /** Number of snapshots allowed. */
053  private final int snapshotQuota;
054  
055  /** Full path of the parent. */
056  private final 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
170  public static class Bean {
171    private final String path;
172    private final int snapshotNumber;
173    private final int snapshotQuota;
174    private final long modificationTime;
175    private final short permission;
176    private final String owner;
177    private final String group;
178
179    public Bean(String path, int snapshotNumber, int snapshotQuota,
180        long modificationTime, short permission, String owner, String group) {
181      this.path = path;
182      this.snapshotNumber = snapshotNumber;
183      this.snapshotQuota = snapshotQuota;
184      this.modificationTime = modificationTime;
185      this.permission = permission;
186      this.owner = owner;
187      this.group = group;
188    }
189
190    public String getPath() {
191      return path;
192    }
193
194    public int getSnapshotNumber() {
195      return snapshotNumber;
196    }
197
198    public int getSnapshotQuota() {
199      return snapshotQuota;
200    }
201
202    public long getModificationTime() {
203      return modificationTime;
204    }
205
206    public short getPermission() {
207      return permission;
208    }
209
210    public String getOwner() {
211      return owner;
212    }
213
214    public String getGroup() {
215      return group;
216    }
217  }
218}