/**
* 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 BlockDelimitedImageVisitor generates a text representation of the fsimage,
* with each element separated by a delimiter string.
* Each line of the text file represents one block including BLOCK_ID, NUM_BYTES,
* and GENERATION_STAMP.
* The default delimiter is tab. The delimiter value can be via the
* constructor.
*/
class BlockDelimitedImageVisitor extends TextWriterImageVisitor {
private static final String defaultDelimiter = "\t";
public static final String defaultValue = "-1";
final private LinkedList<ImageElement> elemQ = new LinkedList<ImageElement>();
// 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.BLOCK_ID,
ImageElement.NUM_BYTES,
ImageElement.GENERATION_STAMP);
}
public BlockDelimitedImageVisitor(String outputFile, boolean printToScreen,
int numberOfParts) throws IOException {
this(outputFile, printToScreen, defaultDelimiter, numberOfParts);
}
public BlockDelimitedImageVisitor(String outputFile, boolean printToScreen,
String delimiter, int numberOfParts)
throws IOException {
super(outputFile, printToScreen, numberOfParts);
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);
}
@Override
void leaveEnclosingElement() throws IOException {
ImageElement elem = elemQ.pop();
// If we're done with a block, write out our results and start over
if (elem == ImageElement.BLOCK) {
writeLine();
reset();
} else if (elem == ImageElement.INODE) {
super.rollIfNeeded();
}
}
/**
* 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 = elements.get(e);
if(v != null)
write(v);
else
write(defaultValue);
if(it.hasNext())
write(delimiter);
}
write("\n");
}
@Override
void visit(ImageElement element, String value) throws IOException {
if(elements.containsKey(element))
elements.put(element, value);
if (element.equals(ImageElement.GENERATION_STAMP)
&& (elemQ.element() == null ||
!elemQ.element().equals(ImageElement.BLOCK))) {
// Write fake block with current namenode generation stamp
writeLine();
}
}
@Override
void visitEnclosingElement(ImageElement element) throws IOException {
elemQ.push(element);
}
@Override
void visitEnclosingElement(ImageElement element, ImageElement key,
String value) throws IOException {
elemQ.push(element);
}
@Override
void start() throws IOException { /* Nothing to do */ }
}