Skip to content

Commit

Permalink
(fix) Impl moving file atomically on windows, sofastack#54 (sofastack…
Browse files Browse the repository at this point in the history
…#104)

* (fix) Impl move file atomically on windows, sofastack#54

* (feat) Some style changes

* (feat) Checking Files.move return value is not null
  • Loading branch information
killme2008 authored and fengjiachun committed Apr 16, 2019
1 parent d6b9151 commit a4f45f4
Showing 1 changed file with 50 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,13 @@
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.AtomicMoveNotSupportedException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.alipay.sofa.jraft.rpc.ProtobufMsgFactory;
import com.alipay.sofa.jraft.util.Bits;
Expand All @@ -42,14 +49,16 @@
*/
public class ProtoBufFile {

private static final Logger LOG = LoggerFactory.getLogger(ProtoBufFile.class);

static {
ProtobufMsgFactory.load();
}

/** file path */
private final String path;
private final String path;

public ProtoBufFile(String path) {
public ProtoBufFile(final String path) {
this.path = path;
}

Expand Down Expand Up @@ -81,7 +90,7 @@ public <T extends Message> T load() throws IOException {
}
}

private void readBytes(byte[] bs, InputStream input) throws IOException {
private void readBytes(final byte[] bs, final InputStream input) throws IOException {
int read;
if ((read = input.read(bs)) != bs.length) {
throw new IOException("Read error, expects " + bs.length + " bytes, but read " + read);
Expand All @@ -95,7 +104,8 @@ private void readBytes(byte[] bs, InputStream input) throws IOException {
* @param sync if sync flush data to disk
* @return true if save success
*/
public boolean save(Message msg, boolean sync) throws IOException {
public boolean save(final Message msg, final boolean sync) throws IOException {
// Write message into temp file
File file = new File(this.path + ".tmp");
try (FileOutputStream fOut = new FileOutputStream(file);
BufferedOutputStream output = new BufferedOutputStream(fOut)) {
Expand All @@ -117,6 +127,41 @@ public boolean save(Message msg, boolean sync) throws IOException {
}
}

return file.renameTo(new File(path));
// Move temp file to target path atomically.
// The code comes from https://github.com/jenkinsci/jenkins/blob/master/core/src/main/java/hudson/util/AtomicFileWriter.java#L187
Path tmpPath = file.toPath();
File destFile = new File(this.path);
Path destPath = destFile.toPath();
try {
return Files.move(tmpPath, destPath, StandardCopyOption.ATOMIC_MOVE) != null;
} catch (final IOException e) {
// If it falls here that can mean many things. Either that the atomic move is not supported,
// or something wrong happened. Anyway, let's try to be over-diagnosing
if (e instanceof AtomicMoveNotSupportedException) {
LOG.warn("Atomic move not supported. falling back to non-atomic move, error: {}.", e.getMessage());
} else {
LOG.warn("Unable to move atomically, falling back to non-atomic move, error: {}.", e.getMessage());
}

if (destFile.exists()) {
LOG.info("The target file {} was already existing.", destPath);
}

try {
return Files.move(tmpPath, destPath, StandardCopyOption.REPLACE_EXISTING) != null;
} catch (final IOException e1) {
e1.addSuppressed(e);
LOG.warn("Unable to move {} to {}. Attempting to delete {} and abandoning.", tmpPath, destPath, tmpPath);
try {
Files.deleteIfExists(tmpPath);
} catch (IOException e2) {
e2.addSuppressed(e1);
LOG.warn("Unable to delete {}, good bye then!", tmpPath);
throw e2;
}

throw e1;
}
}
}
}

0 comments on commit a4f45f4

Please sign in to comment.