Zookeeper写文件原子类

来源:互联网 发布:java的静态代理 编辑:程序博客网 时间:2024/06/05 12:01
文件实际是被写入一个后缀为.tmp的临时文件中,只有当数据完全写入磁盘后,才会覆盖目标文件。
在window平台下,需要先delete目标文件,再执行renameTo操作。
package org.apache.zookeeper.common;import java.io.File;import java.io.FileNotFoundException;import java.io.FileOutputStream;import java.io.FilterOutputStream;import java.io.IOException;import org.slf4j.Logger;import org.slf4j.LoggerFactory;/* * This code is originally from HDFS, see the similarly named files there * in case of bug fixing, history, etc... *//** * A FileOutputStream that has the property that it will only show up at its * destination once it has been entirely written and flushed to disk. While * being written, it will use a .tmp suffix. *  * When the output stream is closed, it is flushed, fsynced, and will be moved * into place, overwriting any file that already exists at that location. *  * <b>NOTE</b>: on Windows platforms, it will not atomically replace the target * file - instead the target file is deleted before this one is moved into * place. */public class AtomicFileOutputStream extends FilterOutputStream {    private static final String TMP_EXTENSION = ".tmp";    private final static Logger LOG = LoggerFactory            .getLogger(AtomicFileOutputStream.class);    private final File origFile;    private final File tmpFile;    public AtomicFileOutputStream(File f) throws FileNotFoundException {        // Code unfortunately must be duplicated below since we can't assign        // anything        // before calling super        super(new FileOutputStream(new File(f.getParentFile(), f.getName()                + TMP_EXTENSION)));        origFile = f.getAbsoluteFile();        tmpFile = new File(f.getParentFile(), f.getName() + TMP_EXTENSION)                .getAbsoluteFile();    }    @Override    public void close() throws IOException {        boolean triedToClose = false, success = false;        try {            flush();            ((FileOutputStream) out).getChannel().force(true);            triedToClose = true;            super.close();            success = true;        } finally {            if (success) {                boolean renamed = tmpFile.renameTo(origFile);                if (!renamed) {                    // On windows, renameTo does not replace.                    if (!origFile.delete() || !tmpFile.renameTo(origFile)) {                        throw new IOException(                                "Could not rename temporary file " + tmpFile                                        + " to " + origFile);                    }                }            } else {                if (!triedToClose) {                    // If we failed when flushing, try to close it to not leak                    // an FD                    IOUtils.closeStream(out);                }                // close wasn't successful, try to delete the tmp file                if (!tmpFile.delete()) {                    LOG.warn("Unable to delete tmp file " + tmpFile);                }            }        }    }    /**     * Close the atomic file, but do not "commit" the temporary file on top of     * the destination. This should be used if there is a failure in writing.     */    public void abort() {        try {            super.close();        } catch (IOException ioe) {            LOG.warn("Unable to abort file " + tmpFile, ioe);        }        if (!tmpFile.delete()) {            LOG.warn("Unable to delete tmp file during abort " + tmpFile);        }    }}
在QuorumPeer类中,将一个long值写入磁盘时,用到了此类,要么写入成功要么抛出异常:
private void writeLongToFile(String name, long value) throws IOException {        File file = new File(logFactory.getSnapDir(), name);        AtomicFileOutputStream out = new AtomicFileOutputStream(file);        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(out));        boolean aborted = false;        try {            bw.write(Long.toString(value));            bw.flush();            out.flush();        } catch (IOException e) {            LOG.error("Failed to write new file " + file, e);            aborted = true;            out.abort();            throw e;        } finally {            if (!aborted) {                out.close();            }        }    }



0 0
原创粉丝点击