package com.alimama.mdrill.editlog.write;
import java.io.DataOutputStream;
import java.io.IOException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.fs.FSDataOutputStream;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import com.alimama.mdrill.editlog.defined.HdfsConstants;
import com.alimama.mdrill.editlog.read.FSEditLogOp;
import com.alimama.mdrill.editlog.util.IOUtils;
import com.google.common.annotations.VisibleForTesting;
public class EditLogFileOutputStream extends EditLogOutputStream {
private static Log LOG = LogFactory.getLog(EditLogFileOutputStream.class);
public static final int MIN_PREALLOCATION_LENGTH = 1024 * 1024;
private Path file;
FileSystem fs;
private FSDataOutputStream fp; // file stream for storing edit logs
private EditsDoubleBuffer doubleBuf;
private int size;
public EditLogFileOutputStream(FileSystem fs,Path name, int size)
throws IOException {
super();
this.fs=fs;
this.file = name;
this.size=size;
this.create();
}
@Override
public void write(FSEditLogOp op) throws IOException {
doubleBuf.writeOp(op);
}
@Override
public void writeRaw(byte[] bytes, int offset, int length) throws IOException {
doubleBuf.writeRaw(bytes, offset, length);
}
@Override
public void create() throws IOException {
if (fp != null) {
fp.close();
}
if (doubleBuf != null) {
doubleBuf.close();
doubleBuf = null;
}
doubleBuf = new EditsDoubleBuffer(size);
if (this.fs.exists(this.file)) {
fs.delete(this.file, true);
}
fp = this.fs.create(this.file, true);
writeHeader(doubleBuf.getCurrentBuf());
setReadyToFlush();
flush();
}
@VisibleForTesting
public static void writeHeader(DataOutputStream out) throws IOException {
out.writeInt(HdfsConstants.LAYOUT_VERSION);
}
@Override
public void close() throws IOException {
if (fp == null) {
throw new IOException("Trying to use aborted output stream");
}
try {
if (doubleBuf != null) {
doubleBuf.close();
doubleBuf = null;
}
fp.close();
fp = null;
} finally {
IOUtils.cleanup(LOG, fp);
doubleBuf = null;
fp = null;
}
fp = null;
}
@Override
public void abort() throws IOException {
if (fp == null) {
return;
}
IOUtils.cleanup(LOG, fp);
fp = null;
}
@Override
public void setReadyToFlush() throws IOException {
doubleBuf.setReadyToFlush();
}
@Override
public void flushAndSync(boolean durable) throws IOException {
if (fp == null) {
throw new IOException("Trying to use aborted output stream");
}
if (doubleBuf.isFlushed()) {
LOG.info("Nothing to flush");
return;
}
doubleBuf.flushTo(fp);
if (durable) {
fp.flush();
fp.sync();
}
}
public boolean shouldForceSync() {
return doubleBuf.shouldForceSync();
}
public Path getFile() {
return file;
}
public FileSystem getFileSystem() {
return fs;
}
@Override
public String toString() {
return "EditLogFileOutputStream(" + file + ")";
}
public boolean isOpen() {
return fp != null;
}
}