<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array">
    <added>
      <filename>src/java/org/apache/hadoop/hbase/NotServingRegionException.java</filename>
    </added>
    <added>
      <filename>src/java/org/apache/hadoop/hbase/RegionUnavailableListener.java</filename>
    </added>
    <added>
      <filename>src/test/org/apache/hadoop/hbase/HBaseClusterTestCase.java</filename>
    </added>
    <added>
      <filename>src/test/org/apache/hadoop/hbase/HBaseTestCase.java</filename>
    </added>
    <added>
      <filename>src/test/org/apache/hadoop/hbase/StaticTestEnvironment.java</filename>
    </added>
    <added>
      <filename>src/test/org/apache/hadoop/hbase/TestHLog.java</filename>
    </added>
    <added>
      <filename>src/test/org/apache/hadoop/hbase/TestTable.java</filename>
    </added>
  </added>
  <modified type="array">
    <modified>
      <diff>@@ -183,10 +183,10 @@ public abstract class HAbstractScanner implements HInternalScannerInterface {
   abstract boolean getNext(int i) throws IOException;
   
   /** Mechanism used by concrete implementation to shut down a particular scanner */
-  abstract void closeSubScanner(int i) throws IOException;
+  abstract void closeSubScanner(int i);
   
   /** Mechanism used to shut down the whole scan */
-  public abstract void close() throws IOException;
+  public abstract void close();
 
   /* (non-Javadoc)
    * @see org.apache.hadoop.hbase.HInternalScannerInterface#isWildcardScanner()</diff>
      <filename>src/java/org/apache/hadoop/hbase/HAbstractScanner.java</filename>
    </modified>
    <modified>
      <diff>@@ -288,17 +288,35 @@ public class HClient implements HConstants {
         throw new IOException(&quot;Timed out trying to locate root region&quot;);
       }
       
-      // Verify that this server still serves the root region
-      
       HRegionInterface rootRegion = getHRegionConnection(rootRegionLocation);
 
-      if(rootRegion.getRegionInfo(HGlobals.rootRegionInfo.regionName) != null) {
+      try {
+        rootRegion.getRegionInfo(HGlobals.rootRegionInfo.regionName);
         this.tableServers = new TreeMap&lt;Text, TableInfo&gt;();
         this.tableServers.put(EMPTY_START_ROW,
             new TableInfo(HGlobals.rootRegionInfo, rootRegionLocation));
         
         this.tablesToServers.put(ROOT_TABLE_NAME, this.tableServers);
         break;
+        
+      } catch(NotServingRegionException e) {
+        if(tries == numRetries - 1) {
+          // Don't bother sleeping. We've run out of retries.
+          break;
+        }
+        
+        // Sleep and retry finding root region.
+
+        try {
+          if (LOG.isDebugEnabled()) {
+            LOG.debug(&quot;Root region location changed. Sleeping.&quot;);
+          }
+          Thread.sleep(this.clientTimeout);
+          if (LOG.isDebugEnabled()) {
+            LOG.debug(&quot;Wake. Retry finding root region.&quot;);
+          }
+        } catch(InterruptedException iex) {
+        }
       }
       rootRegionLocation = null;
     }
@@ -453,7 +471,7 @@ public class HClient implements HConstants {
    * Right now, it only exists as part of the META table's region info.
    */
   public synchronized HTableDescriptor[] listTables()
-  throws IOException {
+      throws IOException {
     TreeSet&lt;HTableDescriptor&gt; uniqueTables = new TreeSet&lt;HTableDescriptor&gt;();
     
     TreeMap&lt;Text, TableInfo&gt; metaTables =
@@ -523,24 +541,84 @@ public class HClient implements HConstants {
     return this.tableServers.get(serverKey);
   }
   
+  private synchronized void findRegion(TableInfo info) throws IOException {
+    
+    // Wipe out everything we know about this table
+    
+    this.tablesToServers.remove(info.regionInfo.tableDesc.getName());
+    this.tableServers.clear();
+    
+    // Reload information for the whole table
+    
+    findTableInMeta(info.regionInfo.tableDesc.getName());
+    
+    if(this.tableServers.get(info.regionInfo.startKey) == null ) {
+      throw new IOException(&quot;region &quot; + info.regionInfo.regionName + &quot; does not exist&quot;);
+    }
+  }
+  
   /** Get a single value for the specified row and column */
   public byte[] get(Text row, Text column) throws IOException {
-    TableInfo info = getTableInfo(row);
-    return getHRegionConnection(info.serverAddress).get(
-        info.regionInfo.regionName, row, column).get();
+    TableInfo info = null;
+    BytesWritable value = null;
+
+    for(int tries = 0; tries &lt; numRetries &amp;&amp; info == null; tries++) {
+      info = getTableInfo(row);
+      
+      try {
+        value = getHRegionConnection(info.serverAddress).get(
+            info.regionInfo.regionName, row, column);
+        
+      } catch(NotServingRegionException e) {
+        if(tries == numRetries - 1) {
+          // No more tries
+          throw e;
+        }
+        findRegion(info);
+        info = null;
+      }
+    }
+
+    if(value != null) {
+      byte[] bytes = new byte[value.getSize()];
+      System.arraycopy(value.get(), 0, bytes, 0, bytes.length);
+      return bytes;
+    }
+    return null;
   }
  
   /** Get the specified number of versions of the specified row and column */
   public byte[][] get(Text row, Text column, int numVersions) throws IOException {
-    TableInfo info = getTableInfo(row);
-    BytesWritable[] values = getHRegionConnection(info.serverAddress).get(
-        info.regionInfo.regionName, row, column, numVersions);
-    
-    ArrayList&lt;byte[]&gt; bytes = new ArrayList&lt;byte[]&gt;();
-    for(int i = 0 ; i &lt; values.length; i++) {
-      bytes.add(values[i].get());
+    TableInfo info = null;
+    BytesWritable[] values = null;
+
+    for(int tries = 0; tries &lt; numRetries &amp;&amp; info == null; tries++) {
+      info = getTableInfo(row);
+      
+      try {
+        values = getHRegionConnection(info.serverAddress).get(
+            info.regionInfo.regionName, row, column, numVersions);
+        
+      } catch(NotServingRegionException e) {
+        if(tries == numRetries - 1) {
+          // No more tries
+          throw e;
+        }
+        findRegion(info);
+        info = null;
+      }
     }
-    return bytes.toArray(new byte[values.length][]);
+
+    if(values != null) {
+      ArrayList&lt;byte[]&gt; bytes = new ArrayList&lt;byte[]&gt;();
+      for(int i = 0 ; i &lt; values.length; i++) {
+        byte[] value = new byte[values[i].getSize()];
+        System.arraycopy(values[i].get(), 0, value, 0, value.length);
+        bytes.add(value);
+      }
+      return bytes.toArray(new byte[values.length][]);
+    }
+    return null;
   }
   
   /** 
@@ -548,22 +626,61 @@ public class HClient implements HConstants {
    * the specified timestamp.
    */
   public byte[][] get(Text row, Text column, long timestamp, int numVersions) throws IOException {
-    TableInfo info = getTableInfo(row);
-    BytesWritable[] values = getHRegionConnection(info.serverAddress).get(
-        info.regionInfo.regionName, row, column, timestamp, numVersions);
+    TableInfo info = null;
+    BytesWritable[] values = null;
+
+    for(int tries = 0; tries &lt; numRetries &amp;&amp; info == null; tries++) {
+      info = getTableInfo(row);
+      
+      try {
+        values = getHRegionConnection(info.serverAddress).get(
+            info.regionInfo.regionName, row, column, timestamp, numVersions);
     
-    ArrayList&lt;byte[]&gt; bytes = new ArrayList&lt;byte[]&gt;();
-    for(int i = 0 ; i &lt; values.length; i++) {
-      bytes.add(values[i].get());
+      } catch(NotServingRegionException e) {
+        if(tries == numRetries - 1) {
+          // No more tries
+          throw e;
+        }
+        findRegion(info);
+        info = null;
+      }
     }
-    return bytes.toArray(new byte[values.length][]);
-  }
 
+    if(values != null) {
+      ArrayList&lt;byte[]&gt; bytes = new ArrayList&lt;byte[]&gt;();
+      for(int i = 0 ; i &lt; values.length; i++) {
+        byte[] value = new byte[values[i].getSize()];
+        System.arraycopy(values[i].get(), 0, value, 0, value.length);
+        bytes.add(value);
+      }
+      return bytes.toArray(new byte[values.length][]);
+    }
+    return null;
+  }
+    
   /** Get all the data for the specified row */
   public LabelledData[] getRow(Text row) throws IOException {
-    TableInfo info = getTableInfo(row);
-    return getHRegionConnection(info.serverAddress).getRow(
-        info.regionInfo.regionName, row);
+    TableInfo info = null;
+    LabelledData[] value = null;
+    
+    for(int tries = 0; tries &lt; numRetries &amp;&amp; info == null; tries++) {
+      info = getTableInfo(row);
+      
+      try {
+        value = getHRegionConnection(info.serverAddress).getRow(
+            info.regionInfo.regionName, row);
+        
+      } catch(NotServingRegionException e) {
+        if(tries == numRetries - 1) {
+          // No more tries
+          throw e;
+        }
+        findRegion(info);
+        info = null;
+      }
+    }
+    
+    return value;
   }
 
   /** 
@@ -579,19 +696,34 @@ public class HClient implements HConstants {
 
   /** Start an atomic row insertion or update */
   public long startUpdate(Text row) throws IOException {
-    TableInfo info = getTableInfo(row);
-    long lockid;
-    try {
-      this.currentServer = getHRegionConnection(info.serverAddress);
-      this.currentRegion = info.regionInfo.regionName;
-      this.clientid = rand.nextLong();
-      lockid = currentServer.startUpdate(this.currentRegion, this.clientid, row);
+    TableInfo info = null;
+    long lockid = -1L;
+    
+    for(int tries = 0; tries &lt; numRetries &amp;&amp; info == null; tries++) {
+      info = getTableInfo(row);
+      
+      try {
+        this.currentServer = getHRegionConnection(info.serverAddress);
+        this.currentRegion = info.regionInfo.regionName;
+        this.clientid = rand.nextLong();
+        lockid = currentServer.startUpdate(this.currentRegion, this.clientid, row);
+
+      } catch(NotServingRegionException e) {
+        if(tries == numRetries - 1) {
+          // No more tries
+          throw e;
+        }
+        findRegion(info);
+        info = null;
+
+      } catch(IOException e) {
+        this.currentServer = null;
+        this.currentRegion = null;
+        throw e;
+      }
       
-    } catch(IOException e) {
-      this.currentServer = null;
-      this.currentRegion = null;
-      throw e;
     }
+    
     return lockid;
   }
   
@@ -666,24 +798,27 @@ public class HClient implements HConstants {
     private HRegionInterface server;
     private long scannerId;
     
-    public ClientScanner(Text[] columns, Text startRow) throws IOException {
-      this.columns = columns;
-      this.startRow = startRow;
-      this.closed = false;
-      
+    private void loadRegions() {
       Text firstServer = null;
       if(this.startRow == null || this.startRow.getLength() == 0) {
         firstServer = tableServers.firstKey();
-        
+
       } else if(tableServers.containsKey(startRow)) {
         firstServer = startRow;
-        
+
       } else {
         firstServer = tableServers.headMap(startRow).lastKey();
       }
       Collection&lt;TableInfo&gt; info = tableServers.tailMap(firstServer).values();
-      
       this.regions = info.toArray(new TableInfo[info.size()]);
+    }
+    
+    public ClientScanner(Text[] columns, Text startRow) throws IOException {
+      this.columns = columns;
+      this.startRow = startRow;
+      this.closed = false;
+      
+      loadRegions();
       this.currentRegion = -1;
       this.server = null;
       this.scannerId = -1L;
@@ -706,10 +841,26 @@ public class HClient implements HConstants {
       }
       try {
         this.server = getHRegionConnection(this.regions[currentRegion].serverAddress);
-        this.scannerId = this.server.openScanner(
-            this.regions[currentRegion].regionInfo.regionName, this.columns,
-            this.startRow);
         
+        for(int tries = 0; tries &lt; numRetries; tries++) {
+          TableInfo info = this.regions[currentRegion];
+          
+          try {
+            this.scannerId = this.server.openScanner(info.regionInfo.regionName,
+                this.columns, currentRegion == 0 ? this.startRow : EMPTY_START_ROW);
+            
+            break;
+        
+          } catch(NotServingRegionException e) {
+            if(tries == numRetries - 1) {
+              // No more tries
+              throw e;
+            }
+            findRegion(info);
+            loadRegions();
+          }
+        }
+
       } catch(IOException e) {
         close();
         throw e;
@@ -743,6 +894,7 @@ public class HClient implements HConstants {
     public void close() throws IOException {
       if(this.scannerId != -1L) {
         this.server.close(this.scannerId);
+        this.scannerId = -1L;
       }
       this.server = null;
       this.closed = true;</diff>
      <filename>src/java/org/apache/hadoop/hbase/HClient.java</filename>
    </modified>
    <modified>
      <diff>@@ -34,7 +34,7 @@ import org.apache.hadoop.io.Text;
 public interface HInternalScannerInterface {
   
   public boolean next(HStoreKey key, TreeMap&lt;Text, BytesWritable&gt; results) throws IOException;
-  public void close() throws IOException;
+  public void close();
   /** Returns true if the scanner is matching a column family or regex */
   public boolean isWildcardScanner();
   </diff>
      <filename>src/java/org/apache/hadoop/hbase/HInternalScannerInterface.java</filename>
    </modified>
    <modified>
      <diff>@@ -15,6 +15,8 @@
  */
 package org.apache.hadoop.hbase;
 
+import java.util.concurrent.atomic.AtomicInteger;
+
 /*******************************************************************************
  * HLocking is a set of lock primitives that does not rely on a
  * particular thread holding the monitor for an object. This is
@@ -33,12 +35,12 @@ public class HLocking {
   // If lockers &gt; 0, locked for read
   // If lockers == -1 locked for write
   
-  private int lockers;
-
+  private AtomicInteger lockers;
+  
   /** Constructor */
   public HLocking() {
     this.mutex = new Integer(0);
-    this.lockers = 0;
+    this.lockers = new AtomicInteger(0);
   }
 
   /**
@@ -46,13 +48,13 @@ public class HLocking {
    */
   public void obtainReadLock() {
     synchronized(mutex) {
-      while(lockers &lt; 0) {
+      while(lockers.get() &lt; 0) {
         try {
           mutex.wait();
         } catch(InterruptedException ie) {
         }
       }
-      lockers++;
+      lockers.incrementAndGet();
       mutex.notifyAll();
     }
   }
@@ -62,8 +64,7 @@ public class HLocking {
    */
   public void releaseReadLock() {
     synchronized(mutex) {
-      lockers--;
-      if(lockers &lt; 0) {
+      if(lockers.decrementAndGet() &lt; 0) {
         throw new IllegalStateException(&quot;lockers: &quot; + lockers);
       }
       mutex.notifyAll();
@@ -75,13 +76,12 @@ public class HLocking {
    */
   public void obtainWriteLock() {
     synchronized(mutex) {
-      while(lockers != 0) {
+      while(!lockers.compareAndSet(0, -1)) {
         try {
           mutex.wait();
         } catch (InterruptedException ie) {
         }
       }
-      lockers = -1;
       mutex.notifyAll();
     }
   }
@@ -91,10 +91,9 @@ public class HLocking {
    */
   public void releaseWriteLock() {
     synchronized(mutex) {
-      if(lockers != -1) {
+      if(!lockers.compareAndSet(-1, 0)) {
         throw new IllegalStateException(&quot;lockers: &quot; + lockers);
       }
-      lockers = 0;
       mutex.notifyAll();
     }
   }</diff>
      <filename>src/java/org/apache/hadoop/hbase/HLocking.java</filename>
    </modified>
    <modified>
      <diff>@@ -270,8 +270,14 @@ public class HLog implements HConstants {
 
   /** Shut down the log. */
   public synchronized void close() throws IOException {
+    if(LOG.isDebugEnabled()) {
+      LOG.debug(&quot;closing log writer&quot;);
+    }
     this.writer.close();
     this.closed = true;
+    if(LOG.isDebugEnabled()) {
+      LOG.debug(&quot;log writer closed&quot;);
+    }
   }
 
   /**</diff>
      <filename>src/java/org/apache/hadoop/hbase/HLog.java</filename>
    </modified>
    <modified>
      <diff>@@ -164,7 +164,7 @@ public class HMaster implements HConstants, HMasterInterface,
           HRegionInfo info = getRegionInfo(COL_REGIONINFO, results, inbuf);
           String serverName = getServerName(COL_SERVER, results);
           long startCode = getStartCode(COL_STARTCODE, results);
-          
+
           if(LOG.isDebugEnabled()) {
             LOG.debug(&quot;row: &quot; + info.toString() + &quot;, server: &quot; + serverName
                 + &quot;, startCode: &quot; + startCode);
@@ -177,11 +177,11 @@ public class HMaster implements HConstants, HMasterInterface,
         }
       } finally {
         try {
-        if (scannerId != -1L) {
-          server.close(scannerId);
-        }
+          if (scannerId != -1L) {
+            server.close(scannerId);
+          }
         } catch (IOException e) {
-            e.printStackTrace();
+          e.printStackTrace();
         }
         scannerId = -1L;
       }
@@ -581,13 +581,13 @@ public class HMaster implements HConstants, HMasterInterface,
     // Main processing loop
     for(PendingOperation op = null; !closed; ) {
       synchronized(msgQueue) {
-        while(msgQueue.size() == 0 &amp;&amp; serversToServerInfo.size() != 0) {
+        while(msgQueue.size() == 0 &amp;&amp; !closed) {
           try {
             msgQueue.wait(threadWakeFrequency);
           } catch(InterruptedException iex) {
           }
         }
-        if(msgQueue.size() == 0 || closed) {
+        if(closed) {
           continue;
         }
         op = msgQueue.remove(msgQueue.size()-1);
@@ -616,14 +616,6 @@ public class HMaster implements HConstants, HMasterInterface,
     }
     server.stop();                              // Stop server
     serverLeases.close();                       // Turn off the lease monitor
-    try {
-      fs.close();
-      client.close();                           // Shut down the client
-    } catch(IOException iex) {
-      // Print if ever there is an interrupt (Just for kicks. Remove if it
-      // ever happens).
-      iex.printStackTrace();
-    }
     
     // Join up with all threads
     
@@ -652,6 +644,7 @@ public class HMaster implements HConstants, HMasterInterface,
       // ever happens).
       iex.printStackTrace();
     }
+    
     if(LOG.isDebugEnabled()) {
       LOG.debug(&quot;HMaster main thread exiting&quot;);
     }
@@ -774,19 +767,9 @@ public class HMaster implements HConstants, HMasterInterface,
   HMsg[] processMsgs(HServerInfo info, HMsg incomingMsgs[]) throws IOException {
     Vector&lt;HMsg&gt; returnMsgs = new Vector&lt;HMsg&gt;();
     
-    // Process the kill list
-    
     TreeMap&lt;Text, HRegionInfo&gt; regionsToKill =
       killList.remove(info.getServerAddress().toString());
     
-    if(regionsToKill != null) {
-      for(Iterator&lt;HRegionInfo&gt; i = regionsToKill.values().iterator();
-          i.hasNext(); ) {
-        
-        returnMsgs.add(new HMsg(HMsg.MSG_REGION_CLOSE_AND_DELETE, i.next()));
-      }
-    }
-
     // Get reports on what the RegionServer did.
     
     for(int i = 0; i &lt; incomingMsgs.length; i++) {
@@ -872,18 +855,11 @@ public class HMaster implements HConstants, HMasterInterface,
         } else {
           boolean reassignRegion = true;
 
-          synchronized(regionsToKill) {
-            if(regionsToKill.containsKey(region.regionName)) {
-              regionsToKill.remove(region.regionName);
-
-              if(regionsToKill.size() &gt; 0) {
-                killList.put(info.toString(), regionsToKill);
-
-              } else {
-                killList.remove(info.toString());
-              }
-              reassignRegion = false;
-            }
+          if(regionsToKill.containsKey(region.regionName)) {
+            regionsToKill.remove(region.regionName);
+            unassignedRegions.remove(region.regionName);
+            assignAttempts.remove(region.regionName);
+            reassignRegion = false;
           }
 
           synchronized(msgQueue) {
@@ -902,14 +878,15 @@ public class HMaster implements HConstants, HMasterInterface,
         if(LOG.isDebugEnabled()) {
           LOG.debug(&quot;new region &quot; + region.regionName);
         }
+        
+        // A region has split and the old server is serving the two new regions.
 
         if(region.regionName.find(META_TABLE_NAME.toString()) == 0) {
           // A meta region has split.
 
           allMetaRegionsScanned = false;
         }
-        unassignedRegions.put(region.regionName, region);
-        assignAttempts.put(region.regionName, 0L);
+        
         break;
 
       default:
@@ -918,6 +895,16 @@ public class HMaster implements HConstants, HMasterInterface,
       }
     }
 
+    // Process the kill list
+    
+    if(regionsToKill != null) {
+      for(Iterator&lt;HRegionInfo&gt; i = regionsToKill.values().iterator();
+          i.hasNext(); ) {
+        
+        returnMsgs.add(new HMsg(HMsg.MSG_REGION_CLOSE_AND_DELETE, i.next()));
+      }
+    }
+
     // Figure out what the RegionServer ought to do, and write back.
 
     if(unassignedRegions.size() &gt; 0) {
@@ -1460,108 +1447,167 @@ public class HMaster implements HConstants, HMasterInterface,
     } else {
       firstMetaRegion = knownMetaRegions.headMap(tableName).lastKey();
     }
-    for(Iterator&lt;MetaRegion&gt; it =
-      knownMetaRegions.tailMap(firstMetaRegion).values().iterator();
-        it.hasNext(); ) {
 
-      // Find all the regions that make up this table
-      
-      MetaRegion m = it.next();
-      HRegionInterface server = client.getHRegionConnection(m.server);
-      Vector&lt;Text&gt; rowsToDelete = new Vector&lt;Text&gt;();
+    synchronized(metaScannerLock) {     // Prevent meta scanner from running
+      for(Iterator&lt;MetaRegion&gt; it =
+          knownMetaRegions.tailMap(firstMetaRegion).values().iterator();
+          it.hasNext(); ) {
 
-      long scannerId = -1L;
-      try {
-        scannerId = server.openScanner(m.regionName, METACOLUMNS, tableName);
-        
-        
-        DataInputBuffer inbuf = new DataInputBuffer();
-        byte[] bytes;
-        while(true) {
-          LabelledData[] values = null;
-          HStoreKey key = new HStoreKey();
-          values = server.next(scannerId, key);
-          if(values == null || values.length == 0) {
-            break;
-          }
-          TreeMap&lt;Text, byte[]&gt; results = new TreeMap&lt;Text, byte[]&gt;();
-          for(int i = 0; i &lt; values.length; i++) {
-            bytes = new byte[values[i].getData().getSize()];
-            System.arraycopy(values[i].getData().get(), 0, bytes, 0, bytes.length);
-            results.put(values[i].getLabel(), bytes);
-          }
-          bytes = results.get(COL_REGIONINFO);
-          if(bytes == null || bytes.length == 0) {
-            break;
-          }
-          inbuf.reset(bytes, bytes.length);
-          HRegionInfo info = new HRegionInfo();
-          info.readFields(inbuf);
+        // Find all the regions that make up this table
 
-          if(info.tableDesc.getName().compareTo(tableName) &gt; 0) {
-            break;                      // Beyond any more entries for this table
-          }
-          
-          rowsToDelete.add(info.regionName);
+        MetaRegion m = it.next();
+        HRegionInterface server = client.getHRegionConnection(m.server);
 
-          // Is it being served?
-          
-          bytes = results.get(COL_SERVER);
-          if(bytes != null &amp;&amp; bytes.length != 0) {
-            String serverName = new String(bytes, UTF8_ENCODING);
-            
-            bytes = results.get(COL_STARTCODE);
+        // Rows in the meta table we will need to delete
+
+        Vector&lt;Text&gt; rowsToDelete = new Vector&lt;Text&gt;();
+
+        // Regions that are being served. We will get the HRegionServers
+        // to delete them for us, but we don't tell them that until after
+        // we are done scanning to prevent lock contention
+
+        TreeMap&lt;String, TreeMap&lt;Text, HRegionInfo&gt;&gt; localKillList =
+          new TreeMap&lt;String, TreeMap&lt;Text, HRegionInfo&gt;&gt;();
+
+        // Regions that are not being served. We will have to delete
+        // them ourselves
+
+        TreeSet&lt;Text&gt; unservedRegions = new TreeSet&lt;Text&gt;();
+
+        long scannerId = -1L;
+        try {
+          scannerId = server.openScanner(m.regionName, METACOLUMNS, tableName);
+
+
+          DataInputBuffer inbuf = new DataInputBuffer();
+          byte[] bytes;
+          while(true) {
+            LabelledData[] values = null;
+            HStoreKey key = new HStoreKey();
+            values = server.next(scannerId, key);
+            if(values == null || values.length == 0) {
+              break;
+            }
+            TreeMap&lt;Text, byte[]&gt; results = new TreeMap&lt;Text, byte[]&gt;();
+            for(int i = 0; i &lt; values.length; i++) {
+              bytes = new byte[values[i].getData().getSize()];
+              System.arraycopy(values[i].getData().get(), 0, bytes, 0, bytes.length);
+              results.put(values[i].getLabel(), bytes);
+            }
+            bytes = results.get(COL_REGIONINFO);
+            if(bytes == null || bytes.length == 0) {
+              break;
+            }
+            inbuf.reset(bytes, bytes.length);
+            HRegionInfo info = new HRegionInfo();
+            info.readFields(inbuf);
+
+            if(info.tableDesc.getName().compareTo(tableName) &gt; 0) {
+              break;                      // Beyond any more entries for this table
+            }
+
+            rowsToDelete.add(info.regionName);
+
+            // Is it being served?
+
+            bytes = results.get(COL_SERVER);
             if(bytes != null &amp;&amp; bytes.length != 0) {
-              long startCode = Long.valueOf(new String(bytes, UTF8_ENCODING));
+              String serverName = new String(bytes, UTF8_ENCODING);
 
-              HServerInfo s = serversToServerInfo.get(serverName);
-              if(s != null &amp;&amp; s.getStartCode() == startCode) {
+              bytes = results.get(COL_STARTCODE);
+              if(bytes != null &amp;&amp; bytes.length != 0) {
+                long startCode = Long.valueOf(new String(bytes, UTF8_ENCODING));
 
-                // It is being served.
-                // Tell the server to stop it and not report back.
+                HServerInfo s = serversToServerInfo.get(serverName);
+                if(s != null &amp;&amp; s.getStartCode() == startCode) {
 
-                TreeMap&lt;Text, HRegionInfo&gt; regionsToKill =
-                  killList.get(serverName);
-                
-                if(regionsToKill == null) {
-                  regionsToKill = new TreeMap&lt;Text, HRegionInfo&gt;();
+                  // It is being served.
+                  // Tell the server to stop it and not report back.
+
+                  TreeMap&lt;Text, HRegionInfo&gt; regionsToKill =
+                    localKillList.get(serverName);
+
+                  if(regionsToKill == null) {
+                    regionsToKill = new TreeMap&lt;Text, HRegionInfo&gt;();
+                  }
+                  regionsToKill.put(info.regionName, info);
+                  localKillList.put(serverName, regionsToKill);
+                  continue;
                 }
-                regionsToKill.put(info.regionName, info);
-                killList.put(serverName, regionsToKill);
               }
             }
+            
+            // Region is not currently being served.
+            // Prevent it from getting assigned and add it to the list of
+            // regions we need to delete here.
+            
+            unassignedRegions.remove(info.regionName);
+            assignAttempts.remove(info.regionName);
+            unservedRegions.add(info.regionName);
+          }
+          
+        } catch(IOException e) {
+          e.printStackTrace();
+
+        } finally {
+          if(scannerId != -1L) {
+            try {
+              server.close(scannerId);
+
+            } catch(IOException e) {
+              e.printStackTrace();
+
+            }
           }
+          scannerId = -1L;
         }
-      } catch(IOException e) {
-        e.printStackTrace();
+
+        // Wipe the existence of the regions out of the meta table
         
-      } finally {
-        if(scannerId != -1L) {
+        for(Iterator&lt;Text&gt; row = rowsToDelete.iterator(); row.hasNext(); ) {
+          Text rowName = row.next();
+          if(LOG.isDebugEnabled()) {
+            LOG.debug(&quot;deleting columns in row: &quot; + rowName);
+          }
+          long lockid = -1L;
+          long clientId = rand.nextLong();
           try {
-            server.close(scannerId);
-            
-          } catch(IOException e) {
-            e.printStackTrace();
-            
+            lockid = server.startUpdate(m.regionName, clientId, rowName);
+            server.delete(m.regionName, clientId, lockid, COL_REGIONINFO);
+            server.delete(m.regionName, clientId, lockid, COL_SERVER);
+            server.delete(m.regionName, clientId, lockid, COL_STARTCODE);
+            server.commit(m.regionName, clientId, lockid);
+            lockid = -1L;
+            if(LOG.isDebugEnabled()) {
+              LOG.debug(&quot;deleted columns in row: &quot; + rowName);
+            }
+
+          } catch(Exception e) {
+            if(lockid != -1L) {
+              server.abort(m.regionName, clientId, lockid);
+            }
+            LOG.error(&quot;columns deletion failed in row: &quot; + rowName);
+            LOG.error(e);
           }
         }
-        scannerId = -1L;
-      }
-      for(Iterator&lt;Text&gt; row = rowsToDelete.iterator(); row.hasNext(); ) {
-        Text rowName = row.next();
-        if(LOG.isDebugEnabled()) {
-          LOG.debug(&quot;deleting columns in row: &quot; + rowName);
+        
+        // Notify region servers that some regions need to be closed and deleted
+        
+        if(localKillList.size() != 0) {
+          killList.putAll(localKillList);
         }
-        try {
-          long clientId = rand.nextLong();
-          long lockid = server.startUpdate(m.regionName, clientId, rowName);
-          server.delete(m.regionName, clientId, lockid, COL_REGIONINFO);
-          server.delete(m.regionName, clientId, lockid, COL_SERVER);
-          server.delete(m.regionName, clientId, lockid, COL_STARTCODE);
-          server.commit(m.regionName, clientId, lockid);
-          
-        } catch(Exception e) {
-          e.printStackTrace();
+
+        // Delete any regions that are not being served
+        
+        for(Iterator&lt;Text&gt; i = unservedRegions.iterator(); i.hasNext(); ) {
+          Text regionName = i.next();
+          try {
+            HRegion.deleteRegion(fs, dir, regionName);
+            
+          } catch(IOException e) {
+            LOG.error(&quot;failed to delete region &quot; + regionName);
+            LOG.error(e);
+          }
         }
       }
     }</diff>
      <filename>src/java/org/apache/hadoop/hbase/HMaster.java</filename>
    </modified>
    <modified>
      <diff>@@ -296,7 +296,7 @@ public class HMemcache {
         for(int i = history.size() - 1; i &gt; 0; i--) {
           backingMaps[i] = history.elementAt(i);
         }
-
+      
         this.keyIterators = new Iterator[backingMaps.length];
         this.keys = new HStoreKey[backingMaps.length];
         this.vals = new BytesWritable[backingMaps.length];
@@ -322,8 +322,10 @@ public class HMemcache {
           }
         }
         
-      } catch(Exception ex) {
+      } catch(IOException ex) {
+        LOG.error(ex);
         close();
+        throw ex;
       }
     }
 
@@ -365,7 +367,7 @@ public class HMemcache {
     }
 
     /** Shut down map iterators, and release the lock */
-    public void close() throws IOException {
+    public void close() {
       if(! scannerClosed) {
         try {
           for(int i = 0; i &lt; keys.length; i++) {</diff>
      <filename>src/java/org/apache/hadoop/hbase/HMemcache.java</filename>
    </modified>
    <modified>
      <diff>@@ -65,6 +65,19 @@ public class HRegion implements HConstants {
   private static final Log LOG = LogFactory.getLog(HRegion.class);
 
   /**
+   * Deletes all the files for a HRegion
+   * 
+   * @param fs                  - the file system object
+   * @param baseDirectory       - base directory for HBase
+   * @param regionName          - name of the region to delete
+   * @throws IOException
+   */
+  public static void deleteRegion(FileSystem fs, Path baseDirectory,
+      Text regionName) throws IOException {
+    fs.delete(HStoreFile.getHRegionDir(baseDirectory, regionName));
+  }
+  
+  /**
    * Merge two HRegions.  They must be available on the current
    * HRegionServer. Returns a brand-new active HRegion, also
    * running on the current HRegionServer.
@@ -245,7 +258,7 @@ public class HRegion implements HConstants {
   TreeMap&lt;Long, TreeMap&lt;Text, BytesWritable&gt;&gt; targetColumns 
       = new TreeMap&lt;Long, TreeMap&lt;Text, BytesWritable&gt;&gt;();
   
-  HMemcache memcache = new HMemcache();
+  HMemcache memcache;
 
   Path dir;
   HLog log;
@@ -255,9 +268,9 @@ public class HRegion implements HConstants {
   Path regiondir;
 
   class WriteState {
-    public boolean writesOngoing;
-    public boolean writesEnabled;
-    public boolean closed;
+    public volatile boolean writesOngoing;
+    public volatile boolean writesEnabled;
+    public volatile boolean closed;
     public WriteState() {
       this.writesOngoing = true;
       this.writesEnabled = true;
@@ -265,12 +278,13 @@ public class HRegion implements HConstants {
     }
   }
   
-  WriteState writestate = new WriteState();
+  volatile WriteState writestate = new WriteState();
   int recentCommits = 0;
-  int commitsSinceFlush = 0;
+  volatile int commitsSinceFlush = 0;
 
   int maxUnflushedEntries = 0;
   int compactionThreshold = 0;
+  HLocking lock = null;
 
   //////////////////////////////////////////////////////////////////////////////
   // Constructor
@@ -302,10 +316,14 @@ public class HRegion implements HConstants {
     this.fs = fs;
     this.conf = conf;
     this.regionInfo = regionInfo;
+    this.memcache = new HMemcache();
+
 
     this.writestate.writesOngoing = true;
     this.writestate.writesEnabled = true;
     this.writestate.closed = false;
+    
+    this.lock = new HLocking();
 
     // Declare the regionName.  This is a unique string for the region, used to 
     // build a unique filename.
@@ -354,12 +372,22 @@ public class HRegion implements HConstants {
   public HRegionInfo getRegionInfo() {
     return this.regionInfo;
   }
+
+  /** returns true if region is closed */
+  public boolean isClosed() {
+    boolean closed = false;
+    synchronized(writestate) {
+      closed = writestate.closed;
+    }
+    return closed;
+  }
   
   /** Closes and deletes this HRegion. Called when doing a table deletion, for example */
   public void closeAndDelete() throws IOException {
     LOG.info(&quot;deleting region: &quot; + regionInfo.regionName);
     close();
-    fs.delete(regiondir);
+    deleteRegion(fs, dir, regionInfo.regionName);
+    LOG.info(&quot;region deleted: &quot; + regionInfo.regionName);
   }
   
   /**
@@ -373,42 +401,47 @@ public class HRegion implements HConstants {
    * time-sensitive thread.
    */
   public Vector&lt;HStoreFile&gt; close() throws IOException {
-    boolean shouldClose = false;
-    synchronized(writestate) {
-      if(writestate.closed) {
-        LOG.info(&quot;region &quot; + this.regionInfo.regionName + &quot; closed&quot;);
-        return new Vector&lt;HStoreFile&gt;();
-      }
-      while(writestate.writesOngoing) {
-        try {
-          writestate.wait();
-        } catch (InterruptedException iex) {
+    lock.obtainWriteLock();
+    try {
+      boolean shouldClose = false;
+      synchronized(writestate) {
+        if(writestate.closed) {
+          LOG.info(&quot;region &quot; + this.regionInfo.regionName + &quot; closed&quot;);
+          return new Vector&lt;HStoreFile&gt;();
+        }
+        while(writestate.writesOngoing) {
+          try {
+            writestate.wait();
+          } catch (InterruptedException iex) {
+          }
         }
+        writestate.writesOngoing = true;
+        shouldClose = true;
       }
-      writestate.writesOngoing = true;
-      shouldClose = true;
-    }
 
-    if(! shouldClose) {
-      return null;
-      
-    } else {
-      LOG.info(&quot;closing region &quot; + this.regionInfo.regionName);
-      Vector&lt;HStoreFile&gt; allHStoreFiles = internalFlushcache();
-      for(Iterator&lt;HStore&gt; it = stores.values().iterator(); it.hasNext(); ) {
-        HStore store = it.next();
-        store.close();
-      }
-      try {
-        return allHStoreFiles;
-        
-      } finally {
-        synchronized(writestate) {
-          writestate.closed = true;
-          writestate.writesOngoing = false;
+      if(! shouldClose) {
+        return null;
+
+      } else {
+        LOG.info(&quot;closing region &quot; + this.regionInfo.regionName);
+        Vector&lt;HStoreFile&gt; allHStoreFiles = internalFlushcache();
+        for(Iterator&lt;HStore&gt; it = stores.values().iterator(); it.hasNext(); ) {
+          HStore store = it.next();
+          store.close();
+        }
+        try {
+          return allHStoreFiles;
+
+        } finally {
+          synchronized(writestate) {
+            writestate.closed = true;
+            writestate.writesOngoing = false;
+          }
+          LOG.info(&quot;region &quot; + this.regionInfo.regionName + &quot; closed&quot;);
         }
-        LOG.info(&quot;region &quot; + this.regionInfo.regionName + &quot; closed&quot;);
       }
+    } finally {
+      lock.releaseWriteLock();
     }
   }
 
@@ -418,7 +451,9 @@ public class HRegion implements HConstants {
    *
    * Returns two brand-new (and open) HRegions
    */
-  public HRegion[] closeAndSplit(Text midKey) throws IOException {
+  public HRegion[] closeAndSplit(Text midKey, RegionUnavailableListener listener)
+      throws IOException {
+    
     if(((regionInfo.startKey.getLength() != 0)
         &amp;&amp; (regionInfo.startKey.compareTo(midKey) &gt; 0))
         || ((regionInfo.endKey.getLength() != 0)
@@ -428,9 +463,6 @@ public class HRegion implements HConstants {
 
     LOG.info(&quot;splitting region &quot; + this.regionInfo.regionName);
 
-    // Flush this HRegion out to storage, and turn off flushes
-    // or compactions until close() is called.
-    
     Path splits = new Path(regiondir, SPLITDIR);
     if(! fs.exists(splits)) {
       fs.mkdirs(splits);
@@ -453,6 +485,10 @@ public class HRegion implements HConstants {
     }
     
     TreeSet&lt;HStoreFile&gt; alreadySplit = new TreeSet&lt;HStoreFile&gt;();
+
+    // Flush this HRegion out to storage, and turn off flushes
+    // or compactions until close() is called.
+    
     Vector&lt;HStoreFile&gt; hstoreFilesToSplit = flushcache(true);
     for(Iterator&lt;HStoreFile&gt; it = hstoreFilesToSplit.iterator(); it.hasNext(); ) {
       HStoreFile hsf = it.next();
@@ -472,8 +508,12 @@ public class HRegion implements HConstants {
       alreadySplit.add(hsf);
     }
 
-    // We just copied most of the data.  Now close the HRegion
-    // and copy the small remainder
+    // We just copied most of the data.
+    // Notify the caller that we are about to close the region
+    
+    listener.regionIsUnavailable(this.getRegionName());
+    
+    // Now close the HRegion and copy the small remainder
     
     hstoreFilesToSplit = close();
     for(Iterator&lt;HStoreFile&gt; it = hstoreFilesToSplit.iterator(); it.hasNext(); ) {
@@ -577,19 +617,26 @@ public class HRegion implements HConstants {
    * @return            - true if the region should be split
    */
   public boolean needsSplit(Text midKey) {
-    Text key = new Text();
-    long maxSize = 0;
+    lock.obtainReadLock();
 
-    for(Iterator&lt;HStore&gt; i = stores.values().iterator(); i.hasNext(); ) {
-      long size = i.next().getLargestFileSize(key);
-      
-      if(size &gt; maxSize) {                      // Largest so far
-        maxSize = size;
-        midKey.set(key);
+    try {
+      Text key = new Text();
+      long maxSize = 0;
+
+      for(Iterator&lt;HStore&gt; i = stores.values().iterator(); i.hasNext(); ) {
+        long size = i.next().getLargestFileSize(key);
+
+        if(size &gt; maxSize) {                      // Largest so far
+          maxSize = size;
+          midKey.set(key);
+        }
       }
-    }
 
-    return (maxSize &gt; (DESIRED_MAX_FILE_SIZE + (DESIRED_MAX_FILE_SIZE / 2)));
+      return (maxSize &gt; (DESIRED_MAX_FILE_SIZE + (DESIRED_MAX_FILE_SIZE / 2)));
+      
+    } finally {
+      lock.releaseReadLock();
+    }
   }
 
   /**
@@ -597,11 +644,16 @@ public class HRegion implements HConstants {
    */
   public boolean needsCompaction() {
     boolean needsCompaction = false;
-    for(Iterator&lt;HStore&gt; i = stores.values().iterator(); i.hasNext(); ) {
-      if(i.next().getNMaps() &gt; compactionThreshold) {
-        needsCompaction = true;
-        break;
+    lock.obtainReadLock();
+    try {
+      for(Iterator&lt;HStore&gt; i = stores.values().iterator(); i.hasNext(); ) {
+        if(i.next().getNMaps() &gt; compactionThreshold) {
+          needsCompaction = true;
+          break;
+        }
       }
+    } finally {
+      lock.releaseReadLock();
     }
     return needsCompaction;
   }
@@ -621,15 +673,20 @@ public class HRegion implements HConstants {
    */
   public boolean compactStores() throws IOException {
     boolean shouldCompact = false;
-    synchronized(writestate) {
-      if((! writestate.writesOngoing)
-          &amp;&amp; writestate.writesEnabled
-          &amp;&amp; (! writestate.closed)
-          &amp;&amp; recentCommits &gt; MIN_COMMITS_FOR_COMPACTION) {
-        
-        writestate.writesOngoing = true;
-        shouldCompact = true;
+    lock.obtainReadLock();
+    try {
+      synchronized(writestate) {
+        if((! writestate.writesOngoing)
+            &amp;&amp; writestate.writesEnabled
+            &amp;&amp; (! writestate.closed)
+            &amp;&amp; recentCommits &gt; MIN_COMMITS_FOR_COMPACTION) {
+
+          writestate.writesOngoing = true;
+          shouldCompact = true;
+        }
       }
+    } finally {
+      lock.releaseReadLock();
     }
 
     if(! shouldCompact) {
@@ -637,6 +694,7 @@ public class HRegion implements HConstants {
       return false;
       
     } else {
+      lock.obtainWriteLock();
       try {
         LOG.info(&quot;starting compaction on region &quot; + this.regionInfo.regionName);
         for(Iterator&lt;HStore&gt; it = stores.values().iterator(); it.hasNext(); ) {
@@ -652,6 +710,7 @@ public class HRegion implements HConstants {
           recentCommits = 0;
           writestate.notifyAll();
         }
+        lock.releaseWriteLock();
       }
     }
   }
@@ -872,22 +931,28 @@ public class HRegion implements HConstants {
 
   private BytesWritable[] get(HStoreKey key, int numVersions) throws IOException {
 
-    // Check the memcache
+    lock.obtainReadLock();
+    try {
+      // Check the memcache
 
-    BytesWritable[] result = memcache.get(key, numVersions);
-    if(result != null) {
-      return result;
-    }
+      BytesWritable[] result = memcache.get(key, numVersions);
+      if(result != null) {
+        return result;
+      }
 
-    // If unavailable in memcache, check the appropriate HStore
+      // If unavailable in memcache, check the appropriate HStore
 
-    Text colFamily = HStoreKey.extractFamily(key.getColumn());
-    HStore targetStore = stores.get(colFamily);
-    if(targetStore == null) {
-      return null;
+      Text colFamily = HStoreKey.extractFamily(key.getColumn());
+      HStore targetStore = stores.get(colFamily);
+      if(targetStore == null) {
+        return null;
+      }
+
+      return targetStore.get(key, numVersions);
+      
+    } finally {
+      lock.releaseReadLock();
     }
-    
-    return targetStore.get(key, numVersions);
   }
 
   /**
@@ -903,13 +968,19 @@ public class HRegion implements HConstants {
   public TreeMap&lt;Text, BytesWritable&gt; getFull(Text row) throws IOException {
     HStoreKey key = new HStoreKey(row, System.currentTimeMillis());
 
-    TreeMap&lt;Text, BytesWritable&gt; memResult = memcache.getFull(key);
-    for(Iterator&lt;Text&gt; it = stores.keySet().iterator(); it.hasNext(); ) {
-      Text colFamily = it.next();
-      HStore targetStore = stores.get(colFamily);
-      targetStore.getFull(key, memResult);
+    lock.obtainReadLock();
+    try {
+      TreeMap&lt;Text, BytesWritable&gt; memResult = memcache.getFull(key);
+      for(Iterator&lt;Text&gt; it = stores.keySet().iterator(); it.hasNext(); ) {
+        Text colFamily = it.next();
+        HStore targetStore = stores.get(colFamily);
+        targetStore.getFull(key, memResult);
+      }
+      return memResult;
+      
+    } finally {
+      lock.releaseReadLock();
     }
-    return memResult;
   }
 
   /**
@@ -917,18 +988,24 @@ public class HRegion implements HConstants {
    * columns.  This Iterator must be closed by the caller.
    */
   public HInternalScannerInterface getScanner(Text[] cols, Text firstRow) throws IOException {
-    TreeSet&lt;Text&gt; families = new TreeSet&lt;Text&gt;();
-    for(int i = 0; i &lt; cols.length; i++) {
-      families.add(HStoreKey.extractFamily(cols[i]));
-    }
+    lock.obtainReadLock();
+    try {
+      TreeSet&lt;Text&gt; families = new TreeSet&lt;Text&gt;();
+      for(int i = 0; i &lt; cols.length; i++) {
+        families.add(HStoreKey.extractFamily(cols[i]));
+      }
 
-    HStore[] storelist = new HStore[families.size()];
-    int i = 0;
-    for(Iterator&lt;Text&gt; it = families.iterator(); it.hasNext(); ) {
-      Text family = it.next();
-      storelist[i++] = stores.get(family);
+      HStore[] storelist = new HStore[families.size()];
+      int i = 0;
+      for(Iterator&lt;Text&gt; it = families.iterator(); it.hasNext(); ) {
+        Text family = it.next();
+        storelist[i++] = stores.get(family);
+      }
+      return new HScanner(cols, firstRow, memcache, storelist);
+      
+    } finally {
+      lock.releaseReadLock();
     }
-    return new HScanner(cols, firstRow, memcache, storelist);
   }
 
   //////////////////////////////////////////////////////////////////////////////
@@ -949,8 +1026,14 @@ public class HRegion implements HConstants {
 
     // We obtain a per-row lock, so other clients will
     // block while one client performs an update.
-    
-    return obtainLock(row);
+
+    lock.obtainReadLock();
+    try {
+      return obtainLock(row);
+      
+    } finally {
+      lock.releaseReadLock();
+    }
   }
 
   /**
@@ -1176,9 +1259,16 @@ public class HRegion implements HConstants {
 
     /** Create an HScanner with a handle on many HStores. */
     @SuppressWarnings(&quot;unchecked&quot;)
-    public HScanner(Text[] cols, Text firstRow, HMemcache memcache, HStore[] stores) throws IOException {
+    public HScanner(Text[] cols, Text firstRow, HMemcache memcache, HStore[] stores)
+        throws IOException {
+      
       long scanTime = System.currentTimeMillis();
+      
       this.scanners = new HInternalScannerInterface[stores.length + 1];
+      for(int i = 0; i &lt; this.scanners.length; i++) {
+        this.scanners[i] = null;
+      }
+      
       this.resultSets = new TreeMap[scanners.length];
       this.keys = new HStoreKey[scanners.length];
       this.wildcardMatch = false;
@@ -1189,28 +1279,38 @@ public class HRegion implements HConstants {
       
       // NOTE: the memcache scanner should be the first scanner
 
-      HInternalScannerInterface scanner =
-        memcache.getScanner(scanTime, cols, firstRow);
-      
-      if(scanner.isWildcardScanner()) {
-        this.wildcardMatch = true;
-      }
-      if(scanner.isMultipleMatchScanner()) {
-        this.multipleMatchers = true;
-      }
-      scanners[0] = scanner;
-      
-      for(int i = 0; i &lt; stores.length; i++) {
-        scanner = stores[i].getScanner(scanTime, cols, firstRow);
+      try {
+        HInternalScannerInterface scanner =
+          memcache.getScanner(scanTime, cols, firstRow);
+
+
         if(scanner.isWildcardScanner()) {
           this.wildcardMatch = true;
         }
         if(scanner.isMultipleMatchScanner()) {
           this.multipleMatchers = true;
         }
-        scanners[i + 1] = scanner;
-      }
+        scanners[0] = scanner;
 
+        for(int i = 0; i &lt; stores.length; i++) {
+          scanner = stores[i].getScanner(scanTime, cols, firstRow);
+          if(scanner.isWildcardScanner()) {
+            this.wildcardMatch = true;
+          }
+          if(scanner.isMultipleMatchScanner()) {
+            this.multipleMatchers = true;
+          }
+          scanners[i + 1] = scanner;
+        }
+
+      } catch(IOException e) {
+        for(int i = 0; i &lt; this.scanners.length; i++) {
+          if(scanners[i] != null) {
+            closeScanner(i);
+          }
+        }
+        throw e;
+      }
       for(int i = 0; i &lt; scanners.length; i++) {
         keys[i] = new HStoreKey();
         resultSets[i] = new TreeMap&lt;Text, BytesWritable&gt;();
@@ -1319,7 +1419,7 @@ public class HRegion implements HConstants {
     }
 
     /** Shut down a single scanner */
-    void closeScanner(int i) throws IOException {
+    void closeScanner(int i) {
       try {
         scanners[i].close();
         
@@ -1331,7 +1431,7 @@ public class HRegion implements HConstants {
     }
 
     /** All done with the scanner. */
-    public void close() throws IOException {
+    public void close() {
       for(int i = 0; i &lt; scanners.length; i++) {
         if(scanners[i] != null) {
           closeScanner(i);</diff>
      <filename>src/java/org/apache/hadoop/hbase/HRegion.java</filename>
    </modified>
    <modified>
      <diff>@@ -30,7 +30,7 @@ public interface HRegionInterface extends VersionedProtocol {
 
   // Get metainfo about an HRegion
 
-  public HRegionInfo getRegionInfo(Text regionName);
+  public HRegionInfo getRegionInfo(Text regionName) throws NotServingRegionException;
 
   // GET methods for an HRegion.
 </diff>
      <filename>src/java/org/apache/hadoop/hbase/HRegionInterface.java</filename>
    </modified>
    <modified>
      <diff>@@ -46,7 +46,7 @@ public class HRegionServer
   
   private volatile boolean stopRequested;
   private Path regionDir;
-  private HServerAddress address;
+  private HServerInfo info;
   private Configuration conf;
   private Random rand;
   private TreeMap&lt;Text, HRegion&gt; regions;               // region name -&gt; HRegion
@@ -64,24 +64,26 @@ public class HRegionServer
   private Thread splitOrCompactCheckerThread;
   private Integer splitOrCompactLock = new Integer(0);
   
-  private class SplitOrCompactChecker implements Runnable {
+  private class SplitOrCompactChecker implements Runnable, RegionUnavailableListener {
     private HClient client = new HClient(conf);
   
-    private class SplitRegion {
-      public HRegion region;
-      public Text midKey;
-      
-      SplitRegion(HRegion region, Text midKey) {
-        this.region = region;
-        this.midKey = midKey;
-      }
+    /* (non-Javadoc)
+     * @see org.apache.hadoop.hbase.RegionUnavailableListener#regionIsUnavailable(org.apache.hadoop.io.Text)
+     */
+    public void regionIsUnavailable(Text regionName) {
+      lock.obtainWriteLock();
+      regions.remove(regionName);
+      lock.releaseWriteLock();
     }
-    
+
+    /* (non-Javadoc)
+     * @see java.lang.Runnable#run()
+     */
     public void run() {
       while(! stopRequested) {
         long startTime = System.currentTimeMillis();
 
-        synchronized(splitOrCompactLock) {
+        synchronized(splitOrCompactLock) { // Don't interrupt us while we're working
 
           // Grab a list of regions to check
 
@@ -93,85 +95,81 @@ public class HRegionServer
             lock.releaseReadLock();
           }
 
-          // Check to see if they need splitting or compacting
-
-          Vector&lt;SplitRegion&gt; toSplit = new Vector&lt;SplitRegion&gt;();
-          Vector&lt;HRegion&gt; toCompact = new Vector&lt;HRegion&gt;();
-          for(Iterator&lt;HRegion&gt; it = regionsToCheck.iterator(); it.hasNext(); ) {
-            HRegion cur = it.next();
-            Text midKey = new Text();
-
-            if(cur.needsCompaction()) {
-              toCompact.add(cur);
-
-            } else if(cur.needsSplit(midKey)) {
-              toSplit.add(new SplitRegion(cur, midKey));
-            }
-          }
-
           try {
-            for(Iterator&lt;HRegion&gt;it = toCompact.iterator(); it.hasNext(); ) {
-              it.next().compactStores();
-            }
-
-            for(Iterator&lt;SplitRegion&gt; it = toSplit.iterator(); it.hasNext(); ) {
-              SplitRegion r = it.next();
-
-              lock.obtainWriteLock();
-              regions.remove(r.region.getRegionName());
-              lock.releaseWriteLock();
-
-              HRegion[] newRegions = null;
-              Text oldRegion = r.region.getRegionName();
-
-              LOG.info(&quot;splitting region: &quot; + oldRegion);
-
-              newRegions = r.region.closeAndSplit(r.midKey);
-
-              // When a region is split, the META table needs to updated if we're
-              // splitting a 'normal' region, and the ROOT table needs to be
-              // updated if we are splitting a META region.
-
-              Text tableToUpdate =
-                (oldRegion.find(META_TABLE_NAME.toString()) == 0) ?
-                    ROOT_TABLE_NAME : META_TABLE_NAME;
-
-              if(LOG.isDebugEnabled()) {
-                LOG.debug(&quot;region split complete. updating meta&quot;);
-              }
-
-              client.openTable(tableToUpdate);
-              long lockid = client.startUpdate(oldRegion);
-              client.delete(lockid, COL_REGIONINFO);
-              client.delete(lockid, COL_SERVER);
-              client.delete(lockid, COL_STARTCODE);
-              client.commit(lockid);
-
-              for(int i = 0; i &lt; newRegions.length; i++) {
-                ByteArrayOutputStream bytes = new ByteArrayOutputStream();
-                DataOutputStream out = new DataOutputStream(bytes);
-                newRegions[i].getRegionInfo().write(out);
-
-                lockid = client.startUpdate(newRegions[i].getRegionName());
-                client.put(lockid, COL_REGIONINFO, bytes.toByteArray());
-                client.commit(lockid);
+            for(Iterator&lt;HRegion&gt;it = regionsToCheck.iterator(); it.hasNext(); ) {
+              HRegion cur = it.next();
+              
+              if(cur.isClosed()) {
+                continue;                               // Skip if closed
               }
-
-              // Now tell the master about the new regions
-
-              if(LOG.isDebugEnabled()) {
-                LOG.debug(&quot;reporting region split to master&quot;);
+              
+              if(cur.needsCompaction()) {
+                
+                // The best time to split a region is right after it has been compacted
+                
+                if(cur.compactStores()) {
+                  Text midKey = new Text();
+                  if(cur.needsSplit(midKey)) {
+                    Text oldRegion = cur.getRegionName();
+
+                    LOG.info(&quot;splitting region: &quot; + oldRegion);
+
+                    HRegion[] newRegions = cur.closeAndSplit(midKey, this);
+
+                    // When a region is split, the META table needs to updated if we're
+                    // splitting a 'normal' region, and the ROOT table needs to be
+                    // updated if we are splitting a META region.
+
+                    if(LOG.isDebugEnabled()) {
+                      LOG.debug(&quot;region split complete. updating meta&quot;);
+                    }
+
+                    Text tableToUpdate =
+                      (oldRegion.find(META_TABLE_NAME.toString()) == 0) ?
+                          ROOT_TABLE_NAME : META_TABLE_NAME;
+
+                    client.openTable(tableToUpdate);
+                    long lockid = client.startUpdate(oldRegion);
+                    client.delete(lockid, COL_REGIONINFO);
+                    client.delete(lockid, COL_SERVER);
+                    client.delete(lockid, COL_STARTCODE);
+                    client.commit(lockid);
+
+                    for(int i = 0; i &lt; newRegions.length; i++) {
+                      ByteArrayOutputStream bytes = new ByteArrayOutputStream();
+                      DataOutputStream out = new DataOutputStream(bytes);
+                      newRegions[i].getRegionInfo().write(out);
+
+                      lockid = client.startUpdate(newRegions[i].getRegionName());
+                      client.put(lockid, COL_REGIONINFO, bytes.toByteArray());
+                      client.put(lockid, COL_SERVER, 
+                          info.getServerAddress().toString().getBytes(UTF8_ENCODING));
+                      client.put(lockid, COL_STARTCODE, 
+                          String.valueOf(info.getStartCode()).getBytes(UTF8_ENCODING));
+                      client.commit(lockid);
+                    }
+                    
+                    // Now tell the master about the new regions
+
+                    if(LOG.isDebugEnabled()) {
+                      LOG.debug(&quot;reporting region split to master&quot;);
+                    }
+
+                    reportSplit(newRegions[0].getRegionInfo(), newRegions[1].getRegionInfo());
+
+                    LOG.info(&quot;region split successful. old region=&quot; + oldRegion
+                        + &quot;, new regions: &quot; + newRegions[0].getRegionName() + &quot;, &quot;
+                        + newRegions[1].getRegionName());
+
+                    // Finally, start serving the new regions
+                    
+                    lock.obtainWriteLock();
+                    regions.put(newRegions[0].getRegionName(), newRegions[0]);
+                    regions.put(newRegions[1].getRegionName(), newRegions[1]);
+                    lock.releaseWriteLock();
+                  }
+                }
               }
-
-              reportSplit(newRegions[0].getRegionInfo(), newRegions[1].getRegionInfo());
-
-              LOG.info(&quot;region split successful. old region=&quot; + oldRegion
-                  + &quot;, new regions: &quot; + newRegions[0].getRegionName() + &quot;, &quot;
-                  + newRegions[1].getRegionName());
-
-              newRegions[0].close();
-              newRegions[1].close();
-
             }
           } catch(IOException e) {
             //TODO: What happens if this fails? Are we toast?
@@ -228,6 +226,10 @@ public class HRegionServer
 
           for(Iterator&lt;HRegion&gt; it = toFlush.iterator(); it.hasNext(); ) {
             HRegion cur = it.next();
+            
+            if(cur.isClosed()) {                // Skip if closed
+              continue;
+            }
 
             try {
               cur.optionallyFlush();
@@ -330,8 +332,7 @@ public class HRegionServer
   
   /** Start a HRegionServer at an indicated location */
   public HRegionServer(Path regionDir, HServerAddress address,
-      Configuration conf) 
-  throws IOException {
+      Configuration conf) throws IOException {
     
     // Basic setup
     this.stopRequested = false;
@@ -369,19 +370,25 @@ public class HRegionServer
 
     try {
       // Server to handle client requests
+      
       this.server = RPC.getServer(this, address.getBindAddress().toString(), 
         address.getPort(), conf.getInt(&quot;hbase.regionserver.handler.count&quot;, 10),
         false, conf);
 
-      this.address = new HServerAddress(server.getListenerAddress());
+      this.info = new HServerInfo(new HServerAddress(server.getListenerAddress()),
+          this.rand.nextLong());
 
       // Local file paths
+      
       String serverName =
-        this.address.getBindAddress() + &quot;_&quot; + this.address.getPort();
+        this.info.getServerAddress().getBindAddress() + &quot;_&quot;
+        + this.info.getServerAddress().getPort();
+      
       Path newlogdir = new Path(regionDir, &quot;log&quot; + &quot;_&quot; + serverName);
       this.oldlogfile = new Path(regionDir, &quot;oldlogfile&quot; + &quot;_&quot; + serverName);
 
       // Logging
+      
       this.fs = FileSystem.get(conf);
       HLog.consolidateOldLog(newlogdir, oldlogfile, fs, conf);
       // TODO: Now we have a consolidated log for all regions, sort and
@@ -393,13 +400,14 @@ public class HRegionServer
       this.logRollerThread = new Thread(logRoller, &quot;HRegionServer.logRoller&quot;);
 
       // Remote HMaster
-      this.hbaseMaster = (HMasterRegionInterface)RPC.
-        waitForProxy(HMasterRegionInterface.class,
-        HMasterRegionInterface.versionID,
-        new HServerAddress(conf.get(MASTER_ADDRESS)).getInetSocketAddress(),
-        conf);
+      
+      this.hbaseMaster = (HMasterRegionInterface)RPC.waitForProxy(
+          HMasterRegionInterface.class, HMasterRegionInterface.versionID,
+          new HServerAddress(conf.get(MASTER_ADDRESS)).getInetSocketAddress(),
+          conf);
 
       // Threads
+      
       this.workerThread.start();
       this.cacheFlusherThread.start();
       this.splitOrCompactCheckerThread.start();
@@ -452,7 +460,7 @@ public class HRegionServer
       this.server.join();
     } catch(InterruptedException iex) {
     }
-    LOG.info(&quot;HRegionServer stopped at: &quot; + address.toString());
+    LOG.info(&quot;HRegionServer stopped at: &quot; + info.getServerAddress().toString());
   }
   
   /**
@@ -462,7 +470,6 @@ public class HRegionServer
    */
   public void run() {
     while(! stopRequested) {
-      HServerInfo info = new HServerInfo(address, rand.nextLong());
       long lastMsg = 0;
       long waitTime;
 
@@ -557,7 +564,7 @@ public class HRegionServer
             }
 
           } catch(IOException e) {
-            e.printStackTrace();
+            LOG.error(e);
           }
         }
 
@@ -580,7 +587,7 @@ public class HRegionServer
       }
     }
     try {
-      LOG.info(&quot;stopping server at: &quot; + address.toString());
+      LOG.info(&quot;stopping server at: &quot; + info.getServerAddress().toString());
 
       // Send interrupts to wake up threads if sleeping so they notice shutdown.
 
@@ -761,58 +768,68 @@ public class HRegionServer
       throws IOException {
     
     this.lock.obtainWriteLock();
+    HRegion region = null;
     try {
-      HRegion region = regions.remove(info.regionName);
-      
-      if(region != null) {
-        region.close();
-        
-        if(reportWhenCompleted) {
-          reportClose(region);
-        }
-      }
-      
+      region = regions.remove(info.regionName);
     } finally {
       this.lock.releaseWriteLock();
     }
+      
+    if(region != null) {
+      region.close();
+
+      if(reportWhenCompleted) {
+        reportClose(region);
+      }
+    }
   }
 
   private void closeAndDeleteRegion(HRegionInfo info) throws IOException {
-
     this.lock.obtainWriteLock();
+    HRegion region = null;
     try {
-      HRegion region = regions.remove(info.regionName);
-  
-      if(region != null) {
-        region.closeAndDelete();
-      }
+      region = regions.remove(info.regionName);
   
     } finally {
       this.lock.releaseWriteLock();
     }
+    if(region != null) {
+      if(LOG.isDebugEnabled()) {
+        LOG.debug(&quot;deleting region &quot; + info.regionName);
+      }
+      
+      region.closeAndDelete();
+      
+      if(LOG.isDebugEnabled()) {
+        LOG.debug(&quot;region &quot; + info.regionName + &quot; deleted&quot;);
+      }
+    }
   }
 
   /** Called either when the master tells us to restart or from stop() */
   private void closeAllRegions() {
+    Vector&lt;HRegion&gt; regionsToClose = new Vector&lt;HRegion&gt;();
     this.lock.obtainWriteLock();
     try {
-      for(Iterator&lt;HRegion&gt; it = regions.values().iterator(); it.hasNext(); ) {
-        HRegion region = it.next();
-        if (LOG.isDebugEnabled()) {
-          LOG.debug(&quot;closing region &quot; + region.getRegionName());
-        }
-        try {
-          region.close();
-          
-        } catch(IOException e) {
-          e.printStackTrace();
-        }
-      }
+      regionsToClose.addAll(regions.values());
       regions.clear();
       
     } finally {
       this.lock.releaseWriteLock();
     }
+    for(Iterator&lt;HRegion&gt; it = regionsToClose.iterator(); it.hasNext(); ) {
+      HRegion region = it.next();
+      if (LOG.isDebugEnabled()) {
+        LOG.debug(&quot;closing region &quot; + region.getRegionName());
+      }
+      try {
+        region.close();
+        LOG.debug(&quot;region closed &quot; + region.getRegionName());
+        
+      } catch(IOException e) {
+        LOG.error(&quot;error closing region &quot; + region.getRegionName(), e);
+      }
+    }
   }
 
   /*****************************************************************************
@@ -847,20 +864,14 @@ public class HRegionServer
   //////////////////////////////////////////////////////////////////////////////
 
   /** Obtain a table descriptor for the given region */
-  public HRegionInfo getRegionInfo(Text regionName) {
+  public HRegionInfo getRegionInfo(Text regionName) throws NotServingRegionException {
     HRegion region = getRegion(regionName);
-    if(region == null) {
-      return null;
-    }
     return region.getRegionInfo();
   }
 
   /** Get the indicated row/column */
   public BytesWritable get(Text regionName, Text row, Text column) throws IOException {
     HRegion region = getRegion(regionName);
-    if(region == null) {
-      throw new IOException(&quot;Not serving region &quot; + regionName);
-    }
     
     if (LOG.isDebugEnabled()) {
       LOG.debug(&quot;get &quot; + row.toString() + &quot;, &quot; + column.toString());
@@ -877,9 +888,6 @@ public class HRegionServer
       int numVersions) throws IOException {
     
     HRegion region = getRegion(regionName);
-    if(region == null) {
-      throw new IOException(&quot;Not serving region &quot; + regionName);
-    }
     
     BytesWritable[] results = region.get(row, column, numVersions);
     if(results != null) {
@@ -893,9 +901,6 @@ public class HRegionServer
       long timestamp, int numVersions) throws IOException {
     
     HRegion region = getRegion(regionName);
-    if(region == null) {
-      throw new IOException(&quot;Not serving region &quot; + regionName);
-    }
     
     BytesWritable[] results = region.get(row, column, timestamp, numVersions);
     if(results != null) {
@@ -907,9 +912,6 @@ public class HRegionServer
   /** Get all the columns (along with their names) for a given row. */
   public LabelledData[] getRow(Text regionName, Text row) throws IOException {
     HRegion region = getRegion(regionName);
-    if(region == null) {
-      throw new IOException(&quot;Not serving region &quot; + regionName);
-    }
     
     TreeMap&lt;Text, BytesWritable&gt; map = region.getFull(row);
     LabelledData result[] = new LabelledData[map.size()];
@@ -949,9 +951,6 @@ public class HRegionServer
       throws IOException {
     
     HRegion region = getRegion(regionName);
-    if(region == null) {
-      throw new IOException(&quot;Not serving region &quot; + regionName);
-    }
     
     long lockid = region.startUpdate(row);
     leases.createLease(new Text(String.valueOf(clientid)), 
@@ -966,9 +965,6 @@ public class HRegionServer
       BytesWritable val) throws IOException {
     
     HRegion region = getRegion(regionName);
-    if(region == null) {
-      throw new IOException(&quot;Not serving region &quot; + regionName);
-    }
     
     leases.renewLease(new Text(String.valueOf(clientid)), 
         new Text(String.valueOf(lockid)));
@@ -981,9 +977,6 @@ public class HRegionServer
       throws IOException {
     
     HRegion region = getRegion(regionName);
-    if(region == null) {
-      throw new IOException(&quot;Not serving region &quot; + regionName);
-    }
     
     leases.renewLease(new Text(String.valueOf(clientid)), 
         new Text(String.valueOf(lockid)));
@@ -996,9 +989,6 @@ public class HRegionServer
       throws IOException {
     
     HRegion region = getRegion(regionName);
-    if(region == null) {
-      throw new IOException(&quot;Not serving region &quot; + regionName);
-    }
     
     leases.cancelLease(new Text(String.valueOf(clientid)), 
         new Text(String.valueOf(lockid)));
@@ -1011,9 +1001,6 @@ public class HRegionServer
       throws IOException {
     
     HRegion region = getRegion(regionName);
-    if(region == null) {
-      throw new IOException(&quot;Not serving region &quot; + regionName);
-    }
     
     leases.cancelLease(new Text(String.valueOf(clientid)), 
         new Text(String.valueOf(lockid)));
@@ -1028,14 +1015,20 @@ public class HRegionServer
   }
 
   /** Private utility method for safely obtaining an HRegion handle. */
-  private HRegion getRegion(Text regionName) {
+  private HRegion getRegion(Text regionName) throws NotServingRegionException {
     this.lock.obtainReadLock();
+    HRegion region = null;
     try {
-      return regions.get(regionName);
+      region = regions.get(regionName);
       
     } finally {
       this.lock.releaseReadLock();
     }
+
+    if(region == null) {
+      throw new NotServingRegionException(regionName.toString());
+    }
+    return region;
   }
 
   //////////////////////////////////////////////////////////////////////////////
@@ -1051,14 +1044,12 @@ public class HRegionServer
     }
     
     public void leaseExpired() {
-      HInternalScannerInterface s = scanners.remove(scannerName);
+      HInternalScannerInterface s = null;
+      synchronized(scanners) {
+        s = scanners.remove(scannerName);
+      }
       if(s != null) {
-        try {
-          s.close();
-          
-        } catch(IOException e) {
-          e.printStackTrace();
-        }
+        s.close();
       }
     }
   }
@@ -1068,16 +1059,14 @@ public class HRegionServer
       throws IOException {
 
     HRegion r = getRegion(regionName);
-    if(r == null) {
-      throw new IOException(&quot;Not serving region &quot; + regionName);
-    }
-
     long scannerId = -1L;
     try {
       HInternalScannerInterface s = r.getScanner(cols, firstRow);
       scannerId = rand.nextLong();
       Text scannerName = new Text(String.valueOf(scannerId));
-      scanners.put(scannerName, s);
+      synchronized(scanners) {
+        scanners.put(scannerName, s);
+      }
       leases.createLease(scannerName, scannerName, new ScannerListener(scannerName));
     
     } catch(IOException e) {
@@ -1121,16 +1110,14 @@ public class HRegionServer
   
   public void close(long scannerId) throws IOException {
     Text scannerName = new Text(String.valueOf(scannerId));
-    HInternalScannerInterface s = scanners.remove(scannerName);
+    HInternalScannerInterface s = null;
+    synchronized(scanners) {
+      s = scanners.remove(scannerName);
+    }
     if(s == null) {
       throw new IOException(&quot;unknown scanner&quot;);
     }
-    try {
-      s.close();
-        
-    } catch(IOException ex) {
-      ex.printStackTrace();
-    }
+    s.close();
     leases.cancelLease(scannerName, scannerName);
   }
 </diff>
      <filename>src/java/org/apache/hadoop/hbase/HRegionServer.java</filename>
    </modified>
    <modified>
      <diff>@@ -342,8 +342,14 @@ public class HStore {
     }
   }
 
-  public synchronized Vector&lt;HStoreFile&gt; getAllMapFiles() {
-    return new Vector&lt;HStoreFile&gt;(mapFiles.values());
+  public Vector&lt;HStoreFile&gt; getAllMapFiles() {
+    this.lock.obtainReadLock();
+    try {
+      return new Vector&lt;HStoreFile&gt;(mapFiles.values());
+      
+    } finally {
+      this.lock.releaseReadLock();
+    }
   }
 
   //////////////////////////////////////////////////////////////////////////////
@@ -938,7 +944,9 @@ public class HStore {
   class HStoreScanner extends HAbstractScanner {
     private MapFile.Reader[] readers;
     
-    public HStoreScanner(long timestamp, Text[] targetCols, Text firstRow) throws IOException {
+    public HStoreScanner(long timestamp, Text[] targetCols, Text firstRow)
+        throws IOException {
+      
       super(timestamp, targetCols);
 
       lock.obtainReadLock();
@@ -976,6 +984,7 @@ public class HStore {
         }
         
       } catch (Exception ex) {
+        LOG.error(ex);
         close();
       }
     }
@@ -1021,10 +1030,15 @@ public class HStore {
     }
     
     /** Close down the indicated reader. */
-    void closeSubScanner(int i) throws IOException {
+    void closeSubScanner(int i) {
       try {
         if(readers[i] != null) {
-          readers[i].close();
+          try {
+            readers[i].close();
+            
+          } catch(IOException e) {
+            LOG.error(e);
+          }
         }
         
       } finally {
@@ -1035,12 +1049,17 @@ public class HStore {
     }
 
     /** Shut it down! */
-    public void close() throws IOException {
+    public void close() {
       if(! scannerClosed) {
         try {
           for(int i = 0; i &lt; readers.length; i++) {
             if(readers[i] != null) {
-              readers[i].close();
+              try {
+                readers[i].close();
+                
+              } catch(IOException e) {
+                LOG.error(e);
+              }
             }
           }
           </diff>
      <filename>src/java/org/apache/hadoop/hbase/HStore.java</filename>
    </modified>
    <modified>
      <diff>@@ -15,6 +15,8 @@
  */
 package org.apache.hadoop.hbase;
 
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
 import org.apache.hadoop.io.*;
 
 import java.io.*;
@@ -36,6 +38,8 @@ import java.util.*;
  * You should close() the instance if you want to clean up the thread properly.
  ******************************************************************************/
 public class Leases {
+  private static final Log LOG = LogFactory.getLog(Leases.class);
+
   long leasePeriod;
   long leaseCheckFrequency;
   LeaseMonitor leaseMonitor;
@@ -47,7 +51,7 @@ public class Leases {
   /** Indicate the length of the lease, in milliseconds */
   public Leases(long leasePeriod, long leaseCheckFrequency) {
     this.leasePeriod = leasePeriod;
-
+    this.leaseCheckFrequency = leaseCheckFrequency;
     this.leaseMonitor = new LeaseMonitor();
     this.leaseMonitorThread = new Thread(leaseMonitor);
     this.leaseMonitorThread.setName(&quot;Lease.monitor&quot;);
@@ -59,6 +63,9 @@ public class Leases {
    * without any cancellation calls.
    */
   public void close() {
+    if(LOG.isDebugEnabled()) {
+      LOG.debug(&quot;closing leases&quot;);
+    }
     this.running = false;
     try {
       this.leaseMonitorThread.interrupt();
@@ -71,6 +78,9 @@ public class Leases {
         sortedLeases.clear();
       }
     }
+    if(LOG.isDebugEnabled()) {
+      LOG.debug(&quot;leases closed&quot;);
+    }
   }
 
   /** A client obtains a lease... */</diff>
      <filename>src/java/org/apache/hadoop/hbase/Leases.java</filename>
    </modified>
    <modified>
      <diff>@@ -35,9 +35,9 @@ public class MiniHBaseCluster implements HConstants {
   private MiniDFSCluster cluster;
   private FileSystem fs;
   private Path parentdir;
-  private HMasterRunner masterRunner;
-  private Thread masterRunnerThread;
-  private HRegionServerRunner[] regionServers;
+  private HMaster master;
+  private Thread masterThread;
+  private HRegionServer[] regionServers;
   private Thread[] regionThreads;
   
   public MiniHBaseCluster(Configuration conf, int nRegionNodes) {
@@ -58,13 +58,13 @@ public class MiniHBaseCluster implements HConstants {
 
     try {
       try {
-        if(System.getProperty(&quot;test.build.data&quot;) == null) {
+        if(System.getProperty(StaticTestEnvironment.TEST_DIRECTORY_KEY) == null) {
           File testDir = new File(new File(&quot;&quot;).getAbsolutePath(),
               &quot;build/contrib/hbase/test&quot;);
 
           String dir = testDir.getAbsolutePath();
           LOG.info(&quot;Setting test.build.data to &quot; + dir);
-          System.setProperty(&quot;test.build.data&quot;, dir);
+          System.setProperty(StaticTestEnvironment.TEST_DIRECTORY_KEY, dir);
         }
 
         if (miniHdfsFilesystem) {
@@ -85,26 +85,15 @@ public class MiniHBaseCluster implements HConstants {
       }
       
       // Create the master
-      this.masterRunner = new HMasterRunner();
-      this.masterRunnerThread = new Thread(masterRunner, &quot;masterRunner&quot;);
+      this.master = new HMaster(conf);
+      this.masterThread = new Thread(this.master, &quot;HMaster&quot;);
 
       // Start up the master
       LOG.info(&quot;Starting HMaster&quot;);
-      masterRunnerThread.start();
-      while(! masterRunner.isCrashed() &amp;&amp; ! masterRunner.isInitialized()) {
-        try {
-          LOG.info(&quot;...waiting for HMaster to initialize...&quot;);
-          Thread.sleep(1000);
-        } catch(InterruptedException e) {
-        }
-        if(masterRunner.isCrashed()) {
-          throw new RuntimeException(&quot;HMaster crashed&quot;);
-        }
-      }
-      LOG.info(&quot;HMaster started.&quot;);
+      masterThread.start();
       
       // Set the master's port for the HRegionServers
-      String address = masterRunner.getHMasterAddress().toString();
+      String address = master.getMasterAddress().toString();
       this.conf.set(MASTER_ADDRESS, address);
 
       // Start the HRegionServers
@@ -115,34 +104,20 @@ public class MiniHBaseCluster implements HConstants {
       
       LOG.info(&quot;Starting HRegionServers&quot;);
       startRegionServers(this.conf, nRegionNodes);
-      LOG.info(&quot;HRegionServers running&quot;);
-
-      // Wait for things to get started
-
-      while(! masterRunner.isCrashed() &amp;&amp; ! masterRunner.isUp()) {
-        try {
-          LOG.info(&quot;Waiting for Mini HBase cluster to start...&quot;);
-          Thread.sleep(1000);
-        } catch(InterruptedException e) {
-        }
-        if(masterRunner.isCrashed()) {
-          throw new RuntimeException(&quot;HMaster crashed&quot;);
-        }
-      }
       
     } catch(Throwable e) {
-      // Delete all DFS files
-      deleteFile(new File(System.getProperty(&quot;test.build.data&quot;), &quot;dfs&quot;));
-      throw new RuntimeException(&quot;Mini HBase cluster did not start&quot;);
+      e.printStackTrace();
+      shutdown();
     }
   }
   
-  private void startRegionServers(Configuration conf, int nRegionNodes) {
-    this.regionServers = new HRegionServerRunner[nRegionNodes];
+  private void startRegionServers(Configuration conf, int nRegionNodes)
+      throws IOException {
+    this.regionServers = new HRegionServer[nRegionNodes];
     this.regionThreads = new Thread[nRegionNodes];
     
     for(int i = 0; i &lt; nRegionNodes; i++) {
-      regionServers[i] = new HRegionServerRunner(conf);
+      regionServers[i] = new HRegionServer(conf);
       regionThreads[i] = new Thread(regionServers[i], &quot;HRegionServer-&quot; + i);
       regionThreads[i].start();
     }
@@ -153,35 +128,48 @@ public class MiniHBaseCluster implements HConstants {
    * supplied port is not necessarily the actual port used.
    */
   public HServerAddress getHMasterAddress() {
-    return masterRunner.getHMasterAddress();
+    return master.getMasterAddress();
   }
   
   /** Shut down the HBase cluster */
   public void shutdown() {
     LOG.info(&quot;Shutting down the HBase Cluster&quot;);
     for(int i = 0; i &lt; regionServers.length; i++) {
-      regionServers[i].shutdown();
+      try {
+        regionServers[i].stop();
+        
+      } catch(IOException e) {
+        e.printStackTrace();
+      }
+    }
+    try {
+      master.shutdown();
+      
+    } catch(IOException e) {
+      e.printStackTrace();
     }
-    masterRunner.shutdown();
     for(int i = 0; i &lt; regionServers.length; i++) {
       try {
         regionThreads[i].join();
-      } catch (InterruptedException e) {
-        e.printStackTrace();
+        
+      } catch(InterruptedException e) {
       }
     }
     try {
-      masterRunnerThread.join();
-    } catch (InterruptedException e) {
-      e.printStackTrace();
+      masterThread.join();
+      
+    } catch(InterruptedException e) {
     }
-    if (cluster != null) {
+    LOG.info(&quot;HBase Cluster shutdown complete&quot;);
+
+    if(cluster != null) {
       LOG.info(&quot;Shutting down Mini DFS cluster&quot;);
       cluster.shutdown();
     }
     
     // Delete all DFS files
-    deleteFile(new File(System.getProperty(&quot;test.build.data&quot;), &quot;dfs&quot;));
+    deleteFile(new File(System.getProperty(
+        StaticTestEnvironment.TEST_DIRECTORY_KEY), &quot;dfs&quot;));
   }
   
   private void deleteFile(File f) {
@@ -193,126 +181,4 @@ public class MiniHBaseCluster implements HConstants {
     }
     f.delete();
   }
-  
-  private class HMasterRunner implements Runnable {
-    private HMaster master = null;
-    private Thread masterThread = null;
-    private volatile boolean isInitialized = false;
-    private boolean isCrashed = false;
-    private boolean isRunning = true;
-    private long threadSleepTime = conf.getLong(THREAD_WAKE_FREQUENCY, 10 * 1000);
-    
-    public HServerAddress getHMasterAddress() {
-      return this.master.getMasterAddress();
-    }
-    
-    public synchronized boolean isInitialized() {
-      return isInitialized;
-    }
-    
-    public synchronized boolean isCrashed() {
-      return isCrashed;
-    }
-    
-    public boolean isUp() {
-      if(master == null) {
-        return false;
-      }
-      synchronized(this) {
-        return isInitialized;
-      }
-    }
-    
-    /** Create the HMaster and run it */
-    public void run() {
-      try {
-        synchronized(this) {
-          if(isRunning) {
-            this.master = new HMaster(conf);
-            masterThread = new Thread(this.master);
-            masterThread.start();
-          }
-          isInitialized = true;
-        }
-      } catch(Throwable e) {
-        shutdown();
-        LOG.error(&quot;HMaster crashed:&quot;, e);
-        synchronized(this) {
-          isCrashed = true;
-        }
-      }
-
-      while(this.master != null &amp;&amp; this.master.isMasterRunning()) {
-        try {
-          Thread.sleep(threadSleepTime);
-          
-        } catch(InterruptedException e) {
-        }
-      }
-      synchronized(this) {
-        isCrashed = true;
-      }
-      shutdown();
-    }
-    
-    /** Shut down the HMaster and wait for it to finish */
-    public synchronized void shutdown() {
-      isRunning = false;
-      if (this.master != null) {
-        try {
-          this.master.shutdown();
-        } catch(IOException e) {
-          LOG.error(&quot;Master crashed during stop&quot;, e);
-        } finally {
-          try {
-            masterThread.join();
-          } catch(InterruptedException e) {
-          }
-          master = null;
-        }
-      }
-    }
-  }
-  
-  private class HRegionServerRunner implements Runnable {
-    private HRegionServer server = null;
-    private boolean isRunning = true;
-    private Configuration conf;
-    
-    public HRegionServerRunner(Configuration conf) {
-      this.conf = conf;
-    }
-    
-    /** Start up the HRegionServer */
-    public void run() {
-      try {
-        synchronized(this) {
-          if(isRunning) {
-            server = new HRegionServer(conf);
-          }
-        }
-        server.run();
-        
-      } catch(Throwable e) {
-        shutdown();
-        LOG.error(&quot;HRegionServer crashed:&quot;, e);
-      }
-    }
-    
-    /** Shut down the HRegionServer */
-    public synchronized void shutdown() {
-      isRunning = false;
-      if(server != null) {
-        try {
-          server.stop();
-          
-        } catch(IOException e) {
-          LOG.error(&quot;HRegionServer crashed during stop&quot;, e);
-        } finally {
-          server.join();
-          server = null;
-        }
-      }
-    }
-  }
 }</diff>
      <filename>src/test/org/apache/hadoop/hbase/MiniHBaseCluster.java</filename>
    </modified>
    <modified>
      <diff>@@ -17,29 +17,17 @@ package org.apache.hadoop.hbase;
 
 import java.io.ByteArrayOutputStream;
 import java.io.DataOutputStream;
-import java.io.File;
 import java.io.IOException;
-import java.util.Enumeration;
 import java.util.Iterator;
 import java.util.TreeMap;
 
-import org.apache.hadoop.conf.Configuration;
 import org.apache.hadoop.dfs.MiniDFSCluster;
 import org.apache.hadoop.fs.FileSystem;
 import org.apache.hadoop.fs.Path;
 import org.apache.hadoop.io.BytesWritable;
 import org.apache.hadoop.io.Text;
 
-import org.apache.log4j.Appender;
-import org.apache.log4j.ConsoleAppender;
-import org.apache.log4j.Layout;
-import org.apache.log4j.Level;
-import org.apache.log4j.Logger;
-import org.apache.log4j.PatternLayout;
-
-import junit.framework.TestCase;
-
-public class TestGet extends TestCase {
+public class TestGet extends HBaseTestCase {
   private static final Text CONTENTS = new Text(&quot;contents:&quot;);
   private static final Text ROW_KEY = new Text(HGlobals.rootRegionInfo.regionName);
 
@@ -71,7 +59,6 @@ public class TestGet extends TestCase {
     }
   }
   
-  @SuppressWarnings(&quot;unchecked&quot;)
   public void testGet() throws IOException {
     MiniDFSCluster cluster = null;
 
@@ -79,37 +66,6 @@ public class TestGet extends TestCase {
       
       // Initialization
       
-      if(System.getProperty(&quot;test.build.data&quot;) == null) {
-        String dir = new File(new File(&quot;&quot;).getAbsolutePath(), &quot;build/contrib/hbase/test&quot;).getAbsolutePath();
-        System.out.println(dir);
-        System.setProperty(&quot;test.build.data&quot;, dir);
-      }
-      Configuration conf = new HBaseConfiguration();
-    
-      Environment.getenv();
-      if(Environment.debugging) {
-        Logger rootLogger = Logger.getRootLogger();
-        rootLogger.setLevel(Level.WARN);
-
-        ConsoleAppender consoleAppender = null;
-        for(Enumeration&lt;Appender&gt; e = (Enumeration&lt;Appender&gt;)rootLogger.getAllAppenders();
-            e.hasMoreElements();) {
-        
-          Appender a = e.nextElement();
-          if(a instanceof ConsoleAppender) {
-            consoleAppender = (ConsoleAppender)a;
-            break;
-          }
-        }
-        if(consoleAppender != null) {
-          Layout layout = consoleAppender.getLayout();
-          if(layout instanceof PatternLayout) {
-            PatternLayout consoleLayout = (PatternLayout)layout;
-            consoleLayout.setConversionPattern(&quot;%d %-5p [%t] %l: %m%n&quot;);
-          }
-        }
-        Logger.getLogger(&quot;org.apache.hadoop.hbase&quot;).setLevel(Environment.logLevel);
-      }
       cluster = new MiniDFSCluster(conf, 2, true, (String[])null);
       FileSystem fs = cluster.getFileSystem();
       Path dir = new Path(&quot;/hbase&quot;);</diff>
      <filename>src/test/org/apache/hadoop/hbase/TestGet.java</filename>
    </modified>
    <modified>
      <diff>@@ -15,45 +15,52 @@
  */
 package org.apache.hadoop.hbase;
 
-import java.io.File;
 import java.io.IOException;
-import java.util.Enumeration;
 import java.util.Iterator;
 import java.util.TreeMap;
 import java.util.TreeSet;
 
-import junit.framework.TestCase;
-import junit.framework.Test;
-import junit.framework.TestSuite;
-
-import org.apache.hadoop.conf.Configuration;
 import org.apache.hadoop.io.Text;
 
-import org.apache.log4j.Appender;
-import org.apache.log4j.ConsoleAppender;
-import org.apache.log4j.Layout;
-import org.apache.log4j.Logger;
-import org.apache.log4j.Level;
-import org.apache.log4j.PatternLayout;
-
 /**
  * Test HBase Master and Region servers, client API 
  */
-public class TestHBaseCluster extends TestCase {
+public class TestHBaseCluster extends HBaseClusterTestCase {
+
+  private HTableDescriptor desc;
+  private HClient client;
 
   /** constructor */
-  public TestHBaseCluster(String name) {
-    super(name);
+  public TestHBaseCluster() {
+    super(true);
+    this.desc = null;
+    this.client = null;
   }
 
-  /** Test suite so that all tests get run */
-  public static Test suite() {
-    TestSuite suite = new TestSuite();
-    suite.addTest(new TestHBaseCluster(&quot;testSetup&quot;));
-    suite.addTest(new TestHBaseCluster(&quot;testBasic&quot;));
-    suite.addTest(new TestHBaseCluster(&quot;testScanner&quot;));
-    suite.addTest(new TestHBaseCluster(&quot;testCleanup&quot;));
-    return suite;
+  /**
+   * Since all the &quot;tests&quot; depend on the results of the previous test, they are
+   * not Junit tests that can stand alone. Consequently we have a single Junit
+   * test that runs the &quot;sub-tests&quot; as private methods.
+   */
+  public void testHBaseCluster() {
+    try {
+      setup();
+      basic();
+      scanner();
+      listTables();
+      cleanup();
+      
+    } catch(IOException e) {
+      e.printStackTrace();
+      fail();
+    }
+  }
+
+  public void tearDown() throws Exception {
+    super.tearDown();
+    if(client != null) {
+      client.close();
+    }
   }
 
   private static final int FIRST_ROW = 1;
@@ -65,126 +72,61 @@ public class TestHBaseCluster extends TestCase {
   private static final String ANCHORNUM = &quot;anchor:anchornum-&quot;;
   private static final String ANCHORSTR = &quot;anchorstr&quot;;
 
-  private static Configuration conf = null;
-  private static boolean failures = false;
-  private static boolean initialized = false;
-  private static MiniHBaseCluster cluster = null;
-  private static HTableDescriptor desc = null;
-  private static HClient client = null;
-
-  // Set up environment, start mini cluster, etc.
-  
-  @SuppressWarnings(&quot;unchecked&quot;)
-  public void testSetup() throws Exception {
-    try {
-      if(System.getProperty(&quot;test.build.data&quot;) == null) {
-        String dir = new File(new File(&quot;&quot;).getAbsolutePath(), &quot;build/contrib/hbase/test&quot;).getAbsolutePath();
-        System.out.println(dir);
-        System.setProperty(&quot;test.build.data&quot;, dir);
-      }
-      conf = new HBaseConfiguration();
-      
-      Environment.getenv();
-      Logger rootLogger = Logger.getRootLogger();
-      if(Environment.debugging) {
-        rootLogger.setLevel(Level.WARN);
-      }
-
-      ConsoleAppender consoleAppender = null;
-      for(Enumeration&lt;Appender&gt; e = (Enumeration&lt;Appender&gt;)rootLogger.getAllAppenders();
-      e.hasMoreElements();) {
-
-        Appender a = e.nextElement();
-        if(a instanceof ConsoleAppender) {
-          consoleAppender = (ConsoleAppender)a;
-          break;
-        }
-      }
-      if(consoleAppender != null) {
-        Layout layout = consoleAppender.getLayout();
-        if(layout instanceof PatternLayout) {
-          PatternLayout consoleLayout = (PatternLayout)layout;
-          consoleLayout.setConversionPattern(&quot;%d %-5p [%t] %l: %m%n&quot;);
-        }
-      }
-      Logger.getLogger(&quot;org.apache.hadoop.hbase&quot;).setLevel(Environment.logLevel);
-
-      cluster = new MiniHBaseCluster(conf, 1);
-      client = new HClient(conf);
-
-      desc = new HTableDescriptor(&quot;test&quot;, 3);
-      desc.addFamily(new Text(CONTENTS));
-      desc.addFamily(new Text(ANCHOR));
-      client.createTable(desc);
-      
-    } catch(Exception e) {
-      failures = true;
-      throw e;
-    }
-    initialized = true;
+  private void setup() throws IOException {
+    client = new HClient(conf);
+    desc = new HTableDescriptor(&quot;test&quot;, 3);
+    desc.addFamily(new Text(CONTENTS));
+    desc.addFamily(new Text(ANCHOR));
+    client.createTable(desc);
   }
       
   // Test basic functionality. Writes to contents:basic and anchor:anchornum-*
 
-  public void testBasic() throws IOException {
-    if(!initialized) {
-      throw new IllegalStateException();
-    }
-
-    try {
-      long startTime = System.currentTimeMillis();
-      
-      client.openTable(desc.getName());
-      
-      // Write out a bunch of values
-      
-      for (int k = FIRST_ROW; k &lt;= NUM_VALS; k++) {
-        long writeid = client.startUpdate(new Text(&quot;row_&quot; + k));
-        client.put(writeid, CONTENTS_BASIC, (CONTENTSTR + k).getBytes());
-        client.put(writeid, new Text(ANCHORNUM + k), (ANCHORSTR + k).getBytes());
-        client.commit(writeid);
-      }
-      System.out.println(&quot;Write &quot; + NUM_VALS + &quot; rows. Elapsed time: &quot;
-          + ((System.currentTimeMillis() - startTime) / 1000.0));
-
-      // Read them back in
+  private void basic() throws IOException {
+    long startTime = System.currentTimeMillis();
 
-      startTime = System.currentTimeMillis();
-      
-      Text collabel = null;
-      for (int k = FIRST_ROW; k &lt;= NUM_VALS; k++) {
-        Text rowlabel = new Text(&quot;row_&quot; + k);
+    client.openTable(desc.getName());
 
-        byte bodydata[] = client.get(rowlabel, CONTENTS_BASIC);
-        assertNotNull(bodydata);
-        String bodystr = new String(bodydata).toString().trim();
-        String teststr = CONTENTSTR + k;
-        assertEquals(&quot;Incorrect value for key: (&quot; + rowlabel + &quot;,&quot; + CONTENTS_BASIC
-            + &quot;), expected: '&quot; + teststr + &quot;' got: '&quot; + bodystr + &quot;'&quot;,
-            bodystr, teststr);
-        collabel = new Text(ANCHORNUM + k);
-        bodydata = client.get(rowlabel, collabel);
-        bodystr = new String(bodydata).toString().trim();
-        teststr = ANCHORSTR + k;
-        assertEquals(&quot;Incorrect value for key: (&quot; + rowlabel + &quot;,&quot; + collabel
-            + &quot;), expected: '&quot; + teststr + &quot;' got: '&quot; + bodystr + &quot;'&quot;,
-            bodystr, teststr);
-      }
-      
-      System.out.println(&quot;Read &quot; + NUM_VALS + &quot; rows. Elapsed time: &quot;
-          + ((System.currentTimeMillis() - startTime) / 1000.0));
+    // Write out a bunch of values
 
-    } catch(IOException e) {
-      failures = true;
-      throw e;
+    for (int k = FIRST_ROW; k &lt;= NUM_VALS; k++) {
+      long writeid = client.startUpdate(new Text(&quot;row_&quot; + k));
+      client.put(writeid, CONTENTS_BASIC, (CONTENTSTR + k).getBytes());
+      client.put(writeid, new Text(ANCHORNUM + k), (ANCHORSTR + k).getBytes());
+      client.commit(writeid);
     }
-  }
-  
-  public void testScanner() throws IOException {
-    if(!initialized || failures) {
-      throw new IllegalStateException();
+    System.out.println(&quot;Write &quot; + NUM_VALS + &quot; rows. Elapsed time: &quot;
+        + ((System.currentTimeMillis() - startTime) / 1000.0));
+
+    // Read them back in
+
+    startTime = System.currentTimeMillis();
+
+    Text collabel = null;
+    for (int k = FIRST_ROW; k &lt;= NUM_VALS; k++) {
+      Text rowlabel = new Text(&quot;row_&quot; + k);
+
+      byte bodydata[] = client.get(rowlabel, CONTENTS_BASIC);
+      assertNotNull(bodydata);
+      String bodystr = new String(bodydata).toString().trim();
+      String teststr = CONTENTSTR + k;
+      assertEquals(&quot;Incorrect value for key: (&quot; + rowlabel + &quot;,&quot; + CONTENTS_BASIC
+          + &quot;), expected: '&quot; + teststr + &quot;' got: '&quot; + bodystr + &quot;'&quot;,
+          bodystr, teststr);
+      collabel = new Text(ANCHORNUM + k);
+      bodydata = client.get(rowlabel, collabel);
+      bodystr = new String(bodydata).toString().trim();
+      teststr = ANCHORSTR + k;
+      assertEquals(&quot;Incorrect value for key: (&quot; + rowlabel + &quot;,&quot; + collabel
+          + &quot;), expected: '&quot; + teststr + &quot;' got: '&quot; + bodystr + &quot;'&quot;,
+          bodystr, teststr);
     }
 
+    System.out.println(&quot;Read &quot; + NUM_VALS + &quot; rows. Elapsed time: &quot;
+        + ((System.currentTimeMillis() - startTime) / 1000.0));
+  }
+  
+  private void scanner() throws IOException {
     Text[] cols = new Text[] {
         new Text(ANCHORNUM + &quot;[0-9]+&quot;),
         new Text(CONTENTS_BASIC)
@@ -234,57 +176,31 @@ public class TestHBaseCluster extends TestCase {
           + &quot; rows. Elapsed time: &quot;
           + ((System.currentTimeMillis() - startTime) / 1000.0));
 
-    } catch(IOException e) {
-      failures = true;
-      throw e;
-      
     } finally {
       s.close();
     }
   }
 
-  public void testListTables() throws IOException {
-    if(!initialized || failures) {
-      throw new IllegalStateException();
-    }
-    
-    try {
-      HTableDescriptor[] tables = client.listTables();
-      assertEquals(1, tables.length);
-      assertEquals(desc.getName(), tables[0].getName());
-      TreeSet&lt;Text&gt; families = tables[0].families();
-      assertEquals(2, families.size());
-      assertTrue(families.contains(new Text(CONTENTS)));
-      assertTrue(families.contains(new Text(ANCHOR)));
-      
-    } catch(IOException e) {
-      failures = true;
-      throw e;
-    }
+  private void listTables() throws IOException {
+    HTableDescriptor[] tables = client.listTables();
+    assertEquals(1, tables.length);
+    assertEquals(desc.getName(), tables[0].getName());
+    TreeSet&lt;Text&gt; families = tables[0].families();
+    assertEquals(2, families.size());
+    assertTrue(families.contains(new Text(CONTENTS)));
+    assertTrue(families.contains(new Text(ANCHOR)));
   }
   
-  public void testCleanup() throws IOException {
-    if(!initialized) {
-      throw new IllegalStateException();
-    }
-    
+  private void cleanup() throws IOException {
+
+    // Delete the table we created
+
+    client.deleteTable(desc.getName());
     try {
-      if(!failures) {
-        // Delete the table we created
+      Thread.sleep(30000);                    // Wait for table to be deleted
 
-        client.deleteTable(desc.getName());
-        try {
-          Thread.sleep(60000);                  // Wait for table to be deleted
-          
-        } catch(InterruptedException e) {
-        }
-      }
-      
-    } finally {
-      // Shut down the cluster
-    
-      cluster.shutdown();
-      client.close();
+    } catch(InterruptedException e) {
     }
   }
+  
 }</diff>
      <filename>src/test/org/apache/hadoop/hbase/TestHBaseCluster.java</filename>
    </modified>
    <modified>
      <diff>@@ -15,31 +15,20 @@
  */
 package org.apache.hadoop.hbase;
 
-import junit.framework.TestCase;
-import junit.framework.Test;
-import junit.framework.TestSuite;
-
 import java.io.File;
 import java.io.IOException;
 import java.util.ArrayList;
-import java.util.Enumeration;
 import java.util.Iterator;
 import java.util.List;
 import java.util.TreeMap;
 
-import org.apache.hadoop.conf.Configuration;
 import org.apache.hadoop.dfs.MiniDFSCluster;
 import org.apache.hadoop.fs.FileSystem;
 import org.apache.hadoop.fs.Path;
 import org.apache.hadoop.io.BytesWritable;
 import org.apache.hadoop.io.Text;
 
-import org.apache.log4j.Appender;
-import org.apache.log4j.ConsoleAppender;
-import org.apache.log4j.Layout;
 import org.apache.log4j.Logger;
-import org.apache.log4j.Level;
-import org.apache.log4j.PatternLayout;
 
 /**
  * Basic stand-alone testing of HRegion.
@@ -47,27 +36,35 @@ import org.apache.log4j.PatternLayout;
  * A lot of the meta information for an HRegion now lives inside other
  * HRegions or in the HBaseMaster, so only basic testing is possible.
  */
-public class TestHRegion extends TestCase {
+public class TestHRegion extends HBaseTestCase implements RegionUnavailableListener {
   private Logger LOG = Logger.getLogger(this.getClass().getName());
   
   /** Constructor */
-  public TestHRegion(String name) {
-    super(name);
+  public TestHRegion() {
+    super();
   }
   
-  /** Test suite so that all tests get run */
-  public static Test suite() {
-    TestSuite suite = new TestSuite();
-    suite.addTest(new TestHRegion(&quot;testSetup&quot;));
-    suite.addTest(new TestHRegion(&quot;testLocks&quot;));
-    suite.addTest(new TestHRegion(&quot;testBadPuts&quot;));
-    suite.addTest(new TestHRegion(&quot;testBasic&quot;));
-    suite.addTest(new TestHRegion(&quot;testScan&quot;));
-    suite.addTest(new TestHRegion(&quot;testBatchWrite&quot;));
-    suite.addTest(new TestHRegion(&quot;testSplitAndMerge&quot;));
-    suite.addTest(new TestHRegion(&quot;testRead&quot;));
-    suite.addTest(new TestHRegion(&quot;testCleanup&quot;));
-    return suite;
+  /**
+   * Since all the &quot;tests&quot; depend on the results of the previous test, they are
+   * not Junit tests that can stand alone. Consequently we have a single Junit
+   * test that runs the &quot;sub-tests&quot; as private methods.
+   */
+  public void testHRegion() {
+    try {
+      setup();
+      locks();
+      badPuts();
+      basic();
+      scan();
+      batchWrite();
+      splitAndMerge();
+      read();
+      cleanup();
+      
+    } catch(Exception e) {
+      e.printStackTrace();
+      fail();
+    }
   }
   
   
@@ -82,9 +79,6 @@ public class TestHRegion extends TestCase {
   private static final Text CONTENTS_FIRSTCOL = new Text(&quot;contents:firstcol&quot;);
   private static final Text ANCHOR_SECONDCOL = new Text(&quot;anchor:secondcol&quot;);
   
-  private static boolean initialized = false;
-  private static boolean failures = false;
-  private static Configuration conf = null;
   private static MiniDFSCluster cluster = null;
   private static FileSystem fs = null;
   private static Path parentdir = null;
@@ -96,138 +90,86 @@ public class TestHRegion extends TestCase {
   
   private static int numInserted = 0;
 
-  // Set up environment, start mini cluster, etc.
+  // Create directories, start mini cluster, etc.
   
-  @SuppressWarnings(&quot;unchecked&quot;)
-  public void testSetup() throws IOException {
-    try {
-      if(System.getProperty(&quot;test.build.data&quot;) == null) {
-        String dir = new File(new File(&quot;&quot;).getAbsolutePath(), &quot;build/contrib/hbase/test&quot;).getAbsolutePath();
-        System.out.println(dir);
-        System.setProperty(&quot;test.build.data&quot;, dir);
-      }
-      conf = new HBaseConfiguration();
-      
-      Environment.getenv();
-      if(Environment.debugging) {
-        Logger rootLogger = Logger.getRootLogger();
-        rootLogger.setLevel(Level.WARN);
-
-        ConsoleAppender consoleAppender = null;
-        for(Enumeration&lt;Appender&gt; e = (Enumeration&lt;Appender&gt;)rootLogger.getAllAppenders();
-            e.hasMoreElements();) {
-        
-          Appender a = e.nextElement();
-          if(a instanceof ConsoleAppender) {
-            consoleAppender = (ConsoleAppender)a;
-            break;
-          }
-        }
-        if(consoleAppender != null) {
-          Layout layout = consoleAppender.getLayout();
-          if(layout instanceof PatternLayout) {
-            PatternLayout consoleLayout = (PatternLayout)layout;
-            consoleLayout.setConversionPattern(&quot;%d %-5p [%t] %l: %m%n&quot;);
-          }
-        }
-        Logger.getLogger(&quot;org.apache.hadoop.hbase&quot;).setLevel(Environment.logLevel);
-      }
-      
-      cluster = new MiniDFSCluster(conf, 2, true, (String[])null);
-      fs = cluster.getFileSystem();
-      parentdir = new Path(&quot;/hbase&quot;);
-      fs.mkdirs(parentdir);
-      newlogdir = new Path(parentdir, &quot;log&quot;);
-      oldlogfile = new Path(parentdir, &quot;oldlogfile&quot;);
-
-      log = new HLog(fs, newlogdir, conf);
-      desc = new HTableDescriptor(&quot;test&quot;, 3);
-      desc.addFamily(new Text(&quot;contents:&quot;));
-      desc.addFamily(new Text(&quot;anchor:&quot;));
-      region = new HRegion(parentdir, log, fs, conf, 
-          new HRegionInfo(1, desc, null, null), null, oldlogfile);
-      
-    } catch(IOException e) {
-      failures = true;
-      throw e;
-    }
-    initialized = true;
+  private void setup() throws IOException {
+
+    cluster = new MiniDFSCluster(conf, 2, true, (String[])null);
+    fs = cluster.getFileSystem();
+    parentdir = new Path(&quot;/hbase&quot;);
+    fs.mkdirs(parentdir);
+    newlogdir = new Path(parentdir, &quot;log&quot;);
+    oldlogfile = new Path(parentdir, &quot;oldlogfile&quot;);
+
+    log = new HLog(fs, newlogdir, conf);
+    desc = new HTableDescriptor(&quot;test&quot;, 3);
+    desc.addFamily(new Text(&quot;contents:&quot;));
+    desc.addFamily(new Text(&quot;anchor:&quot;));
+    region = new HRegion(parentdir, log, fs, conf, 
+        new HRegionInfo(1, desc, null, null), null, oldlogfile);
   }
 
   // Test basic functionality. Writes to contents:basic and anchor:anchornum-*
 
-  public void testBasic() throws IOException {
-    if(!initialized) {
-      throw new IllegalStateException();
+  private void basic() throws IOException {
+    long startTime = System.currentTimeMillis();
+
+    // Write out a bunch of values
+
+    for (int k = FIRST_ROW; k &lt;= NUM_VALS; k++) {
+      long writeid = region.startUpdate(new Text(&quot;row_&quot; + k));
+      region.put(writeid, CONTENTS_BASIC,
+          new BytesWritable((CONTENTSTR + k).getBytes()));
+
+      region.put(writeid, new Text(ANCHORNUM + k),
+          new BytesWritable((ANCHORSTR + k).getBytes()));
+      region.commit(writeid);
     }
+    System.out.println(&quot;Write &quot; + NUM_VALS + &quot; rows. Elapsed time: &quot;
+        + ((System.currentTimeMillis() - startTime) / 1000.0));
 
-    try {
-      long startTime = System.currentTimeMillis();
-      
-      // Write out a bunch of values
-      
-      for (int k = FIRST_ROW; k &lt;= NUM_VALS; k++) {
-        long writeid = region.startUpdate(new Text(&quot;row_&quot; + k));
-        region.put(writeid, CONTENTS_BASIC,
-            new BytesWritable((CONTENTSTR + k).getBytes()));
-        
-        region.put(writeid, new Text(ANCHORNUM + k),
-            new BytesWritable((ANCHORSTR + k).getBytes()));
-        region.commit(writeid);
-      }
-      System.out.println(&quot;Write &quot; + NUM_VALS + &quot; rows. Elapsed time: &quot;
-          + ((System.currentTimeMillis() - startTime) / 1000.0));
+    // Flush cache
 
-      // Flush cache
-      
-      startTime = System.currentTimeMillis();
-      
-      region.flushcache(false);
-      
-      System.out.println(&quot;Cache flush elapsed time: &quot;
-          + ((System.currentTimeMillis() - startTime) / 1000.0));
+    startTime = System.currentTimeMillis();
 
-      // Read them back in
+    region.flushcache(false);
 
-      startTime = System.currentTimeMillis();
-      
-      Text collabel = null;
-      for (int k = FIRST_ROW; k &lt;= NUM_VALS; k++) {
-        Text rowlabel = new Text(&quot;row_&quot; + k);
-
-        BytesWritable bodydata = region.get(rowlabel, CONTENTS_BASIC);
-        assertNotNull(bodydata);
-        byte[] bytes = new byte[bodydata.getSize()];
-        System.arraycopy(bodydata.get(), 0, bytes, 0, bytes.length);
-        String bodystr = new String(bytes).toString().trim();
-        String teststr = CONTENTSTR + k;
-        assertEquals(&quot;Incorrect value for key: (&quot; + rowlabel + &quot;,&quot; + CONTENTS_BASIC
-            + &quot;), expected: '&quot; + teststr + &quot;' got: '&quot; + bodystr + &quot;'&quot;,
-            bodystr, teststr);
-        collabel = new Text(ANCHORNUM + k);
-        bodydata = region.get(rowlabel, collabel);
-        bytes = new byte[bodydata.getSize()];
-        System.arraycopy(bodydata.get(), 0, bytes, 0, bytes.length);
-        bodystr = new String(bytes).toString().trim();
-        teststr = ANCHORSTR + k;
-        assertEquals(&quot;Incorrect value for key: (&quot; + rowlabel + &quot;,&quot; + collabel
-            + &quot;), expected: '&quot; + teststr + &quot;' got: '&quot; + bodystr + &quot;'&quot;,
-            bodystr, teststr);
-      }
-      
-      System.out.println(&quot;Read &quot; + NUM_VALS + &quot; rows. Elapsed time: &quot;
-          + ((System.currentTimeMillis() - startTime) / 1000.0));
+    System.out.println(&quot;Cache flush elapsed time: &quot;
+        + ((System.currentTimeMillis() - startTime) / 1000.0));
+
+    // Read them back in
+
+    startTime = System.currentTimeMillis();
 
-    } catch(IOException e) {
-      failures = true;
-      throw e;
+    Text collabel = null;
+    for (int k = FIRST_ROW; k &lt;= NUM_VALS; k++) {
+      Text rowlabel = new Text(&quot;row_&quot; + k);
+
+      BytesWritable bodydata = region.get(rowlabel, CONTENTS_BASIC);
+      assertNotNull(bodydata);
+      byte[] bytes = new byte[bodydata.getSize()];
+      System.arraycopy(bodydata.get(), 0, bytes, 0, bytes.length);
+      String bodystr = new String(bytes).toString().trim();
+      String teststr = CONTENTSTR + k;
+      assertEquals(&quot;Incorrect value for key: (&quot; + rowlabel + &quot;,&quot; + CONTENTS_BASIC
+          + &quot;), expected: '&quot; + teststr + &quot;' got: '&quot; + bodystr + &quot;'&quot;,
+          bodystr, teststr);
+      collabel = new Text(ANCHORNUM + k);
+      bodydata = region.get(rowlabel, collabel);
+      bytes = new byte[bodydata.getSize()];
+      System.arraycopy(bodydata.get(), 0, bytes, 0, bytes.length);
+      bodystr = new String(bytes).toString().trim();
+      teststr = ANCHORSTR + k;
+      assertEquals(&quot;Incorrect value for key: (&quot; + rowlabel + &quot;,&quot; + collabel
+          + &quot;), expected: '&quot; + teststr + &quot;' got: '&quot; + bodystr + &quot;'&quot;,
+          bodystr, teststr);
     }
+
+    System.out.println(&quot;Read &quot; + NUM_VALS + &quot; rows. Elapsed time: &quot;
+        + ((System.currentTimeMillis() - startTime) / 1000.0));
   }
   
-  public void testBadPuts() throws IOException {
-    if(!initialized) {
-      throw new IllegalStateException();
-    }  
+  private void badPuts() throws IOException {
     
     // Try put with bad lockid.
     boolean exceptionThrown = false;
@@ -259,7 +201,7 @@ public class TestHRegion extends TestCase {
   /**
    * Test getting and releasing locks.
    */
-  public void testLocks() {
+  private void locks() {
     final int threadCount = 10;
     final int lockCount = 10;
     
@@ -317,11 +259,7 @@ public class TestHRegion extends TestCase {
 
   // Test scanners. Writes contents:firstcol and anchor:secondcol
   
-  public void testScan() throws IOException {
-    if(!initialized) {
-      throw new IllegalStateException();
-    }
-
+  private void scan() throws IOException {
     Text cols[] = new Text[] {
         CONTENTS_FIRSTCOL,
         ANCHOR_SECONDCOL
@@ -583,138 +521,126 @@ public class TestHRegion extends TestCase {
   // long time to run.
   // Creates contents:body
   
-  public void testBatchWrite() throws IOException {
-    if(!initialized || failures) {
-      throw new IllegalStateException();
-    }
-    if(! Environment.debugging) {
+  private void batchWrite() throws IOException {
+    if(! StaticTestEnvironment.debugging) {
       return;
     }
 
-    try {
-      long totalFlush = 0;
-      long totalCompact = 0;
-      long totalLog = 0;
-      long startTime = System.currentTimeMillis();
-
-      // 1M writes
-
-      int valsize = 1000;
-      for (int k = FIRST_ROW; k &lt;= N_ROWS; k++) {
-        // Come up with a random 1000-byte string
-        String randstr1 = &quot;&quot; + System.currentTimeMillis();
-        StringBuffer buf1 = new StringBuffer(&quot;val_&quot; + k + &quot;__&quot;);
-        while (buf1.length() &lt; valsize) {
-          buf1.append(randstr1);
-        }
+    long totalFlush = 0;
+    long totalCompact = 0;
+    long totalLog = 0;
+    long startTime = System.currentTimeMillis();
 
-        // Write to the HRegion
-        long writeid = region.startUpdate(new Text(&quot;row_&quot; + k));
-        region.put(writeid, CONTENTS_BODY, new BytesWritable(buf1.toString().getBytes()));
-        region.commit(writeid);
-        if (k &gt; 0 &amp;&amp; k % (N_ROWS / 100) == 0) {
-          System.out.println(&quot;Flushing write #&quot; + k);
-
-          long flushStart = System.currentTimeMillis();
-          region.flushcache(false);
-          long flushEnd = System.currentTimeMillis();
-          totalFlush += (flushEnd - flushStart);
-
-          if (k % (N_ROWS / 10) == 0) {
-            System.out.print(&quot;Rolling log...&quot;);
-            long logStart = System.currentTimeMillis();
-            log.rollWriter();
-            long logEnd = System.currentTimeMillis();
-            totalLog += (logEnd - logStart);
-            System.out.println(&quot;  elapsed time: &quot; + ((logEnd - logStart) / 1000.0));
-          }
-        }
+    // 1M writes
+
+    int valsize = 1000;
+    for (int k = FIRST_ROW; k &lt;= N_ROWS; k++) {
+      // Come up with a random 1000-byte string
+      String randstr1 = &quot;&quot; + System.currentTimeMillis();
+      StringBuffer buf1 = new StringBuffer(&quot;val_&quot; + k + &quot;__&quot;);
+      while (buf1.length() &lt; valsize) {
+        buf1.append(randstr1);
       }
-      long startCompact = System.currentTimeMillis();
-      if(region.compactStores()) {
-        totalCompact = System.currentTimeMillis() - startCompact;
-        System.out.println(&quot;Region compacted - elapsedTime: &quot; + (totalCompact / 1000.0));
-        
-      } else {
-        System.out.println(&quot;No compaction required.&quot;);
+
+      // Write to the HRegion
+      long writeid = region.startUpdate(new Text(&quot;row_&quot; + k));
+      region.put(writeid, CONTENTS_BODY, new BytesWritable(buf1.toString().getBytes()));
+      region.commit(writeid);
+      if (k &gt; 0 &amp;&amp; k % (N_ROWS / 100) == 0) {
+        System.out.println(&quot;Flushing write #&quot; + k);
+
+        long flushStart = System.currentTimeMillis();
+        region.flushcache(false);
+        long flushEnd = System.currentTimeMillis();
+        totalFlush += (flushEnd - flushStart);
+
+        if (k % (N_ROWS / 10) == 0) {
+          System.out.print(&quot;Rolling log...&quot;);
+          long logStart = System.currentTimeMillis();
+          log.rollWriter();
+          long logEnd = System.currentTimeMillis();
+          totalLog += (logEnd - logStart);
+          System.out.println(&quot;  elapsed time: &quot; + ((logEnd - logStart) / 1000.0));
+        }
       }
-      long endTime = System.currentTimeMillis();
-
-      long totalElapsed = (endTime - startTime);
-      System.out.println();
-      System.out.println(&quot;Batch-write complete.&quot;);
-      System.out.println(&quot;Wrote &quot; + N_ROWS + &quot; rows, each of ~&quot; + valsize + &quot; bytes&quot;);
-      System.out.println(&quot;Total flush-time: &quot; + (totalFlush / 1000.0));
-      System.out.println(&quot;Total compact-time: &quot; + (totalCompact / 1000.0));
-      System.out.println(&quot;Total log-time: &quot; + (totalLog / 1000.0));
-      System.out.println(&quot;Total time elapsed: &quot; + (totalElapsed / 1000.0));
-      System.out.println(&quot;Total time, rows/second: &quot; + (N_ROWS / (totalElapsed / 1000.0)));
-      System.out.println(&quot;Adjusted time (not including flush, compact, or log): &quot; + ((totalElapsed - totalFlush - totalCompact - totalLog) / 1000.0));
-      System.out.println(&quot;Adjusted time, rows/second: &quot; + (N_ROWS / ((totalElapsed - totalFlush - totalCompact - totalLog) / 1000.0)));
-      System.out.println();
-      
-    } catch(IOException e) {
-      failures = true;
-      throw e;
     }
+    long startCompact = System.currentTimeMillis();
+    if(region.compactStores()) {
+      totalCompact = System.currentTimeMillis() - startCompact;
+      System.out.println(&quot;Region compacted - elapsedTime: &quot; + (totalCompact / 1000.0));
+
+    } else {
+      System.out.println(&quot;No compaction required.&quot;);
+    }
+    long endTime = System.currentTimeMillis();
+
+    long totalElapsed = (endTime - startTime);
+    System.out.println();
+    System.out.println(&quot;Batch-write complete.&quot;);
+    System.out.println(&quot;Wrote &quot; + N_ROWS + &quot; rows, each of ~&quot; + valsize + &quot; bytes&quot;);
+    System.out.println(&quot;Total flush-time: &quot; + (totalFlush / 1000.0));
+    System.out.println(&quot;Total compact-time: &quot; + (totalCompact / 1000.0));
+    System.out.println(&quot;Total log-time: &quot; + (totalLog / 1000.0));
+    System.out.println(&quot;Total time elapsed: &quot; + (totalElapsed / 1000.0));
+    System.out.println(&quot;Total time, rows/second: &quot; + (N_ROWS / (totalElapsed / 1000.0)));
+    System.out.println(&quot;Adjusted time (not including flush, compact, or log): &quot; + ((totalElapsed - totalFlush - totalCompact - totalLog) / 1000.0));
+    System.out.println(&quot;Adjusted time, rows/second: &quot; + (N_ROWS / ((totalElapsed - totalFlush - totalCompact - totalLog) / 1000.0)));
+    System.out.println();
+
   }
 
   // NOTE: This test depends on testBatchWrite succeeding
   
-  public void testSplitAndMerge() throws IOException {
-    if(!initialized || failures) {
-      throw new IllegalStateException();
+  private void splitAndMerge() throws IOException {
+    Text midKey = new Text();
+
+    if(region.needsSplit(midKey)) {
+      System.out.println(&quot;Needs split&quot;);
     }
+
+    // Split it anyway
+
+    Text midkey = new Text(&quot;row_&quot;
+        + (StaticTestEnvironment.debugging ? (N_ROWS / 2) : (NUM_VALS/2)));
     
-    try {
-      Text midKey = new Text();
-      
-      if(region.needsSplit(midKey)) {
-        System.out.println(&quot;Needs split&quot;);
-      }
-      
-      // Split it anyway
+    Path oldRegionPath = region.getRegionDir();
 
-      Text midkey = new Text(&quot;row_&quot; + (Environment.debugging ? (N_ROWS / 2) : (NUM_VALS/2)));
-      Path oldRegionPath = region.getRegionDir();
-      
-      long startTime = System.currentTimeMillis();
-      
-      HRegion subregions[] = region.closeAndSplit(midkey);
-      
-      System.out.println(&quot;Split region elapsed time: &quot;
-          + ((System.currentTimeMillis() - startTime) / 1000.0));
-      
-      assertEquals(&quot;Number of subregions&quot;, subregions.length, 2);
+    long startTime = System.currentTimeMillis();
 
-      // Now merge it back together
+    HRegion subregions[] = region.closeAndSplit(midkey, this);
 
-      Path oldRegion1 = subregions[0].getRegionDir();
-      Path oldRegion2 = subregions[1].getRegionDir();
-      
-      startTime = System.currentTimeMillis();
-      
-      region = HRegion.closeAndMerge(subregions[0], subregions[1]);
+    System.out.println(&quot;Split region elapsed time: &quot;
+        + ((System.currentTimeMillis() - startTime) / 1000.0));
 
-      System.out.println(&quot;Merge regions elapsed time: &quot;
-          + ((System.currentTimeMillis() - startTime) / 1000.0));
-      
-      fs.delete(oldRegionPath);
-      fs.delete(oldRegion1);
-      fs.delete(oldRegion2);
-      
-    } catch(IOException e) {
-      failures = true;
-      throw e;
-    }
+    assertEquals(&quot;Number of subregions&quot;, subregions.length, 2);
+
+    // Now merge it back together
+
+    Path oldRegion1 = subregions[0].getRegionDir();
+    Path oldRegion2 = subregions[1].getRegionDir();
+
+    startTime = System.currentTimeMillis();
+
+    region = HRegion.closeAndMerge(subregions[0], subregions[1]);
+
+    System.out.println(&quot;Merge regions elapsed time: &quot;
+        + ((System.currentTimeMillis() - startTime) / 1000.0));
+
+    fs.delete(oldRegionPath);
+    fs.delete(oldRegion1);
+    fs.delete(oldRegion2);
   }
 
+  /* (non-Javadoc)
+   * @see org.apache.hadoop.hbase.RegionUnavailableListener#regionIsUnavailable(org.apache.hadoop.io.Text)
+   */
+  public void regionIsUnavailable(Text regionName) {
+    // We don't use this here. It is only for the HRegionServer
+  }
+  
   // This test verifies that everything is still there after splitting and merging
   
-  public void testRead() throws IOException {
-    if(!initialized || failures) {
-      throw new IllegalStateException();
-    }
+  private void read() throws IOException {
 
     // First verify the data written by testBasic()
 
@@ -820,9 +746,8 @@ public class TestHRegion extends TestCase {
     
     // Verify testBatchWrite data
 
-    if(Environment.debugging) {
+    if(StaticTestEnvironment.debugging) {
       startTime = System.currentTimeMillis();
-      
       s = region.getScanner(new Text[] { CONTENTS_BODY }, new Text());
       try {
         int numFetched = 0;
@@ -883,7 +808,6 @@ public class TestHRegion extends TestCase {
       s.close();
     }
   }
-
   
   private static void deleteFile(File f) {
     if(f.isDirectory()) {
@@ -895,18 +819,14 @@ public class TestHRegion extends TestCase {
     f.delete();
   }
   
-  public void testCleanup() throws IOException {
-    if(!initialized) {
-      throw new IllegalStateException();
-    }
+  private void cleanup() throws IOException {
 
     // Shut down the mini cluster
-    
+
     cluster.shutdown();
-    
+
     // Delete all the DFS files
-    
+
     deleteFile(new File(System.getProperty(&quot;test.build.data&quot;), &quot;dfs&quot;));
-    
-    }
+  }
 }</diff>
      <filename>src/test/org/apache/hadoop/hbase/TestHRegion.java</filename>
    </modified>
    <modified>
      <diff>@@ -17,9 +17,7 @@ package org.apache.hadoop.hbase;
 
 import java.io.ByteArrayOutputStream;
 import java.io.DataOutputStream;
-import java.io.File;
 import java.io.IOException;
-import java.util.Enumeration;
 import java.util.TreeMap;
 
 import org.apache.hadoop.conf.Configuration;
@@ -30,16 +28,7 @@ import org.apache.hadoop.io.BytesWritable;
 import org.apache.hadoop.io.DataInputBuffer;
 import org.apache.hadoop.io.Text;
 
-import org.apache.log4j.Appender;
-import org.apache.log4j.ConsoleAppender;
-import org.apache.log4j.Layout;
-import org.apache.log4j.Level;
-import org.apache.log4j.Logger;
-import org.apache.log4j.PatternLayout;
-
-import junit.framework.TestCase;
-
-public class TestScanner extends TestCase {
+public class TestScanner extends HBaseTestCase {
   private static final Text FIRST_ROW = new Text();
   private static final Text[] COLS = {
       HConstants.COLUMN_FAMILY
@@ -127,12 +116,7 @@ public class TestScanner extends TestCase {
       
       } finally {
         if(scanner != null) {
-          try {
-            scanner.close();
-          
-          } catch(IOException e) {
-            e.printStackTrace();
-          }
+          scanner.close();
           scanner = null;
         }
       }
@@ -146,7 +130,6 @@ public class TestScanner extends TestCase {
   }
  
   /** The test! */
-  @SuppressWarnings(&quot;unchecked&quot;)
   public void testScanner() throws IOException {
     MiniDFSCluster cluster = null;
     FileSystem fs = null;
@@ -155,37 +138,7 @@ public class TestScanner extends TestCase {
       
       // Initialization
       
-      if(System.getProperty(&quot;test.build.data&quot;) == null) {
-        String dir = new File(new File(&quot;&quot;).getAbsolutePath(), &quot;build/contrib/hbase/test&quot;).getAbsolutePath();
-        System.out.println(dir);
-        System.setProperty(&quot;test.build.data&quot;, dir);
-      }
       Configuration conf = new HBaseConfiguration();
-    
-      Environment.getenv();
-      if(Environment.debugging) {
-        Logger rootLogger = Logger.getRootLogger();
-        rootLogger.setLevel(Level.WARN);
-
-        ConsoleAppender consoleAppender = null;
-        for(Enumeration&lt;Appender&gt; e = (Enumeration&lt;Appender&gt;)rootLogger.getAllAppenders();
-            e.hasMoreElements();) {
-        
-          Appender a = e.nextElement();
-          if(a instanceof ConsoleAppender) {
-            consoleAppender = (ConsoleAppender)a;
-            break;
-          }
-        }
-        if(consoleAppender != null) {
-          Layout layout = consoleAppender.getLayout();
-          if(layout instanceof PatternLayout) {
-            PatternLayout consoleLayout = (PatternLayout)layout;
-            consoleLayout.setConversionPattern(&quot;%d %-5p [%t] %l: %m%n&quot;);
-          }
-        }
-        Logger.getLogger(&quot;org.apache.hadoop.hbase&quot;).setLevel(Environment.logLevel);
-      }
       cluster = new MiniDFSCluster(conf, 2, true, (String[])null);
       fs = cluster.getFileSystem();
       Path dir = new Path(&quot;/hbase&quot;);</diff>
      <filename>src/test/org/apache/hadoop/hbase/TestScanner.java</filename>
    </modified>
  </modified>
  <removed type="array">
    <removed>
      <filename>src/test/org/apache/hadoop/hbase/Environment.java</filename>
    </removed>
  </removed>
  <parents type="array">
    <parent>
      <id>5e510dc68fb639686af7422ee4fa4b90a679f9c8</id>
    </parent>
  </parents>
  <author>
    <name>Jim Kellerman</name>
    <email>jimk@apache.org</email>
  </author>
  <url>http://github.com/andrewmccall/hbase/commit/9ed00df9d014ab36b4b9a6ad71d1b13cd758eb40</url>
  <id>9ed00df9d014ab36b4b9a6ad71d1b13cd758eb40</id>
  <committed-date>2007-05-17T20:22:54-07:00</committed-date>
  <authored-date>2007-05-17T20:22:54-07:00</authored-date>
  <message>Hadoop-1384

HBase omnibus patch. Contributions by Vuk Ercegovac and Michael Stack.

git-svn-id: https://svn.apache.org/repos/asf/lucene/hadoop/trunk/src/contrib/hbase@539243 13f79535-47bb-0310-9956-ffa450edef68</message>
  <tree>444f5a8accdbc9c9ee294db1a11a0dd9efbe6174</tree>
  <committer>
    <name>Jim Kellerman</name>
    <email>jimk@apache.org</email>
  </committer>
</commit>
