hbase-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From mbau...@apache.org
Subject svn commit: r1301790 [2/2] - in /hbase/branches/0.89-fb/src: main/java/org/apache/hadoop/hbase/ main/java/org/apache/hadoop/hbase/client/ main/java/org/apache/hadoop/hbase/io/ main/java/org/apache/hadoop/hbase/ipc/ main/java/org/apache/hadoop/hbase/mas...
Date Fri, 16 Mar 2012 22:09:13 GMT
Copied: hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/master/RegionPlacement.java (from r1301789, hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/util/RegionPlacement.java)
URL: http://svn.apache.org/viewvc/hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/master/RegionPlacement.java?p2=hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/master/RegionPlacement.java&p1=hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/util/RegionPlacement.java&r1=1301789&r2=1301790&rev=1301790&view=diff
==============================================================================
--- hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/util/RegionPlacement.java (original)
+++ hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/master/RegionPlacement.java Fri Mar 16 22:09:11 2012
@@ -1,20 +1,21 @@
-package org.apache.hadoop.hbase.util;
+package org.apache.hadoop.hbase.master;
 
 import java.io.IOException;
+import java.net.InetSocketAddress;
 import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.Collection;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Random;
-import java.util.TreeMap;
+import java.util.concurrent.atomic.AtomicInteger;
 
 import org.apache.commons.cli.CommandLine;
 import org.apache.commons.cli.GnuParser;
 import org.apache.commons.cli.HelpFormatter;
 import org.apache.commons.cli.Options;
 import org.apache.commons.cli.ParseException;
+import org.apache.commons.lang.StringUtils;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.apache.hadoop.conf.Configuration;
@@ -23,16 +24,23 @@ import org.apache.hadoop.hbase.HConstant
 import org.apache.hadoop.hbase.HRegionInfo;
 import org.apache.hadoop.hbase.HServerAddress;
 import org.apache.hadoop.hbase.HServerInfo;
-import org.apache.hadoop.hbase.MasterNotRunningException;
 import org.apache.hadoop.hbase.client.HBaseAdmin;
+import org.apache.hadoop.hbase.client.HConnection;
 import org.apache.hadoop.hbase.client.HTable;
 import org.apache.hadoop.hbase.client.MetaScanner;
 import org.apache.hadoop.hbase.client.MetaScanner.MetaScannerVisitor;
 import org.apache.hadoop.hbase.client.Put;
 import org.apache.hadoop.hbase.client.Result;
-import org.apache.hadoop.hbase.master.RegionPlacementPolicy;
+import org.apache.hadoop.hbase.ipc.HRegionInterface;
+import org.apache.hadoop.hbase.master.AssignmentPlan.POSITION;
+import org.apache.hadoop.hbase.util.Bytes;
+import org.apache.hadoop.hbase.util.FSUtils;
+import org.apache.hadoop.hbase.util.MunkresAssignment;
+import org.apache.hadoop.hbase.util.Writables;
 import org.apache.hadoop.net.DNSToSwitchMapping;
 import org.apache.hadoop.net.IPv4AddressTruncationMapping;
+import org.apache.log4j.Level;
+import org.apache.log4j.Logger;
 
 public class RegionPlacement implements RegionPlacementPolicy{
   private static final Log LOG = LogFactory.getLog(RegionPlacement.class
@@ -59,15 +67,11 @@ public class RegionPlacement implements 
 
   private final boolean enforceLocality;
   private final boolean enforceMinAssignmentMove;
-  private Map<String, Map<String, Float>> regionLocalityMap;
+  private HBaseAdmin admin;
 
   public RegionPlacement(Configuration conf)
   throws IOException {
-    this.conf = conf;
-    this.switchMapping = new IPv4AddressTruncationMapping();
-    this.rackCache = new HashMap<HServerInfo, String>();
-    this.enforceLocality = true;
-    this.enforceMinAssignmentMove = true;
+    this(conf, true, true);
   }
 
   public RegionPlacement(Configuration conf, boolean enforceLocality,
@@ -80,6 +84,503 @@ public class RegionPlacement implements 
     this.enforceMinAssignmentMove = enforceMinAssignmentMove;
   }
 
+  @Override
+  public AssignmentPlan getAssignmentPlan(final HRegionInfo[] regions)
+  throws IOException{
+    Map<HRegionInfo, HServerAddress> currentAssignment =
+      this.getCurrentRegionToRSAssignment();
+    for (HRegionInfo newRegion : regions) {
+      // There is no currently hosting region server for new created regions.
+      currentAssignment.put(newRegion, null);
+    }
+    // Get the all online region servers
+    List<HServerInfo> servers =
+      new ArrayList<HServerInfo>(this.getHBaseAdmin().
+          getClusterStatus().getServerInfo());
+
+    return getAssignmentPlanForAllRegions(currentAssignment,
+        null, servers);
+  }
+
+  @Override
+  public AssignmentPlan getAssignmentPlan() throws IOException {
+    // Get the current assignment
+    Map<HRegionInfo, HServerAddress> currentAssignment =
+      this.getCurrentRegionToRSAssignment();
+    // Get the cached locality map
+    Map<String, Map<String, Float>> regionLocalityMap =
+      FSUtils.getRegionDegreeLocalityMappingFromFS(conf);
+    // Get the all online region servers
+    List<HServerInfo> servers =
+      new ArrayList<HServerInfo>(this.getHBaseAdmin()
+          .getClusterStatus().getServerInfo());
+
+    // Get the assignment plan for the new regions
+    return this.getAssignmentPlanForAllRegions(
+          currentAssignment, regionLocalityMap, servers);
+  }
+
+  @Override
+  public void updateAssignmentPlan(AssignmentPlan plan)
+  throws IOException {
+    // Update the new assignment plan to META
+    updateAssignmentPlanToMeta(plan);
+    // Update the new assignment plan to Region Servers
+    updateAssignmentPlanToRegionServers(plan);
+  }
+
+  /**
+   * Update the assignment plan into .META.
+   * @param plan the assignments plan to be updated into .META.
+   * @throws IOException if cannot update assignment plan in .META.
+   */
+  private void updateAssignmentPlanToMeta(AssignmentPlan plan)
+  throws IOException {
+    try {
+      LOG.info("Start to update the META with the new assignment plan");
+      List<Put> puts = new ArrayList<Put>();
+      Map<HRegionInfo, List<HServerAddress>> assignmentMap =
+        plan.getAssignmentMap();
+      for (Map.Entry<HRegionInfo, List<HServerAddress>> entry :
+        assignmentMap.entrySet()) {
+        String favoredNodes = RegionPlacement.getFavoredNodes(entry.getValue());
+        Put put = new Put(entry.getKey().getRegionName());
+        put.add(HConstants.CATALOG_FAMILY, HConstants.FAVOREDNODES_QUALIFIER,
+            favoredNodes.getBytes());
+        puts.add(put);
+      }
+
+      // Write the region assignments to the meta table.
+      HTable metaTable = new HTable(conf, HConstants.META_TABLE_NAME);
+      metaTable.put(puts);
+      LOG.info("Updated the META with the new assignment plan");
+    } catch (Exception e) {
+      LOG.error("Failed to update META with the new assignment" +
+          "plan because " + e.getMessage());
+    }
+  }
+
+  /**
+   * Update the assignment plan to all the region servers
+   * @param plan
+   * @throws IOException
+   */
+  private void updateAssignmentPlanToRegionServers(AssignmentPlan plan)
+  throws IOException{
+    LOG.info("Start to update the region servers with the new assignment plan");
+    // Get the current assignment
+    Map<HServerAddress, List<HRegionInfo>> currentAssignment =
+      this.getCurrentRSToRegionAssignment();
+    HConnection connection = this.getHBaseAdmin().getConnection();
+
+    // track of the failed and succeeded updates
+    int succeededNum = 0;
+    Map<HServerAddress, Exception> failedUpdateMap =
+      new HashMap<HServerAddress, Exception>();
+
+    for (Map.Entry<HServerAddress, List<HRegionInfo>> entry :
+      currentAssignment.entrySet()) {
+      try {
+        // Keep track of the favored updates for the current region server
+        AssignmentPlan singleServerPlan = new AssignmentPlan();
+
+        // Find out all the updates for the current region server
+        for (HRegionInfo region : entry.getValue()) {
+          List<HServerAddress> favoredServerList = plan.getAssignment(region);
+          singleServerPlan.updateAssignmentPlan(region, favoredServerList);
+        }
+
+        // Update the current region server with its updated favored nodes
+        HRegionInterface currentRegionServer =
+          connection.getHRegionConnection(entry.getKey());
+        int updatedRegionNum =
+          currentRegionServer.updateFavoredNodes(singleServerPlan);
+        LOG.info("Region server " +
+            currentRegionServer.getHServerInfo().getHostnamePort() +
+            " has updated " + updatedRegionNum + " / " +
+            singleServerPlan.getAssignmentMap().size() +
+            " regions with the assignment plan");
+        succeededNum ++;
+      } catch (Exception e) {
+        failedUpdateMap.put(entry.getKey(), e);
+      }
+    }
+    // log the succeeded updates
+    LOG.info("Updated " + succeededNum + " the region servers with " +
+			"the new assignment plan");
+
+    // log the failed updates
+    int failedNum = failedUpdateMap.size();
+    if (failedNum != 0) {
+      LOG.error("Failed to update the following + " + failedNum +
+          " region servers with its corresponding favored nodes");
+      for (Map.Entry<HServerAddress, Exception> entry :
+        failedUpdateMap.entrySet() ) {
+        LOG.error("Failed to update " + entry.getKey().getHostNameWithPort() +
+            " because of " + entry.getValue().getMessage());
+      }
+    }
+  }
+
+  /**
+   * Check whether regions are assigned to servers consistent with the explicit
+   * hints that are persisted in the META table.
+   * Also keep track of the number of the regions are assigned to the
+   * primary region server.
+   * @return the number of regions are assigned to the primary region server
+   * @throws IOException
+   */
+  public int getNumRegionisOnPrimaryRS() throws IOException {
+    final AtomicInteger regionOnPrimaryNum = new AtomicInteger(0);
+    final AtomicInteger totalRegionNum = new AtomicInteger(0);
+    LOG.info("The start of region placement verification");
+    MetaScannerVisitor visitor = new MetaScannerVisitor() {
+      public boolean processRow(Result result) throws IOException {
+        try {
+          byte[] regionInfo = result.getValue(HConstants.CATALOG_FAMILY,
+              HConstants.REGIONINFO_QUALIFIER);
+          byte[] server = result.getValue(HConstants.CATALOG_FAMILY,
+              HConstants.SERVER_QUALIFIER);
+          byte[] favoredNodes = result.getValue(HConstants.CATALOG_FAMILY,
+              "favorednodes".getBytes());
+          POSITION[] positions = AssignmentPlan.POSITION.values();
+          if (regionInfo != null) {
+            HRegionInfo info = Writables.getHRegionInfo(regionInfo);
+            totalRegionNum.incrementAndGet();
+            if (server != null) {
+              String serverString = new String(server);
+              if (favoredNodes != null) {
+                String[] splits = new String(favoredNodes).split(",");
+                String placement = "[NOT FAVORED NODE]";
+                for (int i = 0; i < splits.length; i++) {
+                  if (splits[i].equals(serverString)) {
+                    placement = positions[i].toString();
+                    if (i == AssignmentPlan.POSITION.PRIMARY.ordinal()) {
+                      regionOnPrimaryNum.incrementAndGet();
+                    }
+                    break;
+                  }
+                }
+                LOG.info(info.getRegionNameAsString() + " on " +
+                    serverString + " " + placement);
+              } else {
+                LOG.info(info.getRegionNameAsString() + " running on " +
+                    serverString + " but there is no favored region server");
+              }
+            } else {
+              LOG.info(info.getRegionNameAsString() +
+                  " not assigned to any server");
+            }
+          }
+          return true;
+        } catch (RuntimeException e) {
+          LOG.error("Result=" + result);
+          throw e;
+        }
+      }
+    };
+    MetaScanner.metaScan(conf, visitor);
+    LOG.info("There are " + regionOnPrimaryNum.intValue() + " out of " +
+        totalRegionNum.intValue() + " regions running on the primary" +
+			" region servers" );
+    return regionOnPrimaryNum.intValue() ;
+  }
+
+  public AssignmentPlan getAssignmentPlanFromMeta() throws IOException {
+    // Get the assignment Plan from scanning the META
+    LOG.info("Start to scan the META for the current assignment plan");
+    final AssignmentPlan plan = new AssignmentPlan();
+    MetaScannerVisitor visitor = new MetaScannerVisitor() {
+      public boolean processRow(Result result) throws IOException {
+        try {
+          byte[] regionInfo = result.getValue(HConstants.CATALOG_FAMILY,
+              HConstants.REGIONINFO_QUALIFIER);
+          byte[] favoredNodes = result.getValue(HConstants.CATALOG_FAMILY,
+              HConstants.FAVOREDNODES_QUALIFIER);
+          HRegionInfo info = Writables.getHRegionInfo(regionInfo);
+          if (info == null || favoredNodes == null)
+            return true;
+
+          List<HServerAddress> favoredServerList =
+            RegionPlacement.getFavoredNodesList(favoredNodes);
+          plan.updateAssignmentPlan(info, favoredServerList);
+          return true;
+        } catch (RuntimeException e) {
+          LOG.error("Catche remote exception " + e.getMessage() +
+              " when processing" + result);
+          throw e;
+        }
+      }
+    };
+    // Scan .META. to pick up user regions
+    MetaScanner.metaScan(conf, visitor);
+    LOG.info("Finished to scan the META for the current assignment plan");
+    return plan;
+  }
+
+  /**
+   * Verify the region placement is consistent with the assignment plan;
+   * @throws IOException
+   */
+  public void verifyRegionPlacement() throws IOException {
+    // TODO: need more dimensions to verify the region placement.
+    // Currently it checks whether each region is running the primary rs.
+    this.getNumRegionisOnPrimaryRS();
+  }
+  /**
+   * @param serverList
+   * @return string the favoredNodes generated by the server list.
+   */
+  public static String getFavoredNodes(List<HServerAddress> serverAddrList) {
+    String favoredNodes = "";
+    for (int i = 0 ; i < serverAddrList.size(); i++) {
+      favoredNodes += serverAddrList.get(i).getHostNameWithPort();
+      if (i != serverAddrList.size() - 1 ) {
+        favoredNodes += ",";
+      }
+    }
+    return favoredNodes;
+  }
+
+  /**
+   * @param favoredNodes The joint string of the favored nodes.
+   * @return The array of the InetSocketAddress
+   */
+  public static InetSocketAddress[] getFavoredInetSocketAddress(
+      String favoredNodes) {
+    String[] favoredNodesArray = StringUtils.split(favoredNodes, ",");
+    InetSocketAddress[] addresses =
+      new InetSocketAddress[favoredNodesArray.length];
+    for (int i = 0; i < favoredNodesArray.length; i++) {
+      HServerAddress serverAddress = new HServerAddress(favoredNodesArray[i]);
+      addresses[i] = serverAddress.getInetSocketAddress();
+    }
+    return addresses;
+  }
+
+  /**
+   * @param serverList
+   * @return The array of the InetSocketAddress
+   */
+  public static InetSocketAddress[] getFavoredInetSocketAddress(
+      List<HServerAddress> serverList) {
+    if (serverList == null || serverList.size() == 0)
+      return null;
+
+    InetSocketAddress[] addresses =
+      new InetSocketAddress[serverList.size()];
+    for (int i = 0; i < serverList.size(); i++) {
+      addresses[i] = serverList.get(i).getInetSocketAddress();
+    }
+    return addresses;
+  }
+
+  /**
+   * @param favoredNodes The bytes of favored nodes
+   * @return the list of HServerAddress for the byte array of favored nodes.
+   */
+  public static List<HServerAddress> getFavoredNodesList(byte[] favoredNodes) {
+    String favoredNodesStr = Bytes.toString(favoredNodes);
+    String[] favoredNodesArray = StringUtils.split(favoredNodesStr, ",");
+    if (favoredNodesArray == null)
+      return null;
+
+    List<HServerAddress> serverList = new ArrayList<HServerAddress>();
+    for (String hostNameAndPort : favoredNodesArray) {
+      serverList.add(new HServerAddress(hostNameAndPort));
+    }
+    return serverList;
+  }
+
+  /**
+   * @param favoredNodes The byte array of the favored nodes
+   * @return string the favoredNodes generated by the byte array of favored nodes.
+   */
+  public static String getFavoredNodes(byte[] favoredNodes) {
+    List<HServerAddress> serverList = getFavoredNodesList(favoredNodes);
+    String favoredNodesStr = getFavoredNodes(serverList);
+    return favoredNodesStr;
+  }
+
+  /**
+   * Print the assignment plan to the system output stream
+   * @param plan
+   */
+  public static void printAssignmentPlan(AssignmentPlan plan) {
+    if (plan == null) return;
+    LOG.info("Start to print the assignment plan:");
+    Map<HRegionInfo, List<HServerAddress>> assignmentMap =
+      plan.getAssignmentMap();
+
+    for (Map.Entry<HRegionInfo, List<HServerAddress>> entry :
+      assignmentMap.entrySet()) {
+      String serverList = RegionPlacement.getFavoredNodes(entry.getValue());
+      String regionName = entry.getKey().getRegionNameAsString();
+      LOG.info("Region: " + regionName + " Favored Nodes: " + serverList);
+    }
+    LOG.info("Finished to print the assignment plan");
+  }
+
+  public static void main(String[] args) throws IOException,
+      InterruptedException {
+    Options opt = new Options();
+    opt.addOption("w", "write", false,
+        "write assignments to META and update RegionServers");
+    opt.addOption("n", "dry-run", false, "do not write assignments to META");
+    opt.addOption("v", "verify", false, "verify current assignments against META");
+    opt.addOption("p", "print", false, "print the current assignment plan in META");
+    opt.addOption("h", "help", false, "print usage");
+    opt.addOption("l", "enforce-locality-assignment", true,
+        "enforce locality assignment");
+    opt.addOption("m", "enforce-min-assignment-move", true,
+        "enforce minium assignment move");
+
+    try {
+      Logger.getLogger("org.apache.zookeeper").setLevel(Level.ERROR);
+      Logger.getLogger("org.apache.hadoop.hbase").setLevel(Level.ERROR);
+      Logger.getLogger("org.apache.hadoop.hbase.master.RegionPlacement").
+        setLevel(Level.INFO);
+
+      CommandLine cmd = new GnuParser().parse(opt, args);
+      Configuration conf = HBaseConfiguration.create();
+      boolean enforceMinAssignmentMove = cmd.hasOption("m") ||
+        cmd.hasOption("enforce-min-assignment-move");
+      boolean enforceLocality = cmd.hasOption("l") ||
+        cmd.hasOption("enforce-locality-assignment");
+
+      RegionPlacement rp = new RegionPlacement(conf, enforceLocality,
+          enforceMinAssignmentMove);
+
+      if (cmd.hasOption("v") || cmd.hasOption("verify")) {
+        // Verify the region placement.
+        rp.verifyRegionPlacement();
+
+      } else if (cmd.hasOption("n") || cmd.hasOption("dry-run")) {
+        // Generate the assignment plan only without updating the META and RS
+        AssignmentPlan plan = rp.getAssignmentPlan();
+        RegionPlacement.printAssignmentPlan(plan);
+      } else if (cmd.hasOption("w") || cmd.hasOption("write")) {
+        // Generate the new assignment plan
+        AssignmentPlan plan = rp.getAssignmentPlan();
+        RegionPlacement.printAssignmentPlan(plan);
+        // Update the assignment to META and Region Servers
+        // TODO: The client may update any customized plan to META/RegionServers
+        rp.updateAssignmentPlan(plan);
+      } else if (cmd.hasOption("p") || cmd.hasOption("print")) {
+        AssignmentPlan plan = rp.getAssignmentPlanFromMeta();
+        RegionPlacement.printAssignmentPlan(plan);
+      } else {
+        printHelp(opt);
+      }
+    } catch (ParseException e) {
+      printHelp(opt);
+    }
+  }
+
+  private static void printHelp(Options opt) {
+    new HelpFormatter().printHelp(
+        "RegionPlacement < -w | -n | -v | -t | -h > [-l] | [-m]", opt);
+  }
+
+  private HBaseAdmin getHBaseAdmin() throws IOException {
+    if (this.admin == null) {
+      this.admin = new HBaseAdmin(this.conf);
+    }
+    return this.admin;
+  }
+  /**
+   * Get the Region to RegionServer assignment mapping from .META.
+   * @return map of the regions to region servers from .META.
+   * @throws IOException
+   */
+  private Map<HRegionInfo, HServerAddress> getCurrentRegionToRSAssignment()
+  throws IOException {
+    LOG.info("Start to scan the META for the current online regions to" +
+		"region servers assignment");
+    final Map<HRegionInfo, HServerAddress> regionsToRegionServers =
+        new HashMap<HRegionInfo, HServerAddress>();
+    MetaScannerVisitor visitor = new MetaScannerVisitor() {
+      public boolean processRow(Result result) throws IOException {
+        try {
+          byte[] regionInfo = result.getValue(HConstants.CATALOG_FAMILY,
+              HConstants.REGIONINFO_QUALIFIER);
+          byte[] server = result.getValue(HConstants.CATALOG_FAMILY,
+              HConstants.SERVER_QUALIFIER);
+          if (regionInfo != null) {
+            if (server != null) {
+              regionsToRegionServers.put(Writables.getHRegionInfo(regionInfo),
+                  new HServerAddress(Bytes.toString(server)));
+            } else {
+              regionsToRegionServers.put(Writables.getHRegionInfo(regionInfo),
+                  new HServerAddress());
+            }
+          }
+          return true;
+        } catch (RuntimeException e) {
+          LOG.error("Catche remote exception " + e.getMessage() +
+              " when processing" + result);
+          throw e;
+        }
+      }
+    };
+
+    // Scan .META. to pick up user regions
+    MetaScanner.metaScan(conf, visitor);
+    LOG.info("Finsished to scan the META for the current " +
+        regionsToRegionServers.size() + " online regions to" +
+    "region servers assignment");
+    return regionsToRegionServers;
+  }
+
+  /**
+   * Get the RegionServer to Region assignment mapping from .META.
+   * @return map of the region servers to regions from .META.
+   * @throws IOException
+   */
+  private Map<HServerAddress, List<HRegionInfo>> getCurrentRSToRegionAssignment()
+  throws IOException {
+    LOG.info("Start to scan the META for the current region servers to " +
+		"regions assignments");
+    final Map<HServerAddress, List<HRegionInfo>> regionServersToRegions =
+        new HashMap<HServerAddress, List<HRegionInfo>>();
+
+    MetaScannerVisitor visitor = new MetaScannerVisitor() {
+      public boolean processRow(Result result) throws IOException {
+        try {
+          byte[] regionInfo = result.getValue(HConstants.CATALOG_FAMILY,
+              HConstants.REGIONINFO_QUALIFIER);
+          byte[] server = result.getValue(HConstants.CATALOG_FAMILY,
+              HConstants.SERVER_QUALIFIER);
+          if (regionInfo != null && server != null) {
+            // Get the server address and region info
+            HServerAddress serverAddress =
+              new HServerAddress(Bytes.toString(server));
+            HRegionInfo info = Writables.getHRegionInfo(regionInfo);
+
+            // Update the regionServersToRegions mapping
+            List<HRegionInfo> regionInfoList =
+              regionServersToRegions.get(serverAddress);
+            if (regionInfoList == null) {
+              regionInfoList = new ArrayList<HRegionInfo>();
+              regionServersToRegions.put(serverAddress, regionInfoList);
+            }
+            regionInfoList.add(info);
+          }
+          return true;
+        } catch (RuntimeException e) {
+          LOG.error("Catche remote exception " + e.getMessage() +
+              " when processing" + result);
+          throw e;
+        }
+      }
+    };
+    // Scan .META. to pick up user regions
+    MetaScanner.metaScan(conf, visitor);
+    LOG.info("Finished to scan the META for the current " +
+      regionServersToRegions.size() + " region servers to regions assignments");
+    return regionServersToRegions;
+  }
+
   /**
    * Get the name of the rack containing a server, according to the DNS to
    * switch mapping.
@@ -102,59 +603,20 @@ public class RegionPlacement implements 
     return "";
   }
 
-  @Override
-  public Map<HRegionInfo, List<HServerInfo>> getFaroredNodesForAllRegions()
-      throws MasterNotRunningException, IOException, InterruptedException {
-    // Get all regions with the its currently hosting RS in the cluster.
-    Map<HRegionInfo, HServerAddress> regionToHostingRSMap = getMetaEntries();
-    // Get all servers in the cluster.
-    List<HServerInfo> servers = new ArrayList<HServerInfo>();
-    servers.addAll(new HBaseAdmin(conf).getClusterStatus().getServerInfo());
-
-    return getRegionToFavoredNodesMap(regionToHostingRSMap, servers);
-  }
-
-  @Override
-  public Map<HRegionInfo, List<HServerInfo>> getFaroredNodesForNewRegions(
-      final HRegionInfo[] newRegions, Collection<HServerInfo> serverInfo)
-      throws IOException {
-    List<HServerInfo> servers = new ArrayList<HServerInfo>();
-    servers.addAll(serverInfo);
-
-    // Get all regions with the its currently hosting RS in the cluster.
-    // TODO: This map is supposed to be cached and optimized by assignment manager.
-    Map<HRegionInfo, HServerAddress> regionToHostingRSMap = getMetaEntries();
-    for (HRegionInfo newRegion : newRegions) {
-      // There is no currently hosting region server for new created regions.
-      regionToHostingRSMap.put(newRegion, null);
-    }
-
-    return getRegionToFavoredNodesMap(regionToHostingRSMap, servers);
-  }
-
-  /**
-   * Get the region to its favorite nodes map.
-   *
-   * @param regionToHostingRSMap
-   *          The map is between the region and its currently hosting region
-   *          server.
-   * @param servers
-   *          The list of live region servers
-   * @return A map between each region to its favorite nodes.
-   * @throws MasterNotRunningException
-   * @throws IOException
-   * @throws InterruptedException
-   */
-  private synchronized Map<HRegionInfo, List<HServerInfo>> getRegionToFavoredNodesMap(
-      Map<HRegionInfo, HServerAddress> regionToHostingRSMap,
+  private AssignmentPlan getAssignmentPlanForAllRegions(
+      Map<HRegionInfo, HServerAddress> currentAssignmentMap,
+      Map<String, Map<String, Float>> regionLocalityMap,
       List<HServerInfo> servers)
-      throws MasterNotRunningException, IOException {
+      throws IOException {
     // Each server may serve multiple regions. Assume that each server has equal
     // capacity in terms of the number of regions that may be served.
     List<HRegionInfo> regions =
-      new ArrayList<HRegionInfo>(regionToHostingRSMap.keySet());
+      new ArrayList<HRegionInfo>(currentAssignmentMap.keySet());
     int numRegions = regions.size();
-    int slotsPerServer = (int)Math.ceil((float) numRegions / servers.size());
+    LOG.info("Start to generate assignment plan for the " + numRegions +
+        " regions and " + servers.size() + " region servers");
+    int slotsPerServer = (int) Math.ceil((float) numRegions /
+        servers.size());
     int regionSlots = slotsPerServer * servers.size();
 
     // Compute the primary, secondary and tertiary costs for each region/server
@@ -164,13 +626,7 @@ public class RegionPlacement implements 
     float[][] secondaryCost = new float[numRegions][regionSlots];
     float[][] tertiaryCost = new float[numRegions][regionSlots];
 
-    if (this.enforceLocality) {
-      // Get the locality for each region to each server.
-      if (this.regionLocalityMap == null) {
-        //TODO: This map will optimized and cached by assignment manager.
-        this.regionLocalityMap = FSUtils.getRegionDegreeLocalityMappingFromFS(conf);
-      }
-
+    if (this.enforceLocality && regionLocalityMap != null) {
       // Transform the locality mapping into a 2D array, assuming that any
       // unspecified locality value is 0.
       float[][] localityPerServer = new float[numRegions][regionSlots];
@@ -246,13 +702,13 @@ public class RegionPlacement implements 
       }
     }
 
-    if (this.enforceMinAssignmentMove) {
+    if (this.enforceMinAssignmentMove && currentAssignmentMap != null) {
       // We want to minimize the number of regions which move as the result of a
       // new assignment. Therefore, slightly penalize any placement which is for
       // a host that is not currently serving the region.
       for (int i = 0; i < numRegions; i++) {
         for (int j = 0; j < servers.size(); j++) {
-          HServerAddress currentAddress = regionToHostingRSMap.get(regions.get(i));
+          HServerAddress currentAddress = currentAssignmentMap.get(regions.get(i));
           if (currentAddress != null && !currentAddress.equals(
               servers.get(j).getServerAddress())) {
             for (int k = 0; k < slotsPerServer; k++) {
@@ -340,220 +796,22 @@ public class RegionPlacement implements 
     int[] tertiaryAssignment = new MunkresAssignment(tertiaryCost).solve();
     tertiaryAssignment = randomizedMatrix.invertIndices(tertiaryAssignment);
 
-    Map<HRegionInfo, List<HServerInfo>> assignments =
-        new TreeMap<HRegionInfo, List<HServerInfo>>();
+    AssignmentPlan plan = new AssignmentPlan();
     for (int i = 0; i < numRegions; i++) {
-      List<HServerInfo> assignment = new ArrayList<HServerInfo>(3);
-      assignment.add(servers.get(primaryAssignment[i] / slotsPerServer));
-      assignment.add(servers.get(secondaryAssignment[i] / slotsPerServer));
-      assignment.add(servers.get(tertiaryAssignment[i] / slotsPerServer));
-
-      assignments.put(regions.get(i), assignment);
-    }
-    return assignments;
-  }
-
-  /**
-   * Check that the assignment map has the expected number of assignments for
-   * each region, and that none of the assignments are duplicates.
-   * @param map the assignments to verify
-   */
-  private void verifyAssignments(Map<HRegionInfo, List<HServerInfo>> map) {
-    for (Map.Entry<HRegionInfo, List<HServerInfo>> entry : map.entrySet()) {
-      List<HServerInfo> servers = entry.getValue();
-      if (servers.size() != 3) {
-        throw new IllegalStateException("Not enough assignments for region "
-            + entry.getKey().getRegionNameAsString());
-      }
-      for (int i = 0; i < servers.size() - 1; i++) {
-        HServerInfo first = servers.get(i);
-        for (int j = i + 1; j < servers.size(); j++) {
-          if (first.equals(servers.get(j))) {
-            throw new IllegalStateException("Region " +
-                entry.getKey().getRegionNameAsString() + " was assigned to " +
-                first.getServerName() + " more than once");
-          }
-        }
-      }
-    }
-  }
-
-  /**
-   * Persist the map of assignment hints into .META.
-   * @param map the assignments to be put into .META.
-   * @throws IOException if cannot put assignment hint in .META.
-   */
-  public void putFavoredNodes(Map<HRegionInfo, List<HServerInfo>> map)
-      throws IOException {
-    List<Put> puts = new ArrayList<Put>();
-    for (Map.Entry<HRegionInfo, List<HServerInfo>> entry : map.entrySet()) {
-      String favoredNodes = "";
-      for (HServerInfo info : entry.getValue()) {
-        favoredNodes += info.getHostnamePort() + ",";
-      }
-      favoredNodes = favoredNodes.substring(0, favoredNodes.length() - 1);
-
-      Put put = new Put(entry.getKey().getRegionName());
-      put.add(HConstants.CATALOG_FAMILY, HConstants.FAVOREDNODES_QUALIFIER,
-          System.currentTimeMillis(), favoredNodes.getBytes());
-      puts.add(put);
-
-      LOG.debug("Favored nodes region: " + put.toString() + " are " +
-          favoredNodes);
-    }
-
-    // Write the region assignments to the meta table.
-    HTable metaTable = new HTable(conf, HConstants.META_TABLE_NAME);
-    metaTable.put(puts);
-  }
-
-  /**
-   * Get a list of regions from .META., not including .META. itself, mapped to
-   * the host currently serving that region. If there is no host serving that
-   * region, an empty (not null) server address will be the value of the entry.
-   * @return map of regions to servers from .META.
-   * @throws IOException
-   */
-  private Map<HRegionInfo, HServerAddress> getMetaEntries() throws IOException {
-    final Map<HRegionInfo, HServerAddress> regions =
-        new TreeMap<HRegionInfo, HServerAddress>();
-
-    MetaScannerVisitor visitor = new MetaScannerVisitor() {
-      public boolean processRow(Result result) throws IOException {
-        try {
-          byte[] regionInfo = result.getValue(HConstants.CATALOG_FAMILY,
-              HConstants.REGIONINFO_QUALIFIER);
-          byte[] server = result.getValue(HConstants.CATALOG_FAMILY,
-              HConstants.SERVER_QUALIFIER);
-          if (regionInfo != null) {
-            if (server != null) {
-              regions.put(Writables.getHRegionInfo(regionInfo),
-                  new HServerAddress(new String(server)));
-            } else {
-              regions.put(Writables.getHRegionInfo(regionInfo),
-                  new HServerAddress());
-            }
-          }
-          return true;
-        } catch (RuntimeException e) {
-          LOG.error("Result=" + result);
-          throw e;
-        }
-      }
-    };
-
-    // Scan .META. to pick up user regions
-    MetaScanner.metaScan(conf, visitor);
-
-    return regions;
-  }
-
-  /**
-   * Check whether regions are assigned to servers consistent with the explicit
-   * hints that are persisted in the META table, if any, printing results to
-   * standard out.
-   * @throws IOException
-   */
-  private void verifyPlacement() throws IOException {
-    MetaScannerVisitor visitor = new MetaScannerVisitor() {
-      private String[] PLACEMENTS = {"[Primary]", "[Secondary]", "[Tertiary]"};
-      public boolean processRow(Result result) throws IOException {
-        try {
-          byte[] regionInfo = result.getValue(HConstants.CATALOG_FAMILY,
-              HConstants.REGIONINFO_QUALIFIER);
-          byte[] server = result.getValue(HConstants.CATALOG_FAMILY,
-              HConstants.SERVER_QUALIFIER);
-          byte[] favoredNodes = result.getValue(HConstants.CATALOG_FAMILY,
-              "favorednodes".getBytes());
-          if (regionInfo != null) {
-            HRegionInfo info = Writables.getHRegionInfo(regionInfo);
-            if (server != null) {
-              String serverString = new String(server);
-              if (favoredNodes != null) {
-                String[] splits = new String(favoredNodes).split(",");
-                String placement = "not a favored node <<<<<<<<<<";
-                for (int i = 0; i < splits.length; i++) {
-                  if (splits[i].equals(serverString)) {
-                    placement = PLACEMENTS[i];
-                  }
-                }
-                System.out.println(info.getRegionNameAsString() + " on " +
-                    serverString + " " + placement);
-              } else {
-                System.out.println(info.getRegionNameAsString() + " on " +
-                    serverString + " no favored nodes");
-              }
-            } else {
-              System.out.println(info.getRegionNameAsString() +
-                  " not assigned to a server");
-            }
-          }
-          return true;
-        } catch (RuntimeException e) {
-          LOG.error("Result=" + result);
-          throw e;
-        }
-      }
-    };
-
-    // Scan .META. to pick up user regions
-    MetaScanner.metaScan(conf, visitor);
-  }
-
-  private static void printHelp(Options opt) {
-    new HelpFormatter().printHelp(
-        "RegionPlacement < -w | -n | -v | -t | -h > [-r]", opt);
-  }
-
-  public static void main(String[] args) throws IOException,
-      InterruptedException {
-    Options opt = new Options();
-    opt.addOption("w", "write", false, "write assignments to META");
-    opt.addOption("n", "dry-run", false, "do not write assignments to META");
-    opt.addOption("v", "verify", false, "check current placement against META");
-    opt.addOption("t", "test", false, "test RandomizedMatrix");
-    opt.addOption("h", "help", false, "print usage");
-    opt.addOption("l", "enforce-locality-assignment", true,
-        "enforce locality assignment");
-    opt.addOption("m", "enforce-min-assignment-move", true,
-        "enforce minium assignment move");
-
-    try {
-      CommandLine cmd = new GnuParser().parse(opt, args);
-      boolean enforceLocalityAssignment = cmd.hasOption("l") ||
-        cmd.hasOption("enforce-locality-assignment");
-      boolean enforceMinAssignmentMove = cmd.hasOption("m") ||
-        cmd.hasOption("enforce-min-assignment-move");
-      if (cmd.hasOption("h") || cmd.hasOption("help")) {
-        printHelp(opt);
-      } else if (cmd.hasOption("t") || cmd.hasOption("test")) {
-        RandomizedMatrix.test();
-      } else if (cmd.hasOption("v") || cmd.hasOption("verify")) {
-        Configuration conf = HBaseConfiguration.create();
-        RegionPlacement rp = new RegionPlacement(conf,
-            enforceLocalityAssignment, enforceMinAssignmentMove);
-        rp.verifyPlacement();
-      } else if (cmd.hasOption("n") || cmd.hasOption("dry-run")) {
-        Configuration conf = HBaseConfiguration.create();
-        RegionPlacement rp = new RegionPlacement(conf,
-            enforceLocalityAssignment, enforceMinAssignmentMove);
-        Map<HRegionInfo, List<HServerInfo>> assignments =
-          rp.getFaroredNodesForAllRegions();
-        rp.verifyAssignments(assignments);
-      } else if (cmd.hasOption("w") || cmd.hasOption("write")) {
-        Configuration conf = HBaseConfiguration.create();
-        RegionPlacement rp = new RegionPlacement(conf,
-            enforceLocalityAssignment, enforceMinAssignmentMove);
-        Map<HRegionInfo, List<HServerInfo>> assignments =
-          rp.getFaroredNodesForAllRegions();
-        rp.verifyAssignments(assignments);
-        rp.putFavoredNodes(assignments);
-      } else {
-        printHelp(opt);
-      }
-    } catch (ParseException e) {
-      printHelp(opt);
-    }
+      List<HServerAddress> favoredServers =
+        new ArrayList<HServerAddress>(HConstants.FAVORED_NODES_NUM);
+      favoredServers.add(servers.get(primaryAssignment[i] / slotsPerServer).
+          getServerAddress());
+      favoredServers.add(servers.get(secondaryAssignment[i] / slotsPerServer).
+          getServerAddress());
+      favoredServers.add(servers.get(tertiaryAssignment[i] / slotsPerServer).
+          getServerAddress());
+
+      plan.updateAssignmentPlan(regions.get(i), favoredServers);
+    }
+    LOG.info("Generated assignment plan for the " + numRegions +
+        " regions and " + servers.size() + " region servers");
+    return plan;
   }
 
   /**
@@ -569,7 +827,7 @@ public class RegionPlacement implements 
    * and each row has its elements transformed in the same way. Similarly for
    * columns.
    */
-  private static class RandomizedMatrix {
+  protected static class RandomizedMatrix {
     private final int rows;
     private final int cols;
     private final int[] rowTransform;
@@ -669,54 +927,5 @@ public class RegionPlacement implements 
       }
       return result;
     }
-
-    /**
-     * Used to test the correctness of this class.
-     * TODO Move this to a unit test?
-     */
-    public static void test() {
-      int rows = 100;
-      int cols = 100;
-      float[][] matrix = new float[rows][cols];
-      Random random = new Random();
-      for (int i = 0; i < rows; i++) {
-        for (int j = 0; j < cols; j++) {
-          matrix[i][j] = random.nextFloat();
-        }
-      }
-
-      // Test that inverting a transformed matrix gives the original matrix.
-      RandomizedMatrix rm = new RandomizedMatrix(rows, cols);
-      float[][] transformed = rm.transform(matrix);
-      float[][] invertedTransformed = rm.invert(transformed);
-      for (int i = 0; i < rows; i++) {
-        for (int j = 0; j < cols; j++) {
-          if (matrix[i][j] != invertedTransformed[i][j]) {
-            throw new RuntimeException();
-          }
-        }
-      }
-
-      // Test that the indices on a transformed matrix can be inverted to give
-      // the same values on the original matrix.
-      int[] transformedIndices = new int[rows];
-      for (int i = 0; i < rows; i++) {
-        transformedIndices[i] = random.nextInt(cols);
-      }
-      int[] invertedTransformedIndices = rm.invertIndices(transformedIndices);
-      float[] transformedValues = new float[rows];
-      float[] invertedTransformedValues = new float[rows];
-      for (int i = 0; i < rows; i++) {
-        transformedValues[i] = transformed[i][transformedIndices[i]];
-        invertedTransformedValues[i] = matrix[i][invertedTransformedIndices[i]];
-      }
-      Arrays.sort(transformedValues);
-      Arrays.sort(invertedTransformedValues);
-      if (!Arrays.equals(transformedValues, invertedTransformedValues)) {
-        throw new RuntimeException();
-      }
-
-      System.out.println("Test passed");
-    }
   }
 }

Modified: hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/master/RegionPlacementPolicy.java
URL: http://svn.apache.org/viewvc/hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/master/RegionPlacementPolicy.java?rev=1301790&r1=1301789&r2=1301790&view=diff
==============================================================================
--- hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/master/RegionPlacementPolicy.java (original)
+++ hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/master/RegionPlacementPolicy.java Fri Mar 16 22:09:11 2012
@@ -1,20 +1,33 @@
 package org.apache.hadoop.hbase.master;
 
 import java.io.IOException;
-import java.util.Collection;
-import java.util.List;
-import java.util.Map;
 
 import org.apache.hadoop.hbase.HRegionInfo;
-import org.apache.hadoop.hbase.HServerInfo;
-import org.apache.hadoop.hbase.MasterNotRunningException;
 
 public interface RegionPlacementPolicy {
 
-  public Map<HRegionInfo, List<HServerInfo>> getFaroredNodesForNewRegions(
-      final HRegionInfo[] newRegions, Collection<HServerInfo> serverInfo)
-      throws IOException;
+/**
+ * Get the assignment plan for the new regions
+ * @param regions
+ * @return the favored assignment plan for the regions
+ * @throws IOException
+ */
+  public AssignmentPlan getAssignmentPlan(final HRegionInfo[] regions)
+  throws IOException;
 
-  public Map<HRegionInfo, List<HServerInfo>> getFaroredNodesForAllRegions()
-      throws MasterNotRunningException, IOException, InterruptedException;
+  /**
+   * Get the favored assignment plan for all the regions
+   * @return the favored assignment plan for all the regions
+   * @throws IOException
+   */
+  public AssignmentPlan getAssignmentPlan()
+  throws IOException;
+
+  /**
+   * Update the favored assignment plan
+   * @param plan
+   * @throws IOException
+   */
+  public void updateAssignmentPlan(AssignmentPlan plan)
+  throws IOException;
 }

Modified: hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/master/ServerManager.java
URL: http://svn.apache.org/viewvc/hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/master/ServerManager.java?rev=1301790&r1=1301789&r2=1301790&view=diff
==============================================================================
--- hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/master/ServerManager.java (original)
+++ hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/master/ServerManager.java Fri Mar 16 22:09:11 2012
@@ -701,6 +701,8 @@ public class ServerManager {
           this.master.getServerConnection().setRootRegionLocation(
             new HRegionLocation(region, rootServer));
           this.master.getRegionManager().setRootRegionLocation(rootServer);
+          // Increase the region opened counter
+          this.master.getMetrics().incRegionsOpened();
         } else {
           // Note that the table has been assigned and is waiting for the
           // meta table to be updated.
@@ -1038,7 +1040,7 @@ public class ServerManager {
     }
   }
 
-  public boolean canAssignUserRegions() {
+  public boolean hasEnoughRegionServers() {
     if (minimumServerCount == 0) {
       return true;
     }

Modified: hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/master/ThrottledRegionReopener.java
URL: http://svn.apache.org/viewvc/hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/master/ThrottledRegionReopener.java?rev=1301790&r1=1301789&r2=1301790&view=diff
==============================================================================
--- hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/master/ThrottledRegionReopener.java (original)
+++ hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/master/ThrottledRegionReopener.java Fri Mar 16 22:09:11 2012
@@ -192,7 +192,7 @@ public class ThrottledRegionReopener {
   public synchronized void addPreferredAssignmentForReopen(HRegionInfo region,
       HServerInfo serverInfo) {
     if (regionsBeingReopened.contains(region)) {
-      regionManager.assignmentManager.addTransientAssignment(
+      regionManager.getAssignmentManager().addTransientAssignment(
           serverInfo.getServerAddress(), region);
     }
   }

Modified: hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/master/metrics/MasterMetrics.java
URL: http://svn.apache.org/viewvc/hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/master/metrics/MasterMetrics.java?rev=1301790&r1=1301789&r2=1301790&view=diff
==============================================================================
--- hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/master/metrics/MasterMetrics.java (original)
+++ hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/master/metrics/MasterMetrics.java Fri Mar 16 22:09:11 2012
@@ -18,12 +18,12 @@
 package org.apache.hadoop.hbase.master.metrics;
 
 import java.io.IOException;
+
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.apache.hadoop.hbase.master.ServerManager;
 import org.apache.hadoop.hbase.metrics.HBaseInfo;
 import org.apache.hadoop.hbase.metrics.MetricsRate;
-import org.apache.hadoop.hbase.metrics.PersistentMetricsTimeVaryingRate;
 import org.apache.hadoop.metrics.ContextFactory;
 import org.apache.hadoop.metrics.MetricsContext;
 import org.apache.hadoop.metrics.MetricsRecord;
@@ -186,8 +186,16 @@ public class MasterMetrics implements Up
 	  numRegionsOpened.set(numRegionsOpened.get() + 1);
   }
 
+  public synchronized int getRegionsOpened() {
+    return numRegionsOpened.get();
+  }
+
   public synchronized void incRegionServerExpired() {
 	  numRSExpired.set(numRSExpired.get() + 1);
   }
 
+  public synchronized int getRegionServerExpired() {
+    return numRSExpired.get();
+  }
+
 }

Modified: hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/regionserver/HRegion.java
URL: http://svn.apache.org/viewvc/hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/regionserver/HRegion.java?rev=1301790&r1=1301789&r2=1301790&view=diff
==============================================================================
--- hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/regionserver/HRegion.java (original)
+++ hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/regionserver/HRegion.java Fri Mar 16 22:09:11 2012
@@ -1662,11 +1662,7 @@ public class HRegion implements HeapSize
    * @param favoredNodes the favored nodes, or null
    */
   public void setFavoredNodes(InetSocketAddress[] favoredNodes) {
-    if (favoredNodes == null) {
-      this.favoredNodes = null;
-      return;
-    }
-    this.favoredNodes = Arrays.copyOf(favoredNodes, favoredNodes.length);
+    this.favoredNodes = favoredNodes;
   }
 
   /**

Modified: hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/regionserver/HRegionServer.java
URL: http://svn.apache.org/viewvc/hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/regionserver/HRegionServer.java?rev=1301790&r1=1301789&r2=1301790&view=diff
==============================================================================
--- hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/regionserver/HRegionServer.java (original)
+++ hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/regionserver/HRegionServer.java Fri Mar 16 22:09:11 2012
@@ -105,6 +105,8 @@ import org.apache.hadoop.hbase.ipc.HBase
 import org.apache.hadoop.hbase.ipc.HBaseServer;
 import org.apache.hadoop.hbase.ipc.HMasterRegionInterface;
 import org.apache.hadoop.hbase.ipc.HRegionInterface;
+import org.apache.hadoop.hbase.master.AssignmentPlan;
+import org.apache.hadoop.hbase.master.RegionPlacement;
 import org.apache.hadoop.hbase.regionserver.metrics.RegionServerDynamicMetrics;
 import org.apache.hadoop.hbase.regionserver.metrics.RegionServerMetrics;
 import org.apache.hadoop.hbase.regionserver.metrics.SchemaMetrics;
@@ -1575,7 +1577,7 @@ public class HRegionServer implements HR
                 }
               }
               if (e.msg.getMessage() != null && e.msg.getMessage().length > 0) {
-                openRegion(info, new String(e.msg.getMessage()).split(","));
+                openRegion(info, new String(e.msg.getMessage()));
               } else {
                 openRegion(info, null);
               }
@@ -1678,7 +1680,7 @@ public class HRegionServer implements HR
     }
   }
 
-  void openRegion(final HRegionInfo regionInfo, String[] favoredNodes) {
+  void openRegion(final HRegionInfo regionInfo, String favoredNodes) {
     Integer mapKey = Bytes.mapKey(regionInfo.getRegionName());
     HRegion region = this.onlineRegions.get(mapKey);
     RSZookeeperUpdater zkUpdater = new RSZookeeperUpdater(
@@ -1738,20 +1740,13 @@ public class HRegionServer implements HR
     }
   }
 
-  private void setFavoredNodes(HRegion region, String[] favoredNodes) {
-    if (favoredNodes != null && favoredNodes.length > 0) {
-      InetSocketAddress[] nodes = new InetSocketAddress[favoredNodes.length];
-      StringBuilder favoratedNodesList = new StringBuilder();
-      for (int i = 0; i < favoredNodes.length; i++) {
-        int colon = favoredNodes[i].indexOf(':');
-        String hostname = colon >= 0 ? favoredNodes[i].substring(0, colon) :
-          favoredNodes[i];
-        favoratedNodesList.append(hostname + ",");
-        nodes[i] = new InetSocketAddress(hostname, 0);
-      }
+  private void setFavoredNodes(HRegion region, String favoredNodes) {
+    if (favoredNodes != null && favoredNodes.length() > 0) {
+      InetSocketAddress[] nodes =
+        RegionPlacement.getFavoredInetSocketAddress(favoredNodes);
       region.setFavoredNodes(nodes);
       LOG.debug("Set the region " + region.getRegionNameAsString() +
-          " with the favored nodes: " + favoratedNodesList);
+          " with the favored nodes: " + favoredNodes);
     }
   }
 
@@ -2985,6 +2980,40 @@ public class HRegionServer implements HR
         this, protocol, clientVersion, clientMethodsHash);
   }
 
+  @Override
+  public int updateFavoredNodes(AssignmentPlan plan)
+  throws IOException {
+    if (plan == null) {
+      LOG.debug("The assignment plan is empty");
+      return 0;
+    }
+    int counter = 0;
+    for (Map.Entry<HRegionInfo, List<HServerAddress>> entry :
+      plan.getAssignmentMap().entrySet()) {
+        // Get the online region
+      HRegion region =
+        this.onlineRegions.get(Bytes.mapKey(entry.getKey().getRegionName()));
+
+      if (region == null) {
+        LOG.warn("Region " + entry.getKey().getRegionNameAsString() +
+            " is not running on this" + this.serverInfo.getHostnamePort()
+            + " region server any more !");
+        continue;
+      }
+      List<HServerAddress> serverList = entry.getValue();
+      if (serverList != null) {
+        String favoredNodes = RegionPlacement.getFavoredNodes(serverList);
+        InetSocketAddress[] favoredAddress =
+          RegionPlacement.getFavoredInetSocketAddress(serverList);
+        // Set the favored nodes
+        region.setFavoredNodes(favoredAddress);
+        LOG.debug("Update region " + region.getRegionNameAsString() +
+            " with new favored nodes: " + favoredNodes);
+        counter++;
+      }
+    }
+    return counter;
+  }
   /**
    * @param args
    */

Modified: hbase/branches/0.89-fb/src/test/java/org/apache/hadoop/hbase/client/TestAdmin.java
URL: http://svn.apache.org/viewvc/hbase/branches/0.89-fb/src/test/java/org/apache/hadoop/hbase/client/TestAdmin.java?rev=1301790&r1=1301789&r2=1301790&view=diff
==============================================================================
--- hbase/branches/0.89-fb/src/test/java/org/apache/hadoop/hbase/client/TestAdmin.java (original)
+++ hbase/branches/0.89-fb/src/test/java/org/apache/hadoop/hbase/client/TestAdmin.java Fri Mar 16 22:09:11 2012
@@ -25,12 +25,9 @@ import static org.junit.Assert.assertFal
 import static org.junit.Assert.assertTrue;
 
 import java.io.IOException;
-import java.util.Collection;
-import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
-import java.util.Set;
 import java.util.concurrent.atomic.AtomicInteger;
 
 import org.apache.commons.logging.Log;
@@ -47,7 +44,6 @@ import org.apache.hadoop.hbase.TableNotF
 import org.apache.hadoop.hbase.master.HMaster;
 import org.apache.hadoop.hbase.util.Bytes;
 import org.apache.hadoop.hbase.util.Pair;
-import org.apache.hadoop.hbase.util.Writables;
 import org.junit.AfterClass;
 import org.junit.Before;
 import org.junit.BeforeClass;
@@ -63,7 +59,7 @@ public class TestAdmin {
   final Log LOG = LogFactory.getLog(getClass());
   private final static HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
   private HBaseAdmin admin;
-  private static final int NUM_REGION_SERVER = 4;
+  private static final int NUM_REGION_SERVER = 3;
   @BeforeClass
   public static void setUpBeforeClass() throws Exception {
     TEST_UTIL.getConfiguration().setInt("hbase.regionserver.msginterval", 100);
@@ -105,63 +101,6 @@ public class TestAdmin {
     assertTrue(metaRegions.size() != 0);
   }
 
-  @Test
-  public void testCreateTableWithFavoriteNodes() throws IOException, InterruptedException {
-    Set<HServerAddress> set = new HashSet<HServerAddress>();
-    final int REGION_NUM = 1 ;
-    set.addAll(getRegionServerSetForNewCreatedTable("test1", REGION_NUM));
-    assertEquals(REGION_NUM, set.size());
-
-    set.addAll(getRegionServerSetForNewCreatedTable("test2", REGION_NUM));
-    assertEquals(REGION_NUM * 2, set.size());
-
-    set.addAll(getRegionServerSetForNewCreatedTable("test3", 100));
-    assertEquals(NUM_REGION_SERVER, set.size());
-  }
-
-  private Collection<HServerAddress> getRegionServerSetForNewCreatedTable(
-      String table, int regionNum) throws IOException {
-    byte[] tableName = Bytes.toBytes(table);
-    int expectedRegions = regionNum;
-    byte[][] splitKeys = new byte[expectedRegions - 1][];
-    for (int i = 1; i < expectedRegions; i++) {
-      byte splitKey = (byte) i;
-      splitKeys[i - 1] = new byte[] { splitKey, splitKey, splitKey };
-    }
-
-    HTableDescriptor desc = new HTableDescriptor(tableName);
-    desc.addFamily(new HColumnDescriptor(HConstants.CATALOG_FAMILY));
-    admin.createTable(desc, splitKeys);
-
-    HTable ht = new HTable(TEST_UTIL.getConfiguration(), tableName);
-    Map<HRegionInfo, HServerAddress> regions = ht.getRegionsInfo();
-    assertEquals("Tried to create " + expectedRegions + " regions "
-        + "but only found " + regions.size(), expectedRegions, regions.size());
-
-    // scan the meta table to verify the favorite nodes has been added.
-    int favoriteNodeNum = 0;
-    HTable metaTable = new HTable(TEST_UTIL.getConfiguration(),
-        HConstants.META_TABLE_NAME);
-    ResultScanner s = metaTable.getScanner(new Scan());
-    for (Result result : s) {
-      HRegionInfo info = Writables.getHRegionInfo(result.getValue(
-          HConstants.CATALOG_FAMILY, HConstants.REGIONINFO_QUALIFIER));
-      if (Bytes.compareTo(info.getTableDesc().getName(), tableName) == 0) {
-        byte[] favoriteNodes = result.getValue(HConstants.CATALOG_FAMILY,
-            HConstants.FAVOREDNODES_QUALIFIER);
-        if (favoriteNodes != null && favoriteNodes.length != 0) {
-          LOG.info("Region: " + info.getEncodedName() + " Favorite Nodes: "
-              + Bytes.toString(favoriteNodes));
-          favoriteNodeNum++;
-        }
-      }
-    }
-    s.close();
-    assertEquals("Tried to add " + expectedRegions
-        + " favorite nodes int meta " + "but only found " + favoriteNodeNum,
-        expectedRegions, favoriteNodeNum);
-    return regions.values();
-  }
 
   @Test
   public void testCreateTableWithRegions() throws IOException {

Added: hbase/branches/0.89-fb/src/test/java/org/apache/hadoop/hbase/master/TestRegionPlacement.java
URL: http://svn.apache.org/viewvc/hbase/branches/0.89-fb/src/test/java/org/apache/hadoop/hbase/master/TestRegionPlacement.java?rev=1301790&view=auto
==============================================================================
--- hbase/branches/0.89-fb/src/test/java/org/apache/hadoop/hbase/master/TestRegionPlacement.java (added)
+++ hbase/branches/0.89-fb/src/test/java/org/apache/hadoop/hbase/master/TestRegionPlacement.java Fri Mar 16 22:09:11 2012
@@ -0,0 +1,485 @@
+/**
+ * Copyright 2009 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 static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.Random;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.hbase.HBaseTestingUtility;
+import org.apache.hadoop.hbase.HColumnDescriptor;
+import org.apache.hadoop.hbase.HConstants;
+import org.apache.hadoop.hbase.HRegionInfo;
+import org.apache.hadoop.hbase.HServerAddress;
+import org.apache.hadoop.hbase.HTableDescriptor;
+import org.apache.hadoop.hbase.MiniHBaseCluster;
+import org.apache.hadoop.hbase.client.HBaseAdmin;
+import org.apache.hadoop.hbase.client.HTable;
+import org.apache.hadoop.hbase.master.AssignmentPlan.POSITION;
+import org.apache.hadoop.hbase.master.RegionManager.AssignmentLoadBalancer;
+import org.apache.hadoop.hbase.master.RegionManager.LoadBalancer;
+import org.apache.hadoop.hbase.regionserver.HRegion;
+import org.apache.hadoop.hbase.regionserver.HRegionServer;
+import org.apache.hadoop.hbase.util.Bytes;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class TestRegionPlacement {
+  final static Log LOG = LogFactory.getLog(TestRegionPlacement.class);
+  private final static HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
+  private final static int SLAVES = 4;
+  private final static int META_REGION_NUM = 2; // META and ROOT
+  private final static int META_REGION_OVERHEAD = 1;
+  private final static int ROOT_REGION_OVERHEAD = 1;
+  private static HBaseAdmin admin;
+  private static RegionPlacement rp;
+  private static POSITION[] positions = AssignmentPlan.POSITION.values();
+  private int lastRegionOpenedCount = 0;
+  private int lastRegionOnPrimaryRSCount = 0;
+  private int REGION_NUM = 10;
+
+  @BeforeClass
+  public static void setupBeforeClass() throws Exception {
+    Configuration conf = TEST_UTIL.getConfiguration();
+    // Enable the favored nodes based load balancer
+    conf.set("hbase.loadbalancer.impl",
+        "org.apache.hadoop.hbase.master.RegionManager$AssignmentLoadBalancer");
+
+    conf.setInt("hbase.master.meta.thread.rescanfrequency", 5000);
+    conf.setInt("hbase.regionserver.msginterval", 1000);
+    conf.setLong("hbase.regionserver.transientAssignment.regionHoldPeriod", 2000);
+    TEST_UTIL.startMiniCluster(SLAVES);
+    admin = new HBaseAdmin(conf);
+    rp = new RegionPlacement(conf);
+  }
+
+  @AfterClass
+  public static void tearDownAfterClass() throws Exception {
+    TEST_UTIL.shutdownMiniCluster();
+  }
+
+  @Test
+  public void testLoadBalancerImpl() throws Exception {
+    MiniHBaseCluster cluster = TEST_UTIL.getHBaseCluster();
+    HMaster m = cluster.getMaster();
+    LoadBalancer loadBalancer = m.getRegionManager().getLoadBalancer();
+    // Verify the master runs with the correct load balancer.
+    assertTrue(loadBalancer instanceof AssignmentLoadBalancer);
+  }
+
+  @Test(timeout = 180000)
+  public void testRegionPlacement() throws Exception {
+    AssignmentPlan currentPlan;
+    // ONLY meta regions, ROOT and META, are assigned at beginning.
+    verifyRegionMovementNum(META_REGION_NUM);
+
+    // Create a table with REGION_NUM regions.
+    createTable("testRegionAssignment", REGION_NUM);
+
+    // Test case1: Verify the region assignment for the exiting table
+    // is consistent with the assignment plan and all the region servers get
+    // correctly favored nodes updated.
+    // Verify all the user region are assigned. REGION_NUM regions are opened
+    verifyRegionMovementNum(REGION_NUM);
+
+    // Get the assignment plan from scanning the META table
+    currentPlan = rp.getAssignmentPlanFromMeta();
+
+    // Verify the plan from the META has covered all the user regions
+    assertEquals(REGION_NUM, currentPlan.getAssignmentMap().keySet().size());
+
+    // Verify all the user regions are assigned to the primary region server
+    // based on the plan
+    verifyRegionOnPrimaryRS(REGION_NUM);
+
+    // Verify all the region server are update with the latest favored nodes
+    verifyRegionServerUpdated(currentPlan);
+
+    // Test Case 2: To verify whether the region placement tools can
+    // correctly update the new assignment plan to META and Region Server.
+    // The new assignment plan is generated by shuffle the existing assignment
+    // plan by switching PRIMARY, SECONDARY and TERTIARY nodes.
+    // Shuffle the plan by switching the secondary region server with
+    // the tertiary.
+
+    // Shuffle the secondary with tertiary favored nodes
+    AssignmentPlan shuffledPlan = this.shuffleAssignmentPlan(currentPlan,
+        AssignmentPlan.POSITION.SECONDARY, AssignmentPlan.POSITION.TERTIARY);
+
+    // Let the region placement update the META and Region Servers
+    rp.updateAssignmentPlan(shuffledPlan);
+
+    // Verify the region assignment. There are supposed to no region reassignment
+    // All the regions are still on the primary regio region server
+    verifyRegionAssignment(shuffledPlan,0, REGION_NUM);
+
+    // Shuffle the plan by switching the primary with secondary and
+    // verify the region reassignment is consistent with the plan.
+    shuffledPlan = this.shuffleAssignmentPlan(currentPlan,
+        AssignmentPlan.POSITION.PRIMARY, AssignmentPlan.POSITION.SECONDARY);
+
+    // Let the region placement update the META and Region Servers
+    rp.updateAssignmentPlan(shuffledPlan);
+    verifyRegionAssignment(shuffledPlan,REGION_NUM, REGION_NUM);
+
+    // Test Case 3: Kill the region server with META region and verify the
+    // region movements and region on primary region server are expected.
+    HRegionServer meta = this.getRegionServerWithMETA();
+    // Get the expected the num of the regions on the its primary region server
+    Collection<HRegion> regionOnMetaRegionServer = meta.getOnlineRegions();
+    int expectedRegionOnPrimaryRS =
+      lastRegionOnPrimaryRSCount - regionOnMetaRegionServer.size() +
+      META_REGION_OVERHEAD;
+    verifyKillRegionServerWithMetaOrRoot(meta, expectedRegionOnPrimaryRS);
+
+    // Test Case 4: Kill the region sever with ROOT and verify the
+    // region movements and region on primary region server are expected.
+    HRegionServer root = this.getRegionServerWithROOT();
+    // Get the expected the num of the regions on the its primary region server
+    Collection<HRegion> regionOnRootRegionServer = root.getOnlineRegions();
+    expectedRegionOnPrimaryRS = lastRegionOnPrimaryRSCount -
+      regionOnRootRegionServer.size() + ROOT_REGION_OVERHEAD;
+
+    // Adjust the number by removing the regions just moved to the ROOT region server
+    for (HRegion region : regionOnRootRegionServer) {
+      if (regionOnMetaRegionServer.contains(region))
+        expectedRegionOnPrimaryRS ++;
+    }
+    verifyKillRegionServerWithMetaOrRoot(root, expectedRegionOnPrimaryRS);
+  }
+
+  /**
+   * To verify the region assignment status.
+   * It will check the assignment plan consistency between META and
+   * region servers.
+   * Also it will verify weather the number of region movement and
+   * the number regions on the primary region server are expected
+   *
+   * @param plan
+   * @param regionMovementNum
+   * @param numRegionsOnPrimaryRS
+   * @throws InterruptedException
+   * @throws IOException
+   */
+  private void verifyRegionAssignment(AssignmentPlan plan,
+      int regionMovementNum, int numRegionsOnPrimaryRS)
+  throws InterruptedException, IOException {
+    // Verify the assignment plan in META is consistent with the expected plan.
+    verifyMETAUpdated(plan);
+
+    // Verify the number of region movement is expected
+    verifyRegionMovementNum(regionMovementNum);
+
+    // Verify the number of regions is assigned to the primary region server
+    // based on the plan is expected
+    verifyRegionOnPrimaryRS(numRegionsOnPrimaryRS);
+
+    // Verify all the online region server are updated with the assignment plan
+    verifyRegionServerUpdated(plan);
+  }
+
+  /**
+   * Test to kill some region server and verify the number of region movement
+   * and the number of region on primary region server are still expected
+   * @param server
+   * @throws InterruptedException
+   * @throws IOException
+   */
+  private void verifyKillRegionServerWithMetaOrRoot(HRegionServer server,
+      int expectedRegionOnPrimary)
+  throws InterruptedException, IOException{
+    assertNotNull(server);
+
+    // Verify this region server with META is also hosting user regions
+    int expectedRegionMovement = server.getOnlineRegions().size();
+    assertTrue("All the user regions are assigned to this region server: " +
+        server.getServerInfo().getHostnamePort(),
+        (expectedRegionMovement < REGION_NUM));
+    assertTrue("NO the user region is assigned to this region server: " +
+        server.getServerInfo().getHostnamePort(),
+        (expectedRegionMovement > 1) );
+
+    // Kill the region server;
+    server.kill();
+
+    // Verify the user regions previously on the killed rs are reassigned.
+    verifyRegionMovementNum(expectedRegionMovement);
+
+    // Verify only expectedRegionOnPrimary of the user regions are assigned
+    // to the primary region server based on the plan.
+    verifyRegionOnPrimaryRS(expectedRegionOnPrimary);
+  }
+
+  /**
+   * Get the region server who is currently hosting ROOT
+   * @return
+   */
+  private HRegionServer getRegionServerWithROOT() {
+    MiniHBaseCluster cluster = TEST_UTIL.getHBaseCluster();
+    HMaster master = cluster.getMaster();
+    for (int i = 0; i < SLAVES; i++) {
+      HRegionServer rs = cluster.getRegionServer(i);
+      HServerAddress addr = rs.getServerInfo().getServerAddress();
+      if (master.getRegionManager().isRootServer(addr)) {
+        return rs;
+      }
+    }
+    return null;
+  }
+
+  /**
+   * Get the region server who is currently hosting META
+   * @return
+   */
+  private HRegionServer getRegionServerWithMETA() {
+    MiniHBaseCluster cluster = TEST_UTIL.getHBaseCluster();
+    HMaster master = cluster.getMaster();
+    for (int i = 0; i < SLAVES; i++) {
+      HRegionServer rs = cluster.getRegionServer(i);
+      HServerAddress addr = rs.getServerInfo().getServerAddress();
+      if (master.getRegionManager().isMetaServer(addr)) {
+        return rs;
+      }
+    }
+    return null;
+  }
+  /**
+   * Verify the number of region movement is expected
+   * @param expected
+   * @throws InterruptedException
+   */
+  private void verifyRegionMovementNum(int expected)
+  throws InterruptedException {
+    MiniHBaseCluster cluster = TEST_UTIL.getHBaseCluster();
+    HMaster m = cluster.getMaster();
+
+    int retry = 5;
+    long sleep = 2 * TEST_UTIL.getConfiguration().
+      getInt("hbase.regionserver.msginterval", 1000);
+    int attempt = 0;
+    int currentRegionOpened, regionMovement;
+    do {
+      currentRegionOpened = m.getMetrics().getRegionsOpened();
+      regionMovement= currentRegionOpened - lastRegionOpenedCount;
+      LOG.debug("There are " + regionMovement + "/" + expected +
+          " regions moved after " + attempt + " attempts");
+      Thread.sleep((++attempt) * sleep);
+    } while (regionMovement != expected && attempt <= retry);
+
+    // update the lastRegionOpenedCount
+    lastRegionOpenedCount = currentRegionOpened;
+
+    assertEquals("There are only " + regionMovement + " instead of "
+          + expected + " region movement for " + attempt + " attempts",
+          regionMovement, expected);
+  }
+
+  /**
+   * Shuffle the assignment plan by switching two favored node positions.
+   * @param plan The assignment plan
+   * @param p1 The first switch position
+   * @param p2 The second switch position
+   * @return
+   */
+  private AssignmentPlan shuffleAssignmentPlan(AssignmentPlan plan,
+      AssignmentPlan.POSITION p1, AssignmentPlan.POSITION p2) {
+    AssignmentPlan shuffledPlan = new AssignmentPlan();
+
+    for (Map.Entry<HRegionInfo, List<HServerAddress>> entry :
+      plan.getAssignmentMap().entrySet()) {
+      HRegionInfo region = entry.getKey();
+
+      // copy the server list from the original plan
+      List<HServerAddress> shuffledServerList = new ArrayList<HServerAddress>();
+      shuffledServerList.addAll(entry.getValue());
+
+      // start to shuffle
+      shuffledServerList.set(p1.ordinal(), entry.getValue().get(p2.ordinal()));
+      shuffledServerList.set(p2.ordinal(), entry.getValue().get(p1.ordinal()));
+
+      // update the plan
+      shuffledPlan.updateAssignmentPlan(region, shuffledServerList);
+    }
+    return shuffledPlan;
+  }
+
+  /**
+   * Verify the number of user regions is assigned to the primary
+   * region server based on the plan is expected
+   * @param expectedNum.
+   * @throws IOException
+   */
+  private void verifyRegionOnPrimaryRS(int expectedNum)
+  throws IOException {
+    this.lastRegionOnPrimaryRSCount = rp.getNumRegionisOnPrimaryRS();
+    assertEquals("Only " +  expectedNum + " of user regions running " +
+        "on the primary region server", expectedNum ,
+        lastRegionOnPrimaryRSCount);
+  }
+
+  /**
+   * Verify the meta has updated to the latest assignment plan
+   * @param plan
+   * @throws IOException
+   */
+  private void verifyMETAUpdated(AssignmentPlan expectedPlan)
+  throws IOException {
+    AssignmentPlan planFromMETA = rp.getAssignmentPlanFromMeta();
+    assertTrue("The assignment plan is NOT consistent with the expected plan ",
+        planFromMETA.equals(expectedPlan));
+  }
+
+  /**
+   * Verify all the online region servers has been updated to the
+   * latest assignment plan
+   * @param plan
+   * @throws IOException
+   */
+  private void verifyRegionServerUpdated(AssignmentPlan plan) throws IOException {
+    // Verify all region servers contain the correct favored nodes information
+    MiniHBaseCluster cluster = TEST_UTIL.getHBaseCluster();
+    for (int i = 0; i < SLAVES; i++) {
+      HRegionServer rs = cluster.getRegionServer(i);
+      for (HRegion region: rs.getOnlineRegions()) {
+        InetSocketAddress[] favoredSockedAddress = region.getFavoredNodes();
+        List<HServerAddress> favoredServerList =
+          plan.getAssignment(region.getRegionInfo());
+
+        // All regions are supposed to have favored nodes,
+        // except for META and ROOT
+        if (favoredServerList == null) {
+          HTableDescriptor desc = region.getTableDesc();
+          // Verify they are ROOT and META regions since no favored nodes
+          assertNull(favoredSockedAddress);
+          assertTrue("User region " +
+              region.getTableDesc().getNameAsString() +
+              " should have favored nodes",
+              (desc.isRootRegion() || desc.isMetaRegion()));
+        } else {
+          // For user region, the favored nodes in the region server should be
+          // identical to favored nodes in the assignmentPlan
+          assertTrue(favoredSockedAddress.length == favoredServerList.size());
+          assertTrue(favoredServerList.size() > 0);
+          for (int j = 0; j < favoredServerList.size(); j++) {
+            InetSocketAddress addrFromRS = favoredSockedAddress[j];
+            InetSocketAddress addrFromPlan =
+              favoredServerList.get(j).getInetSocketAddress();
+
+            assertNotNull(addrFromRS);
+            assertNotNull(addrFromPlan);
+            assertTrue("Region server " + rs.getHServerInfo().getHostnamePort()
+                 + " has the " + positions[j] +
+                 " for region " + region.getRegionNameAsString() + " is " +
+                 addrFromRS + " which is inconsistent with the plan "
+                 + addrFromPlan, addrFromRS.equals(addrFromPlan));
+          }
+        }
+      }
+    }
+  }
+  /**
+   * Create a table with specified table name and region number.
+   * @param table
+   * @param regionNum
+   * @return
+   * @throws IOException
+   */
+   private static void createTable(String table, int regionNum)
+   throws IOException {
+    byte[] tableName = Bytes.toBytes(table);
+    int expectedRegions = regionNum;
+    byte[][] splitKeys = new byte[expectedRegions - 1][];
+    for (int i = 1; i < expectedRegions; i++) {
+      byte splitKey = (byte) i;
+      splitKeys[i - 1] = new byte[] { splitKey, splitKey, splitKey };
+    }
+
+    HTableDescriptor desc = new HTableDescriptor(tableName);
+    desc.addFamily(new HColumnDescriptor(HConstants.CATALOG_FAMILY));
+    admin.createTable(desc, splitKeys);
+
+    HTable ht = new HTable(TEST_UTIL.getConfiguration(), tableName);
+    Map<HRegionInfo, HServerAddress> regions = ht.getRegionsInfo();
+    assertEquals("Tried to create " + expectedRegions + " regions "
+        + "but only found " + regions.size(), expectedRegions, regions.size());
+   }
+
+   /**
+    * Used to test the correctness of this class.
+    */
+   @Test
+   public void testRandomizedMatrix() {
+     int rows = 100;
+     int cols = 100;
+     float[][] matrix = new float[rows][cols];
+     Random random = new Random();
+     for (int i = 0; i < rows; i++) {
+       for (int j = 0; j < cols; j++) {
+         matrix[i][j] = random.nextFloat();
+       }
+     }
+
+     // Test that inverting a transformed matrix gives the original matrix.
+     RegionPlacement.RandomizedMatrix rm =
+       new RegionPlacement.RandomizedMatrix(rows, cols);
+     float[][] transformed = rm.transform(matrix);
+     float[][] invertedTransformed = rm.invert(transformed);
+     for (int i = 0; i < rows; i++) {
+       for (int j = 0; j < cols; j++) {
+         if (matrix[i][j] != invertedTransformed[i][j]) {
+           throw new RuntimeException();
+         }
+       }
+     }
+
+     // Test that the indices on a transformed matrix can be inverted to give
+     // the same values on the original matrix.
+     int[] transformedIndices = new int[rows];
+     for (int i = 0; i < rows; i++) {
+       transformedIndices[i] = random.nextInt(cols);
+     }
+     int[] invertedTransformedIndices = rm.invertIndices(transformedIndices);
+     float[] transformedValues = new float[rows];
+     float[] invertedTransformedValues = new float[rows];
+     for (int i = 0; i < rows; i++) {
+       transformedValues[i] = transformed[i][transformedIndices[i]];
+       invertedTransformedValues[i] = matrix[i][invertedTransformedIndices[i]];
+     }
+     Arrays.sort(transformedValues);
+     Arrays.sort(invertedTransformedValues);
+     if (!Arrays.equals(transformedValues, invertedTransformedValues)) {
+       throw new RuntimeException();
+     }
+   }
+}

Modified: hbase/branches/0.89-fb/src/test/java/org/apache/hadoop/hbase/regionserver/TestRegionFavoredNodes.java
URL: http://svn.apache.org/viewvc/hbase/branches/0.89-fb/src/test/java/org/apache/hadoop/hbase/regionserver/TestRegionFavoredNodes.java?rev=1301790&r1=1301789&r2=1301790&view=diff
==============================================================================
--- hbase/branches/0.89-fb/src/test/java/org/apache/hadoop/hbase/regionserver/TestRegionFavoredNodes.java (original)
+++ hbase/branches/0.89-fb/src/test/java/org/apache/hadoop/hbase/regionserver/TestRegionFavoredNodes.java Fri Mar 16 22:09:11 2012
@@ -1,5 +1,7 @@
 package org.apache.hadoop.hbase.regionserver;
 
+import static org.junit.Assert.fail;
+
 import java.net.InetSocketAddress;
 import java.net.URI;
 import java.util.List;
@@ -15,8 +17,6 @@ import org.junit.AfterClass;
 import org.junit.BeforeClass;
 import org.junit.Test;
 
-import static org.junit.Assert.*;
-
 /**
  * Tests the ability to specify favored nodes for a region.
  */
@@ -26,8 +26,8 @@ public class TestRegionFavoredNodes {
   private static HTable table;
   private static final byte[] TABLE_NAME = Bytes.toBytes("table");
   private static final byte[] COLUMN_FAMILY = Bytes.toBytes("family");
-  private static final int REPLICATION = 3;
-  private static final int REGION_SERVERS = 6;
+  private static final int FAVORED_NODES_NUM = 3;
+  private static final int REGION_SERVERS = 3;
   private static final int FLUSHES = 3;
 
   @BeforeClass
@@ -60,10 +60,10 @@ public class TestRegionFavoredNodes {
 
     // For each region, choose some datanodes as the favored nodes then assign
     // them as favored nodes through the HRegion.
-    InetSocketAddress[] favoredNodes = new InetSocketAddress[REPLICATION];
+    InetSocketAddress[] favoredNodes = new InetSocketAddress[FAVORED_NODES_NUM];
     List<HRegion> regions = TEST_UTIL.getHBaseCluster().getRegions(TABLE_NAME);
     for (int i = 0; i < regions.size(); i++) {
-      for (int j = 0; j < REPLICATION; j++) {
+      for (int j = 0; j < FAVORED_NODES_NUM; j++) {
         favoredNodes[j] = nodes[(i + j) % REGION_SERVERS];
       }
       regions.get(i).setFavoredNodes(favoredNodes);
@@ -88,7 +88,7 @@ public class TestRegionFavoredNodes {
         for (LocatedBlock lbk : lbks.getLocatedBlocks()) {
           locations:
           for (DatanodeInfo info : lbk.getLocations()) {
-            for (int j = 0; j < REPLICATION; j++) {
+            for (int j = 0; j < FAVORED_NODES_NUM; j++) {
               if (info.getName().equals(nodeNames[(i + j) % REGION_SERVERS])) {
                 continue locations;
               }



Mime
View raw message