org.apache.hadoop.hdfs.tools.offlineImageViewer.LsrPBImage.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.hadoop.hdfs.tools.offlineImageViewer.LsrPBImage.java

Source

/**
 * 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.BufferedInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.io.RandomAccessFile;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.permission.PermissionStatus;
import org.apache.hadoop.hdfs.protocol.proto.HdfsProtos.BlockProto;
import org.apache.hadoop.hdfs.server.namenode.FSImageFormatPBINode;
import org.apache.hadoop.hdfs.server.namenode.FSImageFormatProtobuf.SectionName;
import org.apache.hadoop.hdfs.server.namenode.FSImageUtil;
import org.apache.hadoop.hdfs.server.namenode.FsImageProto.FileSummary;
import org.apache.hadoop.hdfs.server.namenode.FsImageProto.INodeDirectorySection;
import org.apache.hadoop.hdfs.server.namenode.FsImageProto.INodeReferenceSection;
import org.apache.hadoop.hdfs.server.namenode.FsImageProto.INodeSection;
import org.apache.hadoop.hdfs.server.namenode.FsImageProto.INodeSection.INode;
import org.apache.hadoop.hdfs.server.namenode.FsImageProto.INodeSection.INodeDirectory;
import org.apache.hadoop.hdfs.server.namenode.FsImageProto.INodeSection.INodeFile;
import org.apache.hadoop.hdfs.server.namenode.FsImageProto.INodeSection.INodeSymlink;
import org.apache.hadoop.hdfs.server.namenode.FsImageProto.StringTableSection;
import org.apache.hadoop.hdfs.server.namenode.INodeId;
import org.apache.hadoop.io.IOUtils;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.io.LimitInputStream;

/**
 * LsrPBImage displays the blocks of the namespace in a format very similar
 * to the output of ls/lsr.  Entries are marked as directories or not,
 * permissions listed, replication, username and groupname, along with size,
 * modification date and full path.
 *
 * Note: A significant difference between the output of the lsr command
 * and this image visitor is that this class cannot sort the file entries;
 * they are listed in the order they are stored within the fsimage file. 
 * Therefore, the output of this class cannot be directly compared to the
 * output of the lsr command.
 */
final class LsrPBImage {

    private static final Log LOG = LogFactory.getLog(LsrPBImage.class);

    private final Configuration conf;
    private final PrintWriter out;
    private String[] stringTable;
    private final HashMap<Long, INodeSection.INode> inodes = Maps.newHashMap();
    private final HashMap<Long, long[]> dirmap = Maps.newHashMap();
    private final ArrayList<INodeReferenceSection.INodeReference> refList = Lists.newArrayList();

    public LsrPBImage(Configuration conf, PrintWriter out) {
        this.conf = conf;
        this.out = out;
    }

    public void visit(RandomAccessFile file) throws IOException {
        if (!FSImageUtil.checkFileFormat(file)) {
            throw new IOException("Unrecognized FSImage");
        }

        FileSummary summary = FSImageUtil.loadSummary(file);
        FileInputStream fin = null;
        try {
            fin = new FileInputStream(file.getFD());

            ArrayList<FileSummary.Section> sections = Lists.newArrayList(summary.getSectionsList());
            Collections.sort(sections, new Comparator<FileSummary.Section>() {
                @Override
                public int compare(FileSummary.Section s1, FileSummary.Section s2) {
                    SectionName n1 = SectionName.fromString(s1.getName());
                    SectionName n2 = SectionName.fromString(s2.getName());
                    if (n1 == null) {
                        return n2 == null ? 0 : -1;
                    } else if (n2 == null) {
                        return -1;
                    } else {
                        return n1.ordinal() - n2.ordinal();
                    }
                }
            });

            for (FileSummary.Section s : sections) {
                fin.getChannel().position(s.getOffset());
                InputStream is = FSImageUtil.wrapInputStreamForCompression(conf, summary.getCodec(),
                        new BufferedInputStream(new LimitInputStream(fin, s.getLength())));

                switch (SectionName.fromString(s.getName())) {
                case STRING_TABLE:
                    loadStringTable(is);
                    break;
                case INODE:
                    loadINodeSection(is);
                    break;
                case INODE_REFERENCE:
                    loadINodeReferenceSection(is);
                    break;
                case INODE_DIR:
                    loadINodeDirectorySection(is);
                    break;
                default:
                    break;
                }
            }
            list("", INodeId.ROOT_INODE_ID);
        } finally {
            IOUtils.cleanup(null, fin);
        }
    }

    private void list(String parent, long dirId) {
        INode inode = inodes.get(dirId);
        if (LOG.isTraceEnabled()) {
            LOG.trace("Listing directory id " + dirId + " parent '" + parent + "' (INode is " + inode + ")");
        }
        listINode(parent.isEmpty() ? "/" : parent, inode);
        long[] children = dirmap.get(dirId);
        if (children == null) {
            return;
        }
        String newParent = parent + inode.getName().toStringUtf8() + "/";
        for (long cid : children) {
            list(newParent, cid);
        }
    }

    private void listINode(String parent, INode inode) {
        switch (inode.getType()) {
        case FILE: {
            INodeFile f = inode.getFile();
            PermissionStatus p = FSImageFormatPBINode.Loader.loadPermission(f.getPermission(), stringTable);
            out.print(String.format("-%s %2s %8s %10s %10s %10d %s%s\n", p.getPermission().toString(),
                    f.getReplication(), p.getUserName(), p.getGroupName(), f.getModificationTime(), getFileSize(f),
                    parent, inode.getName().toStringUtf8()));
        }
            break;
        case DIRECTORY: {
            INodeDirectory d = inode.getDirectory();
            PermissionStatus p = FSImageFormatPBINode.Loader.loadPermission(d.getPermission(), stringTable);
            out.print(
                    String.format("d%s  - %8s %10s %10s %10d %s%s\n", p.getPermission().toString(), p.getUserName(),
                            p.getGroupName(), d.getModificationTime(), 0, parent, inode.getName().toStringUtf8()));
        }
            break;
        case SYMLINK: {
            INodeSymlink d = inode.getSymlink();
            PermissionStatus p = FSImageFormatPBINode.Loader.loadPermission(d.getPermission(), stringTable);
            out.print(String.format("-%s  - %8s %10s %10s %10d %s%s -> %s\n", p.getPermission().toString(),
                    p.getUserName(), p.getGroupName(), d.getModificationTime(), 0, parent,
                    inode.getName().toStringUtf8(), d.getTarget().toStringUtf8()));
        }
            break;
        default:
            break;
        }
    }

    private long getFileSize(INodeFile f) {
        long size = 0;
        for (BlockProto p : f.getBlocksList()) {
            size += p.getNumBytes();
        }
        return size;
    }

    private void loadINodeDirectorySection(InputStream in) throws IOException {
        if (LOG.isDebugEnabled()) {
            LOG.debug("Loading directory section");
        }
        while (true) {
            INodeDirectorySection.DirEntry e = INodeDirectorySection.DirEntry.parseDelimitedFrom(in);
            // note that in is a LimitedInputStream
            if (e == null) {
                break;
            }
            long[] l = new long[e.getChildrenCount() + e.getRefChildrenCount()];
            for (int i = 0; i < e.getChildrenCount(); ++i) {
                l[i] = e.getChildren(i);
            }
            for (int i = e.getChildrenCount(); i < l.length; i++) {
                int refId = e.getRefChildren(i - e.getChildrenCount());
                l[i] = refList.get(refId).getReferredId();
            }
            dirmap.put(e.getParent(), l);
            if (LOG.isDebugEnabled()) {
                LOG.debug("Loaded directory (parent " + e.getParent() + ") with " + e.getChildrenCount()
                        + " children and " + e.getRefChildrenCount() + " reference children");
            }
        }
        if (LOG.isDebugEnabled()) {
            LOG.debug("Loaded " + dirmap.size() + " directories");
        }
    }

    private void loadINodeReferenceSection(InputStream in) throws IOException {
        if (LOG.isDebugEnabled()) {
            LOG.debug("Loading inode reference section");
        }
        while (true) {
            INodeReferenceSection.INodeReference e = INodeReferenceSection.INodeReference.parseDelimitedFrom(in);
            if (e == null) {
                break;
            }
            refList.add(e);
            if (LOG.isTraceEnabled()) {
                LOG.trace("Loaded inode reference named '" + e.getName() + "' referring to id " + e.getReferredId()
                        + "");
            }
        }
        if (LOG.isDebugEnabled()) {
            LOG.debug("Loaded " + refList.size() + " inode references");
        }
    }

    private void loadINodeSection(InputStream in) throws IOException {
        INodeSection s = INodeSection.parseDelimitedFrom(in);
        if (LOG.isDebugEnabled()) {
            LOG.debug("Found " + s.getNumInodes() + " inodes in inode section");
        }
        for (int i = 0; i < s.getNumInodes(); ++i) {
            INodeSection.INode p = INodeSection.INode.parseDelimitedFrom(in);
            inodes.put(p.getId(), p);
            if (LOG.isTraceEnabled()) {
                LOG.trace("Loaded inode id " + p.getId() + " type " + p.getType() + " name '"
                        + p.getName().toStringUtf8() + "'");
            }
        }
    }

    private void loadStringTable(InputStream in) throws IOException {
        StringTableSection s = StringTableSection.parseDelimitedFrom(in);
        if (LOG.isDebugEnabled()) {
            LOG.debug("Found " + s.getNumEntry() + " strings in string section");
        }
        stringTable = new String[s.getNumEntry() + 1];
        for (int i = 0; i < s.getNumEntry(); ++i) {
            StringTableSection.Entry e = StringTableSection.Entry.parseDelimitedFrom(in);
            stringTable[e.getId()] = e.getStr();
            if (LOG.isTraceEnabled()) {
                LOG.trace("Loaded string " + e.getStr());
            }
        }
    }
}