You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hbase.apache.org by ji...@apache.org on 2008/06/21 04:52:35 UTC

svn commit: r670124 - in /hadoop/hbase/trunk: ./ src/java/org/apache/hadoop/hbase/regionserver/ src/test/org/apache/hadoop/hbase/ src/test/org/apache/hadoop/hbase/util/

Author: jimk
Date: Fri Jun 20 19:52:35 2008
New Revision: 670124

URL: http://svn.apache.org/viewvc?rev=670124&view=rev
Log:
HBASE-613 Timestamp-anchored scanning fails to find all records
HBASE-681 NPE in Memcache

HAbstractScanner
- remove HAbstactScanner.iterator() - iterator is not a method on InternalScanner

HRegion
- make getScanner more efficient by iterating only once to find the stores we need to scan
- only pass columns relevant to a store to a HStoreScanner
- remove HScanner.iterator() - iterator is not a method on InternalScanner

Memcache, MemcacheScanner
- Fix NPE in Memcache
- never return HConstants.LATEST_TIMESTAMP as the timestamp value for a row. Instead use the largest timestamp from the cells being returned. This allows a scanner to determine a timestamp that can be used to fetch the same data again should new versions be inserted later.

StoreFileScanner
- getNextViableRow would find a row that matched the row key, but did not consider the requested timestamp. Now if the row it finds has a timestamp greater than the one desired it advances to determine if a row with a timestamp less than or equal to the requested one exists since timestamps are sorted descending.
- removed an unnecessary else

testScanMultipleVersions
- Test program that fails on current trunk but passes when this patch is applied.

Added:
    hadoop/hbase/trunk/src/test/org/apache/hadoop/hbase/TestScanMultipleVersions.java
Modified:
    hadoop/hbase/trunk/CHANGES.txt
    hadoop/hbase/trunk/src/java/org/apache/hadoop/hbase/regionserver/HAbstractScanner.java
    hadoop/hbase/trunk/src/java/org/apache/hadoop/hbase/regionserver/HRegion.java
    hadoop/hbase/trunk/src/java/org/apache/hadoop/hbase/regionserver/Memcache.java
    hadoop/hbase/trunk/src/java/org/apache/hadoop/hbase/regionserver/StoreFileScanner.java
    hadoop/hbase/trunk/src/test/org/apache/hadoop/hbase/AbstractMergeTestBase.java
    hadoop/hbase/trunk/src/test/org/apache/hadoop/hbase/HBaseTestCase.java
    hadoop/hbase/trunk/src/test/org/apache/hadoop/hbase/MultiRegionTable.java
    hadoop/hbase/trunk/src/test/org/apache/hadoop/hbase/TestRegionRebalancing.java
    hadoop/hbase/trunk/src/test/org/apache/hadoop/hbase/util/TestMergeTool.java

Modified: hadoop/hbase/trunk/CHANGES.txt
URL: http://svn.apache.org/viewvc/hadoop/hbase/trunk/CHANGES.txt?rev=670124&r1=670123&r2=670124&view=diff
==============================================================================
--- hadoop/hbase/trunk/CHANGES.txt (original)
+++ hadoop/hbase/trunk/CHANGES.txt Fri Jun 20 19:52:35 2008
@@ -62,6 +62,9 @@
                (Rong-En Fan via Stack)
    HBASE-699   Fix TestMigrate up on Hudson
    HBASE-615   Region balancer oscillates during cluster startup
+   HBASE-613   Timestamp-anchored scanning fails to find all records
+   HBASE-681   NPE in Memcache
+   
    
   IMPROVEMENTS
    HBASE-559   MR example job to count table rows

Modified: hadoop/hbase/trunk/src/java/org/apache/hadoop/hbase/regionserver/HAbstractScanner.java
URL: http://svn.apache.org/viewvc/hadoop/hbase/trunk/src/java/org/apache/hadoop/hbase/regionserver/HAbstractScanner.java?rev=670124&r1=670123&r2=670124&view=diff
==============================================================================
--- hadoop/hbase/trunk/src/java/org/apache/hadoop/hbase/regionserver/HAbstractScanner.java (original)
+++ hadoop/hbase/trunk/src/java/org/apache/hadoop/hbase/regionserver/HAbstractScanner.java Fri Jun 20 19:52:35 2008
@@ -21,11 +21,9 @@
 
 import java.io.IOException;
 import java.util.HashMap;
-import java.util.Iterator;
 import java.util.Map;
 import java.util.SortedMap;
 import java.util.Vector;
-import java.util.Map.Entry;
 import java.util.regex.Pattern;
 
 import org.apache.commons.logging.Log;
@@ -183,12 +181,9 @@
     return this.multipleMatchers;
   }
 
+  /** {@inheritDoc} */
   public abstract boolean next(HStoreKey key,
-    SortedMap<byte [], byte []> results)
+      SortedMap<byte [], byte []> results)
   throws IOException;
   
-  public Iterator<Entry<HStoreKey, SortedMap<byte [], byte[]>>> iterator() {
-    throw new UnsupportedOperationException("Unimplemented serverside. " +
-      "next(HStoreKey, StortedMap(...) is more efficient");
-  }
 }

Modified: hadoop/hbase/trunk/src/java/org/apache/hadoop/hbase/regionserver/HRegion.java
URL: http://svn.apache.org/viewvc/hadoop/hbase/trunk/src/java/org/apache/hadoop/hbase/regionserver/HRegion.java?rev=670124&r1=670123&r2=670124&view=diff
==============================================================================
--- hadoop/hbase/trunk/src/java/org/apache/hadoop/hbase/regionserver/HRegion.java (original)
+++ hadoop/hbase/trunk/src/java/org/apache/hadoop/hbase/regionserver/HRegion.java Fri Jun 20 19:52:35 2008
@@ -23,7 +23,7 @@
 import java.io.UnsupportedEncodingException;
 import java.util.ArrayList;
 import java.util.Collection;
-import java.util.Iterator;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Random;
@@ -31,7 +31,6 @@
 import java.util.SortedMap;
 import java.util.TreeMap;
 import java.util.TreeSet;
-import java.util.Map.Entry;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicInteger;
@@ -64,7 +63,6 @@
 import org.apache.hadoop.hbase.util.Bytes;
 import org.apache.hadoop.hbase.util.FSUtils;
 import org.apache.hadoop.hbase.util.Writables;
-import org.apache.hadoop.io.Text;
 import org.apache.hadoop.io.WritableUtils;
 import org.apache.hadoop.util.Progressable;
 import org.apache.hadoop.util.StringUtils;
@@ -1268,20 +1266,15 @@
       if (this.closed.get()) {
         throw new IOException("Region " + this + " closed");
       }
-      TreeSet<byte []> families = new TreeSet<byte []>(Bytes.BYTES_COMPARATOR);
+      HashSet<HStore> storeSet = new HashSet<HStore>();
       for (int i = 0; i < cols.length; i++) {
-        families.add(HStoreKey.getFamily(cols[i]));
-      }
-      List<HStore> storelist = new ArrayList<HStore>();
-      for (byte [] family: families) {
-        HStore s = stores.get(Bytes.mapKey(family));
-        if (s == null) {
-          continue;
+        HStore s = stores.get(Bytes.mapKey(HStoreKey.getFamily(cols[i])));
+        if (s != null) {
+          storeSet.add(s);
         }
-        storelist.add(s);
       }
       return new HScanner(cols, firstRow, timestamp,
-        storelist.toArray(new HStore [storelist.size()]), filter);
+        storeSet.toArray(new HStore [storeSet.size()]), filter);
     } finally {
       splitsAndClosesLock.readLock().unlock();
     }
@@ -1750,15 +1743,26 @@
       this.scanners = new InternalScanner[stores.length];
       try {
         for (int i = 0; i < stores.length; i++) {
-          // TODO: The cols passed in here can include columns from other
-          // stores; add filter so only pertinent columns are passed.
-          //
-          // Also, if more than one store involved, need to replicate filters.
-          // At least WhileMatchRowFilter will mess up the scan if only
-          // one shared across many rows. See HADOOP-2467.
-          scanners[i] = stores[i].getScanner(timestamp, cols, firstRow,
-            filter != null ?
-              (RowFilterInterface)WritableUtils.clone(filter, conf) : filter);
+          
+          // Only pass relevant columns to each store
+          
+          List<byte[]> columns = new ArrayList<byte[]>();
+          for (int j = 0; j < cols.length; j++) {
+            if (Bytes.equals(HStoreKey.getFamily(cols[j]),
+                stores[i].getFamily().getName())) {
+              columns.add(cols[j]);
+            }
+          }
+
+          RowFilterInterface f = filter;
+          if (f != null) {
+            // Need to replicate filters.
+            // At least WhileMatchRowFilter will mess up the scan if only
+            // one shared across many rows. See HADOOP-2467.
+            f = (RowFilterInterface)WritableUtils.clone(filter, conf);
+          }
+          scanners[i] = stores[i].getScanner(timestamp,
+              columns.toArray(new byte[columns.size()][]), firstRow, f);
         }
       } catch (IOException e) {
         for (int i = 0; i < this.scanners.length; i++) {
@@ -1928,14 +1932,6 @@
       }
     }
 
-    /**
-     * @return an iterator for the scanner
-     */
-    public Iterator<Entry<HStoreKey, SortedMap<Text, byte[]>>> iterator() {
-      throw new UnsupportedOperationException("Unimplemented serverside. " +
-        "next(HStoreKey, StortedMap(...) is more efficient");
-    }
-    
     /** {@inheritDoc} */
     public boolean isWildcardScanner() {
       throw new UnsupportedOperationException("Unimplemented on HScanner");

Modified: hadoop/hbase/trunk/src/java/org/apache/hadoop/hbase/regionserver/Memcache.java
URL: http://svn.apache.org/viewvc/hadoop/hbase/trunk/src/java/org/apache/hadoop/hbase/regionserver/Memcache.java?rev=670124&r1=670123&r2=670124&view=diff
==============================================================================
--- hadoop/hbase/trunk/src/java/org/apache/hadoop/hbase/regionserver/Memcache.java (original)
+++ hadoop/hbase/trunk/src/java/org/apache/hadoop/hbase/regionserver/Memcache.java Fri Jun 20 19:52:35 2008
@@ -584,7 +584,7 @@
       HStoreKey key = es.getKey();
   
       // if there's no column name, then compare rows and timestamps
-      if (origin.getColumn().length == 0) {
+      if (origin.getColumn() != null && origin.getColumn().length == 0) {
         // if the current and origin row don't match, then we can jump
         // out of the loop entirely.
         if (!Bytes.equals(key.getRow(), origin.getRow())) {
@@ -697,6 +697,7 @@
       if (results.size() > 0) {
         results.clear();
       }
+      long latestTimestamp = -1;
       while (results.size() <= 0 && this.currentRow != null) {
         if (deletes.size() > 0) {
           deletes.clear();
@@ -723,11 +724,23 @@
               continue;
             }
           }
+          // We should never return HConstants.LATEST_TIMESTAMP as the time for
+          // the row. As a compromise, we return the largest timestamp for the
+          // entries that we find that match.
+          if (c.getTimestamp() != HConstants.LATEST_TIMESTAMP &&
+              c.getTimestamp() > latestTimestamp) {
+            latestTimestamp = c.getTimestamp();
+          }
           results.put(column, c.getValue());
         }
         this.currentRow = getNextRow(this.currentRow);
 
       }
+      // Set the timestamp to the largest one for the row if we would otherwise
+      // return HConstants.LATEST_TIMESTAMP
+      if (key.getTimestamp() == HConstants.LATEST_TIMESTAMP) {
+        key.setVersion(latestTimestamp);
+      }
       return results.size() > 0;
     }
 

Modified: hadoop/hbase/trunk/src/java/org/apache/hadoop/hbase/regionserver/StoreFileScanner.java
URL: http://svn.apache.org/viewvc/hadoop/hbase/trunk/src/java/org/apache/hadoop/hbase/regionserver/StoreFileScanner.java?rev=670124&r1=670123&r2=670124&view=diff
==============================================================================
--- hadoop/hbase/trunk/src/java/org/apache/hadoop/hbase/regionserver/StoreFileScanner.java (original)
+++ hadoop/hbase/trunk/src/java/org/apache/hadoop/hbase/regionserver/StoreFileScanner.java Fri Jun 20 19:52:35 2008
@@ -49,6 +49,13 @@
   // Used around replacement of Readers if they change while we're scanning.
   private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
   
+  /**
+   * @param store
+   * @param timestamp
+   * @param targetCols
+   * @param firstRow
+   * @throws IOException
+   */
   public StoreFileScanner(final HStore store, final long timestamp,
     final byte [][] targetCols, final byte [] firstRow)
   throws IOException {
@@ -209,7 +216,7 @@
       return this.ts;
     }
   }
-  
+
   /*
    * @return An instance of <code>ViableRow</code>
    * @throws IOException
@@ -221,9 +228,21 @@
     long now = System.currentTimeMillis();
     long ttl = store.ttl;
     for(int i = 0; i < keys.length; i++) {
+      // The first key that we find that matches may have a timestamp greater
+      // than the one we're looking for. We have to advance to see if there
+      // is an older version present, since timestamps are sorted descending
+      while (keys[i] != null &&
+          keys[i].getTimestamp() > this.timestamp &&
+          columnMatch(i) &&
+          getNext(i)) {
+        if (columnMatch(i)) {
+          break;
+        }
+      }
       if((keys[i] != null)
-          && (columnMatch(i))
-          && (keys[i].getTimestamp() <= this.timestamp)
+          // If we get here and keys[i] is not null, we already know that the
+          // column matches and the timestamp of the row is less than or equal
+          // to this.timestamp, so we do not need to test that here
           && ((viableRow == null)
               || (Bytes.compareTo(keys[i].getRow(), viableRow) < 0)
               || ((Bytes.compareTo(keys[i].getRow(), viableRow) == 0)
@@ -293,10 +312,9 @@
           vals[i] = ibw.get();
           result = true;
           break;
-        } else {
-          if (LOG.isDebugEnabled()) {
-            LOG.debug("getNext: " + keys[i] + ": expired, skipped");
-          }
+        }
+        if (LOG.isDebugEnabled()) {
+          LOG.debug("getNext: " + keys[i] + ": expired, skipped");
         }
       }
     }
@@ -343,6 +361,8 @@
   }
 
   // Implementation of ChangedReadersObserver
+  
+  /** {@inheritDoc} */
   public void updateReaders() throws IOException {
     this.lock.writeLock().lock();
     try {

Modified: hadoop/hbase/trunk/src/test/org/apache/hadoop/hbase/AbstractMergeTestBase.java
URL: http://svn.apache.org/viewvc/hadoop/hbase/trunk/src/test/org/apache/hadoop/hbase/AbstractMergeTestBase.java?rev=670124&r1=670123&r2=670124&view=diff
==============================================================================
--- hadoop/hbase/trunk/src/test/org/apache/hadoop/hbase/AbstractMergeTestBase.java (original)
+++ hadoop/hbase/trunk/src/test/org/apache/hadoop/hbase/AbstractMergeTestBase.java Fri Jun 20 19:52:35 2008
@@ -99,21 +99,14 @@
     
     // Now create the root and meta regions and insert the data regions
     // created above into the meta
-    
-    HRegion root = HRegion.createHRegion(HRegionInfo.ROOT_REGIONINFO,
-      testDir, this.conf);
-    HRegion meta = HRegion.createHRegion(HRegionInfo.FIRST_META_REGIONINFO,
-      testDir, this.conf);
-    HRegion.addRegionToMETA(root, meta);
+
+    createRootAndMetaRegions();
     
     for(int i = 0; i < regions.length; i++) {
       HRegion.addRegionToMETA(meta, regions[i]);
     }
-    
-    root.close();
-    root.getLog().closeAndDelete();
-    meta.close();
-    meta.getLog().closeAndDelete();
+
+    closeRootAndMeta();
   }
 
   private HRegion createAregion(byte [] startKey, byte [] endKey, int firstRow,

Modified: hadoop/hbase/trunk/src/test/org/apache/hadoop/hbase/HBaseTestCase.java
URL: http://svn.apache.org/viewvc/hadoop/hbase/trunk/src/test/org/apache/hadoop/hbase/HBaseTestCase.java?rev=670124&r1=670123&r2=670124&view=diff
==============================================================================
--- hadoop/hbase/trunk/src/test/org/apache/hadoop/hbase/HBaseTestCase.java (original)
+++ hadoop/hbase/trunk/src/test/org/apache/hadoop/hbase/HBaseTestCase.java Fri Jun 20 19:52:35 2008
@@ -60,6 +60,8 @@
   private boolean localfs = false;
   protected Path testDir = null;
   protected FileSystem fs = null;
+  protected HRegion root = null;
+  protected HRegion meta = null;
   protected static final char FIRST_CHAR = 'a';
   protected static final char LAST_CHAR = 'z';
   protected static final String PUNCTUATION = "~`@#$%^&*()-_+=:;',.<>/?[]{}|";
@@ -626,4 +628,22 @@
       }
     }
   }
+  
+  protected void createRootAndMetaRegions() throws IOException {
+    root = HRegion.createHRegion(HRegionInfo.ROOT_REGIONINFO, testDir, conf);
+    meta = HRegion.createHRegion(HRegionInfo.FIRST_META_REGIONINFO, testDir, 
+        conf);
+    HRegion.addRegionToMETA(root, meta);
+  }
+  
+  protected void closeRootAndMeta() throws IOException {
+    if (meta != null) {
+      meta.close();
+      meta.getLog().closeAndDelete();
+    }
+    if (root != null) {
+      root.close();
+      root.getLog().closeAndDelete();
+    }
+  }
 }

Modified: hadoop/hbase/trunk/src/test/org/apache/hadoop/hbase/MultiRegionTable.java
URL: http://svn.apache.org/viewvc/hadoop/hbase/trunk/src/test/org/apache/hadoop/hbase/MultiRegionTable.java?rev=670124&r1=670123&r2=670124&view=diff
==============================================================================
--- hadoop/hbase/trunk/src/test/org/apache/hadoop/hbase/MultiRegionTable.java (original)
+++ hadoop/hbase/trunk/src/test/org/apache/hadoop/hbase/MultiRegionTable.java Fri Jun 20 19:52:35 2008
@@ -85,16 +85,14 @@
 
       // Now create the root and meta regions and insert the data regions
       // created above into the meta
-      HRegion root = HRegion.createHRegion(HRegionInfo.ROOT_REGIONINFO,
-          testDir, this.conf);
-      HRegion meta = HRegion.createHRegion(HRegionInfo.FIRST_META_REGIONINFO,
-          testDir, this.conf);
-      HRegion.addRegionToMETA(root, meta);
+
+      createRootAndMetaRegions();
+
       for(int i = 0; i < regions.length; i++) {
         HRegion.addRegionToMETA(meta, regions[i]);
       }
-      closeRegionAndDeleteLog(root);
-      closeRegionAndDeleteLog(meta);
+      
+      closeRootAndMeta();
     } catch (Exception e) {
       shutdownDfs(dfsCluster);
       throw e;

Modified: hadoop/hbase/trunk/src/test/org/apache/hadoop/hbase/TestRegionRebalancing.java
URL: http://svn.apache.org/viewvc/hadoop/hbase/trunk/src/test/org/apache/hadoop/hbase/TestRegionRebalancing.java?rev=670124&r1=670123&r2=670124&view=diff
==============================================================================
--- hadoop/hbase/trunk/src/test/org/apache/hadoop/hbase/TestRegionRebalancing.java (original)
+++ hadoop/hbase/trunk/src/test/org/apache/hadoop/hbase/TestRegionRebalancing.java Fri Jun 20 19:52:35 2008
@@ -84,20 +84,13 @@
     // Now create the root and meta regions and insert the data regions
     // created above into the meta
     
-    HRegion root = HRegion.createHRegion(HRegionInfo.ROOT_REGIONINFO,
-      testDir, conf);
-    HRegion meta = HRegion.createHRegion(HRegionInfo.FIRST_META_REGIONINFO,
-      testDir, conf);
-    HRegion.addRegionToMETA(root, meta);
+    createRootAndMetaRegions();
     
     for (HRegion region : regions) {
       HRegion.addRegionToMETA(meta, region);
     }
     
-    root.close();
-    root.getLog().closeAndDelete();
-    meta.close();
-    meta.getLog().closeAndDelete();
+    closeRootAndMeta();
   }
   
   /**

Added: hadoop/hbase/trunk/src/test/org/apache/hadoop/hbase/TestScanMultipleVersions.java
URL: http://svn.apache.org/viewvc/hadoop/hbase/trunk/src/test/org/apache/hadoop/hbase/TestScanMultipleVersions.java?rev=670124&view=auto
==============================================================================
--- hadoop/hbase/trunk/src/test/org/apache/hadoop/hbase/TestScanMultipleVersions.java (added)
+++ hadoop/hbase/trunk/src/test/org/apache/hadoop/hbase/TestScanMultipleVersions.java Fri Jun 20 19:52:35 2008
@@ -0,0 +1,167 @@
+/**
+ * Copyright 2008 The Apache Software Foundation
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.hadoop.hbase;
+
+import org.apache.hadoop.fs.Path;
+import org.apache.hadoop.hbase.client.HTable;
+import org.apache.hadoop.hbase.client.Scanner;
+import org.apache.hadoop.hbase.io.BatchUpdate;
+import org.apache.hadoop.hbase.regionserver.HRegion;
+import org.apache.hadoop.hbase.util.Bytes;
+
+/**
+ * Regression test for HBASE-613
+ */
+public class TestScanMultipleVersions extends HBaseClusterTestCase {
+  private final byte[] TABLE_NAME = Bytes.toBytes("TestScanMultipleVersions");
+  private final HRegionInfo[] INFOS = new HRegionInfo[2];
+  private final HRegion[] REGIONS = new HRegion[2];
+  private final byte[][] ROWS = new byte[][] {
+      Bytes.toBytes("row_0200"),
+      Bytes.toBytes("row_0800")
+  };
+  private final long[] TIMESTAMPS = new long[] {
+      100L,
+      1000L
+  };
+  private HTableDescriptor desc = null;
+
+  @Override
+  protected void preHBaseClusterSetup() throws Exception {
+    testDir = new Path(conf.get(HConstants.HBASE_DIR));
+    
+    // Create table description
+    
+    this.desc = new HTableDescriptor(TABLE_NAME);
+    this.desc.addFamily(new HColumnDescriptor(HConstants.COLUMN_FAMILY));
+
+    // Region 0 will contain the key range [,row_0500)
+    INFOS[0] = new HRegionInfo(this.desc, HConstants.EMPTY_START_ROW,
+        Bytes.toBytes("row_0500"));
+    // Region 1 will contain the key range [row_0500,)
+    INFOS[1] = new HRegionInfo(this.desc, Bytes.toBytes("row_0500"),
+        HConstants.EMPTY_END_ROW);
+
+    // Create root and meta regions
+    createRootAndMetaRegions();
+    // Create the regions
+    for (int i = 0; i < REGIONS.length; i++) {
+      REGIONS[i] =
+        HRegion.createHRegion(this.INFOS[i], this.testDir, this.conf);
+      // Insert data
+      for (int j = 0; j < TIMESTAMPS.length; j++) {
+        BatchUpdate b = new BatchUpdate(ROWS[i], TIMESTAMPS[j]);
+        b.put(HConstants.COLUMN_FAMILY, Bytes.toBytes(TIMESTAMPS[j]));
+        REGIONS[i].batchUpdate(b);
+      }
+      // Insert the region we created into the meta
+      HRegion.addRegionToMETA(meta, REGIONS[i]);
+      // Close region
+      REGIONS[i].close();
+      REGIONS[i].getLog().closeAndDelete();
+    }
+    // Close root and meta regions
+    closeRootAndMeta();
+  }
+  
+  /**
+   * @throws Exception
+   */
+  public void testScanMultipleVersions() throws Exception {
+    // At this point we have created multiple regions and both HDFS and HBase
+    // are running. There are 5 cases we have to test. Each is described below.
+
+    HTable t = new HTable(conf, TABLE_NAME);
+    
+    // Case 1: scan with LATEST_TIMESTAMP. Should get two rows
+    
+    int count = 0;
+    Scanner s = t.getScanner(HConstants.COLUMN_FAMILY_ARRAY);
+    try {
+      while (s.next() != null) {
+        count += 1;
+      }
+      assertEquals("Number of rows should be 2", 2, count);
+    } finally {
+      s.close();
+    }
+
+    // Case 2: Scan with a timestamp greater than most recent timestamp
+    // (in this case > 1000 and < LATEST_TIMESTAMP. Should get 2 rows.
+    
+    count = 0;
+    s = t.getScanner(HConstants.COLUMN_FAMILY_ARRAY, HConstants.EMPTY_START_ROW,
+        10000L);
+    try {
+      while (s.next() != null) {
+        count += 1;
+      }
+      assertEquals("Number of rows should be 2", 2, count);
+    } finally {
+      s.close();
+    }
+    
+    // Case 3: scan with timestamp equal to most recent timestamp
+    // (in this case == 1000. Should get 2 rows.
+    
+    count = 0;
+    s = t.getScanner(HConstants.COLUMN_FAMILY_ARRAY, HConstants.EMPTY_START_ROW,
+        1000L);
+    try {
+      while (s.next() != null) {
+        count += 1;
+      }
+      assertEquals("Number of rows should be 2", 2, count);
+    } finally {
+      s.close();
+    }
+    
+    // Case 4: scan with timestamp greater than first timestamp but less than
+    // second timestamp (100 < timestamp < 1000). Should get 2 rows.
+    
+    count = 0;
+    s = t.getScanner(HConstants.COLUMN_FAMILY_ARRAY, HConstants.EMPTY_START_ROW,
+        500L);
+    try {
+      while (s.next() != null) {
+        count += 1;
+      }
+      assertEquals("Number of rows should be 2", 2, count);
+    } finally {
+      s.close();
+    }
+    
+    // Case 5: scan with timestamp equal to first timestamp (100)
+    // Should get 2 rows.
+    
+    count = 0;
+    s = t.getScanner(HConstants.COLUMN_FAMILY_ARRAY, HConstants.EMPTY_START_ROW,
+        100L);
+    try {
+      while (s.next() != null) {
+        count += 1;
+      }
+      assertEquals("Number of rows should be 2", 2, count);
+    } finally {
+      s.close();
+    }
+  }
+}

Modified: hadoop/hbase/trunk/src/test/org/apache/hadoop/hbase/util/TestMergeTool.java
URL: http://svn.apache.org/viewvc/hadoop/hbase/trunk/src/test/org/apache/hadoop/hbase/util/TestMergeTool.java?rev=670124&r1=670123&r2=670124&view=diff
==============================================================================
--- hadoop/hbase/trunk/src/test/org/apache/hadoop/hbase/util/TestMergeTool.java (original)
+++ hadoop/hbase/trunk/src/test/org/apache/hadoop/hbase/util/TestMergeTool.java Fri Jun 20 19:52:35 2008
@@ -47,7 +47,6 @@
   private final HRegion[] regions = new HRegion[5];
   private HTableDescriptor desc;
   private byte [][][] rows;
-  private Path rootdir = null;
   private MiniDFSCluster dfsCluster = null;
   private FileSystem fs;
   
@@ -102,9 +101,6 @@
     // Start up dfs
     this.dfsCluster = new MiniDFSCluster(conf, 2, true, (String[])null);
     this.fs = this.dfsCluster.getFileSystem();
-    // Set the hbase.rootdir to be the home directory in mini dfs.
-    this.rootdir = new Path(this.fs.getHomeDirectory(), "hbase");
-    this.conf.set(HConstants.HBASE_DIR, this.rootdir.toString());
     
     // Note: we must call super.setUp after starting the mini cluster or
     // we will end up with a local file system
@@ -117,7 +113,7 @@
        */
       for (int i = 0; i < sourceRegions.length; i++) {
         regions[i] =
-          HRegion.createHRegion(this.sourceRegions[i], this.rootdir, this.conf);
+          HRegion.createHRegion(this.sourceRegions[i], this.testDir, this.conf);
         /*
          * Insert data
          */
@@ -128,23 +124,14 @@
           regions[i].batchUpdate(b);
         }
       }
-      // Create root region
-      HRegion root = HRegion.createHRegion(HRegionInfo.ROOT_REGIONINFO,
-          this.rootdir, this.conf);
-      // Create meta region
-      HRegion meta = HRegion.createHRegion(HRegionInfo.FIRST_META_REGIONINFO,
-          this.rootdir, this.conf);
-      // Insert meta into root region
-      HRegion.addRegionToMETA(root, meta);
+      // Create root and meta regions
+      createRootAndMetaRegions();
       // Insert the regions we created into the meta
       for(int i = 0; i < regions.length; i++) {
         HRegion.addRegionToMETA(meta, regions[i]);
       }
       // Close root and meta regions
-      root.close();
-      root.getLog().closeAndDelete();
-      meta.close();
-      meta.getLog().closeAndDelete();
+      closeRootAndMeta();
       
     } catch (Exception e) {
       shutdownDfs(dfsCluster);
@@ -182,7 +169,7 @@
     // Now verify that we can read all the rows from regions 0, 1
     // in the new merged region.
     HRegion merged =
-      HRegion.openHRegion(mergedInfo, this.rootdir, log, this.conf);
+      HRegion.openHRegion(mergedInfo, this.testDir, log, this.conf);
     verifyMerge(merged, upperbound);
     merged.close();
     LOG.info("Verified " + msg);