From 55278c012fbd5dcabee0276f8f42d0ab920cec93 Mon Sep 17 00:00:00 2001 From: Arpit Agarwal Date: Fri, 19 Jun 2015 18:23:34 -0700 Subject: [PATCH] HDFS-8626. Reserved RBW space is not released if creation of RBW File fails. (Contributed by kanaka kumar avvaru) --- hadoop-hdfs-project/hadoop-hdfs/CHANGES.txt | 3 ++ .../datanode/fsdataset/impl/FsVolumeImpl.java | 7 ++- .../impl/TestRbwSpaceReservation.java | 45 +++++++++++++++++++ 3 files changed, 54 insertions(+), 1 deletion(-) diff --git a/hadoop-hdfs-project/hadoop-hdfs/CHANGES.txt b/hadoop-hdfs-project/hadoop-hdfs/CHANGES.txt index 749a3cebcfe..a93a2149fd2 100644 --- a/hadoop-hdfs-project/hadoop-hdfs/CHANGES.txt +++ b/hadoop-hdfs-project/hadoop-hdfs/CHANGES.txt @@ -1064,6 +1064,9 @@ Release 2.7.1 - UNRELEASED HDFS-8633. Fix setting of dfs.datanode.readahead.bytes in hdfs-default.xml to match DFSConfigKeys. (Ray Chiang via Yongjun Zhang) + HDFS-8626. Reserved RBW space is not released if creation of RBW File + fails. (kanaka kumar avvaru via Arpit Agarwal) + Release 2.7.0 - 2015-04-20 INCOMPATIBLE CHANGES diff --git a/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/datanode/fsdataset/impl/FsVolumeImpl.java b/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/datanode/fsdataset/impl/FsVolumeImpl.java index 49a56bb9a0a..e90f5d2affb 100644 --- a/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/datanode/fsdataset/impl/FsVolumeImpl.java +++ b/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/datanode/fsdataset/impl/FsVolumeImpl.java @@ -780,7 +780,12 @@ public class FsVolumeImpl implements FsVolumeSpi { File createRbwFile(String bpid, Block b) throws IOException { checkReference(); reserveSpaceForRbw(b.getNumBytes()); - return getBlockPoolSlice(bpid).createRbwFile(b); + try { + return getBlockPoolSlice(bpid).createRbwFile(b); + } catch (IOException exception) { + releaseReservedSpace(b.getNumBytes()); + throw exception; + } } /** diff --git a/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/server/datanode/fsdataset/impl/TestRbwSpaceReservation.java b/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/server/datanode/fsdataset/impl/TestRbwSpaceReservation.java index 9b83b39917a..44bf81b43ea 100644 --- a/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/server/datanode/fsdataset/impl/TestRbwSpaceReservation.java +++ b/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/server/datanode/fsdataset/impl/TestRbwSpaceReservation.java @@ -27,10 +27,13 @@ import org.apache.hadoop.conf.Configuration; import static org.apache.hadoop.hdfs.DFSConfigKeys.*; import static org.hamcrest.core.Is.is; import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; import org.apache.hadoop.fs.FSDataOutputStream; import org.apache.hadoop.fs.Path; import org.apache.hadoop.hdfs.*; +import org.apache.hadoop.hdfs.protocol.Block; import org.apache.hadoop.hdfs.server.datanode.DataNode; import org.apache.hadoop.hdfs.server.datanode.fsdataset.FsDatasetSpi; import org.apache.hadoop.hdfs.server.datanode.fsdataset.FsVolumeReference; @@ -42,9 +45,12 @@ import org.junit.After; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; +import org.mockito.Mockito; import java.io.IOException; import java.io.OutputStream; +import java.lang.reflect.Field; +import java.util.Map; import java.util.Random; import java.util.concurrent.TimeoutException; @@ -279,6 +285,45 @@ public class TestRbwSpaceReservation { } } + @SuppressWarnings("unchecked") + @Test(timeout = 30000) + public void testRBWFileCreationError() throws Exception { + + final short replication = 1; + startCluster(BLOCK_SIZE, replication, -1); + + final FsVolumeImpl fsVolumeImpl = (FsVolumeImpl) cluster.getDataNodes() + .get(0).getFSDataset().getFsVolumeReferences().get(0); + final String methodName = GenericTestUtils.getMethodName(); + final Path file = new Path("/" + methodName + ".01.dat"); + + // Mock BlockPoolSlice so that RBW file creation gives IOExcception + BlockPoolSlice blockPoolSlice = Mockito.mock(BlockPoolSlice.class); + Mockito.when(blockPoolSlice.createRbwFile((Block) Mockito.any())) + .thenThrow(new IOException("Synthetic IO Exception Throgh MOCK")); + + Field field = FsVolumeImpl.class.getDeclaredField("bpSlices"); + field.setAccessible(true); + Map bpSlices = (Map) field + .get(fsVolumeImpl); + bpSlices.put(fsVolumeImpl.getBlockPoolList()[0], blockPoolSlice); + + try { + // Write 1 byte to the file + FSDataOutputStream os = fs.create(file, replication); + os.write(new byte[1]); + os.hsync(); + os.close(); + fail("Expecting IOException file creation failure"); + } catch (IOException e) { + // Exception can be ignored (expected) + } + + // Ensure RBW space reserved is released + assertTrue("Expected ZERO but got " + fsVolumeImpl.getReservedForRbw(), + fsVolumeImpl.getReservedForRbw() == 0); + } + /** * Stress test to ensure we are not leaking reserved space. * @throws IOException