From d8175c831d319f7666d0f8a1a01d743a92dc9096 Mon Sep 17 00:00:00 2001 From: Todd Lipcon Date: Wed, 29 Feb 2012 19:57:46 +0000 Subject: [PATCH] HDFS-3020. Fix editlog to automatically sync when buffer is full. Contributed by Todd Lipcon. git-svn-id: https://svn.apache.org/repos/asf/hadoop/common/branches/branch-0.23@1295241 13f79535-47bb-0310-9956-ffa450edef68 --- hadoop-hdfs-project/hadoop-hdfs/CHANGES.txt | 2 ++ .../server/namenode/EditsDoubleBuffer.java | 2 +- .../hdfs/server/namenode/FSEditLog.java | 8 +++++ .../hdfs/server/namenode/TestEditLog.java | 35 +++++++++++++++++++ 4 files changed, 46 insertions(+), 1 deletion(-) diff --git a/hadoop-hdfs-project/hadoop-hdfs/CHANGES.txt b/hadoop-hdfs-project/hadoop-hdfs/CHANGES.txt index 614fd30861b..7db0d4ff089 100644 --- a/hadoop-hdfs-project/hadoop-hdfs/CHANGES.txt +++ b/hadoop-hdfs-project/hadoop-hdfs/CHANGES.txt @@ -131,6 +131,8 @@ Release 0.23.3 - UNRELEASED HDFS-2968. Protocol translator for BlockRecoveryCommand broken when multiple blocks need recovery. (todd) + HDFS-3020. Fix editlog to automatically sync when buffer is full. (todd) + Release 0.23.2 - UNRELEASED INCOMPATIBLE CHANGES diff --git a/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/namenode/EditsDoubleBuffer.java b/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/namenode/EditsDoubleBuffer.java index 5312b145aea..2aa736d6387 100644 --- a/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/namenode/EditsDoubleBuffer.java +++ b/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/namenode/EditsDoubleBuffer.java @@ -86,7 +86,7 @@ void flushTo(OutputStream out) throws IOException { } boolean shouldForceSync() { - return bufReady.size() >= initBufferSize; + return bufCurrent.size() >= initBufferSize; } DataOutputBuffer getCurrentBuf() { diff --git a/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/namenode/FSEditLog.java b/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/namenode/FSEditLog.java index 7f9c218ee59..ca4ace0fdf3 100644 --- a/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/namenode/FSEditLog.java +++ b/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/namenode/FSEditLog.java @@ -730,6 +730,14 @@ List getJournals() { synchronized void setRuntimeForTesting(Runtime runtime) { this.runtime = runtime; } + + /** + * Used only by tests. + */ + @VisibleForTesting + void setMetricsForTests(NameNodeMetrics metrics) { + this.metrics = metrics; + } /** * Return a manifest of what finalized edit logs are available diff --git a/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/server/namenode/TestEditLog.java b/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/server/namenode/TestEditLog.java index 4ec9202157f..2ebfc48d01b 100644 --- a/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/server/namenode/TestEditLog.java +++ b/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/server/namenode/TestEditLog.java @@ -50,6 +50,7 @@ import org.apache.hadoop.hdfs.server.common.Storage.StorageDirectory; import org.apache.hadoop.hdfs.server.namenode.NNStorage.NameNodeDirType; import org.apache.hadoop.hdfs.server.namenode.NNStorage; +import org.apache.hadoop.hdfs.server.namenode.metrics.NameNodeMetrics; import org.apache.hadoop.test.GenericTestUtils; import org.apache.hadoop.util.StringUtils; import org.apache.log4j.Level; @@ -798,6 +799,40 @@ public void testFailedOpen() throws Exception { log.close(); } } + + /** + * Regression test for HDFS-1112/HDFS-3020. Ensures that, even if + * logSync isn't called periodically, the edit log will sync itself. + */ + public void testAutoSync() throws Exception { + File logDir = new File(TEST_DIR, "testAutoSync"); + logDir.mkdirs(); + FSEditLog log = FSImageTestUtil.createStandaloneEditLog(logDir); + + String oneKB = StringUtils.byteToHexString( + new byte[500]); + + try { + log.open(); + NameNodeMetrics mockMetrics = Mockito.mock(NameNodeMetrics.class); + log.setMetricsForTests(mockMetrics); + + for (int i = 0; i < 400; i++) { + log.logDelete(oneKB, 1L); + } + // After ~400KB, we're still within the 512KB buffer size + Mockito.verify(mockMetrics, Mockito.times(0)).addSync(Mockito.anyLong()); + + // After ~400KB more, we should have done an automatic sync + for (int i = 0; i < 400; i++) { + log.logDelete(oneKB, 1L); + } + Mockito.verify(mockMetrics, Mockito.times(1)).addSync(Mockito.anyLong()); + + } finally { + log.close(); + } + } /** * Tests the getEditLogManifest function using mock storage for a number