You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hbase.apache.org by st...@apache.org on 2008/02/12 07:19:54 UTC

svn commit: r620706 [3/3] - in /hadoop/hbase/trunk: ./ src/java/org/apache/hadoop/hbase/ src/java/org/apache/hadoop/hbase/generated/master/ src/java/org/apache/hadoop/hbase/master/ src/webapps/master/

Added: hadoop/hbase/trunk/src/java/org/apache/hadoop/hbase/master/ProcessRegionOpen.java
URL: http://svn.apache.org/viewvc/hadoop/hbase/trunk/src/java/org/apache/hadoop/hbase/master/ProcessRegionOpen.java?rev=620706&view=auto
==============================================================================
--- hadoop/hbase/trunk/src/java/org/apache/hadoop/hbase/master/ProcessRegionOpen.java (added)
+++ hadoop/hbase/trunk/src/java/org/apache/hadoop/hbase/master/ProcessRegionOpen.java Mon Feb 11 22:19:46 2008
@@ -0,0 +1,119 @@
+/**
+ * Copyright 2008 The Apache Software Foundation
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.hadoop.hbase.master;
+
+import java.io.IOException;
+
+import org.apache.hadoop.hbase.HServerAddress;
+import org.apache.hadoop.hbase.HServerInfo;
+import org.apache.hadoop.hbase.HRegionInfo;
+import org.apache.hadoop.hbase.util.Writables;
+import org.apache.hadoop.hbase.HRegionInterface;
+import org.apache.hadoop.hbase.io.BatchUpdate;
+import org.apache.hadoop.hbase.RemoteExceptionHandler;
+
+/** 
+ * ProcessRegionOpen is instantiated when a region server reports that it is
+ * serving a region. This applies to all meta and user regions except the 
+ * root region which is handled specially.
+ */
+class ProcessRegionOpen extends ProcessRegionStatusChange {
+  private final HServerAddress serverAddress;
+  private final byte [] startCode;
+
+  /**
+   * @param info
+   * @param regionInfo
+   * @throws IOException
+   */
+  public ProcessRegionOpen(HMaster master, HServerInfo info, 
+    HRegionInfo regionInfo)
+  throws IOException {
+    super(master, regionInfo);
+    this.serverAddress = info.getServerAddress();
+    this.startCode = Writables.longToBytes(info.getStartCode());
+  }
+
+  /** {@inheritDoc} */
+  @Override
+  public String toString() {
+    return "PendingOpenOperation from " + serverAddress.toString();
+  }
+
+  @Override
+  protected boolean process() throws IOException {
+    for (int tries = 0; tries < numRetries; tries++) {
+      if (master.closed.get()) {
+        return true;
+      }
+      LOG.info(regionInfo.toString() + " open on " + 
+          this.serverAddress.toString());
+
+      if (!metaRegionAvailable()) {
+        // We can't proceed unless the meta region we are going to update
+        // is online. metaRegionAvailable() has put this operation on the
+        // delayedToDoQueue, so return true so the operation is not put 
+        // back on the toDoQueue
+        return true;
+      }
+
+      // Register the newly-available Region's location.
+      
+      HRegionInterface server = getMetaServer();
+      LOG.info("updating row " + regionInfo.getRegionName() + " in table " +
+        metaRegionName + " with startcode " +
+        Writables.bytesToLong(this.startCode) + " and server "+
+        serverAddress.toString());
+      try {
+        BatchUpdate b = new BatchUpdate(regionInfo.getRegionName());
+        b.put(COL_SERVER, Writables.stringToBytes(serverAddress.toString()));
+        b.put(COL_STARTCODE, startCode);
+        server.batchUpdate(metaRegionName, b);
+        if (isMetaTable) {
+          // It's a meta region.
+          MetaRegion m = new MetaRegion(this.serverAddress,
+            this.regionInfo.getRegionName(), this.regionInfo.getStartKey());
+          if (!master.initialMetaScanComplete) {
+            // Put it on the queue to be scanned for the first time.
+            try {
+              LOG.debug("Adding " + m.toString() + " to regions to scan");
+              master.metaRegionsToScan.put(m);
+            } catch (InterruptedException e) {
+              throw new RuntimeException(
+                  "Putting into metaRegionsToScan was interrupted.", e);
+            }
+          } else {
+            // Add it to the online meta regions
+            LOG.debug("Adding to onlineMetaRegions: " + m.toString());
+            master.onlineMetaRegions.put(this.regionInfo.getStartKey(), m);
+          }
+        }
+        // If updated successfully, remove from pending list.
+        master.pendingRegions.remove(regionInfo.getRegionName());
+        break;
+      } catch (IOException e) {
+        if (tries == numRetries - 1) {
+          throw RemoteExceptionHandler.checkIOException(e);
+        }
+      }
+    }
+    return true;
+  }
+}

Added: hadoop/hbase/trunk/src/java/org/apache/hadoop/hbase/master/ProcessRegionStatusChange.java
URL: http://svn.apache.org/viewvc/hadoop/hbase/trunk/src/java/org/apache/hadoop/hbase/master/ProcessRegionStatusChange.java?rev=620706&view=auto
==============================================================================
--- hadoop/hbase/trunk/src/java/org/apache/hadoop/hbase/master/ProcessRegionStatusChange.java (added)
+++ hadoop/hbase/trunk/src/java/org/apache/hadoop/hbase/master/ProcessRegionStatusChange.java Mon Feb 11 22:19:46 2008
@@ -0,0 +1,96 @@
+/**
+ * Copyright 2008 The Apache Software Foundation
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.hadoop.hbase.master;
+
+import java.io.IOException;
+
+import org.apache.hadoop.hbase.HRegionInfo;
+import org.apache.hadoop.hbase.HRegionInterface;
+import org.apache.hadoop.hbase.HServerAddress;
+import org.apache.hadoop.io.Text;
+
+/**
+ * Abstract class that performs common operations for 
+ * @see #ProcessRegionClose and @see #ProcessRegionOpen
+ */
+abstract class ProcessRegionStatusChange extends RegionServerOperation {
+  protected final boolean isMetaTable;
+  protected final HRegionInfo regionInfo;
+  private MetaRegion metaRegion;
+  protected Text metaRegionName;
+  
+  /**
+   * @param regionInfo
+   */
+  public ProcessRegionStatusChange(HMaster master, HRegionInfo regionInfo) {
+    super(master);
+    this.regionInfo = regionInfo;
+    this.isMetaTable = regionInfo.isMetaTable();
+    this.metaRegion = null;
+    this.metaRegionName = null;
+  }
+  
+  protected boolean metaRegionAvailable() {
+    boolean available = true;
+    if (isMetaTable) {
+      // This operation is for the meta table
+      if (!rootAvailable()) {
+        // But we can't proceed unless the root region is available
+        available = false;
+      }
+    } else {
+      if (!master.rootScanned || !metaTableAvailable()) {
+        // The root region has not been scanned or the meta table is not
+        // available so we can't proceed.
+        // Put the operation on the delayedToDoQueue
+        requeue();
+        available = false;
+      }
+    }
+    return available;
+  }
+  
+  protected HRegionInterface getMetaServer() throws IOException {
+    if (this.isMetaTable) {
+      this.metaRegionName = HRegionInfo.rootRegionInfo.getRegionName();
+    } else {
+      if (this.metaRegion == null) {
+        synchronized (master.onlineMetaRegions) {
+          metaRegion = master.onlineMetaRegions.size() == 1 ? 
+              master.onlineMetaRegions.get(master.onlineMetaRegions.firstKey()) :
+                master.onlineMetaRegions.containsKey(regionInfo.getRegionName()) ?
+                    master.onlineMetaRegions.get(regionInfo.getRegionName()) :
+                      master.onlineMetaRegions.get(master.onlineMetaRegions.headMap(
+                          regionInfo.getRegionName()).lastKey());
+        }
+        this.metaRegionName = metaRegion.getRegionName();
+      }
+    }
+
+    HServerAddress server = null;
+    if (isMetaTable) {
+      server = master.rootRegionLocation.get();
+      
+    } else {
+      server = metaRegion.getServer();
+    }
+    return master.connection.getHRegionConnection(server);
+  } 
+}
\ No newline at end of file

Added: hadoop/hbase/trunk/src/java/org/apache/hadoop/hbase/master/ProcessServerShutdown.java
URL: http://svn.apache.org/viewvc/hadoop/hbase/trunk/src/java/org/apache/hadoop/hbase/master/ProcessServerShutdown.java?rev=620706&view=auto
==============================================================================
--- hadoop/hbase/trunk/src/java/org/apache/hadoop/hbase/master/ProcessServerShutdown.java (added)
+++ hadoop/hbase/trunk/src/java/org/apache/hadoop/hbase/master/ProcessServerShutdown.java Mon Feb 11 22:19:46 2008
@@ -0,0 +1,337 @@
+/**
+ * Copyright 2008 The Apache Software Foundation
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.hadoop.hbase.master;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.HashMap;
+import java.util.SortedMap;
+import java.io.UnsupportedEncodingException;
+import java.util.List;
+
+import org.apache.hadoop.hbase.HServerAddress;
+import org.apache.hadoop.fs.Path;
+import org.apache.hadoop.hbase.HServerInfo;
+import org.apache.hadoop.hbase.HRegionInfo;
+import org.apache.hadoop.hbase.HRegionInterface;
+import org.apache.hadoop.hbase.HRegion;
+import org.apache.hadoop.io.Text;
+import org.apache.hadoop.hbase.io.HbaseMapWritable;
+import org.apache.hadoop.hbase.RemoteExceptionHandler;
+import org.apache.hadoop.hbase.util.Writables;
+import org.apache.hadoop.hbase.HLog;
+
+/** 
+ * Instantiated when a server's lease has expired, meaning it has crashed.
+ * The region server's log file needs to be split up for each region it was
+ * serving, and the regions need to get reassigned.
+ */
+class ProcessServerShutdown extends RegionServerOperation {
+  private HServerAddress deadServer;
+  private String deadServerName;
+  private Path oldLogDir;
+  private boolean logSplit;
+  private boolean rootRescanned;
+
+  private class ToDoEntry {
+    boolean deleteRegion;
+    boolean regionOffline;
+    Text row;
+    HRegionInfo info;
+
+    ToDoEntry(Text row, HRegionInfo info) {
+      this.deleteRegion = false;
+      this.regionOffline = false;
+      this.row = row;
+      this.info = info;
+    }
+  }
+
+  /**
+   * @param serverInfo
+   */
+  public ProcessServerShutdown(HMaster master, HServerInfo serverInfo) {
+    super(master);
+    this.deadServer = serverInfo.getServerAddress();
+    this.deadServerName = this.deadServer.toString();
+    this.logSplit = false;
+    this.rootRescanned = false;
+    StringBuilder dirName = new StringBuilder("log_");
+    dirName.append(deadServer.getBindAddress());
+    dirName.append("_");
+    dirName.append(serverInfo.getStartCode());
+    dirName.append("_");
+    dirName.append(deadServer.getPort());
+    this.oldLogDir = new Path(master.rootdir, dirName.toString());
+  }
+
+  /** {@inheritDoc} */
+  @Override
+  public String toString() {
+    return "ProcessServerShutdown of " + this.deadServer.toString();
+  }
+
+  /** Finds regions that the dead region server was serving */
+  private void scanMetaRegion(HRegionInterface server, long scannerId,
+      Text regionName) throws IOException {
+
+    ArrayList<ToDoEntry> toDoList = new ArrayList<ToDoEntry>();
+    HashSet<HRegionInfo> regions = new HashSet<HRegionInfo>();
+
+    try {
+      while (true) {
+        HbaseMapWritable values = null;
+        try {
+          values = server.next(scannerId);
+        } catch (IOException e) {
+          LOG.error("Shutdown scanning of meta region",
+            RemoteExceptionHandler.checkIOException(e));
+          break;
+        }
+        if (values == null || values.size() == 0) {
+          break;
+        }
+        // TODO: Why does this have to be a sorted map?
+        RowMap rm = RowMap.fromHbaseMapWritable(values);
+        Text row = rm.getRow();
+        SortedMap<Text, byte[]> map = rm.getMap();
+        if (LOG.isDebugEnabled() && row != null) {
+          LOG.debug("shutdown scanner looking at " + row.toString());
+        }
+
+        // Check server name.  If null, be conservative and treat as though
+        // region had been on shutdown server (could be null because we
+        // missed edits in hlog because hdfs does not do write-append).
+        String serverName;
+        try {
+          serverName = Writables.bytesToString(map.get(COL_SERVER));
+        } catch (UnsupportedEncodingException e) {
+          LOG.error("Server name", e);
+          break;
+        }
+        if (serverName.length() > 0 &&
+            deadServerName.compareTo(serverName) != 0) {
+          // This isn't the server you're looking for - move along
+          if (LOG.isDebugEnabled()) {
+            LOG.debug("Server name " + serverName + " is not same as " +
+                deadServerName + ": Passing");
+          }
+          continue;
+        }
+
+        // Bingo! Found it.
+        HRegionInfo info = master.getHRegionInfo(map);
+        if (info == null) {
+          continue;
+        }
+        LOG.info(info.getRegionName() + " was on shutdown server <" +
+            serverName + "> (or server is null). Marking unassigned in " +
+        "meta and clearing pendingRegions");
+
+        if (info.isMetaTable()) {
+          if (LOG.isDebugEnabled()) {
+            LOG.debug("removing meta region " + info.getRegionName() +
+                " from online meta regions");
+          }
+          master.onlineMetaRegions.remove(info.getStartKey());
+        }
+
+        ToDoEntry todo = new ToDoEntry(row, info);
+        toDoList.add(todo);
+
+        if (master.killList.containsKey(deadServerName)) {
+          HashMap<Text, HRegionInfo> regionsToKill =
+            new HashMap<Text, HRegionInfo>();
+          synchronized (master.killList) {
+            regionsToKill.putAll(master.killList.get(deadServerName));
+          }
+
+          if (regionsToKill.containsKey(info.getRegionName())) {
+            regionsToKill.remove(info.getRegionName());
+            master.killList.put(deadServerName, regionsToKill);
+            master.unassignedRegions.remove(info);
+            synchronized (master.regionsToDelete) {
+              if (master.regionsToDelete.contains(info.getRegionName())) {
+                // Delete this region
+                master.regionsToDelete.remove(info.getRegionName());
+                todo.deleteRegion = true;
+              } else {
+                // Mark region offline
+                todo.regionOffline = true;
+              }
+            }
+          }
+
+        } else {
+          // Get region reassigned
+          regions.add(info);
+
+          // If it was pending, remove.
+          // Otherwise will obstruct its getting reassigned.
+          master.pendingRegions.remove(info.getRegionName());
+        }
+      }
+    } finally {
+      if(scannerId != -1L) {
+        try {
+          server.close(scannerId);
+        } catch (IOException e) {
+          LOG.error("Closing scanner",
+            RemoteExceptionHandler.checkIOException(e));
+        }
+      }
+    }
+
+    // Update server in root/meta entries
+    for (ToDoEntry e: toDoList) {
+      if (e.deleteRegion) {
+        HRegion.removeRegionFromMETA(server, regionName, e.row);
+      } else if (e.regionOffline) {
+        HRegion.offlineRegionInMETA(server, regionName, e.info);
+      }
+    }
+
+    // Get regions reassigned
+    for (HRegionInfo info: regions) {
+      master.unassignedRegions.put(info, ZERO_L);
+    }
+  }
+
+  @Override
+  protected boolean process() throws IOException {
+    LOG.info("process shutdown of server " + deadServer + ": logSplit: " +
+        this.logSplit + ", rootRescanned: " + this.rootRescanned +
+        ", numberOfMetaRegions: " + master.numberOfMetaRegions.get() +
+        ", onlineMetaRegions.size(): " + master.onlineMetaRegions.size());
+
+    if (!logSplit) {
+      // Process the old log file
+      if (master.fs.exists(oldLogDir)) {
+        if (!master.splitLogLock.tryLock()) {
+          return false;
+        }
+        try {
+          HLog.splitLog(master.rootdir, oldLogDir, master.fs, master.conf);
+        } finally {
+          master.splitLogLock.unlock();
+        }
+      }
+      logSplit = true;
+    }
+
+    if (!rootAvailable()) {
+      // Return true so that worker does not put this request back on the
+      // toDoQueue.
+      // rootAvailable() has already put it on the delayedToDoQueue
+      return true;
+    }
+
+    if (!rootRescanned) {
+      // Scan the ROOT region
+
+      HRegionInterface server = null;
+      long scannerId = -1L;
+      for (int tries = 0; tries < numRetries; tries ++) {
+        if (master.closed.get()) {
+          return true;
+        }
+        server = master.connection.getHRegionConnection(master.rootRegionLocation.get());
+        scannerId = -1L;
+
+        try {
+          if (LOG.isDebugEnabled()) {
+            LOG.debug("process server shutdown scanning root region on " +
+                master.rootRegionLocation.get().getBindAddress());
+          }
+          scannerId =
+            server.openScanner(HRegionInfo.rootRegionInfo.getRegionName(),
+                COLUMN_FAMILY_ARRAY, EMPTY_START_ROW,
+                System.currentTimeMillis(), null);
+          
+          scanMetaRegion(server, scannerId,
+              HRegionInfo.rootRegionInfo.getRegionName());
+          break;
+
+        } catch (IOException e) {
+          if (tries == numRetries - 1) {
+            throw RemoteExceptionHandler.checkIOException(e);
+          }
+        }
+      }
+      if (LOG.isDebugEnabled()) {
+        LOG.debug("process server shutdown scanning root region on " +
+            master.rootRegionLocation.get().getBindAddress() + " finished " +
+            Thread.currentThread().getName());
+      }
+      rootRescanned = true;
+    }
+    
+    if (!metaTableAvailable()) {
+      // We can't proceed because not all meta regions are online.
+      // metaAvailable() has put this request on the delayedToDoQueue
+      // Return true so that worker does not put this on the toDoQueue
+      return true;
+    }
+
+    for (int tries = 0; tries < numRetries; tries++) {
+      try {
+        if (master.closed.get()) {
+          return true;
+        }
+        List<MetaRegion> regions = new ArrayList<MetaRegion>();
+        synchronized (master.onlineMetaRegions) {
+          regions.addAll(master.onlineMetaRegions.values());
+        }
+        for (MetaRegion r: regions) {
+          HRegionInterface server = null;
+          long scannerId = -1L;
+
+          if (LOG.isDebugEnabled()) {
+            LOG.debug("process server shutdown scanning " +
+                r.getRegionName() + " on " + r.getServer() + " " +
+                Thread.currentThread().getName());
+          }
+          server = master.connection.getHRegionConnection(r.getServer());
+
+          scannerId =
+            server.openScanner(r.getRegionName(), COLUMN_FAMILY_ARRAY,
+                EMPTY_START_ROW, System.currentTimeMillis(), null);
+
+          scanMetaRegion(server, scannerId, r.getRegionName());
+
+          if (LOG.isDebugEnabled()) {
+            LOG.debug("process server shutdown finished scanning " +
+                r.getRegionName() + " on " + r.getServer() + " " +
+                Thread.currentThread().getName());
+          }
+        }
+        master.deadServers.remove(deadServerName);
+        break;
+
+      } catch (IOException e) {
+        if (tries == numRetries - 1) {
+          throw RemoteExceptionHandler.checkIOException(e);
+        }
+      }
+    }
+    return true;
+  }
+}
\ No newline at end of file

Added: hadoop/hbase/trunk/src/java/org/apache/hadoop/hbase/master/RegionServerOperation.java
URL: http://svn.apache.org/viewvc/hadoop/hbase/trunk/src/java/org/apache/hadoop/hbase/master/RegionServerOperation.java?rev=620706&view=auto
==============================================================================
--- hadoop/hbase/trunk/src/java/org/apache/hadoop/hbase/master/RegionServerOperation.java (added)
+++ hadoop/hbase/trunk/src/java/org/apache/hadoop/hbase/master/RegionServerOperation.java Mon Feb 11 22:19:46 2008
@@ -0,0 +1,94 @@
+/**
+ * Copyright 2008 The Apache Software Foundation
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.hadoop.hbase.master;
+
+import java.util.concurrent.Delayed;
+import java.util.concurrent.TimeUnit;
+import java.io.IOException;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.hadoop.hbase.HConstants;
+
+abstract class RegionServerOperation implements Delayed, HConstants {
+  protected static final Log LOG = 
+    LogFactory.getLog(RegionServerOperation.class.getName());
+  
+  private long expire;
+  protected final HMaster master;
+  protected final int numRetries;
+  
+  protected RegionServerOperation(HMaster master) {
+    this.master = master;
+    this.numRetries = master.numRetries;
+    // Set the future time at which we expect to be released from the
+    // DelayQueue we're inserted in on lease expiration.
+    this.expire = System.currentTimeMillis() + this.master.leaseTimeout / 2;
+  }
+  
+  /** {@inheritDoc} */
+  public long getDelay(TimeUnit unit) {
+    return unit.convert(this.expire - System.currentTimeMillis(),
+      TimeUnit.MILLISECONDS);
+  }
+  
+  /** {@inheritDoc} */
+  public int compareTo(Delayed o) {
+    return Long.valueOf(getDelay(TimeUnit.MILLISECONDS)
+        - o.getDelay(TimeUnit.MILLISECONDS)).intValue();
+  }
+  
+  protected void requeue() {
+    this.expire = System.currentTimeMillis() + this.master.leaseTimeout / 2;
+    master.delayedToDoQueue.put(this);
+  }
+  
+  protected boolean rootAvailable() {
+    boolean available = true;
+    if (master.rootRegionLocation.get() == null) {
+      available = false;
+      requeue();
+    }
+    return available;
+  }
+
+  protected boolean metaTableAvailable() {
+    boolean available = true;
+    if (LOG.isDebugEnabled()) {
+      LOG.debug("numberOfMetaRegions: " + master.numberOfMetaRegions.get() +
+          ", onlineMetaRegions.size(): " + master.onlineMetaRegions.size());
+    }
+    if (master.numberOfMetaRegions.get() != master.onlineMetaRegions.size()) {
+      // We can't proceed because not all of the meta regions are online.
+      // We can't block either because that would prevent the meta region
+      // online message from being processed. In order to prevent spinning
+      // in the run queue, put this request on the delay queue to give
+      // other threads the opportunity to get the meta regions on-line.
+      if (LOG.isDebugEnabled()) {
+        LOG.debug("Requeuing because not all meta regions are online");
+      }
+      available = false;
+      requeue();
+    }
+    return available;
+  }
+  
+  protected abstract boolean process() throws IOException;
+}
\ No newline at end of file

Added: hadoop/hbase/trunk/src/java/org/apache/hadoop/hbase/master/RootScanner.java
URL: http://svn.apache.org/viewvc/hadoop/hbase/trunk/src/java/org/apache/hadoop/hbase/master/RootScanner.java?rev=620706&view=auto
==============================================================================
--- hadoop/hbase/trunk/src/java/org/apache/hadoop/hbase/master/RootScanner.java (added)
+++ hadoop/hbase/trunk/src/java/org/apache/hadoop/hbase/master/RootScanner.java Mon Feb 11 22:19:46 2008
@@ -0,0 +1,85 @@
+/**
+ * Copyright 2008 The Apache Software Foundation
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.hadoop.hbase.master;
+
+import java.io.IOException;
+
+import org.apache.hadoop.hbase.HRegionInfo;
+import org.apache.hadoop.hbase.RemoteExceptionHandler;
+
+/** Scanner for the <code>ROOT</code> HRegion. */
+class RootScanner extends BaseScanner {
+  /** Constructor */
+  public RootScanner(HMaster master) {
+    super(master, true, master.metaRescanInterval, master.closed);
+  }
+
+  private boolean scanRoot() {
+    // Don't retry if we get an error while scanning. Errors are most often
+    // caused by the server going away. Wait until next rescan interval when
+    // things should be back to normal
+    boolean scanSuccessful = false;
+    synchronized (master.rootRegionLocation) {
+      while(!master.closed.get() && master.rootRegionLocation.get() == null) {
+        // rootRegionLocation will be filled in when we get an 'open region'
+        // regionServerReport message from the HRegionServer that has been
+        // allocated the ROOT region below.
+        try {
+          master.rootRegionLocation.wait();
+        } catch (InterruptedException e) {
+          // continue
+        }
+      }
+    }
+    if (master.closed.get()) {
+      return scanSuccessful;
+    }
+
+    try {
+      // Don't interrupt us while we're working
+      synchronized(master.rootScannerLock) {
+        scanRegion(new MetaRegion(master.rootRegionLocation.get(),
+            HRegionInfo.rootRegionInfo.getRegionName(), null));
+      }
+      scanSuccessful = true;
+    } catch (IOException e) {
+      e = RemoteExceptionHandler.checkIOException(e);
+      LOG.warn("Scan ROOT region", e);
+      // Make sure the file system is still available
+      master.checkFileSystem();
+    } catch (Exception e) {
+      // If for some reason we get some other kind of exception, 
+      // at least log it rather than go out silently.
+      LOG.error("Unexpected exception", e);
+    }
+    return scanSuccessful;
+  }
+
+  @Override
+  protected boolean initialScan() {
+    master.rootScanned = scanRoot();
+    return master.rootScanned;
+  }
+
+  @Override
+  protected void maintenanceScan() {
+    scanRoot();
+  }
+}
\ No newline at end of file

Added: hadoop/hbase/trunk/src/java/org/apache/hadoop/hbase/master/RowMap.java
URL: http://svn.apache.org/viewvc/hadoop/hbase/trunk/src/java/org/apache/hadoop/hbase/master/RowMap.java?rev=620706&view=auto
==============================================================================
--- hadoop/hbase/trunk/src/java/org/apache/hadoop/hbase/master/RowMap.java (added)
+++ hadoop/hbase/trunk/src/java/org/apache/hadoop/hbase/master/RowMap.java Mon Feb 11 22:19:46 2008
@@ -0,0 +1,85 @@
+/**
+ * Copyright 2008 The Apache Software Foundation
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.hadoop.hbase.master;
+
+import java.util.Map;
+import java.util.SortedMap;
+import java.util.TreeMap;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.apache.hadoop.io.Text;
+import org.apache.hadoop.hbase.io.HbaseMapWritable;
+import org.apache.hadoop.io.Writable;
+import org.apache.hadoop.hbase.HStoreKey;
+import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
+
+/*
+ * Data structure used to return results out of the toRowMap method.
+ */
+class RowMap {
+  static final Log LOG = LogFactory.getLog(RowMap.class.getName());
+  
+  final Text row;
+  final SortedMap<Text, byte[]> map;
+  
+  RowMap(final Text r, final SortedMap<Text, byte[]> m) {
+    this.row = r;
+    this.map = m;
+  }
+
+  Text getRow() {
+    return this.row;
+  }
+
+  SortedMap<Text, byte[]> getMap() {
+    return this.map;
+  }
+  
+  /*
+   * Convert an HbaseMapWritable to a Map keyed by column.
+   * Utility method used scanning meta regions
+   * @param mw The MapWritable to convert.  Cannot be null.
+   * @return Returns a SortedMap currently.  TODO: This looks like it could
+   * be a plain Map.
+   */
+  public static RowMap fromHbaseMapWritable(HbaseMapWritable mw) {
+    if (mw == null) {
+      throw new IllegalArgumentException("Passed MapWritable cannot be null");
+    }
+    SortedMap<Text, byte[]> m = new TreeMap<Text, byte[]>();
+    Text row = null;
+    for (Map.Entry<Writable, Writable> e: mw.entrySet()) {
+      HStoreKey key = (HStoreKey) e.getKey();
+      Text thisRow = key.getRow();
+      if (row == null) {
+        row = thisRow;
+      } else {
+        if (!row.equals(thisRow)) {
+          LOG.error("Multiple rows in same scanner result set. firstRow=" +
+            row + ", currentRow=" + thisRow);
+        }
+      }
+      m.put(key.getColumn(), ((ImmutableBytesWritable) e.getValue()).get());
+    }
+    return new RowMap(row, m);
+  }
+}
\ No newline at end of file

Added: hadoop/hbase/trunk/src/java/org/apache/hadoop/hbase/master/TableDelete.java
URL: http://svn.apache.org/viewvc/hadoop/hbase/trunk/src/java/org/apache/hadoop/hbase/master/TableDelete.java?rev=620706&view=auto
==============================================================================
--- hadoop/hbase/trunk/src/java/org/apache/hadoop/hbase/master/TableDelete.java (added)
+++ hadoop/hbase/trunk/src/java/org/apache/hadoop/hbase/master/TableDelete.java Mon Feb 11 22:19:46 2008
@@ -0,0 +1,75 @@
+/**
+ * Copyright 2008 The Apache Software Foundation
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.hadoop.hbase.master;
+
+import java.io.IOException;
+import java.util.HashSet;
+
+import org.apache.hadoop.hbase.HRegion;
+import org.apache.hadoop.hbase.HRegionInfo;
+import org.apache.hadoop.hbase.HRegionInterface;
+import org.apache.hadoop.hbase.RemoteExceptionHandler;
+import org.apache.hadoop.hbase.io.BatchUpdate;
+import org.apache.hadoop.io.Text;
+
+/** 
+ * Instantiated to delete a table
+ * Note that it extends ChangeTableState, which takes care of disabling
+ * the table.
+ */
+class TableDelete extends ChangeTableState {
+
+  TableDelete(final HMaster master, final Text tableName) throws IOException {
+    super(master, tableName, false);
+  }
+
+  @Override
+  protected void postProcessMeta(MetaRegion m, HRegionInterface server)
+  throws IOException {
+    // For regions that are being served, mark them for deletion          
+    for (HashSet<HRegionInfo> s: servedRegions.values()) {
+      for (HRegionInfo i: s) {
+        this.master.regionsToDelete.add(i.getRegionName());
+      }
+    }
+
+    // Unserved regions we can delete now
+    for (HRegionInfo i: unservedRegions) {
+      // Delete the region
+      try {
+        HRegion.deleteRegion(this.master.fs, this.master.rootdir, i);
+      
+      } catch (IOException e) {
+        LOG.error("failed to delete region " + i.getRegionName(),
+          RemoteExceptionHandler.checkIOException(e));
+      }
+    }
+    super.postProcessMeta(m, server);
+  }
+
+  @Override
+  protected void updateRegionInfo(BatchUpdate b,
+    @SuppressWarnings("unused") HRegionInfo info) {
+    for (int i = 0; i < ALL_META_COLUMNS.length; i++) {
+      // Be sure to clean all cells
+      b.delete(ALL_META_COLUMNS[i]);
+    }
+  }
+}
\ No newline at end of file

Added: hadoop/hbase/trunk/src/java/org/apache/hadoop/hbase/master/TableOperation.java
URL: http://svn.apache.org/viewvc/hadoop/hbase/trunk/src/java/org/apache/hadoop/hbase/master/TableOperation.java?rev=620706&view=auto
==============================================================================
--- hadoop/hbase/trunk/src/java/org/apache/hadoop/hbase/master/TableOperation.java (added)
+++ hadoop/hbase/trunk/src/java/org/apache/hadoop/hbase/master/TableOperation.java Mon Feb 11 22:19:46 2008
@@ -0,0 +1,184 @@
+/**
+ * Copyright 2008 The Apache Software Foundation
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.hadoop.hbase.master;
+
+import java.io.IOException;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.SortedMap;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.hadoop.hbase.HConstants;
+import org.apache.hadoop.hbase.HRegionInfo;
+import org.apache.hadoop.hbase.HRegionInterface;
+import org.apache.hadoop.hbase.HServerInfo;
+import org.apache.hadoop.hbase.MasterNotRunningException;
+import org.apache.hadoop.hbase.RemoteExceptionHandler;
+import org.apache.hadoop.hbase.io.HbaseMapWritable;
+import org.apache.hadoop.hbase.util.Writables;
+import org.apache.hadoop.io.Text;
+
+abstract class TableOperation implements HConstants {
+  static final Long ZERO_L = Long.valueOf(0L);
+  
+  protected static final Log LOG = 
+    LogFactory.getLog(TableOperation.class.getName());
+  
+  protected Set<MetaRegion> metaRegions;
+  protected Text tableName;
+  protected Set<HRegionInfo> unservedRegions;
+  protected HMaster master;
+  protected final int numRetries;
+  
+  protected TableOperation(final HMaster master, final Text tableName) 
+  throws IOException {
+    this.numRetries = master.numRetries;
+    
+    this.master = master;
+    
+    if (!this.master.isMasterRunning()) {
+      throw new MasterNotRunningException();
+    }
+
+    this.metaRegions = new HashSet<MetaRegion>();
+    this.tableName = tableName;
+    this.unservedRegions = new HashSet<HRegionInfo>();
+
+    // We can not access any meta region if they have not already been
+    // assigned and scanned.
+
+    if (this.master.metaScannerThread.waitForMetaRegionsOrClose()) {
+      throw new MasterNotRunningException(); // We're shutting down. Forget it.
+    }
+
+    Text firstMetaRegion = null;
+    synchronized (this.master.onlineMetaRegions) {
+      if (this.master.onlineMetaRegions.size() == 1) {
+        firstMetaRegion = this.master.onlineMetaRegions.firstKey();
+
+      } else if (this.master.onlineMetaRegions.containsKey(tableName)) {
+        firstMetaRegion = tableName;
+
+      } else {
+        firstMetaRegion = this.master.onlineMetaRegions.headMap(tableName).lastKey();
+      }
+      this.metaRegions.addAll(this.master.onlineMetaRegions.tailMap(
+          firstMetaRegion).values());
+    }
+  }
+
+  void process() throws IOException {
+    for (int tries = 0; tries < numRetries; tries++) {
+      boolean tableExists = false;
+      try {
+        // Prevent meta scanner from running
+        synchronized(this.master.metaScannerLock) {
+          for (MetaRegion m: metaRegions) {
+
+            // Get a connection to a meta server
+
+            HRegionInterface server =
+              this.master.connection.getHRegionConnection(m.getServer());
+
+            // Open a scanner on the meta region
+
+            long scannerId =
+              server.openScanner(m.getRegionName(), COLUMN_FAMILY_ARRAY,
+                  tableName, System.currentTimeMillis(), null);
+
+            try {
+              while (true) {
+                HbaseMapWritable values = server.next(scannerId);
+                if(values == null || values.size() == 0) {
+                  break;
+                }
+                RowMap rm = RowMap.fromHbaseMapWritable(values);
+                SortedMap<Text, byte[]> map = rm.getMap();
+                HRegionInfo info = this.master.getHRegionInfo(map);
+                if (info == null) {
+                  throw new IOException(COL_REGIONINFO + " not found on " +
+                    rm.getRow());
+                }
+                String serverName = Writables.bytesToString(map.get(COL_SERVER));
+                long startCode = Writables.bytesToLong(map.get(COL_STARTCODE));
+                if (info.getTableDesc().getName().compareTo(tableName) > 0) {
+                  break; // Beyond any more entries for this table
+                }
+
+                tableExists = true;
+                if (!isBeingServed(serverName, startCode)) {
+                  unservedRegions.add(info);
+                }
+                processScanItem(serverName, startCode, info);
+              } // while(true)
+            } finally {
+              if (scannerId != -1L) {
+                try {
+                  server.close(scannerId);
+                } catch (IOException e) {
+                  e = RemoteExceptionHandler.checkIOException(e);
+                  LOG.error("closing scanner", e);
+                }
+              }
+              scannerId = -1L;
+            }
+
+            if (!tableExists) {
+              throw new IOException(tableName + " does not exist");
+            }
+
+            postProcessMeta(m, server);
+            unservedRegions.clear();
+
+          } // for(MetaRegion m:)
+        } // synchronized(metaScannerLock)
+
+      } catch (IOException e) {
+        if (tries == numRetries - 1) {
+          // No retries left
+          this.master.checkFileSystem();
+          throw RemoteExceptionHandler.checkIOException(e);
+        }
+        continue;
+      }
+      break;
+    } // for(tries...)
+  }
+
+  protected boolean isBeingServed(String serverName, long startCode) {
+    boolean result = false;
+    if (serverName != null && serverName.length() > 0 && startCode != -1L) {
+      HServerInfo s = this.master.serversToServerInfo.get(serverName);
+      result = s != null && s.getStartCode() == startCode;
+    }
+    return result;
+  }
+
+  protected boolean isEnabled(HRegionInfo info) {
+    return !info.isOffline();
+  }
+
+  protected abstract void processScanItem(String serverName, long startCode,
+    HRegionInfo info) throws IOException;
+
+  protected abstract void postProcessMeta(MetaRegion m,
+    HRegionInterface server) throws IOException;
+}
\ No newline at end of file

Modified: hadoop/hbase/trunk/src/webapps/master/master.jsp
URL: http://svn.apache.org/viewvc/hadoop/hbase/trunk/src/webapps/master/master.jsp?rev=620706&r1=620705&r2=620706&view=diff
==============================================================================
--- hadoop/hbase/trunk/src/webapps/master/master.jsp (original)
+++ hadoop/hbase/trunk/src/webapps/master/master.jsp Mon Feb 11 22:19:46 2008
@@ -4,11 +4,10 @@
   import="org.apache.hadoop.util.VersionInfo"
   import="org.apache.hadoop.hbase.master.HMaster"
   import="org.apache.hadoop.hbase.HConstants"
-  import="org.apache.hadoop.hbase.master.HMaster.MetaRegion"
+  import="org.apache.hadoop.hbase.master.MetaRegion"
   import="org.apache.hadoop.hbase.HBaseAdmin"
   import="org.apache.hadoop.hbase.HServerInfo"
   import="org.apache.hadoop.hbase.HServerAddress"
-  import="org.apache.hadoop.hbase.HRegionInfo"
   import="org.apache.hadoop.hbase.HBaseConfiguration"
   import="org.apache.hadoop.hbase.hql.ShowCommand"
   import="org.apache.hadoop.hbase.hql.TableFormatter"
@@ -56,7 +55,7 @@
 <tr><td><%= HConstants.ROOT_TABLE_NAME.toString() %></td><td><%= rootLocation.toString() %></td></tr>
 <%
   if (onlineRegions != null && onlineRegions.size() > 0) { %>
-  <% for (Map.Entry<Text, HMaster.MetaRegion> e: onlineRegions.entrySet()) {
+  <% for (Map.Entry<Text, MetaRegion> e: onlineRegions.entrySet()) {
     MetaRegion meta = e.getValue();
   %>
   <tr><td><%= meta.getRegionName().toString() %></td><td><%= meta.getServer().toString() %></td></tr>