Author: jdcryans
Date: Mon Dec  6 20:58:53 2010
New Revision: 1042790

URL: http://svn.apache.org/viewvc?rev=1042790&view=rev
Log:
HBASE-2467  Concurrent flushers in HLog sync using HDFS-895

Modified:
    hbase/trunk/CHANGES.txt
    hbase/trunk/src/main/java/org/apache/hadoop/hbase/regionserver/wal/HLog.java
    
hbase/trunk/src/test/java/org/apache/hadoop/hbase/regionserver/wal/TestHLog.java

Modified: hbase/trunk/CHANGES.txt
URL: 
http://svn.apache.org/viewvc/hbase/trunk/CHANGES.txt?rev=1042790&r1=1042789&r2=1042790&view=diff
==============================================================================
--- hbase/trunk/CHANGES.txt (original)
+++ hbase/trunk/CHANGES.txt Mon Dec  6 20:58:53 2010
@@ -1227,6 +1227,7 @@ Release 0.90.0 - Unreleased
    HBASE-3223  Get VersionInfo for Running HBase Process
                (Nicolas Spiegelberg via Stack)
    HBASE-3303  Lower hbase.regionserver.handler.count from 25 back to 10
+   HBASE-2467  Concurrent flushers in HLog sync using HDFS-895
 
 
   NEW FEATURES

Modified: 
hbase/trunk/src/main/java/org/apache/hadoop/hbase/regionserver/wal/HLog.java
URL: 
http://svn.apache.org/viewvc/hbase/trunk/src/main/java/org/apache/hadoop/hbase/regionserver/wal/HLog.java?rev=1042790&r1=1042789&r2=1042790&view=diff
==============================================================================
--- 
hbase/trunk/src/main/java/org/apache/hadoop/hbase/regionserver/wal/HLog.java 
(original)
+++ 
hbase/trunk/src/main/java/org/apache/hadoop/hbase/regionserver/wal/HLog.java 
Mon Dec  6 20:58:53 2010
@@ -128,8 +128,8 @@ public class HLog implements Syncable {
   private final long blocksize;
   private final int flushlogentries;
   private final String prefix;
-  private final AtomicInteger unflushedEntries = new AtomicInteger(0);
   private final Path oldLogDir;
+  private boolean logRollRequested;
 
 
   private static Class<? extends Writer> logWriterClass;
@@ -202,6 +202,7 @@ public class HLog implements Syncable {
 
   // We synchronize on updateLock to prevent updates and to prevent a log roll
   // during an update
+  // locked during appends
   private final Object updateLock = new Object();
 
   private final boolean enabled;
@@ -214,7 +215,7 @@ public class HLog implements Syncable {
   private final int maxLogs;
 
   /**
-   * Thread that handles group commit
+   * Thread that handles optional sync'ing
    */
   private final LogSyncer logSyncerThread;
 
@@ -506,6 +507,7 @@ public class HLog implements Syncable {
             this.fs.getFileStatus(oldFile).getLen() + ". ": "") +
           "New hlog " + FSUtils.getPath(newPath));
         this.numEntries.set(0);
+        this.logRollRequested = false;
       }
       // Tell our listeners that a new log was created
       if (!this.listeners.isEmpty()) {
@@ -870,7 +872,6 @@ public class HLog implements Syncable {
       this.lastSeqWritten.putIfAbsent(regionInfo.getEncodedNameAsBytes(),
         Long.valueOf(seqNum));
       doWrite(regionInfo, logKey, logEdit);
-      this.unflushedEntries.incrementAndGet();
       this.numEntries.incrementAndGet();
     }
 
@@ -927,9 +928,6 @@ public class HLog implements Syncable {
       HLogKey logKey = makeKey(hriKey, tableName, seqNum, now);
       doWrite(info, logKey, edits);
       this.numEntries.incrementAndGet();
-
-      // Only count 1 row as an unflushed entry.
-      this.unflushedEntries.incrementAndGet();
     }
     // Sync if catalog region, and if not then check if that table supports
     // deferred log flushing
@@ -946,15 +944,6 @@ public class HLog implements Syncable {
    */
    class LogSyncer extends Thread {
 
-    // Using fairness to make sure locks are given in order
-    private final ReentrantLock lock = new ReentrantLock(true);
-
-    // Condition used to wait until we have something to sync
-    private final Condition queueEmpty = lock.newCondition();
-
-    // Condition used to signal that the sync is done
-    private final Condition syncDone = lock.newCondition();
-
     private final long optionalFlushInterval;
 
     private boolean syncerShuttingDown = false;
@@ -966,28 +955,12 @@ public class HLog implements Syncable {
     @Override
     public void run() {
       try {
-        lock.lock();
         // awaiting with a timeout doesn't always
         // throw exceptions on interrupt
         while(!this.isInterrupted()) {
 
-          // Wait until something has to be hflushed or do it if we waited
-          // enough time (useful if something appends but does not hflush).
-          // 0 or less means that it timed out and maybe waited a bit more.
-          if (!(queueEmpty.awaitNanos(
-              this.optionalFlushInterval*1000000) <= 0)) {
-            forceSync = true;
-          }
-
-          // We got the signal, let's hflush. We currently own the lock so new
-          // writes are waiting to acquire it in addToSyncQueue while the ones
-          // we hflush are waiting on await()
-          hflush();
-
-          // Release all the clients waiting on the hflush. Notice that we 
still
-          // own the lock until we get back to await at which point all the
-          // other threads waiting will first acquire and release locks
-          syncDone.signalAll();
+          Thread.sleep(this.optionalFlushInterval);
+          sync();
         }
       } catch (IOException e) {
         LOG.error("Error while syncing, requesting close of hlog ", e);
@@ -996,101 +969,56 @@ public class HLog implements Syncable {
         LOG.debug(getName() + " interrupted while waiting for sync requests");
       } finally {
         syncerShuttingDown = true;
-        syncDone.signalAll();
-        lock.unlock();
         LOG.info(getName() + " exiting");
       }
     }
-
-    /**
-     * This method first signals the thread that there's a sync needed
-     * and then waits for it to happen before returning.
-     */
-    public void addToSyncQueue(boolean force) {
-
-      // Don't bother if somehow our append was already hflushed
-      if (unflushedEntries.get() == 0) {
-        return;
-      }
-      lock.lock();
-      try {
-        if (syncerShuttingDown) {
-          LOG.warn(getName() + " was shut down while waiting for sync");
-          return;
-        }
-        if(force) {
-          forceSync = true;
-        }
-        // Wake the thread
-        queueEmpty.signal();
-
-        // Wait for it to hflush
-        syncDone.await();
-      } catch (InterruptedException e) {
-        LOG.debug(getName() + " was interrupted while waiting for sync", e);
-      }
-      finally {
-        lock.unlock();
-      }
-    }
   }
 
-  public void sync(){
-    sync(false);
-  }
-
-  /**
-   * This method calls the LogSyncer in order to group commit the sync
-   * with other threads.
-   * @param force For catalog regions, force the sync to happen
-   */
-  public void sync(boolean force) {
-    logSyncerThread.addToSyncQueue(force);
-  }
-
-  public void hflush() throws IOException {
+  public void sync() throws IOException {
     synchronized (this.updateLock) {
       if (this.closed) {
         return;
       }
-      boolean logRollRequested = false;
-      if (this.forceSync ||
-          this.unflushedEntries.get() >= this.flushlogentries) {
-        try {
-          long now = System.currentTimeMillis();
-          this.writer.sync();
-          syncTime += System.currentTimeMillis() - now;
-          syncOps++;
-          this.forceSync = false;
-          this.unflushedEntries.set(0);
-
-          // if the number of replicas in HDFS has fallen below the initial
-          // value, then roll logs.
-          try {
-            int numCurrentReplicas = getLogReplication();
-            if (numCurrentReplicas != 0 &&
-                numCurrentReplicas < this.initialReplication) {
-              LOG.warn("HDFS pipeline error detected. " +
-                  "Found " + numCurrentReplicas + " replicas but expecting " +
-                  this.initialReplication + " replicas. " +
-                  " Requesting close of hlog.");
-              requestLogRoll();
-              logRollRequested = true;
-            }
-          } catch (Exception e) {
-              LOG.warn("Unable to invoke 
DFSOutputStream.getNumCurrentReplicas" + e +
-                       " still proceeding ahead...");
+    }
+    try {
+      long now = System.currentTimeMillis();
+      // Done in parallel for all writer threads, thanks to HDFS-895
+      this.writer.sync();
+      synchronized (this.updateLock) {
+        syncTime += System.currentTimeMillis() - now;
+        syncOps++;
+        if (!logRollRequested) {
+          checkLowReplication();
+          if (this.writer.getLength() > this.logrollsize) {
+            requestLogRoll();
           }
-        } catch (IOException e) {
-          LOG.fatal("Could not append. Requesting close of hlog", e);
-          requestLogRoll();
-          throw e;
         }
       }
 
-      if (!logRollRequested && (this.writer.getLength() > this.logrollsize)) {
+    } catch (IOException e) {
+      LOG.fatal("Could not append. Requesting close of hlog", e);
+      requestLogRoll();
+      throw e;
+    }
+  }
+
+  private void checkLowReplication() {
+    // if the number of replicas in HDFS has fallen below the initial
+    // value, then roll logs.
+    try {
+      int numCurrentReplicas = getLogReplication();
+      if (numCurrentReplicas != 0 &&
+          numCurrentReplicas < this.initialReplication) {
+        LOG.warn("HDFS pipeline error detected. " +
+            "Found " + numCurrentReplicas + " replicas but expecting " +
+            this.initialReplication + " replicas. " +
+            " Requesting close of hlog.");
         requestLogRoll();
+        logRollRequested = true;
       }
+    } catch (Exception e) {
+      LOG.warn("Unable to invoke DFSOutputStream.getNumCurrentReplicas" + e +
+          " still proceeding ahead...");
     }
   }
 
@@ -1122,7 +1050,7 @@ public class HLog implements Syncable {
 
   public void hsync() throws IOException {
     // Not yet implemented up in hdfs so just call hflush.
-    hflush();
+    sync();
   }
 
   private void requestLogRoll() {
@@ -1233,7 +1161,7 @@ public class HLog implements Syncable {
         }
       }
       // sync txn to file system
-      this.sync(isMetaRegion);
+      this.sync();
 
     } finally {
       this.cacheFlushLock.unlock();

Modified: 
hbase/trunk/src/test/java/org/apache/hadoop/hbase/regionserver/wal/TestHLog.java
URL: 
http://svn.apache.org/viewvc/hbase/trunk/src/test/java/org/apache/hadoop/hbase/regionserver/wal/TestHLog.java?rev=1042790&r1=1042789&r2=1042790&view=diff
==============================================================================
--- 
hbase/trunk/src/test/java/org/apache/hadoop/hbase/regionserver/wal/TestHLog.java
 (original)
+++ 
hbase/trunk/src/test/java/org/apache/hadoop/hbase/regionserver/wal/TestHLog.java
 Mon Dec  6 20:58:53 2010
@@ -341,7 +341,7 @@ public class TestHLog  {
       wal.append(regioninfo, tableName, kvs, System.currentTimeMillis());
     }
     // Now call sync to send the data to HDFS datanodes
-    wal.sync(true);
+    wal.sync();
      int namenodePort = cluster.getNameNodePort();
     final Path walPath = wal.computeFilename();
     


Reply via email to