You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hbase.apache.org by ra...@apache.org on 2010/05/25 02:27:39 UTC

svn commit: r947873 - in /hbase/branches/0.20: CHANGES.txt src/java/org/apache/hadoop/hbase/regionserver/HRegion.java

Author: rawson
Date: Tue May 25 00:27:38 2010
New Revision: 947873

URL: http://svn.apache.org/viewvc?rev=947873&view=rev
Log:
HBASE-1880 (also fixes HBASE-2606) DeleteColumns are not recovered properly from the write-ahead-log


Modified:
    hbase/branches/0.20/CHANGES.txt
    hbase/branches/0.20/src/java/org/apache/hadoop/hbase/regionserver/HRegion.java

Modified: hbase/branches/0.20/CHANGES.txt
URL: http://svn.apache.org/viewvc/hbase/branches/0.20/CHANGES.txt?rev=947873&r1=947872&r2=947873&view=diff
==============================================================================
--- hbase/branches/0.20/CHANGES.txt (original)
+++ hbase/branches/0.20/CHANGES.txt Tue May 25 00:27:38 2010
@@ -11,6 +11,8 @@ Release 0.20.5 - Mon May 17 10:14:58 PDT
                crashes (Todd Lipcon via Stack)
    HBASE-2428  NPE in ProcessRegionClose because meta is offline kills master
                and thus the cluster
+   HBASE-1880  DeleteColumns are not recovered properly from the write-ahead-log
+   	       (via HBASE-2606)
 
   IMPROVEMENTS
    HBASE-2567  [stargate] minimize differences between 0.20 branch and trunk

Modified: hbase/branches/0.20/src/java/org/apache/hadoop/hbase/regionserver/HRegion.java
URL: http://svn.apache.org/viewvc/hbase/branches/0.20/src/java/org/apache/hadoop/hbase/regionserver/HRegion.java?rev=947873&r1=947872&r2=947873&view=diff
==============================================================================
--- hbase/branches/0.20/src/java/org/apache/hadoop/hbase/regionserver/HRegion.java (original)
+++ hbase/branches/0.20/src/java/org/apache/hadoop/hbase/regionserver/HRegion.java Tue May 25 00:27:38 2010
@@ -75,9 +75,9 @@ package org.apache.hadoop.hbase.regionse
  * for each row. A given table consists of one or more HRegions.
  *
  * <p>We maintain multiple HStores for a single HRegion.
- * 
+ *
  * <p>An Store is a set of rows with some column data; together,
- * they make up all the data for the rows.  
+ * they make up all the data for the rows.
  *
  * <p>Each HRegion has a 'startKey' and 'endKey'.
  * <p>The first is inclusive, the second is exclusive (except for
@@ -93,15 +93,15 @@ package org.apache.hadoop.hbase.regionse
  * constructed, it holds a read lock until it is closed. A close takes out a
  * write lock and consequently will block for ongoing operations and will block
  * new operations from starting while the close is in progress.
- * 
+ *
  * <p>An HRegion is defined by its table and its key extent.
- * 
+ *
  * <p>It consists of at least one Store.  The number of Stores should be
  * configurable, so that data which is accessed together is stored in the same
- * Store.  Right now, we approximate that by building a single Store for 
- * each column family.  (This config info will be communicated via the 
+ * Store.  Right now, we approximate that by building a single Store for
+ * each column family.  (This config info will be communicated via the
  * tabledesc.)
- * 
+ *
  * <p>The HTableDescriptor contains metainfo about the HRegion's table.
  * regionName is a unique identifier for this HRegion. (startKey, endKey]
  * defines the keyspace for this HRegion.
@@ -111,8 +111,8 @@ public class HRegion implements HConstan
   static final String SPLITDIR = "splits";
   static final String MERGEDIR = "merges";
   final AtomicBoolean closed = new AtomicBoolean(false);
-  /* Closing can take some time; use the closing flag if there is stuff we don't 
-   * want to do while in closing state; e.g. like offer this region up to the 
+  /* Closing can take some time; use the closing flag if there is stuff we don't
+   * want to do while in closing state; e.g. like offer this region up to the
    * master as a region to close if the carrying regionserver is overloaded.
    * Once set, it is never cleared.
    */
@@ -126,13 +126,13 @@ public class HRegion implements HConstan
     new ConcurrentHashMap<Integer, byte []>();
   protected final Map<byte [], Store> stores =
     new ConcurrentSkipListMap<byte [], Store>(Bytes.BYTES_RAWCOMPARATOR);
-  
+
   //These variable are just used for getting data out of the region, to test on
   //client side
   // private int numStores = 0;
   // private int [] storeSize = null;
   // private byte [] name = null;
-  
+
   final AtomicLong memstoreSize = new AtomicLong(0);
 
   // This is the table subdirectory.
@@ -176,7 +176,7 @@ public class HRegion implements HConstan
       this.writesEnabled = !onOff;
       this.readOnly = onOff;
     }
-    
+
     boolean isReadOnly() {
       return this.readOnly;
     }
@@ -196,7 +196,7 @@ public class HRegion implements HConstan
   // Used to guard splits and closes
   private final ReentrantReadWriteLock splitsAndClosesLock =
     new ReentrantReadWriteLock();
-  private final ReentrantReadWriteLock newScannerLock = 
+  private final ReentrantReadWriteLock newScannerLock =
     new ReentrantReadWriteLock();
 
   // Stop updates lock
@@ -242,7 +242,7 @@ public class HRegion implements HConstan
     this.regionInfo = null;
     this.threadWakeFrequency = 0L;
   }
-  
+
   /**
    * HRegion constructor.  This constructor should only be used for testing and
    * extensions.  Instances of HRegion should be instantiated with the
@@ -257,7 +257,7 @@ public class HRegion implements HConstan
    * appropriate log info for this HRegion. If there is a previous log file
    * (implying that the HRegion has been written-to before), then read it from
    * the supplied path.
-   * @param fs is the filesystem.  
+   * @param fs is the filesystem.
    * @param conf is global configuration settings.
    * @param regionInfo - HRegionInfo that describes the region
    * is new), then read them from the supplied path.
@@ -299,7 +299,7 @@ public class HRegion implements HConstan
   /**
    * Initialize this region and get it ready to roll.
    * Called after construction.
-   * 
+   *
    * @param initialFiles path
    * @param reporter progressable
    * @throws IOException e
@@ -316,7 +316,7 @@ public class HRegion implements HConstan
     // Load in all the HStores.
     long maxSeqId = -1;
     long minSeqIdToRecover = Integer.MAX_VALUE;
-    
+
     for (HColumnDescriptor c : this.regionInfo.getTableDesc().getFamilies()) {
       Store store = instantiateHStore(this.basedir, c, oldLogFile, reporter);
       this.stores.put(c.getName(), store);
@@ -324,7 +324,7 @@ public class HRegion implements HConstan
       if (storeSeqId > maxSeqId) {
         maxSeqId = storeSeqId;
       }
-      
+
       long storeSeqIdBeforeRecovery = store.getMaxSeqIdBeforeLogRecovery();
       if (storeSeqIdBeforeRecovery < minSeqIdToRecover) {
         minSeqIdToRecover = storeSeqIdBeforeRecovery;
@@ -339,7 +339,7 @@ public class HRegion implements HConstan
       }
       fs.delete(oldLogFile, false);
     }
-    
+
     // Add one to the current maximum sequence id so new edits are beyond.
     this.minSequenceId = maxSeqId + 1;
 
@@ -398,7 +398,7 @@ public class HRegion implements HConstan
     // Name of this file has two leading and trailing underscores so it doesn't
     // clash w/ a store/family name.  There is possibility, but assumption is
     // that its slim (don't want to use control character in filename because
-    // 
+    //
     Path regioninfo = new Path(this.regiondir, REGIONINFO_FILE);
     if (this.fs.exists(regioninfo) &&
         this.fs.getFileStatus(regioninfo).getLen() > 0) {
@@ -422,7 +422,7 @@ public class HRegion implements HConstan
   long getMinSequenceId() {
     return this.minSequenceId;
   }
-  
+
   /** @return a HRegionInfo object for this region */
   public HRegionInfo getRegionInfo() {
     return this.regionInfo;
@@ -432,7 +432,7 @@ public class HRegion implements HConstan
   public boolean isClosed() {
     return this.closed.get();
   }
-  
+
   /**
    * @return True if closing process has started.
    */
@@ -441,16 +441,16 @@ public class HRegion implements HConstan
   }
 
   /**
-   * Close down this HRegion.  Flush the cache, shut down each HStore, don't 
+   * Close down this HRegion.  Flush the cache, shut down each HStore, don't
    * service any more calls.
    *
-   * <p>This method could take some time to execute, so don't call it from a 
+   * <p>This method could take some time to execute, so don't call it from a
    * time-sensitive thread.
-   * 
-   * @return Vector of all the storage files that the HRegion's component 
+   *
+   * @return Vector of all the storage files that the HRegion's component
    * HStores make use of.  It's a list of all HStoreFile objects. Returns empty
    * vector if already closed and null if judged that it should not close.
-   * 
+   *
    * @throws IOException e
    */
   public List<StoreFile> close() throws IOException {
@@ -461,14 +461,14 @@ public class HRegion implements HConstan
    * Close down this HRegion.  Flush the cache unless abort parameter is true,
    * Shut down each HStore, don't service any more calls.
    *
-   * This method could take some time to execute, so don't call it from a 
+   * This method could take some time to execute, so don't call it from a
    * time-sensitive thread.
-   * 
+   *
    * @param abort true if server is aborting (only during testing)
-   * @return Vector of all the storage files that the HRegion's component 
+   * @return Vector of all the storage files that the HRegion's component
    * HStores make use of.  It's a list of HStoreFile objects.  Can be null if
    * we are not to close at this time or we are already closed.
-   * 
+   *
    * @throws IOException e
    */
   public List<StoreFile> close(final boolean abort) throws IOException {
@@ -516,12 +516,12 @@ public class HRegion implements HConstan
           // outstanding updates.
           waitOnRowLocks();
           LOG.debug("No more row locks outstanding on region " + this);
-  
+
           // Don't flush the cache if we are aborting
           if (!abort) {
             internalFlushcache();
           }
-  
+
           List<StoreFile> result = new ArrayList<StoreFile>();
           for (Store store: stores.values()) {
             result.addAll(store.close());
@@ -606,11 +606,11 @@ public class HRegion implements HConstan
   public long getLastFlushTime() {
     return this.lastFlushTime;
   }
-  
+
   //////////////////////////////////////////////////////////////////////////////
-  // HRegion maintenance.  
+  // HRegion maintenance.
   //
-  // These methods are meant to be called periodically by the HRegionServer for 
+  // These methods are meant to be called periodically by the HRegionServer for
   // upkeep.
   //////////////////////////////////////////////////////////////////////////////
 
@@ -732,7 +732,7 @@ public class HRegion implements HConstan
   protected void prepareToSplit() {
     // nothing
   }
-  
+
   /*
    * @param dir
    * @return compaction directory for the passed in <code>dir</code>
@@ -749,7 +749,7 @@ public class HRegion implements HConstan
   private void doRegionCompactionPrep() throws IOException {
     doRegionCompactionCleanup();
   }
-  
+
   /*
    * Removes the compaction directory for this Store.
    * @throws IOException
@@ -770,13 +770,13 @@ public class HRegion implements HConstan
    * Called by compaction thread and after region is opened to compact the
    * HStores if necessary.
    *
-   * <p>This operation could block for a long time, so don't call it from a 
+   * <p>This operation could block for a long time, so don't call it from a
    * time-sensitive thread.
    *
    * Note that no locking is necessary at this level because compaction only
    * conflicts with a region split, and that cannot happen because the region
    * server does them sequentially and not in parallel.
-   * 
+   *
    * @return mid key if split is needed
    * @throws IOException e
    */
@@ -790,13 +790,13 @@ public class HRegion implements HConstan
    * Called by compaction thread and after region is opened to compact the
    * HStores if necessary.
    *
-   * <p>This operation could block for a long time, so don't call it from a 
+   * <p>This operation could block for a long time, so don't call it from a
    * time-sensitive thread.
    *
    * Note that no locking is necessary at this level because compaction only
    * conflicts with a region split, and that cannot happen because the region
    * server does them sequentially and not in parallel.
-   * 
+   *
    * @param majorCompaction True to force a major compaction regardless of thresholds
    * @return split row if split is needed
    * @throws IOException e
@@ -824,7 +824,7 @@ public class HRegion implements HConstan
               return splitRow;
           }
         }
-        LOG.info("Starting" + (majorCompaction? " major " : " ") + 
+        LOG.info("Starting" + (majorCompaction? " major " : " ") +
             "compaction on region " + this);
         long startTime = System.currentTimeMillis();
         doRegionCompactionPrep();
@@ -837,7 +837,7 @@ public class HRegion implements HConstan
           }
         }
         doRegionCompactionCleanup();
-        String timeTaken = StringUtils.formatTimeDiff(System.currentTimeMillis(), 
+        String timeTaken = StringUtils.formatTimeDiff(System.currentTimeMillis(),
             startTime);
         LOG.info("compaction completed on region " + this + " in " + timeTaken);
       } finally {
@@ -854,7 +854,7 @@ public class HRegion implements HConstan
 
   /**
    * Flush the cache.
-   * 
+   *
    * When this method is called the cache will be flushed unless:
    * <ol>
    *   <li>the cache is empty</li>
@@ -863,11 +863,11 @@ public class HRegion implements HConstan
    *   <li>writes are disabled</li>
    * </ol>
    *
-   * <p>This method may block for some time, so it should not be called from a 
+   * <p>This method may block for some time, so it should not be called from a
    * time-sensitive thread.
-   * 
+   *
    * @return true if cache was flushed
-   * 
+   *
    * @throws IOException general io exceptions
    * @throws DroppedSnapshotException Thrown when replay of hlog is required
    * because a Snapshot was not properly persisted.
@@ -886,7 +886,7 @@ public class HRegion implements HConstan
               writestate.flushing + ", writesEnabled=" +
               writestate.writesEnabled);
         }
-        return false;  
+        return false;
       }
     }
     try {
@@ -915,25 +915,25 @@ public class HRegion implements HConstan
    * flushed. (That way, during recovery, we know when we can rely on the
    * on-disk flushed structures and when we have to recover the memstore from
    * the log.)
-   * 
+   *
    * <p>So, we have a three-step process:
-   * 
+   *
    * <ul><li>A. Flush the memstore to the on-disk stores, noting the current
    * sequence ID for the log.<li>
-   * 
+   *
    * <li>B. Write a FLUSHCACHE-COMPLETE message to the log, using the sequence
    * ID that was current at the time of memstore-flush.</li>
-   * 
+   *
    * <li>C. Get rid of the memstore structures that are now redundant, as
    * they've been flushed to the on-disk HStores.</li>
    * </ul>
    * <p>This method is protected, but can be accessed via several public
    * routes.
-   * 
+   *
    * <p> This method may block for some time.
-   * 
+   *
    * @return true if the region needs compacting
-   * 
+   *
    * @throws IOException general io exceptions
    * @throws DroppedSnapshotException Thrown when replay of hlog is required
    * because a Snapshot was not properly persisted.
@@ -1059,7 +1059,7 @@ public class HRegion implements HConstan
 
     // B.  Write a FLUSHCACHE-COMPLETE message to the log.
     //     This tells future readers that the HStores were emitted correctly,
-    //     and that all updates to the log for this regionName that have lower 
+    //     and that all updates to the log for this regionName that have lower
     //     log-sequence-ids can be safely ignored.
     this.log.completeCacheFlush(getRegionName(),
         regionInfo.getTableDesc().getName(), completeSequenceId);
@@ -1069,7 +1069,7 @@ public class HRegion implements HConstan
     synchronized (this) {
       notifyAll();
     }
-    
+
     if (LOG.isDebugEnabled()) {
       long now = System.currentTimeMillis();
       LOG.debug("Finished memstore flush of ~" +
@@ -1098,23 +1098,23 @@ public class HRegion implements HConstan
    /**
    * Get the sequence number to be associated with this cache flush. Used by
    * TransactionalRegion to not complete pending transactions.
-   * 
-   * 
+   *
+   *
    * @param currentSequenceId
    * @return sequence id to complete the cache flush with
-   */ 
+   */
   protected long getCompleteCacheFlushSequenceId(long currentSequenceId) {
     return currentSequenceId;
   }
-  
+
   //////////////////////////////////////////////////////////////////////////////
   // get() methods for client use.
   //////////////////////////////////////////////////////////////////////////////
   /**
-   * Return all the data for the row that matches <i>row</i> exactly, 
-   * or the one that immediately preceeds it, at or immediately before 
+   * Return all the data for the row that matches <i>row</i> exactly,
+   * or the one that immediately preceeds it, at or immediately before
    * <i>ts</i>.
-   * 
+   *
    * @param row row key
    * @return map of values
    * @throws IOException
@@ -1125,10 +1125,10 @@ public class HRegion implements HConstan
   }
 
   /**
-   * Return all the data for the row that matches <i>row</i> exactly, 
-   * or the one that immediately preceeds it, at or immediately before 
+   * Return all the data for the row that matches <i>row</i> exactly,
+   * or the one that immediately preceeds it, at or immediately before
    * <i>ts</i>.
-   * 
+   *
    * @param row row key
    * @param family column family to find on
    * @return map of values
@@ -1159,7 +1159,7 @@ public class HRegion implements HConstan
   }
 
   /**
-   * Return an iterator that scans over the HRegion, returning the indicated 
+   * Return an iterator that scans over the HRegion, returning the indicated
    * columns and rows specified by the {@link Scan}.
    * <p>
    * This Iterator must be closed by the caller.
@@ -1249,7 +1249,7 @@ public class HRegion implements HConstan
     familyMap.put(family, edits);
     delete(familyMap, writeToWAL);
   }
-  
+
   /**
    * @param familyMap
    * @param writeToWAL
@@ -1264,51 +1264,36 @@ public class HRegion implements HConstan
     ReadWriteConsistencyControl.WriteEntry w = null;
     updatesLock.readLock().lock();
     try {
-      if (writeToWAL) {
-      for (Map.Entry<byte[], List<KeyValue>> e : familyMap.entrySet()) {
-        List<KeyValue> kvs = e.getValue();
-
-          this.log.append(regionInfo.getRegionName(),
-              regionInfo.getTableDesc().getName(), kvs,
-              (regionInfo.isMetaRegion() || regionInfo.isRootRegion()), now);
-        }
-      }
 
+      for (Map.Entry<byte[], List<KeyValue>> e : familyMap.entrySet()) {
 
-      w = rwcc.beginMemstoreInsert();
-      long size = 0;
-      for (Map.Entry<byte[], List<KeyValue>> e: familyMap.entrySet()) {
-        byte [] family = e.getKey();
+        byte[] family = e.getKey();
         List<KeyValue> kvs = e.getValue();
+        Map<byte[], Integer> kvCount = new TreeMap<byte[], Integer>(Bytes.BYTES_COMPARATOR);
 
         Store store = getStore(family);
-        Map<byte[], Integer> kvCount = new TreeMap<byte[], Integer>(Bytes.BYTES_COMPARATOR);
         for (KeyValue kv: kvs) {
-          // Check if time is LATEST, change to time of most recent addition if so
-          // This is expensive.
+          //  Check if time is LATEST, change to time of most recent addition if so
+          //  This is expensive.
           if (kv.isLatestTimestamp() && kv.isDeleteType()) {
-            byte [] qual = kv.getQualifier();
+            byte[] qual = kv.getQualifier();
             if (qual == null) qual = HConstants.EMPTY_BYTE_ARRAY;
 
             Integer count = kvCount.get(qual);
             if (count == null) {
               kvCount.put(qual, 1);
             } else {
-              System.out.println("Deleting more than 1: " + (count+1));
               kvCount.put(qual, count + 1);
             }
             count = kvCount.get(qual);
 
             Get get = new Get(kv.getRow());
-            get.addColumn(family, qual);
             get.setMaxVersions(count);
+            get.addColumn(family, qual);
 
             List<KeyValue> result = get(get);
 
             if (result.size() < count) {
-              System.out.println("Result.size = " + result.size() +
-                  " which is less than count = " + count);
-              System.out.println(result);
               // Nothing to delete
               kv.updateLatestStamp(byteNow);
               continue;
@@ -1322,8 +1307,30 @@ public class HRegion implements HConstan
           } else {
             kv.updateLatestStamp(byteNow);
           }
-          kv.setMemstoreTS(w.getWriteNumber());
+        }
+      }
+
+      if (writeToWAL) {
+      for (Map.Entry<byte[], List<KeyValue>> e : familyMap.entrySet()) {
+        List<KeyValue> kvs = e.getValue();
+
+          this.log.append(regionInfo.getRegionName(),
+              regionInfo.getTableDesc().getName(), kvs,
+              (regionInfo.isMetaRegion() || regionInfo.isRootRegion()), now);
+        }
+      }
+
+
+      w = rwcc.beginMemstoreInsert();
+      long size = 0;
+      for (Map.Entry<byte[], List<KeyValue>> e: familyMap.entrySet()) {
+        byte [] family = e.getKey();
+        List<KeyValue> kvs = e.getValue();
 
+        Store store = getStore(family);
+        Map<byte[], Integer> kvCount = new TreeMap<byte[], Integer>(Bytes.BYTES_COMPARATOR);
+        for (KeyValue kv: kvs) {
+          kv.setMemstoreTS(w.getWriteNumber());
           size = this.memstoreSize.addAndGet(store.delete(kv));
         }
       }
@@ -1339,7 +1346,7 @@ public class HRegion implements HConstan
       requestFlush();
     }
   }
-  
+
   /**
    * @param put
    * @throws IOException
@@ -1347,7 +1354,7 @@ public class HRegion implements HConstan
   public void put(Put put) throws IOException {
     this.put(put, null, put.getWriteToWAL());
   }
-  
+
   /**
    * @param put
    * @param writeToWAL
@@ -1377,7 +1384,7 @@ public class HRegion implements HConstan
     checkReadOnly();
 
     // Do a rough check that we have resources to accept a write.  The check is
-    // 'rough' in that between the resource check and the call to obtain a 
+    // 'rough' in that between the resource check and the call to obtain a
     // read lock, resources may run out.  For now, the thought is that this
     // will be extremely rare; we'll deal with it when it happens.
     checkResources();
@@ -1402,7 +1409,7 @@ public class HRegion implements HConstan
   }
 
   /**
-   * 
+   *
    * @param row
    * @param family
    * @param qualifier
@@ -1414,7 +1421,7 @@ public class HRegion implements HConstan
    * @return true if the new put was execute, false otherwise
    */
   public boolean checkAndPut(byte [] row, byte [] family, byte [] qualifier,
-      byte [] expectedValue, Put put, Integer lockId, boolean writeToWAL) 
+      byte [] expectedValue, Put put, Integer lockId, boolean writeToWAL)
       throws IOException{
     checkReadOnly();
     checkResources();
@@ -1425,7 +1432,7 @@ public class HRegion implements HConstan
       get.addColumn(family, qualifier);
 
       // Lock row
-      Integer lid = getLock(lockId, get.getRow()); 
+      Integer lid = getLock(lockId, get.getRow());
       List<KeyValue> result;
 
       try {
@@ -1450,10 +1457,10 @@ public class HRegion implements HConstan
       }
     } finally {
       splitsAndClosesLock.readLock().unlock();
-    }    
+    }
   }
-      
-  
+
+
   /**
    * Checks if any stamps is Long.MAX_VALUE.  If so, sets them to now.
    * <p>
@@ -1473,10 +1480,10 @@ public class HRegion implements HConstan
     }
     return true;
   }
-  
+
 
 //  /*
-//   * Utility method to verify values length. 
+//   * Utility method to verify values length.
 //   * @param batchUpdate The update to verify
 //   * @throws IOException Thrown if a value is too long
 //   */
@@ -1484,7 +1491,7 @@ public class HRegion implements HConstan
 //  throws IOException {
 //    Map<byte[], List<KeyValue>> families = put.getFamilyMap();
 //    for(Map.Entry<byte[], List<KeyValue>> entry : families.entrySet()) {
-//      HColumnDescriptor hcd = 
+//      HColumnDescriptor hcd =
 //        this.regionInfo.getTableDesc().getFamily(entry.getKey());
 //      int maxLen = hcd.getMaxValueLength();
 //      for(KeyValue kv : entry.getValue()) {
@@ -1499,7 +1506,7 @@ public class HRegion implements HConstan
 
   /*
    * Check if resources to support an update.
-   * 
+   *
    * Here we synchronize on HRegion, a broad scoped lock.  Its appropriate
    * given we're figuring in here whether this region is able to take on
    * writes.  This is only method with a synchronize (at time of writing),
@@ -1546,7 +1553,7 @@ public class HRegion implements HConstan
     }
   }
 
-  /** 
+  /**
    * Add updates first to the hlog (if writeToWal) and then add values to memstore.
    * Warning: Assumption is caller has lock on passed in row.
    * @param familyMap
@@ -1636,7 +1643,7 @@ public class HRegion implements HConstan
     // Used by subclasses; e.g. THBase.
   }
 
-  protected Store instantiateHStore(Path baseDir, 
+  protected Store instantiateHStore(Path baseDir,
     HColumnDescriptor c, Path oldLogFile, Progressable reporter)
   throws IOException {
     return new Store(baseDir, this, c, this.fs, oldLogFile,
@@ -1651,7 +1658,7 @@ public class HRegion implements HConstan
    * TODO: Make this lookup faster.
    */
   public Store getStore(final byte [] column) {
-    return this.stores.get(column); 
+    return this.stores.get(column);
   }
 
   //////////////////////////////////////////////////////////////////////////////
@@ -1684,10 +1691,10 @@ public class HRegion implements HConstan
    * But it acts as a guard on the client; a miswritten client just can't
    * submit the name of a row and start writing to it; it must know the correct
    * lockid, which matches the lock list in memory.
-   * 
-   * <p>It would be more memory-efficient to assume a correctly-written client, 
+   *
+   * <p>It would be more memory-efficient to assume a correctly-written client,
    * which maybe we'll do in the future.
-   * 
+   *
    * @param row Name of row to lock.
    * @throws IOException
    * @return The id of the held lock.
@@ -1716,7 +1723,7 @@ public class HRegion implements HConstan
       splitsAndClosesLock.readLock().unlock();
     }
   }
-  
+
   /**
    * Used by unit tests.
    * @param lockid
@@ -1725,8 +1732,8 @@ public class HRegion implements HConstan
   byte [] getRowFromLock(final Integer lockid) {
     return locksToRows.get(lockid);
   }
-  
-  /** 
+
+  /**
    * Release the row lock!
    * @param lockid  The lock ID to release.
    */
@@ -1736,7 +1743,7 @@ public class HRegion implements HConstan
       locksToRows.notifyAll();
     }
   }
-  
+
   /**
    * See if row is currently locked.
    * @param lockid
@@ -1750,14 +1757,14 @@ public class HRegion implements HConstan
       return false;
     }
   }
-  
+
   /**
    * Returns existing row lock if found, otherwise
    * obtains a new row lock and returns it.
    * @param lockid
    * @return lockid
    */
-  private Integer getLock(Integer lockid, byte [] row) 
+  private Integer getLock(Integer lockid, byte [] row)
   throws IOException {
     Integer lid = null;
     if (lockid == null) {
@@ -1770,7 +1777,7 @@ public class HRegion implements HConstan
     }
     return lid;
   }
-  
+
   private void waitOnRowLocks() {
     synchronized (locksToRows) {
       while (this.locksToRows.size() > 0) {
@@ -1783,17 +1790,17 @@ public class HRegion implements HConstan
       }
     }
   }
-  
+
   @Override
   public boolean equals(Object o) {
     return this.hashCode() == ((HRegion)o).hashCode();
   }
-  
+
   @Override
   public int hashCode() {
     return this.regionInfo.getRegionName().hashCode();
   }
-  
+
   @Override
   public String toString() {
     return this.regionInfo.getRegionNameAsString();
@@ -1992,7 +1999,7 @@ public class HRegion implements HConstan
     }
 
     /**
-     * 
+     *
      * @param scanner to be closed
      */
     public synchronized void close(KeyValueScanner scanner) {
@@ -2001,12 +2008,12 @@ public class HRegion implements HConstan
       } catch(NullPointerException npe) {}
     }
   }
-  
+
   // Utility methods
   /**
    * A utility method to create new instances of HRegion based on the
    * {@link org.apache.hadoop.hbase.HConstants#REGION_IMPL} configuration
-   * property. 
+   * property.
    * @param basedir qualified path of directory where region should be located,
    * usually the table directory.
    * @param log The HLog is the outbound log for any updates to the HRegion
@@ -2053,7 +2060,7 @@ public class HRegion implements HConstan
    * @param rootDir Root directory for HBase instance
    * @param conf
    * @return new HRegion
-   * 
+   *
    * @throws IOException
    */
   public static HRegion createHRegion(final HRegionInfo info, final Path rootDir,
@@ -2070,7 +2077,7 @@ public class HRegion implements HConstan
     region.initialize(null, null);
     return region;
   }
-  
+
   /**
    * Convenience method to open a HRegion outside of an HRegionServer context.
    * @param info Info for region to be opened.
@@ -2081,7 +2088,7 @@ public class HRegion implements HConstan
    * up.  HRegionStore does this every time it opens a new region.
    * @param conf
    * @return new HRegion
-   * 
+   *
    * @throws IOException
    */
   public static HRegion openHRegion(final HRegionInfo info, final Path rootDir,
@@ -2102,18 +2109,18 @@ public class HRegion implements HConstan
     }
     return r;
   }
-  
+
   /**
    * Inserts a new region's meta information into the passed
    * <code>meta</code> region. Used by the HMaster bootstrap code adding
    * new table to ROOT table.
-   * 
+   *
    * @param meta META HRegion to be updated
    * @param r HRegion to add to <code>meta</code>
    *
    * @throws IOException
    */
-  public static void addRegionToMETA(HRegion meta, HRegion r) 
+  public static void addRegionToMETA(HRegion meta, HRegion r)
   throws IOException {
     meta.checkResources();
     // The row key is the region name
@@ -2135,7 +2142,7 @@ public class HRegion implements HConstan
    * Delete a region's meta information from the passed
    * <code>meta</code> region.  Removes content in the 'info' column family.
    * Does not remove region historian info.
-   * 
+   *
    * @param srvr META server to be updated
    * @param metaRegionName Meta region name
    * @param regionName HRegion to remove from <code>meta</code>
@@ -2171,7 +2178,7 @@ public class HRegion implements HConstan
     srvr.put(metaRegionName, put);
     cleanRegionInMETA(srvr, metaRegionName, info);
   }
-  
+
   /**
    * Clean COL_SERVER and COL_STARTCODE for passed <code>info</code> in
    * <code>.META.</code>
@@ -2191,7 +2198,7 @@ public class HRegion implements HConstan
 
   /**
    * Deletes all the files for a HRegion
-   * 
+   *
    * @param fs the file system object
    * @param rootdir qualified path of HBase root directory
    * @param info HRegionInfo for region to be deleted
@@ -2214,7 +2221,7 @@ public class HRegion implements HConstan
 
   /**
    * Computes the Path of the HRegion
-   * 
+   *
    * @param tabledir qualified path for table
    * @param name ENCODED region name
    * @return Path of HRegion directory
@@ -2222,10 +2229,10 @@ public class HRegion implements HConstan
   public static Path getRegionDir(final Path tabledir, final int name) {
     return new Path(tabledir, Integer.toString(name));
   }
-  
+
   /**
    * Computes the Path of the HRegion
-   * 
+   *
    * @param rootdir qualified path of HBase root directory
    * @param info HRegionInfo for the region
    * @return qualified path of region directory
@@ -2239,7 +2246,7 @@ public class HRegion implements HConstan
   /**
    * Determines if the specified row is within the row range specified by the
    * specified HRegionInfo
-   *  
+   *
    * @param info HRegionInfo that specifies the row range
    * @param row row to be checked
    * @return true if the row is within the range specified by the HRegionInfo
@@ -2253,7 +2260,7 @@ public class HRegion implements HConstan
 
   /**
    * Make the directories for a specific column family
-   * 
+   *
    * @param fs the file system
    * @param tabledir base directory where region will live (usually the table dir)
    * @param hri
@@ -2271,7 +2278,7 @@ public class HRegion implements HConstan
 
   /**
    * Merge two HRegions.  The regions must be adjacent and must not overlap.
-   * 
+   *
    * @param srcA
    * @param srcB
    * @return new merged HRegion
@@ -2303,7 +2310,7 @@ public class HRegion implements HConstan
 
   /**
    * Merge two regions whether they are adjacent or not.
-   * 
+   *
    * @param a region a
    * @param b region b
    * @return new merged region
@@ -2318,12 +2325,12 @@ public class HRegion implements HConstan
     FileSystem fs = a.getFilesystem();
 
     // Make sure each region's cache is empty
-    
+
     a.flushcache();
     b.flushcache();
-    
+
     // Compact each region so we only have one store file per family
-    
+
     a.compactStores(true);
     if (LOG.isDebugEnabled()) {
       LOG.debug("Files for region: " + a);
@@ -2334,12 +2341,12 @@ public class HRegion implements HConstan
       LOG.debug("Files for region: " + b);
       listPaths(fs, b.getRegionDir());
     }
-    
+
     HBaseConfiguration conf = a.getConf();
     HTableDescriptor tabledesc = a.getTableDesc();
     HLog log = a.getLog();
     Path basedir = a.getBaseDir();
-    // Presume both are of same region type -- i.e. both user or catalog 
+    // Presume both are of same region type -- i.e. both user or catalog
     // table regions.  This way can use comparator.
     final byte [] startKey = a.comparator.matchingRows(a.getStartKey(), 0,
           a.getStartKey().length,
@@ -2347,7 +2354,7 @@ public class HRegion implements HConstan
       b.comparator.matchingRows(b.getStartKey(), 0, b.getStartKey().length,
         EMPTY_BYTE_ARRAY, 0, EMPTY_BYTE_ARRAY.length)?
         EMPTY_BYTE_ARRAY:
-          a.comparator.compareRows(a.getStartKey(), 0, a.getStartKey().length, 
+          a.comparator.compareRows(a.getStartKey(), 0, a.getStartKey().length,
           b.getStartKey(), 0, b.getStartKey().length) <= 0?
         a.getStartKey(): b.getStartKey();
     final byte [] endKey = a.comparator.matchingRows(a.getEndKey(), 0,
@@ -2361,7 +2368,7 @@ public class HRegion implements HConstan
 
     HRegionInfo newRegionInfo = new HRegionInfo(tabledesc, startKey, endKey);
     LOG.info("Creating new region " + newRegionInfo.toString());
-    int encodedName = newRegionInfo.getEncodedName(); 
+    int encodedName = newRegionInfo.getEncodedName();
     Path newRegionDir = HRegion.getRegionDir(a.getBaseDir(), encodedName);
     if(fs.exists(newRegionDir)) {
       throw new IOException("Cannot merge; target file collision at " +
@@ -2421,7 +2428,7 @@ public class HRegion implements HConstan
   }
 
   /*
-   * Fills a map with a vector of store files keyed by column family. 
+   * Fills a map with a vector of store files keyed by column family.
    * @param byFamily Map to fill.
    * @param storeFiles Store files to process.
    * @param family
@@ -2443,7 +2450,7 @@ public class HRegion implements HConstan
 
   /**
    * @return True if needs a mojor compaction.
-   * @throws IOException 
+   * @throws IOException
    */
   boolean isMajorCompaction() throws IOException {
     for (Store store: this.stores.values()) {
@@ -2456,7 +2463,7 @@ public class HRegion implements HConstan
 
   /*
    * List the files under the specified directory
-   * 
+   *
    * @param fs
    * @param dir
    * @throws IOException
@@ -2479,7 +2486,7 @@ public class HRegion implements HConstan
     }
   }
 
-  
+
   //
   // HBASE-880
   //
@@ -2523,7 +2530,7 @@ public class HRegion implements HConstan
   }
 
   /**
-   * 
+   *
    * @param row
    * @param family
    * @param qualifier
@@ -2592,13 +2599,13 @@ public class HRegion implements HConstan
 
     return result;
   }
-    
-  
+
+
   //
   // New HBASE-880 Helpers
   //
-  
-  private void checkFamily(final byte [] family) 
+
+  private void checkFamily(final byte [] family)
   throws NoSuchColumnFamilyException {
     if(!regionInfo.getTableDesc().hasFamily(family)) {
       throw new NoSuchColumnFamilyException("Column family " +
@@ -2610,17 +2617,17 @@ public class HRegion implements HConstan
   public static final long FIXED_OVERHEAD = ClassSize.align(
       (5 * Bytes.SIZEOF_LONG) + Bytes.SIZEOF_BOOLEAN +
       (20 * ClassSize.REFERENCE) + ClassSize.OBJECT);
-  
+
   public static final long DEEP_OVERHEAD = ClassSize.align(FIXED_OVERHEAD +
-      ClassSize.OBJECT + (2 * ClassSize.ATOMIC_BOOLEAN) + 
+      ClassSize.OBJECT + (2 * ClassSize.ATOMIC_BOOLEAN) +
       ClassSize.ATOMIC_LONG + ClassSize.ATOMIC_INTEGER +
-      ClassSize.CONCURRENT_HASHMAP + 
-      (16 * ClassSize.CONCURRENT_HASHMAP_ENTRY) + 
+      ClassSize.CONCURRENT_HASHMAP +
+      (16 * ClassSize.CONCURRENT_HASHMAP_ENTRY) +
       (16 * ClassSize.CONCURRENT_HASHMAP_SEGMENT) +
       ClassSize.CONCURRENT_SKIPLISTMAP + ClassSize.CONCURRENT_SKIPLISTMAP_ENTRY +
       ClassSize.align(ClassSize.OBJECT + (5 * Bytes.SIZEOF_BOOLEAN)) +
       (3 * ClassSize.REENTRANT_LOCK));
-  
+
   @Override
   public long heapSize() {
     long heapSize = DEEP_OVERHEAD;
@@ -2730,7 +2737,7 @@ public class HRegion implements HConstan
    *   ./bin/hbase org.apache.hadoop.hbase.regionserver.HRegion
    * </pre>
    * @param args
-   * @throws IOException 
+   * @throws IOException
    */
   public static void main(String[] args) throws IOException {
     if (args.length < 1) {