package org.apache.hadoop.io.simpleseekableformat;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.OutputStream;
/**
* This OutputStream calls metaDataProducer to produce
* metadata at fixed periodic locations in the output stream.
*/
class InterleavedOutputStream extends OutputStream {
public interface MetaDataProducer {
/**
* This function should write a metadata block with size metaDataBlockSize
* @param out The raw output stream
*/
void writeMetaData(DataOutputStream out, int metaDataBlockSize) throws IOException;
}
private final DataOutputStream out;
private final int metaDataBlockSize;
private final int dataBlockSize;
private final MetaDataProducer metaDataProducer;
private long completeMetaDataBlocks;
private int currentDataBlockSize;
InterleavedOutputStream(DataOutputStream out,
int metaDataBlockSize, int dataBlockSize,
MetaDataProducer metaDataProducer) {
this.out = out;
this.metaDataBlockSize = metaDataBlockSize;
this.dataBlockSize = dataBlockSize;
this.metaDataProducer = metaDataProducer;
// indicate that we need to write a metadata block right away.
currentDataBlockSize = dataBlockSize;
}
private void writeMetaDataIfNeeded() throws IOException {
if (currentDataBlockSize == dataBlockSize) {
metaDataProducer.writeMetaData(out, metaDataBlockSize);
completeMetaDataBlocks ++;
currentDataBlockSize = 0;
}
}
// Number of bytes written to the underlying stream
public long getOffset() {
return completeMetaDataBlocks * metaDataBlockSize
+ getDataOffset();
}
// Number of data bytes written to the underlying stream
public long getDataOffset() {
return (completeMetaDataBlocks - 1) * dataBlockSize
+ currentDataBlockSize;
}
@Override
public void write(int b) throws IOException {
writeMetaDataIfNeeded();
out.write(b);
currentDataBlockSize ++;
}
@Override
public void write(byte[] b, int start, int length) throws IOException {
while (length > 0) {
writeMetaDataIfNeeded();
int dataToWrite = Math.min(length, dataBlockSize - currentDataBlockSize);
out.write(b, start, dataToWrite);
start += dataToWrite;
length -= dataToWrite;
currentDataBlockSize += dataToWrite;
}
}
@Override
public void flush() throws IOException {
out.flush();
}
@Override
public void close() throws IOException {
out.close();
}
}