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>