| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package org.apache.hadoop.hdfs.server.namenode.visitor; |
| |
| import org.apache.hadoop.thirdparty.com.google.common.base.Preconditions; |
| import org.apache.hadoop.hdfs.server.blockmanagement.BlockInfo; |
| import org.apache.hadoop.hdfs.server.namenode.DirectoryWithQuotaFeature; |
| import org.apache.hadoop.hdfs.server.namenode.FSNamesystem; |
| import org.apache.hadoop.hdfs.server.namenode.INode; |
| import org.apache.hadoop.hdfs.server.namenode.INodeDirectory; |
| import org.apache.hadoop.hdfs.server.namenode.INodeFile; |
| import org.apache.hadoop.hdfs.server.namenode.INodeReference; |
| import org.apache.hadoop.hdfs.server.namenode.INodeSymlink; |
| import org.apache.hadoop.hdfs.server.namenode.snapshot.DirectorySnapshottableFeature; |
| import org.apache.hadoop.hdfs.server.namenode.snapshot.DirectoryWithSnapshotFeature; |
| import org.apache.hadoop.hdfs.server.namenode.snapshot.DirectoryWithSnapshotFeature.DirectoryDiff; |
| import org.apache.hadoop.hdfs.server.namenode.snapshot.FileWithSnapshotFeature; |
| import org.apache.hadoop.hdfs.server.namenode.snapshot.Snapshot; |
| |
| import java.io.PrintWriter; |
| import java.io.StringWriter; |
| |
| /** |
| * To print the namespace tree recursively for testing. |
| * |
| * \- foo (INodeDirectory@33dd2717) |
| * \- sub1 (INodeDirectory@442172) |
| * +- file1 (INodeFile@78392d4) |
| * +- file2 (INodeFile@78392d5) |
| * +- sub11 (INodeDirectory@8400cff) |
| * \- file3 (INodeFile@78392d6) |
| * \- z_file4 (INodeFile@45848712) |
| */ |
| public final class NamespacePrintVisitor implements NamespaceVisitor { |
| static final String NON_LAST_ITEM = "+-"; |
| static final String LAST_ITEM = "\\-"; |
| |
| /** @return string of the tree in the given {@link FSNamesystem}. */ |
| public static String print2Sting(FSNamesystem ns) { |
| return print2Sting(ns.getFSDirectory().getRoot()); |
| } |
| |
| /** @return string of the tree from the given root. */ |
| public static String print2Sting(INode root) { |
| final StringWriter out = new StringWriter(); |
| new NamespacePrintVisitor(new PrintWriter(out)).print(root); |
| return out.getBuffer().toString(); |
| } |
| |
| private final PrintWriter out; |
| private final StringBuffer prefix = new StringBuffer(); |
| |
| private NamespacePrintVisitor(PrintWriter out) { |
| this.out = out; |
| } |
| |
| private void print(INode root) { |
| root.accept(this, Snapshot.CURRENT_STATE_ID); |
| } |
| |
| private void printINode(INode iNode, int snapshot) { |
| out.print(prefix); |
| out.print(" "); |
| final String name = iNode.getLocalName(); |
| out.print(name != null && name.isEmpty()? "/": name); |
| out.print(" ("); |
| out.print(iNode.getObjectString()); |
| out.print("), "); |
| out.print(iNode.getParentString()); |
| out.print(", " + iNode.getPermissionStatus(snapshot)); |
| } |
| |
| @Override |
| public void visitFile(INodeFile file, int snapshot) { |
| printINode(file, snapshot); |
| |
| out.print(", fileSize=" + file.computeFileSize(snapshot)); |
| // print only the first block, if it exists |
| out.print(", blocks="); |
| final BlockInfo[] blocks = file.getBlocks(); |
| out.print(blocks.length == 0 ? null: blocks[0]); |
| out.println(); |
| |
| final FileWithSnapshotFeature snapshotFeature |
| = file.getFileWithSnapshotFeature(); |
| if (snapshotFeature != null) { |
| if (prefix.length() >= 2) { |
| prefix.setLength(prefix.length() - 2); |
| prefix.append(" "); |
| } |
| out.print(prefix); |
| out.print(snapshotFeature); |
| } |
| out.println(); |
| } |
| |
| @Override |
| public void visitSymlink(INodeSymlink symlink, int snapshot) { |
| printINode(symlink, snapshot); |
| out.print(" ~> "); |
| out.println(symlink.getSymlinkString()); |
| } |
| |
| @Override |
| public void visitReference(INodeReference ref, int snapshot) { |
| printINode(ref, snapshot); |
| |
| if (ref instanceof INodeReference.DstReference) { |
| out.print(", dstSnapshotId=" + ref.getDstSnapshotId()); |
| } else if (ref instanceof INodeReference.WithCount) { |
| out.print(", " + ((INodeReference.WithCount)ref).getCountDetails()); |
| } |
| out.println(); |
| } |
| |
| @Override |
| public void preVisitReferred(INode referred) { |
| prefix.setLength(prefix.length() - 2); |
| prefix.append(" ->"); |
| } |
| |
| @Override |
| public void postVisitReferred(INode referred) { |
| prefix.setLength(prefix.length() - 2); |
| } |
| |
| @Override |
| public void visitDirectory(INodeDirectory dir, int snapshot) { |
| printINode(dir, snapshot); |
| |
| out.print(", childrenSize=" + dir.getChildrenList(snapshot).size()); |
| final DirectoryWithQuotaFeature q = dir.getDirectoryWithQuotaFeature(); |
| if (q != null) { |
| out.print(", " + q); |
| } |
| if (dir instanceof Snapshot.Root) { |
| out.print(", snapshotId=" + snapshot); |
| } |
| out.println(); |
| |
| if (prefix.length() >= 2) { |
| prefix.setLength(prefix.length() - 2); |
| prefix.append(" "); |
| } |
| |
| final DirectoryWithSnapshotFeature snapshotFeature |
| = dir.getDirectoryWithSnapshotFeature(); |
| if (snapshotFeature != null) { |
| out.print(prefix); |
| out.print(snapshotFeature); |
| } |
| out.println(); |
| } |
| |
| @Override |
| public void visitSnapshottable(INodeDirectory dir, |
| DirectorySnapshottableFeature snapshottable) { |
| out.println(); |
| out.print(prefix); |
| |
| out.print("Snapshot of "); |
| final String name = dir.getLocalName(); |
| out.print(name != null && name.isEmpty()? "/": name); |
| out.print(": quota="); |
| out.print(snapshottable.getSnapshotQuota()); |
| |
| int n = 0; |
| for(DirectoryDiff diff : snapshottable.getDiffs()) { |
| if (diff.isSnapshotRoot()) { |
| n++; |
| } |
| } |
| final int numSnapshots = snapshottable.getNumSnapshots(); |
| Preconditions.checkState(n == numSnapshots, |
| "numSnapshots = " + numSnapshots + " != " + n); |
| out.print(", #snapshot="); |
| out.println(n); |
| } |
| |
| @Override |
| public void preVisitSub(Element sub, int index, boolean isLast) { |
| prefix.append(isLast? LAST_ITEM : NON_LAST_ITEM); |
| } |
| |
| @Override |
| public void postVisitSub(Element sub, int index, boolean isLast) { |
| prefix.setLength(prefix.length() - 2); |
| } |
| } |