View Javadoc

1   /**
2    *
3    * Licensed to the Apache Software Foundation (ASF) under one
4    * or more contributor license agreements.  See the NOTICE file
5    * distributed with this work for additional information
6    * regarding copyright ownership.  The ASF licenses this file
7    * to you under the Apache License, Version 2.0 (the
8    * "License"); you may not use this file except in compliance
9    * with the License.  You may obtain a copy of the License at
10   *
11   *     http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing, software
14   * distributed under the License is distributed on an "AS IS" BASIS,
15   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16   * See the License for the specific language governing permissions and
17   * limitations under the License.
18   */
19  package org.apache.hadoop.hbase;
20  
21  import java.io.IOException;
22  import java.security.PrivilegedAction;
23  import java.util.ArrayList;
24  import java.util.List;
25  
26  import org.apache.commons.logging.Log;
27  import org.apache.commons.logging.LogFactory;
28  import org.apache.hadoop.classification.InterfaceAudience;
29  import org.apache.hadoop.classification.InterfaceStability;
30  import org.apache.hadoop.conf.Configuration;
31  import org.apache.hadoop.fs.FileSystem;
32  import org.apache.hadoop.hbase.client.HConnectionManager;
33  import org.apache.hadoop.hbase.master.HMaster;
34  import org.apache.hadoop.hbase.protobuf.generated.AdminProtos.AdminService;
35  import org.apache.hadoop.hbase.protobuf.generated.ClientProtos.ClientService;
36  import org.apache.hadoop.hbase.protobuf.generated.MasterAdminProtos.MasterAdminService;
37  import org.apache.hadoop.hbase.protobuf.generated.MasterMonitorProtos.MasterMonitorService;
38  import org.apache.hadoop.hbase.protobuf.generated.RegionServerStatusProtos.RegionServerStartupResponse;
39  import org.apache.hadoop.hbase.regionserver.HRegion;
40  import org.apache.hadoop.hbase.regionserver.HRegionServer;
41  import org.apache.hadoop.hbase.security.User;
42  import org.apache.hadoop.hbase.test.MetricsAssertHelper;
43  import org.apache.hadoop.hbase.util.JVMClusterUtil;
44  import org.apache.hadoop.hbase.util.JVMClusterUtil.MasterThread;
45  import org.apache.hadoop.hbase.util.JVMClusterUtil.RegionServerThread;
46  import org.apache.hadoop.hbase.util.Threads;
47  
48  /**
49   * This class creates a single process HBase cluster.
50   * each server.  The master uses the 'default' FileSystem.  The RegionServers,
51   * if we are running on DistributedFilesystem, create a FileSystem instance
52   * each and will close down their instance on the way out.
53   */
54  @InterfaceAudience.Public
55  @InterfaceStability.Evolving
56  public class MiniHBaseCluster extends HBaseCluster {
57    static final Log LOG = LogFactory.getLog(MiniHBaseCluster.class.getName());
58    public LocalHBaseCluster hbaseCluster;
59    private static int index;
60  
61    /**
62     * Start a MiniHBaseCluster.
63     * @param conf Configuration to be used for cluster
64     * @param numRegionServers initial number of region servers to start.
65     * @throws IOException
66     */
67    public MiniHBaseCluster(Configuration conf, int numRegionServers)
68    throws IOException, InterruptedException {
69      this(conf, 1, numRegionServers);
70    }
71  
72    /**
73     * Start a MiniHBaseCluster.
74     * @param conf Configuration to be used for cluster
75     * @param numMasters initial number of masters to start.
76     * @param numRegionServers initial number of region servers to start.
77     * @throws IOException
78     */
79    public MiniHBaseCluster(Configuration conf, int numMasters,
80                               int numRegionServers)
81        throws IOException, InterruptedException {
82      this(conf, numMasters, numRegionServers, null, null);
83    }
84  
85    public MiniHBaseCluster(Configuration conf, int numMasters, int numRegionServers,
86           Class<? extends HMaster> masterClass,
87           Class<? extends MiniHBaseCluster.MiniHBaseClusterRegionServer> regionserverClass)
88        throws IOException, InterruptedException {
89      super(conf);
90      conf.set(HConstants.MASTER_PORT, "0");
91  
92      // Hadoop 2
93      CompatibilityFactory.getInstance(MetricsAssertHelper.class).init();
94  
95      init(numMasters, numRegionServers, masterClass, regionserverClass);
96      this.initialClusterStatus = getClusterStatus();
97    }
98  
99    public Configuration getConfiguration() {
100     return this.conf;
101   }
102 
103   /**
104    * Subclass so can get at protected methods (none at moment).  Also, creates
105    * a FileSystem instance per instantiation.  Adds a shutdown own FileSystem
106    * on the way out. Shuts down own Filesystem only, not All filesystems as
107    * the FileSystem system exit hook does.
108    */
109   public static class MiniHBaseClusterRegionServer extends HRegionServer {
110     private Thread shutdownThread = null;
111     private User user = null;
112     public static boolean TEST_SKIP_CLOSE = false;
113 
114     public MiniHBaseClusterRegionServer(Configuration conf)
115         throws IOException, InterruptedException {
116       super(conf);
117       this.user = User.getCurrent();
118     }
119 
120     /*
121      * @param c
122      * @param currentfs We return this if we did not make a new one.
123      * @param uniqueName Same name used to help identify the created fs.
124      * @return A new fs instance if we are up on DistributeFileSystem.
125      * @throws IOException
126      */
127 
128     @Override
129     protected void handleReportForDutyResponse(
130         final RegionServerStartupResponse c) throws IOException {
131       super.handleReportForDutyResponse(c);
132       // Run this thread to shutdown our filesystem on way out.
133       this.shutdownThread = new SingleFileSystemShutdownThread(getFileSystem());
134     }
135 
136     @Override
137     public void run() {
138       try {
139         this.user.runAs(new PrivilegedAction<Object>(){
140           public Object run() {
141             runRegionServer();
142             return null;
143           }
144         });
145       } catch (Throwable t) {
146         LOG.error("Exception in run", t);
147       } finally {
148         // Run this on the way out.
149         if (this.shutdownThread != null) {
150           this.shutdownThread.start();
151           Threads.shutdown(this.shutdownThread, 30000);
152         }
153       }
154     }
155 
156     private void runRegionServer() {
157       super.run();
158     }
159 
160     @Override
161     public void kill() {
162       super.kill();
163     }
164 
165     public void abort(final String reason, final Throwable cause) {
166       this.user.runAs(new PrivilegedAction<Object>() {
167         public Object run() {
168           abortRegionServer(reason, cause);
169           return null;
170         }
171       });
172     }
173 
174     private void abortRegionServer(String reason, Throwable cause) {
175       super.abort(reason, cause);
176     }
177   }
178 
179   /**
180    * Alternate shutdown hook.
181    * Just shuts down the passed fs, not all as default filesystem hook does.
182    */
183   static class SingleFileSystemShutdownThread extends Thread {
184     private final FileSystem fs;
185     SingleFileSystemShutdownThread(final FileSystem fs) {
186       super("Shutdown of " + fs);
187       this.fs = fs;
188     }
189     @Override
190     public void run() {
191       try {
192         LOG.info("Hook closing fs=" + this.fs);
193         this.fs.close();
194       } catch (NullPointerException npe) {
195         LOG.debug("Need to fix these: " + npe.toString());
196       } catch (IOException e) {
197         LOG.warn("Running hook", e);
198       }
199     }
200   }
201 
202   private void init(final int nMasterNodes, final int nRegionNodes,
203                  Class<? extends HMaster> masterClass,
204                  Class<? extends MiniHBaseCluster.MiniHBaseClusterRegionServer> regionserverClass)
205   throws IOException, InterruptedException {
206     try {
207       if (masterClass == null){
208         masterClass =  HMaster.class;
209       }
210       if (regionserverClass == null){
211         regionserverClass = MiniHBaseCluster.MiniHBaseClusterRegionServer.class;
212       }
213 
214       // start up a LocalHBaseCluster
215       hbaseCluster = new LocalHBaseCluster(conf, nMasterNodes, 0,
216           masterClass, regionserverClass);
217 
218       // manually add the regionservers as other users
219       for (int i=0; i<nRegionNodes; i++) {
220         Configuration rsConf = HBaseConfiguration.create(conf);
221         User user = HBaseTestingUtility.getDifferentUser(rsConf,
222             ".hfs."+index++);
223         hbaseCluster.addRegionServer(rsConf, i, user);
224       }
225 
226       hbaseCluster.startup();
227     } catch (IOException e) {
228       shutdown();
229       throw e;
230     } catch (Throwable t) {
231       LOG.error("Error starting cluster", t);
232       shutdown();
233       throw new IOException("Shutting down", t);
234     }
235   }
236 
237   @Override
238   public void startRegionServer(String hostname) throws IOException {
239     this.startRegionServer();
240   }
241 
242   @Override
243   public void killRegionServer(ServerName serverName) throws IOException {
244     HRegionServer server = getRegionServer(getRegionServerIndex(serverName));
245     if (server instanceof MiniHBaseClusterRegionServer) {
246       LOG.info("Killing " + server.toString());
247       ((MiniHBaseClusterRegionServer) server).kill();
248     } else {
249       abortRegionServer(getRegionServerIndex(serverName));
250     }
251   }
252 
253   @Override
254   public void stopRegionServer(ServerName serverName) throws IOException {
255     stopRegionServer(getRegionServerIndex(serverName));
256   }
257 
258   @Override
259   public void waitForRegionServerToStop(ServerName serverName, long timeout) throws IOException {
260     //ignore timeout for now
261     waitOnRegionServer(getRegionServerIndex(serverName));
262   }
263 
264   @Override
265   public void startMaster(String hostname) throws IOException {
266     this.startMaster();
267   }
268 
269   @Override
270   public void killMaster(ServerName serverName) throws IOException {
271     abortMaster(getMasterIndex(serverName));
272   }
273 
274   @Override
275   public void stopMaster(ServerName serverName) throws IOException {
276     stopMaster(getMasterIndex(serverName));
277   }
278 
279   @Override
280   public void waitForMasterToStop(ServerName serverName, long timeout) throws IOException {
281     //ignore timeout for now
282     waitOnMaster(getMasterIndex(serverName));
283   }
284 
285   /**
286    * Starts a region server thread running
287    *
288    * @throws IOException
289    * @return New RegionServerThread
290    */
291   public JVMClusterUtil.RegionServerThread startRegionServer()
292       throws IOException {
293     final Configuration newConf = HBaseConfiguration.create(conf);
294     User rsUser =
295         HBaseTestingUtility.getDifferentUser(newConf, ".hfs."+index++);
296     JVMClusterUtil.RegionServerThread t =  null;
297     try {
298       t = hbaseCluster.addRegionServer(
299           newConf, hbaseCluster.getRegionServers().size(), rsUser);
300       t.start();
301       t.waitForServerOnline();
302     } catch (InterruptedException ie) {
303       throw new IOException("Interrupted adding regionserver to cluster", ie);
304     }
305     return t;
306   }
307 
308   /**
309    * Cause a region server to exit doing basic clean up only on its way out.
310    * @param serverNumber  Used as index into a list.
311    */
312   public String abortRegionServer(int serverNumber) {
313     HRegionServer server = getRegionServer(serverNumber);
314     LOG.info("Aborting " + server.toString());
315     server.abort("Aborting for tests", new Exception("Trace info"));
316     return server.toString();
317   }
318 
319   /**
320    * Shut down the specified region server cleanly
321    *
322    * @param serverNumber  Used as index into a list.
323    * @return the region server that was stopped
324    */
325   public JVMClusterUtil.RegionServerThread stopRegionServer(int serverNumber) {
326     return stopRegionServer(serverNumber, true);
327   }
328 
329   /**
330    * Shut down the specified region server cleanly
331    *
332    * @param serverNumber  Used as index into a list.
333    * @param shutdownFS True is we are to shutdown the filesystem as part of this
334    * regionserver's shutdown.  Usually we do but you do not want to do this if
335    * you are running multiple regionservers in a test and you shut down one
336    * before end of the test.
337    * @return the region server that was stopped
338    */
339   public JVMClusterUtil.RegionServerThread stopRegionServer(int serverNumber,
340       final boolean shutdownFS) {
341     JVMClusterUtil.RegionServerThread server =
342       hbaseCluster.getRegionServers().get(serverNumber);
343     LOG.info("Stopping " + server.toString());
344     server.getRegionServer().stop("Stopping rs " + serverNumber);
345     return server;
346   }
347 
348   /**
349    * Wait for the specified region server to stop. Removes this thread from list
350    * of running threads.
351    * @param serverNumber
352    * @return Name of region server that just went down.
353    */
354   public String waitOnRegionServer(final int serverNumber) {
355     return this.hbaseCluster.waitOnRegionServer(serverNumber);
356   }
357 
358 
359   /**
360    * Starts a master thread running
361    *
362    * @throws IOException
363    * @return New RegionServerThread
364    */
365   public JVMClusterUtil.MasterThread startMaster() throws IOException {
366     Configuration c = HBaseConfiguration.create(conf);
367     User user =
368         HBaseTestingUtility.getDifferentUser(c, ".hfs."+index++);
369 
370     JVMClusterUtil.MasterThread t = null;
371     try {
372       t = hbaseCluster.addMaster(c, hbaseCluster.getMasters().size(), user);
373       t.start();
374     } catch (InterruptedException ie) {
375       throw new IOException("Interrupted adding master to cluster", ie);
376     }
377     return t;
378   }
379 
380   @Override
381   public MasterAdminService.BlockingInterface getMasterAdmin() {
382     return this.hbaseCluster.getActiveMaster();
383   }
384 
385   @Override
386   public MasterMonitorService.BlockingInterface getMasterMonitor() {
387     return this.hbaseCluster.getActiveMaster();
388   }
389 
390   /**
391    * Returns the current active master, if available.
392    * @return the active HMaster, null if none is active.
393    */
394   public HMaster getMaster() {
395     return this.hbaseCluster.getActiveMaster();
396   }
397 
398   /**
399    * Returns the master at the specified index, if available.
400    * @return the active HMaster, null if none is active.
401    */
402   public HMaster getMaster(final int serverNumber) {
403     return this.hbaseCluster.getMaster(serverNumber);
404   }
405 
406   /**
407    * Cause a master to exit without shutting down entire cluster.
408    * @param serverNumber  Used as index into a list.
409    */
410   public String abortMaster(int serverNumber) {
411     HMaster server = getMaster(serverNumber);
412     LOG.info("Aborting " + server.toString());
413     server.abort("Aborting for tests", new Exception("Trace info"));
414     return server.toString();
415   }
416 
417   /**
418    * Shut down the specified master cleanly
419    *
420    * @param serverNumber  Used as index into a list.
421    * @return the region server that was stopped
422    */
423   public JVMClusterUtil.MasterThread stopMaster(int serverNumber) {
424     return stopMaster(serverNumber, true);
425   }
426 
427   /**
428    * Shut down the specified master cleanly
429    *
430    * @param serverNumber  Used as index into a list.
431    * @param shutdownFS True is we are to shutdown the filesystem as part of this
432    * master's shutdown.  Usually we do but you do not want to do this if
433    * you are running multiple master in a test and you shut down one
434    * before end of the test.
435    * @return the master that was stopped
436    */
437   public JVMClusterUtil.MasterThread stopMaster(int serverNumber,
438       final boolean shutdownFS) {
439     JVMClusterUtil.MasterThread server =
440       hbaseCluster.getMasters().get(serverNumber);
441     LOG.info("Stopping " + server.toString());
442     server.getMaster().stop("Stopping master " + serverNumber);
443     return server;
444   }
445 
446   /**
447    * Wait for the specified master to stop. Removes this thread from list
448    * of running threads.
449    * @param serverNumber
450    * @return Name of master that just went down.
451    */
452   public String waitOnMaster(final int serverNumber) {
453     return this.hbaseCluster.waitOnMaster(serverNumber);
454   }
455 
456   /**
457    * Blocks until there is an active master and that master has completed
458    * initialization.
459    *
460    * @return true if an active master becomes available.  false if there are no
461    *         masters left.
462    * @throws InterruptedException
463    */
464   public boolean waitForActiveAndReadyMaster(long timeout) throws IOException {
465     List<JVMClusterUtil.MasterThread> mts;
466     long start = System.currentTimeMillis();
467     while (!(mts = getMasterThreads()).isEmpty()
468         && (System.currentTimeMillis() - start) < timeout) {
469       for (JVMClusterUtil.MasterThread mt : mts) {
470         if (mt.getMaster().isActiveMaster() && mt.getMaster().isInitialized()) {
471           return true;
472         }
473       }
474 
475       Threads.sleep(100);
476     }
477     return false;
478   }
479 
480   /**
481    * @return List of master threads.
482    */
483   public List<JVMClusterUtil.MasterThread> getMasterThreads() {
484     return this.hbaseCluster.getMasters();
485   }
486 
487   /**
488    * @return List of live master threads (skips the aborted and the killed)
489    */
490   public List<JVMClusterUtil.MasterThread> getLiveMasterThreads() {
491     return this.hbaseCluster.getLiveMasters();
492   }
493 
494   /**
495    * Wait for Mini HBase Cluster to shut down.
496    */
497   public void join() {
498     this.hbaseCluster.join();
499   }
500 
501   /**
502    * Shut down the mini HBase cluster
503    * @throws IOException
504    */
505   public void shutdown() throws IOException {
506     if (this.hbaseCluster != null) {
507       this.hbaseCluster.shutdown();
508     }
509     HConnectionManager.deleteAllConnections(false);
510   }
511 
512   @Override
513   public void close() throws IOException {
514   }
515 
516   @Override
517   public ClusterStatus getClusterStatus() throws IOException {
518     HMaster master = getMaster();
519     return master == null ? null : master.getClusterStatus();
520   }
521 
522   /**
523    * Call flushCache on all regions on all participating regionservers.
524    * @throws IOException
525    */
526   public void flushcache() throws IOException {
527     for (JVMClusterUtil.RegionServerThread t:
528         this.hbaseCluster.getRegionServers()) {
529       for(HRegion r: t.getRegionServer().getOnlineRegionsLocalContext()) {
530         r.flushcache();
531       }
532     }
533   }
534 
535   /**
536    * Call flushCache on all regions of the specified table.
537    * @throws IOException
538    */
539   public void flushcache(TableName tableName) throws IOException {
540     for (JVMClusterUtil.RegionServerThread t:
541         this.hbaseCluster.getRegionServers()) {
542       for(HRegion r: t.getRegionServer().getOnlineRegionsLocalContext()) {
543         if(r.getTableDesc().getTableName().equals(tableName)) {
544           r.flushcache();
545         }
546       }
547     }
548   }
549 
550   /**
551    * Call flushCache on all regions on all participating regionservers.
552    * @throws IOException
553    */
554   public void compact(boolean major) throws IOException {
555     for (JVMClusterUtil.RegionServerThread t:
556         this.hbaseCluster.getRegionServers()) {
557       for(HRegion r: t.getRegionServer().getOnlineRegionsLocalContext()) {
558         r.compactStores(major);
559       }
560     }
561   }
562 
563   /**
564    * Call flushCache on all regions of the specified table.
565    * @throws IOException
566    */
567   public void compact(TableName tableName, boolean major) throws IOException {
568     for (JVMClusterUtil.RegionServerThread t:
569         this.hbaseCluster.getRegionServers()) {
570       for(HRegion r: t.getRegionServer().getOnlineRegionsLocalContext()) {
571         if(r.getTableDesc().getTableName().equals(tableName)) {
572           r.compactStores(major);
573         }
574       }
575     }
576   }
577 
578   /**
579    * @return List of region server threads.
580    */
581   public List<JVMClusterUtil.RegionServerThread> getRegionServerThreads() {
582     return this.hbaseCluster.getRegionServers();
583   }
584 
585   /**
586    * @return List of live region server threads (skips the aborted and the killed)
587    */
588   public List<JVMClusterUtil.RegionServerThread> getLiveRegionServerThreads() {
589     return this.hbaseCluster.getLiveRegionServers();
590   }
591 
592   /**
593    * Grab a numbered region server of your choice.
594    * @param serverNumber
595    * @return region server
596    */
597   public HRegionServer getRegionServer(int serverNumber) {
598     return hbaseCluster.getRegionServer(serverNumber);
599   }
600 
601   public List<HRegion> getRegions(byte[] tableName) {
602     return getRegions(TableName.valueOf(tableName));
603   }
604 
605   public List<HRegion> getRegions(TableName tableName) {
606     List<HRegion> ret = new ArrayList<HRegion>();
607     for (JVMClusterUtil.RegionServerThread rst : getRegionServerThreads()) {
608       HRegionServer hrs = rst.getRegionServer();
609       for (HRegion region : hrs.getOnlineRegionsLocalContext()) {
610         if (region.getTableDesc().getTableName().equals(tableName)) {
611           ret.add(region);
612         }
613       }
614     }
615     return ret;
616   }
617 
618   /**
619    * @return Index into List of {@link MiniHBaseCluster#getRegionServerThreads()}
620    * of HRS carrying regionName. Returns -1 if none found.
621    */
622   public int getServerWithMeta() {
623     return getServerWith(HRegionInfo.FIRST_META_REGIONINFO.getRegionName());
624   }
625 
626   /**
627    * Get the location of the specified region
628    * @param regionName Name of the region in bytes
629    * @return Index into List of {@link MiniHBaseCluster#getRegionServerThreads()}
630    * of HRS carrying .META.. Returns -1 if none found.
631    */
632   public int getServerWith(byte[] regionName) {
633     int index = -1;
634     int count = 0;
635     for (JVMClusterUtil.RegionServerThread rst: getRegionServerThreads()) {
636       HRegionServer hrs = rst.getRegionServer();
637       HRegion metaRegion =
638         hrs.getOnlineRegion(regionName);
639       if (metaRegion != null) {
640         index = count;
641         break;
642       }
643       count++;
644     }
645     return index;
646   }
647 
648   @Override
649   public ServerName getServerHoldingRegion(byte[] regionName) throws IOException {
650     int index = getServerWith(regionName);
651     if (index < 0) {
652       return null;
653     }
654     return getRegionServer(index).getServerName();
655   }
656 
657   /**
658    * Counts the total numbers of regions being served by the currently online
659    * region servers by asking each how many regions they have.  Does not look
660    * at META at all.  Count includes catalog tables.
661    * @return number of regions being served by all region servers
662    */
663   public long countServedRegions() {
664     long count = 0;
665     for (JVMClusterUtil.RegionServerThread rst : getLiveRegionServerThreads()) {
666       count += rst.getRegionServer().getNumberOfOnlineRegions();
667     }
668     return count;
669   }
670 
671   /**
672    * Do a simulated kill all masters and regionservers. Useful when it is
673    * impossible to bring the mini-cluster back for clean shutdown.
674    */
675   public void killAll() {
676     for (RegionServerThread rst : getRegionServerThreads()) {
677       rst.getRegionServer().abort("killAll");
678     }
679     for (MasterThread masterThread : getMasterThreads()) {
680       masterThread.getMaster().abort("killAll", new Throwable());
681     }
682   }
683 
684   @Override
685   public void waitUntilShutDown() {
686     this.hbaseCluster.join();
687   }
688 
689   public List<HRegion> findRegionsForTable(TableName tableName) {
690     ArrayList<HRegion> ret = new ArrayList<HRegion>();
691     for (JVMClusterUtil.RegionServerThread rst : getRegionServerThreads()) {
692       HRegionServer hrs = rst.getRegionServer();
693       for (HRegion region : hrs.getOnlineRegions(tableName)) {
694         if (region.getTableDesc().getTableName().equals(tableName)) {
695           ret.add(region);
696         }
697       }
698     }
699     return ret;
700   }
701 
702 
703   protected int getRegionServerIndex(ServerName serverName) {
704     //we have a small number of region servers, this should be fine for now.
705     List<RegionServerThread> servers = getRegionServerThreads();
706     for (int i=0; i < servers.size(); i++) {
707       if (servers.get(i).getRegionServer().getServerName().equals(serverName)) {
708         return i;
709       }
710     }
711     return -1;
712   }
713 
714   protected int getMasterIndex(ServerName serverName) {
715     List<MasterThread> masters = getMasterThreads();
716     for (int i = 0; i < masters.size(); i++) {
717       if (masters.get(i).getMaster().getServerName().equals(serverName)) {
718         return i;
719       }
720     }
721     return -1;
722   }
723 
724   @Override
725   public AdminService.BlockingInterface getAdminProtocol(ServerName serverName) throws IOException {
726     return getRegionServer(getRegionServerIndex(serverName));
727   }
728 
729   @Override
730   public ClientService.BlockingInterface getClientProtocol(ServerName serverName)
731   throws IOException {
732     return getRegionServer(getRegionServerIndex(serverName));
733   }
734 }