HDFS-7119. Split error checks in AtomicFileOutputStream#close into separate conditions to improve diagnostics. Contributed by Chris Nauroth.

(cherry picked from commit 9f9a2222a2)
This commit is contained in:
cnauroth 2014-09-25 13:33:37 -07:00
parent cb9283549f
commit fd3aa38231
3 changed files with 43 additions and 3 deletions

View File

@ -243,6 +243,9 @@ Release 2.6.0 - UNRELEASED
HDFS-6808. Add command line option to ask DataNode reload configuration. HDFS-6808. Add command line option to ask DataNode reload configuration.
(Lei Xu via Colin Patrick McCabe) (Lei Xu via Colin Patrick McCabe)
HDFS-7119. Split error checks in AtomicFileOutputStream#close into separate
conditions to improve diagnostics. (cnauroth)
OPTIMIZATIONS OPTIMIZATIONS
HDFS-6690. Deduplicate xattr names in memory. (wang) HDFS-6690. Deduplicate xattr names in memory. (wang)

View File

@ -26,6 +26,8 @@ import java.io.IOException;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.io.IOUtils; import org.apache.hadoop.io.IOUtils;
import org.apache.hadoop.io.nativeio.NativeIO;
import org.apache.hadoop.io.nativeio.NativeIOException;
/** /**
* A FileOutputStream that has the property that it will only show * A FileOutputStream that has the property that it will only show
@ -73,9 +75,15 @@ public class AtomicFileOutputStream extends FilterOutputStream {
boolean renamed = tmpFile.renameTo(origFile); boolean renamed = tmpFile.renameTo(origFile);
if (!renamed) { if (!renamed) {
// On windows, renameTo does not replace. // On windows, renameTo does not replace.
if (!origFile.delete() || !tmpFile.renameTo(origFile)) { if (origFile.exists() && !origFile.delete()) {
throw new IOException("Could not rename temporary file " + throw new IOException("Could not delete original file " + origFile);
tmpFile + " to " + origFile); }
try {
NativeIO.renameTo(tmpFile, origFile);
} catch (NativeIOException e) {
throw new IOException("Could not rename temporary file " + tmpFile
+ " to " + origFile + " due to failure in native rename. "
+ e.toString());
} }
} }
} else { } else {

View File

@ -21,6 +21,7 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail; import static org.junit.Assert.fail;
import static org.junit.Assume.assumeTrue;
import java.io.File; import java.io.File;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
@ -30,9 +31,13 @@ import java.io.OutputStream;
import org.apache.hadoop.fs.FileUtil; import org.apache.hadoop.fs.FileUtil;
import org.apache.hadoop.hdfs.DFSTestUtil; import org.apache.hadoop.hdfs.DFSTestUtil;
import org.apache.hadoop.io.IOUtils;
import org.apache.hadoop.test.PathUtils; import org.apache.hadoop.test.PathUtils;
import org.apache.hadoop.util.Shell;
import org.junit.Before; import org.junit.Before;
import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
import org.junit.rules.ExpectedException;
import com.google.common.base.Joiner; import com.google.common.base.Joiner;
@ -44,6 +49,9 @@ public class TestAtomicFileOutputStream {
private static final File TEST_DIR = PathUtils.getTestDir(TestAtomicFileOutputStream.class); private static final File TEST_DIR = PathUtils.getTestDir(TestAtomicFileOutputStream.class);
private static final File DST_FILE = new File(TEST_DIR, "test.txt"); private static final File DST_FILE = new File(TEST_DIR, "test.txt");
@Rule
public ExpectedException exception = ExpectedException.none();
@Before @Before
public void cleanupTestDir() throws IOException { public void cleanupTestDir() throws IOException {
@ -119,6 +127,27 @@ public class TestAtomicFileOutputStream {
DST_FILE.getName(), Joiner.on(",").join(TEST_DIR.list())); DST_FILE.getName(), Joiner.on(",").join(TEST_DIR.list()));
} }
@Test
public void testFailToRename() throws IOException {
assumeTrue(Shell.WINDOWS);
OutputStream fos = null;
try {
fos = new AtomicFileOutputStream(DST_FILE);
fos.write(TEST_STRING.getBytes());
FileUtil.setWritable(TEST_DIR, false);
exception.expect(IOException.class);
exception.expectMessage("failure in native rename");
try {
fos.close();
} finally {
fos = null;
}
} finally {
IOUtils.cleanup(null, fos);
FileUtil.setWritable(TEST_DIR, true);
}
}
/** /**
* Create a stream that fails to flush at close time * Create a stream that fails to flush at close time
*/ */