001 /** 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018 019 package org.apache.hadoop.hdfs.server.namenode; 020 021 import java.io.File; 022 import java.io.FileInputStream; 023 import java.io.IOException; 024 import java.io.BufferedInputStream; 025 import java.io.EOFException; 026 import java.io.DataInputStream; 027 import org.apache.hadoop.hdfs.protocol.HdfsConstants; 028 import org.apache.hadoop.hdfs.server.common.Storage; 029 import org.apache.hadoop.io.IOUtils; 030 import org.apache.hadoop.hdfs.protocol.HdfsConstants; 031 032 import com.google.common.annotations.VisibleForTesting; 033 034 /** 035 * An implementation of the abstract class {@link EditLogInputStream}, which 036 * reads edits from a local file. 037 */ 038 public class EditLogFileInputStream extends EditLogInputStream { 039 private final File file; 040 private final FileInputStream fStream; 041 final private long firstTxId; 042 final private long lastTxId; 043 private final int logVersion; 044 private final FSEditLogOp.Reader reader; 045 private final FSEditLogLoader.PositionTrackingInputStream tracker; 046 private final boolean isInProgress; 047 048 /** 049 * Open an EditLogInputStream for the given file. 050 * The file is pretransactional, so has no txids 051 * @param name filename to open 052 * @throws LogHeaderCorruptException if the header is either missing or 053 * appears to be corrupt/truncated 054 * @throws IOException if an actual IO error occurs while reading the 055 * header 056 */ 057 EditLogFileInputStream(File name) 058 throws LogHeaderCorruptException, IOException { 059 this(name, HdfsConstants.INVALID_TXID, HdfsConstants.INVALID_TXID, false); 060 } 061 062 /** 063 * Open an EditLogInputStream for the given file. 064 * @param name filename to open 065 * @param firstTxId first transaction found in file 066 * @param lastTxId last transaction id found in file 067 * @throws LogHeaderCorruptException if the header is either missing or 068 * appears to be corrupt/truncated 069 * @throws IOException if an actual IO error occurs while reading the 070 * header 071 */ 072 public EditLogFileInputStream(File name, long firstTxId, long lastTxId, 073 boolean isInProgress) 074 throws LogHeaderCorruptException, IOException { 075 file = name; 076 fStream = new FileInputStream(name); 077 078 BufferedInputStream bin = new BufferedInputStream(fStream); 079 tracker = new FSEditLogLoader.PositionTrackingInputStream(bin); 080 DataInputStream in = new DataInputStream(tracker); 081 082 try { 083 logVersion = readLogVersion(in); 084 } catch (EOFException eofe) { 085 throw new LogHeaderCorruptException("No header found in log"); 086 } 087 088 reader = new FSEditLogOp.Reader(in, logVersion); 089 this.firstTxId = firstTxId; 090 this.lastTxId = lastTxId; 091 this.isInProgress = isInProgress; 092 } 093 094 @Override 095 public long getFirstTxId() throws IOException { 096 return firstTxId; 097 } 098 099 @Override 100 public long getLastTxId() throws IOException { 101 return lastTxId; 102 } 103 104 @Override 105 public String getName() { 106 return file.getPath(); 107 } 108 109 @Override 110 protected FSEditLogOp nextOp() throws IOException { 111 return reader.readOp(false); 112 } 113 114 @Override 115 protected FSEditLogOp nextValidOp() { 116 try { 117 return reader.readOp(true); 118 } catch (IOException e) { 119 return null; 120 } 121 } 122 123 @Override 124 public int getVersion() throws IOException { 125 return logVersion; 126 } 127 128 @Override 129 public long getPosition() { 130 return tracker.getPos(); 131 } 132 133 @Override 134 public void close() throws IOException { 135 fStream.close(); 136 } 137 138 @Override 139 public long length() throws IOException { 140 // file size + size of both buffers 141 return file.length(); 142 } 143 144 @Override 145 public boolean isInProgress() { 146 return isInProgress; 147 } 148 149 @Override 150 public String toString() { 151 return getName(); 152 } 153 154 static FSEditLogLoader.EditLogValidation validateEditLog(File file) throws IOException { 155 EditLogFileInputStream in; 156 try { 157 in = new EditLogFileInputStream(file); 158 } catch (LogHeaderCorruptException corrupt) { 159 // If the header is malformed or the wrong value, this indicates a corruption 160 FSImage.LOG.warn("Log at " + file + " has no valid header", 161 corrupt); 162 return new FSEditLogLoader.EditLogValidation(0, 163 HdfsConstants.INVALID_TXID, HdfsConstants.INVALID_TXID, true); 164 } 165 166 try { 167 return FSEditLogLoader.validateEditLog(in); 168 } finally { 169 IOUtils.closeStream(in); 170 } 171 } 172 173 /** 174 * Read the header of fsedit log 175 * @param in fsedit stream 176 * @return the edit log version number 177 * @throws IOException if error occurs 178 */ 179 @VisibleForTesting 180 static int readLogVersion(DataInputStream in) 181 throws IOException, LogHeaderCorruptException { 182 int logVersion; 183 try { 184 logVersion = in.readInt(); 185 } catch (EOFException eofe) { 186 throw new LogHeaderCorruptException( 187 "Reached EOF when reading log header"); 188 } 189 if (logVersion < HdfsConstants.LAYOUT_VERSION || // future version 190 logVersion > Storage.LAST_UPGRADABLE_LAYOUT_VERSION) { // unsupported 191 throw new LogHeaderCorruptException( 192 "Unexpected version of the file system log file: " 193 + logVersion + ". Current version = " 194 + HdfsConstants.LAYOUT_VERSION + "."); 195 } 196 return logVersion; 197 } 198 199 /** 200 * Exception indicating that the header of an edits log file is 201 * corrupted. This can be because the header is not present, 202 * or because the header data is invalid (eg claims to be 203 * over a newer version than the running NameNode) 204 */ 205 static class LogHeaderCorruptException extends IOException { 206 private static final long serialVersionUID = 1L; 207 208 private LogHeaderCorruptException(String msg) { 209 super(msg); 210 } 211 } 212 }