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