/** * 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; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.BufferedInputStream; import java.io.EOFException; import java.io.DataInputStream; import org.apache.hadoop.hdfs.protocol.HdfsConstants; import org.apache.hadoop.hdfs.server.common.Storage; import org.apache.hadoop.io.IOUtils; import com.google.common.annotations.VisibleForTesting; /** * An implementation of the abstract class {@link EditLogInputStream}, which * reads edits from a local file. */ class EditLogFileInputStream extends EditLogInputStream { private final File file; private final FileInputStream fStream; private final int logVersion; private final FSEditLogOp.Reader reader; private final FSEditLogLoader.PositionTrackingInputStream tracker; /** * Open an EditLogInputStream for the given file. * @param name filename to open * @throws LogHeaderCorruptException if the header is either missing or * appears to be corrupt/truncated * @throws IOException if an actual IO error occurs while reading the * header */ EditLogFileInputStream(File name) throws LogHeaderCorruptException, IOException { file = name; fStream = new FileInputStream(name); BufferedInputStream bin = new BufferedInputStream(fStream); tracker = new FSEditLogLoader.PositionTrackingInputStream(bin); DataInputStream in = new DataInputStream(tracker); try { logVersion = readLogVersion(in); } catch (EOFException eofe) { throw new LogHeaderCorruptException("No header found in log"); } reader = new FSEditLogOp.Reader(in, logVersion); } @Override // JournalStream public String getName() { return file.getPath(); } @Override // JournalStream public JournalType getType() { return JournalType.FILE; } @Override public FSEditLogOp readOp() throws IOException { return reader.readOp(); } @Override public int getVersion() throws IOException { return logVersion; } @Override public long getPosition() { return tracker.getPos(); } @Override public void close() throws IOException { fStream.close(); } @Override long length() throws IOException { // file size + size of both buffers return file.length(); } @Override public String toString() { return getName(); } static FSEditLogLoader.EditLogValidation validateEditLog(File file) throws IOException { EditLogFileInputStream in; try { in = new EditLogFileInputStream(file); } catch (LogHeaderCorruptException corrupt) { // If it's missing its header, this is equivalent to no transactions FSImage.LOG.warn("Log at " + file + " has no valid header", corrupt); return new FSEditLogLoader.EditLogValidation(0, 0); } try { return FSEditLogLoader.validateEditLog(in); } finally { IOUtils.closeStream(in); } } /** * Read the header of fsedit log * @param in fsedit stream * @return the edit log version number * @throws IOException if error occurs */ @VisibleForTesting static int readLogVersion(DataInputStream in) throws IOException, LogHeaderCorruptException { int logVersion; try { logVersion = in.readInt(); } catch (EOFException eofe) { throw new LogHeaderCorruptException( "Reached EOF when reading log header"); } if (logVersion < HdfsConstants.LAYOUT_VERSION) { // future version throw new LogHeaderCorruptException( "Unexpected version of the file system log file: " + logVersion + ". Current version = " + HdfsConstants.LAYOUT_VERSION + "."); } assert logVersion <= Storage.LAST_UPGRADABLE_LAYOUT_VERSION : "Unsupported version " + logVersion; return logVersion; } /** * Exception indicating that the header of an edits log file is * corrupted. This can be because the header is not present, * or because the header data is invalid (eg claims to be * over a newer version than the running NameNode) */ static class LogHeaderCorruptException extends IOException { private static final long serialVersionUID = 1L; private LogHeaderCorruptException(String msg) { super(msg); } } }