package org.apache.hadoop.io.simpleseekableformat;
import java.io.DataInputStream;
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
import org.apache.hadoop.io.compress.CompressionInputStream;
/**
* The reader for Seekable File Format.
*
* See {@link SimpleSeekableFormat}
*/
public class SimpleSeekableFormatInputStream extends CompressionInputStream {
private final DataInputStream dataIn;
private InputStream dataSegmentIn;
public SimpleSeekableFormatInputStream(InputStream in) {
// we don't use the inherited field "in" at all:
super(null);
this.dataIn = new DataInputStream(new InterleavedInputStream(in,
SimpleSeekableFormat.METADATA_BLOCK_LENGTH,
SimpleSeekableFormat.DATA_BLOCK_LENGTH));
}
@Override
public int read() throws IOException {
if (dataSegmentIn == null) {
if (!moveToNextDataSegment()) {
return -1;
}
}
do {
int result = dataSegmentIn.read();
if (result != -1) {
return result;
}
if (!moveToNextDataSegment()) {
return -1;
}
} while (true);
}
@Override
public int read(byte[] b, int start, int length) throws IOException {
if (dataSegmentIn == null) {
if (!moveToNextDataSegment()) {
return -1;
}
}
do {
int result = dataSegmentIn.read(b, start, length);
if (result != -1) {
return result;
}
if (!moveToNextDataSegment()) {
return -1;
}
} while (true);
}
@Override
public void close() throws IOException {
dataIn.close();
}
/**
* This function depends on that the underlying dataSegmentIn.available() only
* returns 0 when EOF. Otherwise it will break because it jumps over the dataSegmentIn
* that has available() == 0.
*/
@Override
public int available() throws IOException {
if (dataSegmentIn == null) {
if (!moveToNextDataSegment()) {
return 0;
}
}
do {
int result = dataSegmentIn.available();
if (result != 0) {
return result;
}
if (!moveToNextDataSegment()) {
return -1;
}
} while (true);
}
/**
* Returns false if there are no more data segments.
*/
private boolean moveToNextDataSegment() throws IOException {
if (dataIn.available() == 0) {
return false;
}
try {
DataSegmentReader dataSegmentReader = new DataSegmentReader(dataIn);
dataSegmentIn = dataSegmentReader.getInputStream();
} catch (EOFException e) {
// EOFException is thrown when the underlying data stream is truncated, e.g. truncated file.
// This is considered as a normal case.
return false;
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
return true;
}
@Override
public void resetState() throws IOException {
throw new RuntimeException("SeekableFileInputFormat does not support resetState()");
}
}