| /** |
| * 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.tools.offlineImageViewer; |
| |
| import java.io.IOException; |
| import java.util.AbstractMap; |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.Collections; |
| import java.util.HashMap; |
| import java.util.Iterator; |
| import java.util.LinkedList; |
| |
| /** |
| * A DelimitedImageVisitor generates a text representation of the fsimage, |
| * with each element separated by a delimiter string. All of the elements |
| * common to both inodes and inodes-under-construction are included. When |
| * processing an fsimage with a layout version that did not include an |
| * element, such as AccessTime, the output file will include a column |
| * for the value, but no value will be included. |
| * |
| * Individual block information for each file is not currently included. |
| * |
| * The default delimiter is tab, as this is an unlikely value to be included |
| * an inode path or other text metadata. The delimiter value can be via the |
| * constructor. |
| */ |
| class DelimitedImageVisitor extends TextWriterImageVisitor { |
| private static final String defaultDelimiter = "\t"; |
| |
| final private LinkedList<ImageElement> elemQ = new LinkedList<ImageElement>(); |
| private long fileSize = 0l; |
| // Elements of fsimage we're interested in tracking |
| private final Collection<ImageElement> elementsToTrack; |
| // Values for each of the elements in elementsToTrack |
| private final AbstractMap<ImageElement, String> elements = |
| new HashMap<ImageElement, String>(); |
| private final String delimiter; |
| |
| { |
| elementsToTrack = new ArrayList<ImageElement>(); |
| |
| // This collection determines what elements are tracked and the order |
| // in which they are output |
| Collections.addAll(elementsToTrack, ImageElement.INODE_PATH, |
| ImageElement.REPLICATION, |
| ImageElement.MODIFICATION_TIME, |
| ImageElement.ACCESS_TIME, |
| ImageElement.BLOCK_SIZE, |
| ImageElement.NUM_BLOCKS, |
| ImageElement.NUM_BYTES, |
| ImageElement.NS_QUOTA, |
| ImageElement.DS_QUOTA, |
| ImageElement.PERMISSION_STRING, |
| ImageElement.USER_NAME, |
| ImageElement.GROUP_NAME); |
| } |
| |
| public DelimitedImageVisitor(String filename) throws IOException { |
| this(filename, false); |
| } |
| |
| public DelimitedImageVisitor(String outputFile, boolean printToScreen) |
| throws IOException { |
| this(outputFile, printToScreen, defaultDelimiter); |
| } |
| |
| public DelimitedImageVisitor(String outputFile, boolean printToScreen, |
| String delimiter) throws IOException { |
| super(outputFile, printToScreen); |
| this.delimiter = delimiter; |
| reset(); |
| } |
| |
| /** |
| * Reset the values of the elements we're tracking in order to handle |
| * the next file |
| */ |
| private void reset() { |
| elements.clear(); |
| for(ImageElement e : elementsToTrack) |
| elements.put(e, null); |
| |
| fileSize = 0l; |
| } |
| |
| @Override |
| void leaveEnclosingElement() throws IOException { |
| ImageElement elem = elemQ.pop(); |
| |
| // If we're done with an inode, write out our results and start over |
| if(elem == ImageElement.INODE || |
| elem == ImageElement.INODE_UNDER_CONSTRUCTION) { |
| writeLine(); |
| write("\n"); |
| reset(); |
| } |
| } |
| |
| /** |
| * Iterate through all the elements we're tracking and, if a value was |
| * recorded for it, write it out. |
| */ |
| private void writeLine() throws IOException { |
| Iterator<ImageElement> it = elementsToTrack.iterator(); |
| |
| while(it.hasNext()) { |
| ImageElement e = it.next(); |
| |
| String v = null; |
| if(e == ImageElement.NUM_BYTES) |
| v = String.valueOf(fileSize); |
| else |
| v = elements.get(e); |
| |
| if(v != null) |
| write(v); |
| |
| if(it.hasNext()) |
| write(delimiter); |
| } |
| } |
| |
| @Override |
| void visit(ImageElement element, String value) throws IOException { |
| // Explicitly label the root path |
| if(element == ImageElement.INODE_PATH && value.equals("")) |
| value = "/"; |
| |
| // Special case of file size, which is sum of the num bytes in each block |
| if(element == ImageElement.NUM_BYTES) |
| fileSize += Long.valueOf(value); |
| |
| if(elements.containsKey(element) && element != ImageElement.NUM_BYTES) |
| elements.put(element, value); |
| |
| } |
| |
| @Override |
| void visitEnclosingElement(ImageElement element) throws IOException { |
| elemQ.push(element); |
| } |
| |
| @Override |
| void visitEnclosingElement(ImageElement element, ImageElement key, |
| String value) throws IOException { |
| // Special case as numBlocks is an attribute of the blocks element |
| if(key == ImageElement.NUM_BLOCKS |
| && elements.containsKey(ImageElement.NUM_BLOCKS)) |
| elements.put(key, value); |
| |
| elemQ.push(element); |
| } |
| |
| @Override |
| void start() throws IOException { /* Nothing to do */ } |
| } |