diff --git src/main/java/org/apache/hadoop/hbase/ClusterStatus.java src/main/java/org/apache/hadoop/hbase/ClusterStatus.java index b849429..97933e1 100644 --- src/main/java/org/apache/hadoop/hbase/ClusterStatus.java +++ src/main/java/org/apache/hadoop/hbase/ClusterStatus.java @@ -31,7 +31,7 @@ import java.util.HashMap; import java.util.Map; import java.util.TreeMap; -import org.apache.hadoop.hbase.master.AssignmentManager.RegionState; +import org.apache.hadoop.hbase.master.RegionState; import org.apache.hadoop.hbase.util.Bytes; import org.apache.hadoop.io.VersionedWritable; diff --git src/main/java/org/apache/hadoop/hbase/master/AssignmentManager.java src/main/java/org/apache/hadoop/hbase/master/AssignmentManager.java index 6e509f1..e3bbcbc 100644 --- src/main/java/org/apache/hadoop/hbase/master/AssignmentManager.java +++ src/main/java/org/apache/hadoop/hbase/master/AssignmentManager.java @@ -19,14 +19,11 @@ */ package org.apache.hadoop.hbase.master; -import java.io.DataInput; -import java.io.DataOutput; import java.io.IOException; import java.lang.Thread.UncaughtExceptionHandler; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; -import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; @@ -41,7 +38,6 @@ import java.util.concurrent.ConcurrentSkipListMap; import java.util.concurrent.ConcurrentSkipListSet; import java.util.concurrent.Executors; import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicLong; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -95,18 +91,13 @@ import org.apache.zookeeper.data.Stat; * Handles existing regions in transition during master failover. */ public class AssignmentManager extends ZooKeeperListener { - private static final Log LOG = LogFactory.getLog(AssignmentManager.class); - protected Server master; - private ServerManager serverManager; - private CatalogTracker catalogTracker; - private TimeoutMonitor timeoutMonitor; - private LoadBalancer balancer; + private final ServersAndRegions serversAndRegions = new ServersAndRegions(); /** * Map of regions to reopen after the schema of a table is changed. Key - @@ -140,31 +131,11 @@ public class AssignmentManager extends ZooKeeperListener { // store all the enabling state tablenames. Set enablingTables = new HashSet(1); - /** - * Server to regions assignment map. - * Contains the set of regions currently assigned to a given server. - * This Map and {@link #regions} are tied. Always update this in tandem - * with the other under a lock on {@link #regions} - * @see #regions - */ - private final NavigableMap> servers = - new TreeMap>(); - - /** - * Region to server assignment map. - * Contains the server a given region is currently assigned to. - * This Map and {@link #servers} are tied. Always update this in tandem - * with the other under a lock on {@link #regions} - * @see #servers - */ - private final SortedMap regions = - new TreeMap(); - private final ExecutorService executorService; //Thread pool executor service for timeout monitor private java.util.concurrent.ExecutorService threadPoolExecutorService; - + private List ignoreStatesRSOffline = Arrays.asList(new EventType[]{ EventType.RS_ZK_REGION_FAILED_OPEN, EventType.RS_ZK_REGION_CLOSED }); @@ -201,26 +172,15 @@ public class AssignmentManager extends ZooKeeperListener { this.master.getConfiguration().getInt("hbase.assignment.maximum.attempts", 10); this.balancer = LoadBalancerFactory.getLoadBalancer(conf); this.threadPoolExecutorService = Executors.newCachedThreadPool(); + } /** - * Compute the average load across all region servers. - * Currently, this uses a very naive computation - just uses the number of + * @return the average load which is the number of * regions being served, ignoring stats about number of requests. - * @return the average load */ double getAverageLoad() { - int totalLoad = 0; - int numServers = 0; - // Sync on this.regions because access to this.servers always synchronizes - // in this order. - synchronized (this.regions) { - for (Map.Entry> e: servers.entrySet()) { - numServers++; - totalLoad += e.getValue().size(); - } - } - return (double)totalLoad / (double)numServers; + return this.serversAndRegions.getAverageLoad(); } /** @@ -231,17 +191,14 @@ public class AssignmentManager extends ZooKeeperListener { // sharing. return this.zkTable; } + /** - * Returns the RegionServer to which hri is assigned. - * - * @param hri - * HRegion for which this function returns the region server + * Returns the RegionServer to which hri is assigned. + * @param hri HRegion for which this function returns the region server * @return HServerInfo The region server to which hri belongs */ public ServerName getRegionServerOfRegion(HRegionInfo hri) { - synchronized (this.regions ) { - return regions.get(hri); - } + return this.serversAndRegions.getRegionServerOfRegion(hri); } /** @@ -359,21 +316,7 @@ public class AssignmentManager extends ZooKeeperListener { watcher.assignmentZNode); // Run through all regions. If they are not assigned and not in RIT, then // its a clean cluster startup, else its a failover. - boolean regionsToProcess = false; - for (Map.Entry e: this.regions.entrySet()) { - if (!e.getKey().isMetaTable() - && e.getValue() != null) { - LOG.debug("Found " + e + " out on cluster"); - regionsToProcess = true; - break; - } - if (nodes.contains(e.getKey().getEncodedName())) { - LOG.debug("Found " + e.getKey().getRegionNameAsString() + " in RITs"); - // Could be a meta region. - regionsToProcess = true; - break; - } - } + boolean regionsToProcess = this.serversAndRegions.isRegionsToProcess(nodes); // If we found user regions out on cluster, its a failover. if (regionsToProcess) { @@ -381,7 +324,6 @@ public class AssignmentManager extends ZooKeeperListener { // Process list of dead servers and regions in RIT. // See HBASE-4580 for more information. processDeadServersAndRecoverLostRegions(deadServers, nodes); - } else { // Fresh cluster startup. LOG.info("Clean cluster startup. Assigning userregions"); @@ -981,10 +923,10 @@ public class AssignmentManager extends ZooKeeperListener { } private void makeRegionOnline(RegionState rs, HRegionInfo regionInfo) { - regionOnline(regionInfo, rs.serverName); + regionOnline(regionInfo, rs.getServerName()); LOG.info("The master has opened the region " + regionInfo.getRegionNameAsString() + " that was online on " - + rs.serverName); + + rs.getServerName()); if (this.getZKTable().isDisablingOrDisabledTable( regionInfo.getTableNameAsString())) { LOG.debug("Opened region " @@ -1116,14 +1058,7 @@ public class AssignmentManager extends ZooKeeperListener { * @param regionInfo */ public void setOffline(HRegionInfo regionInfo) { - synchronized (this.regions) { - ServerName sn = this.regions.remove(regionInfo); - if (sn == null) return; - Set serverRegions = this.servers.get(sn); - if (!serverRegions.remove(regionInfo)) { - LOG.warn("No " + regionInfo + " on " + sn); - } - } + this.serversAndRegions.remove(regionInfo); } public void offlineDisabledRegion(HRegionInfo regionInfo) { @@ -1477,9 +1412,7 @@ public class AssignmentManager extends ZooKeeperListener { this.regionsInTransition.remove(plan.getRegionInfo() .getEncodedName()); } - synchronized (this.regions) { - this.regions.put(plan.getRegionInfo(), plan.getDestination()); - } + this.serversAndRegions.put(plan); } break; } catch (Throwable t) { @@ -1744,14 +1677,10 @@ public class AssignmentManager extends ZooKeeperListener { // TODO: Method needs refactoring. Ugly buried returns throughout. Beware! LOG.debug("Starting unassignment of region " + region.getRegionNameAsString() + " (offlining)"); - synchronized (this.regions) { - // Check if this region is currently assigned - if (!regions.containsKey(region)) { - LOG.debug("Attempted to unassign region " + - region.getRegionNameAsString() + " but it is not " + - "currently assigned anywhere"); - return; - } + if (!this.serversAndRegions.is(region)) { + LOG.debug("Attempted unassign region " + region.getRegionNameAsString() + + " but it is not currently assigned anywhere"); + return; } String encodedName = region.getEncodedName(); // Grab the state of this region and synchronize on it @@ -1813,10 +1742,7 @@ public class AssignmentManager extends ZooKeeperListener { } } // Send CLOSE RPC - ServerName server = null; - synchronized (this.regions) { - server = regions.get(region); - } + ServerName server = this.serversAndRegions.get(region); try { // TODO: We should consider making this look more like it does for the // region open where we catch all throwables and never abort @@ -1849,9 +1775,7 @@ public class AssignmentManager extends ZooKeeperListener { this.regionsInTransition.remove(region.getEncodedName()); } // Remove from the regionsMap - synchronized (this.regions) { - this.regions.remove(region); - } + this.serversAndRegions.remove(region); } } // RS is already processing this region, only need to update the timestamp @@ -1898,14 +1822,7 @@ public class AssignmentManager extends ZooKeeperListener { */ public void waitForAssignment(HRegionInfo regionInfo) throws InterruptedException { - synchronized(regions) { - while(!regions.containsKey(regionInfo)) { - // We should receive a notification, but it's - // better to have a timeout to recheck the condition here: - // it lowers the impact of a race condition if any - regions.wait(100); - } - } + this.serversAndRegions.wait(regionInfo); } /** @@ -2453,12 +2370,7 @@ public class AssignmentManager extends ZooKeeperListener { synchronized (this.regionsInTransition) { this.regionsInTransition.remove(hri.getEncodedName()); } - synchronized (this.regions) { - this.regions.remove(hri); - for (Set regions : this.servers.values()) { - regions.remove(hri); - } - } + this.serversAndRegions.remove(hri); clearRegionPlan(hri); } @@ -2492,7 +2404,6 @@ public class AssignmentManager extends ZooKeeperListener { } } - /** * Gets the online regions of the specified table. * This method looks at the in-memory state. It does not go to .META.. @@ -2504,19 +2415,7 @@ public class AssignmentManager extends ZooKeeperListener { * @return Online regions from tableName */ public List getRegionsOfTable(byte[] tableName) { - List tableRegions = new ArrayList(); - HRegionInfo boundary = - new HRegionInfo(tableName, null, null); - synchronized (this.regions) { - for (HRegionInfo regionInfo: this.regions.tailMap(boundary).keySet()) { - if(Bytes.equals(regionInfo.getTableName(), tableName)) { - tableRegions.add(regionInfo); - } else { - break; - } - } - } - return tableRegions; + return this.serversAndRegions.getOnlineRegionsOfTable(tableName); } /** @@ -2743,19 +2642,8 @@ public class AssignmentManager extends ZooKeeperListener { // TODO: Do we want to sync on RIT here? // Remove this server from map of servers to regions, and remove all regions // of this server from online map of regions. - Set deadRegions = null; List rits = new ArrayList(); - synchronized (this.regions) { - Set assignedRegions = this.servers.remove(sn); - if (assignedRegions == null || assignedRegions.isEmpty()) { - // No regions on this server, we are done, return empty list of RITs - return rits; - } - deadRegions = new TreeSet(assignedRegions); - for (HRegionInfo region : deadRegions) { - this.regions.remove(region); - } - } + Set deadRegions = this.serversAndRegions.getRegionsOnServer(sn); // See if any of the regions that were online on this server were in RIT // If they are, normal timeouts will deal with them appropriately so // let's skip a manual re-assignment. @@ -2868,15 +2756,7 @@ public class AssignmentManager extends ZooKeeperListener { * and the hosting servers {@link ServerName}. */ Pair getAssignment(final byte [] encodedRegionName) { - String name = Bytes.toString(encodedRegionName); - synchronized(this.regions) { - for (Map.Entry e: this.regions.entrySet()) { - if (e.getKey().getEncodedName().equals(name)) { - return new Pair(e.getKey(), e.getValue()); - } - } - } - return null; + return this.serversAndRegions.getAssignment(encodedRegionName); } /** @@ -2893,7 +2773,6 @@ public class AssignmentManager extends ZooKeeperListener { * Run through remaining regionservers and unassign all catalog regions. */ void unassignCatalogRegions() { - this.servers.entrySet(); synchronized (this.regions) { for (Map.Entry> e: this.servers.entrySet()) { Set regions = e.getValue(); @@ -2907,149 +2786,6 @@ public class AssignmentManager extends ZooKeeperListener { } } - /** - * State of a Region while undergoing transitions. - */ - public static class RegionState implements org.apache.hadoop.io.Writable { - private HRegionInfo region; - - public enum State { - OFFLINE, // region is in an offline state - PENDING_OPEN, // sent rpc to server to open but has not begun - OPENING, // server has begun to open but not yet done - OPEN, // server opened region and updated meta - PENDING_CLOSE, // sent rpc to server to close but has not begun - CLOSING, // server has begun to close but not yet done - CLOSED, // server closed region and updated meta - SPLITTING, // server started split of a region - SPLIT // server completed split of a region - } - - private State state; - // Many threads can update the state at the stamp at the same time - private final AtomicLong stamp; - private ServerName serverName; - - public RegionState() { - this.stamp = new AtomicLong(System.currentTimeMillis()); - } - - RegionState(HRegionInfo region, State state) { - this(region, state, System.currentTimeMillis(), null); - } - - RegionState(HRegionInfo region, State state, long stamp, ServerName serverName) { - this.region = region; - this.state = state; - this.stamp = new AtomicLong(stamp); - this.serverName = serverName; - } - - public void update(State state, long stamp, ServerName serverName) { - this.state = state; - updateTimestamp(stamp); - this.serverName = serverName; - } - - public void update(State state) { - this.state = state; - updateTimestampToNow(); - this.serverName = null; - } - - public void updateTimestamp(long stamp) { - this.stamp.set(stamp); - } - - public void updateTimestampToNow() { - this.stamp.set(System.currentTimeMillis()); - } - - public State getState() { - return state; - } - - public long getStamp() { - return stamp.get(); - } - - public HRegionInfo getRegion() { - return region; - } - - public boolean isClosing() { - return state == State.CLOSING; - } - - public boolean isClosed() { - return state == State.CLOSED; - } - - public boolean isPendingClose() { - return state == State.PENDING_CLOSE; - } - - public boolean isOpening() { - return state == State.OPENING; - } - - public boolean isOpened() { - return state == State.OPEN; - } - - public boolean isPendingOpen() { - return state == State.PENDING_OPEN; - } - - public boolean isOffline() { - return state == State.OFFLINE; - } - - public boolean isSplitting() { - return state == State.SPLITTING; - } - - public boolean isSplit() { - return state == State.SPLIT; - } - - @Override - public String toString() { - return region.getRegionNameAsString() - + " state=" + state - + ", ts=" + stamp - + ", server=" + serverName; - } - - /** - * A slower (but more easy-to-read) stringification - */ - public String toDescriptiveString() { - long lstamp = stamp.get(); - long relTime = System.currentTimeMillis() - lstamp; - - return region.getRegionNameAsString() - + " state=" + state - + ", ts=" + new Date(lstamp) + " (" + (relTime/1000) + "s ago)" - + ", server=" + serverName; - } - - @Override - public void readFields(DataInput in) throws IOException { - region = new HRegionInfo(); - region.readFields(in); - state = State.valueOf(in.readUTF()); - stamp.set(in.readLong()); - } - - @Override - public void write(DataOutput out) throws IOException { - region.write(out); - out.writeUTF(state.name()); - out.writeLong(stamp.get()); - } - } - public void stop() { this.timeoutMonitor.interrupt(); } diff --git src/main/java/org/apache/hadoop/hbase/master/MasterDumpServlet.java src/main/java/org/apache/hadoop/hbase/master/MasterDumpServlet.java index 876eda4..b1992fd 100644 --- src/main/java/org/apache/hadoop/hbase/master/MasterDumpServlet.java +++ src/main/java/org/apache/hadoop/hbase/master/MasterDumpServlet.java @@ -33,7 +33,6 @@ import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.hbase.HServerInfo; import org.apache.hadoop.hbase.HServerLoad; import org.apache.hadoop.hbase.ServerName; -import org.apache.hadoop.hbase.master.AssignmentManager.RegionState; import org.apache.hadoop.hbase.monitoring.LogMonitoring; import org.apache.hadoop.hbase.monitoring.StateDumpServlet; import org.apache.hadoop.hbase.monitoring.TaskMonitor; diff --git src/main/java/org/apache/hadoop/hbase/master/RegionState.java src/main/java/org/apache/hadoop/hbase/master/RegionState.java new file mode 100644 index 0000000..f5f80ab --- /dev/null +++ src/main/java/org/apache/hadoop/hbase/master/RegionState.java @@ -0,0 +1,186 @@ +/** + * 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.DataInput; +import java.io.DataOutput; +import java.io.IOException; +import java.util.Date; +import java.util.concurrent.atomic.AtomicLong; + +import org.apache.hadoop.hbase.HRegionInfo; +import org.apache.hadoop.hbase.ServerName; +import org.apache.hadoop.io.Writable; + +/** + * State of a Region while undergoing transitions orchestrated by + * {@link AssignmentManager}. Its {@link Writable} so can be persisted to the + * likes of zookeeper. + */ +public class RegionState implements Writable { + enum State { + OFFLINE, // region is in an offline state + PENDING_OPEN, // sent rpc to server to open but has not begun + OPENING, // server has begun to open but not yet done + OPEN, // server opened region and updated meta + PENDING_CLOSE, // sent rpc to server to close but has not begun + CLOSING, // server has begun to close but not yet done + CLOSED, // server closed region and updated meta + SPLITTING, // server started split of a region + SPLIT // server completed split of a region + } + + private HRegionInfo region; + + private RegionState.State state; + + // Many threads can update the state at the stamp at the same time + private final AtomicLong stamp; + + private ServerName serverName; + + /** + * Used by {@link Writable} deserializing. Do not use. + */ + public RegionState() { + this.stamp = new AtomicLong(System.currentTimeMillis()); + } + + RegionState(final HRegionInfo region, final RegionState.State state) { + this(region, state, System.currentTimeMillis(), null); + } + + RegionState(final HRegionInfo region, final RegionState.State state, + final long stamp, final ServerName serverName) { + this.region = region; + this.state = state; + this.stamp = new AtomicLong(stamp); + this.serverName = serverName; + } + + public void update(final RegionState.State state, final long stamp, + final ServerName serverName) { + // TODO: This is an odd method; it basically resets this class. Why not + // allocate a new instance altogether? St.Ack 01/24/2012 + this.state = state; + updateTimestamp(stamp); + this.serverName = serverName; + } + + public void update(RegionState.State state) { + this.state = state; + updateTimestampToNow(); + this.serverName = null; + } + + public void updateTimestamp(long stamp) { + this.stamp.set(stamp); + } + + public void updateTimestampToNow() { + this.stamp.set(System.currentTimeMillis()); + } + + public RegionState.State getState() { + return state; + } + + public long getStamp() { + return stamp.get(); + } + + public HRegionInfo getRegion() { + return region; + } + + public ServerName getServerName() { + return this.serverName; + } + + public boolean isClosing() { + return state == State.CLOSING; + } + + public boolean isClosed() { + return state == State.CLOSED; + } + + public boolean isPendingClose() { + return state == State.PENDING_CLOSE; + } + + public boolean isOpening() { + return state == State.OPENING; + } + + public boolean isOpened() { + return state == State.OPEN; + } + + public boolean isPendingOpen() { + return state == State.PENDING_OPEN; + } + + public boolean isOffline() { + return state == State.OFFLINE; + } + + public boolean isSplitting() { + return state == State.SPLITTING; + } + + public boolean isSplit() { + return state == State.SPLIT; + } + + @Override + public String toString() { + return region.getRegionNameAsString() + + " state=" + state + + ", ts=" + stamp + + ", server=" + serverName; + } + + /** + * A slower (but more easy-to-read) stringification + */ + public String toDescriptiveString() { + long lstamp = stamp.get(); + long relTime = System.currentTimeMillis() - lstamp; + + return region.getRegionNameAsString() + + " state=" + state + + ", ts=" + new Date(lstamp) + " (" + (relTime/1000) + "s ago)" + + ", server=" + serverName; + } + + @Override + public void readFields(DataInput in) throws IOException { + region = new HRegionInfo(); + region.readFields(in); + state = State.valueOf(in.readUTF()); + stamp.set(in.readLong()); + } + + @Override + public void write(DataOutput out) throws IOException { + region.write(out); + out.writeUTF(state.name()); + out.writeLong(stamp.get()); + } +} \ No newline at end of file diff --git src/main/java/org/apache/hadoop/hbase/master/ServersAndRegions.java src/main/java/org/apache/hadoop/hbase/master/ServersAndRegions.java new file mode 100644 index 0000000..ab615d0 --- /dev/null +++ src/main/java/org/apache/hadoop/hbase/master/ServersAndRegions.java @@ -0,0 +1,236 @@ +/** + * 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.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.NavigableMap; +import java.util.Set; +import java.util.TreeMap; +import java.util.TreeSet; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.hadoop.hbase.HRegionInfo; +import org.apache.hadoop.hbase.ServerName; +import org.apache.hadoop.hbase.util.Bytes; +import org.apache.hadoop.hbase.util.Pair; + +/** + * Data structure to hold map of regions to servers and then their reverse, of + * region to hosting server. + */ +class ServersAndRegions { + private static final Log LOG = LogFactory.getLog(ServersAndRegions.class); + + // The two below Maps need to be in sync. We'll ensure this by always getting + // lock on this.regions before doing changes. + /** + * Server to regions assignment map. + * Contains the set of regions currently assigned to a given server. + * This Map and {@link #regions} are tied. Always update this in tandem + * with the other under a lock on {@link #regions} + * @see #regions + */ + private final NavigableMap> servers = + new TreeMap>(); + + /** + * Region to server assignment map. + * Contains the server a given region is currently assigned to. + * This Map and {@link #servers} are tied. Always update this in tandem + * with the other under a lock on {@link #regions} + * @see #servers + */ + private final NavigableMap regions = + new TreeMap(); + + /** + * Compute the average load across all region servers. + * Currently, this uses a very naive computation - just uses the number of + * regions being served, ignoring stats about number of requests. + * @return the average load, the total number of regions divided by the + * total number of servers. + */ + double getAverageLoad() { + int totalLoad = 0; + int numServers = 0; + // Sync on this.regions because access to this.servers always synchronizes + // in this order. + synchronized (this.regions) { + for (Map.Entry> e: this.servers.entrySet()) { + numServers++; + totalLoad += e.getValue().size(); + } + } + return (double)totalLoad / (double)numServers; + } + + /** + * Returns the RegionServer to which hri is assigned. + * @param hri HRegion for which this function returns the region server + * @return HServerInfo The region server to which hri belongs + */ + ServerName getRegionServerOfRegion(HRegionInfo hri) { + synchronized (this.regions) { + return this.regions.get(hri); + } + } + + /** + * Run through all regions and return true if we find a non-meta region + * with an associated servername (its been assigned out on the cluster) or we + * find the region in the passed in nodes. + * @param nodes Passed in list of nodes, encoded region names + * @return True if we found non-meta regions with non-zero values (i.e. they + * have a servername) or if we found region in nodes (RIT) + */ + boolean isRegionsToProcess(final List nodes) { + boolean regionsToProcess = false; + for (Map.Entry e: this.regions.entrySet()) { + if (!e.getKey().isMetaTable() && e.getValue() != null) { + LOG.debug("Found " + e + " in regions (out on cluster)"); + regionsToProcess = true; + break; + } + if (nodes.contains(e.getKey().getEncodedName())) { + LOG.debug("Found " + e.getKey().getRegionNameAsString() + " in nodes (RIT)"); + // Could be a meta region. + regionsToProcess = true; + break; + } + } + return regionsToProcess; + } + + /** + * @param encodedRegionName Region encoded name. + * @return Null or a {@link Pair} instance that holds the full {@link HRegionInfo} + * and the hosting servers {@link ServerName}. + */ + Pair getAssignment(final byte [] encodedRegionName) { + String name = Bytes.toString(encodedRegionName); + synchronized(this.regions) { + for (Map.Entry e: this.regions.entrySet()) { + if (e.getKey().getEncodedName().equals(name)) { + return new Pair(e.getKey(), e.getValue()); + } + } + } + return null; + } + + /** + * @param plan Plan to add to regions + * @return Return ServerName from plan + */ + ServerName put(final RegionPlan plan) { + synchronized (this.regions) { + return this.regions.put(plan.getRegionInfo(), plan.getDestination()); + } + } + + /** + * @param hri Region to remove + * @return ServerName this region was on (or null if not set) + */ + ServerName remove(final HRegionInfo hri) { + synchronized (this.regions) { + ServerName sn = this.regions.remove(hri); + if (sn == null) return sn; + Set serverRegions = this.servers.get(sn); + if (!serverRegions.remove(hri)) LOG.warn("No " + hri + " on " + sn); + return sn; + } + } + + /** + * @param hri Wait on this region to show up in Set of regions. + * @throws InterruptedException + */ + void wait(final HRegionInfo hri) throws InterruptedException { + synchronized(this.regions) { + while (!this.regions.containsKey(hri)) { + // We should receive a notification, but it's + // better to have a timeout to recheck the condition here: + // it lowers the impact of a race condition if any + this.regions.wait(100); + } + } + } + + /** + * @param hri HRegionInfo to look up. + * @return Associated server or null + */ + ServerName get(final HRegionInfo hri) { + synchronized (this.regions) { + return regions.get(hri); + } + } + + boolean is(final HRegionInfo hri) { + synchronized (this.regions) { + return this.regions.containsKey(hri); + } + } + + /** + * Remove this server from map of servers to regions, and remove all regions + * of this regions. + * @param sn ServerName + * @return null if ServerName had no regions or Set of + * HRegionInfos found on this ServerName + */ + Set getRegionsOnServer(final ServerName sn) { + Set regions = null; + synchronized (this.regions) { + Set assignedRegions = this.servers.remove(sn); + if (assignedRegions == null || assignedRegions.isEmpty()) { + // No regions on this server, we are done. + return regions; + } + regions = new TreeSet(assignedRegions); + for (HRegionInfo region : regions) { + this.regions.remove(region); + } + } + return regions; + } + + /** + * Gets the online regions of the specified table. + * @param tableName + * @return Online regions from tableName + */ + List getOnlineRegionsOfTable(byte[] tableName) { + List tableRegions = new ArrayList(); + HRegionInfo boundary = new HRegionInfo(tableName, null, null); + synchronized (this.regions) { + for (HRegionInfo regionInfo: this.regions.tailMap(boundary).keySet()) { + if (Bytes.equals(regionInfo.getTableName(), tableName)) { + tableRegions.add(regionInfo); + } else { + break; + } + } + } + return tableRegions; + } +} \ No newline at end of file diff --git src/main/java/org/apache/hadoop/hbase/master/handler/DeleteTableHandler.java src/main/java/org/apache/hadoop/hbase/master/handler/DeleteTableHandler.java index 17dd2f9..b105481 100644 --- src/main/java/org/apache/hadoop/hbase/master/handler/DeleteTableHandler.java +++ src/main/java/org/apache/hadoop/hbase/master/handler/DeleteTableHandler.java @@ -30,6 +30,7 @@ import org.apache.hadoop.hbase.catalog.MetaEditor; import org.apache.hadoop.hbase.ipc.HMasterInterface; import org.apache.hadoop.hbase.master.AssignmentManager; import org.apache.hadoop.hbase.master.MasterServices; +import org.apache.hadoop.hbase.master.RegionState; import org.apache.hadoop.hbase.util.Bytes; import org.apache.hadoop.hbase.util.Threads; import org.apache.zookeeper.KeeperException; @@ -56,7 +57,7 @@ public class DeleteTableHandler extends TableEventHandler { for (HRegionInfo region : regions) { long done = System.currentTimeMillis() + waitTime; while (System.currentTimeMillis() < done) { - AssignmentManager.RegionState rs = am.isRegionInTransition(region); + RegionState rs = am.isRegionInTransition(region); if (rs == null) break; Threads.sleep(waitingTimeForEvents); LOG.debug("Waiting on region to clear regions in transition; " + rs); diff --git src/main/java/org/apache/hadoop/hbase/master/handler/OpenedRegionHandler.java src/main/java/org/apache/hadoop/hbase/master/handler/OpenedRegionHandler.java index f171a5a..c000652 100644 --- src/main/java/org/apache/hadoop/hbase/master/handler/OpenedRegionHandler.java +++ src/main/java/org/apache/hadoop/hbase/master/handler/OpenedRegionHandler.java @@ -27,7 +27,7 @@ import org.apache.hadoop.hbase.Server; import org.apache.hadoop.hbase.ServerName; import org.apache.hadoop.hbase.executor.EventHandler; import org.apache.hadoop.hbase.master.AssignmentManager; -import org.apache.hadoop.hbase.master.AssignmentManager.RegionState; +import org.apache.hadoop.hbase.master.RegionState; import org.apache.hadoop.hbase.zookeeper.ZKAssign; import org.apache.zookeeper.KeeperException; diff --git src/main/java/org/apache/hadoop/hbase/master/handler/ServerShutdownHandler.java src/main/java/org/apache/hadoop/hbase/master/handler/ServerShutdownHandler.java index 4307d89..6c490c2 100644 --- src/main/java/org/apache/hadoop/hbase/master/handler/ServerShutdownHandler.java +++ src/main/java/org/apache/hadoop/hbase/master/handler/ServerShutdownHandler.java @@ -36,9 +36,9 @@ import org.apache.hadoop.hbase.catalog.MetaReader; import org.apache.hadoop.hbase.client.Result; import org.apache.hadoop.hbase.executor.EventHandler; import org.apache.hadoop.hbase.master.AssignmentManager; -import org.apache.hadoop.hbase.master.AssignmentManager.RegionState; import org.apache.hadoop.hbase.master.DeadServer; import org.apache.hadoop.hbase.master.MasterServices; +import org.apache.hadoop.hbase.master.RegionState; import org.apache.hadoop.hbase.master.ServerManager; import org.apache.hadoop.hbase.util.Bytes; import org.apache.zookeeper.KeeperException; diff --git src/test/java/org/apache/hadoop/hbase/coprocessor/TestMasterObserver.java src/test/java/org/apache/hadoop/hbase/coprocessor/TestMasterObserver.java index b369c76..8c5e6fc 100644 --- src/test/java/org/apache/hadoop/hbase/coprocessor/TestMasterObserver.java +++ src/test/java/org/apache/hadoop/hbase/coprocessor/TestMasterObserver.java @@ -40,6 +40,7 @@ import org.apache.hadoop.hbase.client.HTable; import org.apache.hadoop.hbase.master.AssignmentManager; import org.apache.hadoop.hbase.master.HMaster; import org.apache.hadoop.hbase.master.MasterCoprocessorHost; +import org.apache.hadoop.hbase.master.RegionState; import org.apache.hadoop.hbase.regionserver.HRegionServer; import org.apache.hadoop.hbase.util.Bytes; import org.junit.AfterClass; @@ -695,9 +696,9 @@ public class TestMasterObserver { // wait for assignments to finish AssignmentManager mgr = master.getAssignmentManager(); - Collection transRegions = + Collection transRegions = mgr.getRegionsInTransition().values(); - for (AssignmentManager.RegionState state : transRegions) { + for (RegionState state : transRegions) { mgr.waitOnRegionToClearRegionsInTransition(state.getRegion()); } diff --git src/test/java/org/apache/hadoop/hbase/master/TestMasterFailover.java src/test/java/org/apache/hadoop/hbase/master/TestMasterFailover.java index bc98fb0..3210609 100644 --- src/test/java/org/apache/hadoop/hbase/master/TestMasterFailover.java +++ src/test/java/org/apache/hadoop/hbase/master/TestMasterFailover.java @@ -36,7 +36,6 @@ import org.apache.hadoop.fs.Path; import org.apache.hadoop.hbase.*; import org.apache.hadoop.hbase.executor.EventHandler.EventType; import org.apache.hadoop.hbase.executor.RegionTransitionData; -import org.apache.hadoop.hbase.master.AssignmentManager.RegionState; import org.apache.hadoop.hbase.regionserver.HRegion; import org.apache.hadoop.hbase.regionserver.HRegionServer; import org.apache.hadoop.hbase.util.Bytes; diff --git src/test/java/org/apache/hadoop/hbase/master/TestMasterStatusServlet.java src/test/java/org/apache/hadoop/hbase/master/TestMasterStatusServlet.java index 30ae515..3a01fd7 100644 --- src/test/java/org/apache/hadoop/hbase/master/TestMasterStatusServlet.java +++ src/test/java/org/apache/hadoop/hbase/master/TestMasterStatusServlet.java @@ -33,7 +33,6 @@ import java.util.regex.Pattern; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.hbase.*; import org.apache.hadoop.hbase.client.HBaseAdmin; -import org.apache.hadoop.hbase.master.AssignmentManager.RegionState; import org.apache.hadoop.hbase.master.HMaster; import org.apache.hadoop.hbase.master.ServerManager; import org.apache.hadoop.hbase.regionserver.HRegion; diff --git src/test/java/org/apache/hadoop/hbase/master/TestOpenedRegionHandler.java src/test/java/org/apache/hadoop/hbase/master/TestOpenedRegionHandler.java index 6633a20..dfb83c4 100644 --- src/test/java/org/apache/hadoop/hbase/master/TestOpenedRegionHandler.java +++ src/test/java/org/apache/hadoop/hbase/master/TestOpenedRegionHandler.java @@ -32,7 +32,6 @@ import org.apache.commons.logging.LogFactory; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.hbase.*; import org.apache.hadoop.hbase.executor.EventHandler.EventType; -import org.apache.hadoop.hbase.master.AssignmentManager.RegionState; import org.apache.hadoop.hbase.master.handler.OpenedRegionHandler; import org.apache.hadoop.hbase.regionserver.HRegion; import org.apache.hadoop.hbase.regionserver.HRegionServer;