View Javadoc

1   /**
2    * Copyright 2010 The Apache Software Foundation
3    *
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *     http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing, software
15   * distributed under the License is distributed on an "AS IS" BASIS,
16   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17   * See the License for the specific language governing permissions and
18   * limitations under the License.
19   */
20  package org.apache.hadoop.hbase.util;
21  
22  import java.io.IOException;
23  import java.lang.reflect.InvocationTargetException;
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.conf.Configuration;
29  import org.apache.hadoop.hbase.master.HMaster;
30  import org.apache.hadoop.hbase.regionserver.HRegionServer;
31  
32  /**
33   * Utility used running a cluster all in the one JVM.
34   */
35  public class JVMClusterUtil {
36    private static final Log LOG = LogFactory.getLog(JVMClusterUtil.class);
37  
38    /**
39     * Datastructure to hold RegionServer Thread and RegionServer instance
40     */
41    public static class RegionServerThread extends Thread {
42      private final HRegionServer regionServer;
43  
44      public RegionServerThread(final HRegionServer r, final int index) {
45        super(r, "RegionServer:" + index + ";" + r.getServerName());
46        this.regionServer = r;
47      }
48  
49      /** @return the region server */
50      public HRegionServer getRegionServer() {
51        return this.regionServer;
52      }
53  
54      /**
55       * Block until the region server has come online, indicating it is ready
56       * to be used.
57       */
58      public void waitForServerOnline() {
59        // The server is marked online after the init method completes inside of
60        // the HRS#run method.  HRS#init can fail for whatever region.  In those
61        // cases, we'll jump out of the run without setting online flag.  Check
62        // stopRequested so we don't wait here a flag that will never be flipped.
63        while (!this.regionServer.isOnline() &&
64            !this.regionServer.isStopped()) {
65          try {
66            Thread.sleep(1000);
67          } catch (InterruptedException e) {
68            // continue waiting
69          }
70        }
71      }
72    }
73  
74    /**
75     * Creates a {@link RegionServerThread}.
76     * Call 'start' on the returned thread to make it run.
77     * @param c Configuration to use.
78     * @param hrsc Class to create.
79     * @param index Used distinguishing the object returned.
80     * @throws IOException
81     * @return Region server added.
82     */
83    public static JVMClusterUtil.RegionServerThread createRegionServerThread(
84        final Configuration c, final Class<? extends HRegionServer> hrsc,
85        final int index)
86    throws IOException {
87      HRegionServer server;
88      try {
89        server = hrsc.getConstructor(Configuration.class).newInstance(c);
90      } catch (InvocationTargetException ite) {
91        Throwable target = ite.getTargetException();
92        throw new RuntimeException("Failed construction of RegionServer: " +
93          hrsc.toString() + ((target.getCause() != null)?
94            target.getCause().getMessage(): ""), target);
95      } catch (Exception e) {
96        IOException ioe = new IOException();
97        ioe.initCause(e);
98        throw ioe;
99      }
100     return new JVMClusterUtil.RegionServerThread(server, index);
101   }
102 
103 
104   /**
105    * Datastructure to hold Master Thread and Master instance
106    */
107   public static class MasterThread extends Thread {
108     private final HMaster master;
109 
110     public MasterThread(final HMaster m, final int index) {
111       super(m, "Master:" + index + ";" + m.getServerName());
112       this.master = m;
113     }
114 
115     /** @return the master */
116     public HMaster getMaster() {
117       return this.master;
118     }
119 
120     /**
121      * Block until the master has come online, indicating it is ready
122      * to be used.
123      */
124     public void waitForServerOnline() {
125       // The server is marked online after init begins but before race to become
126       // the active master.
127       while (!this.master.isMasterRunning() && !this.master.isStopped()) {
128         try {
129           Thread.sleep(1000);
130         } catch (InterruptedException e) {
131           // continue waiting
132         }
133       }
134     }
135   }
136 
137   /**
138    * Creates a {@link MasterThread}.
139    * Call 'start' on the returned thread to make it run.
140    * @param c Configuration to use.
141    * @param hmc Class to create.
142    * @param index Used distinguishing the object returned.
143    * @throws IOException
144    * @return Master added.
145    */
146   public static JVMClusterUtil.MasterThread createMasterThread(
147       final Configuration c, final Class<? extends HMaster> hmc,
148       final int index)
149   throws IOException {
150     HMaster server;
151     try {
152       server = hmc.getConstructor(Configuration.class).newInstance(c);
153     } catch (InvocationTargetException ite) {
154       Throwable target = ite.getTargetException();
155       throw new RuntimeException("Failed construction of RegionServer: " +
156         hmc.toString() + ((target.getCause() != null)?
157           target.getCause().getMessage(): ""), target);
158     } catch (Exception e) {
159       IOException ioe = new IOException();
160       ioe.initCause(e);
161       throw ioe;
162     }
163     return new JVMClusterUtil.MasterThread(server, index);
164   }
165 
166   /**
167    * Start the cluster.  Waits until there is a primary master and returns its
168    * address.
169    * @param masters
170    * @param regionservers
171    * @return Address to use contacting primary master.
172    */
173   public static String startup(final List<JVMClusterUtil.MasterThread> masters,
174       final List<JVMClusterUtil.RegionServerThread> regionservers) {
175     if (masters != null) {
176       for (JVMClusterUtil.MasterThread t : masters) {
177         t.start();
178       }
179     }
180     if (regionservers != null) {
181       for (JVMClusterUtil.RegionServerThread t: regionservers) {
182         t.start();
183       }
184     }
185     if (masters == null || masters.isEmpty()) {
186       return null;
187     }
188     // Wait for an active master
189     while (true) {
190       for (JVMClusterUtil.MasterThread t : masters) {
191         if (t.master.isActiveMaster()) {
192           return t.master.getMasterAddress().toString();
193         }
194       }
195       try {
196         Thread.sleep(1000);
197       } catch(InterruptedException e) {
198         // Keep waiting
199       }
200     }
201   }
202 
203   /**
204    * @param masters
205    * @param regionservers
206    */
207   public static void shutdown(final List<MasterThread> masters,
208       final List<RegionServerThread> regionservers) {
209     LOG.debug("Shutting down HBase Cluster");
210     if (masters != null) {
211       for (JVMClusterUtil.MasterThread t : masters) {
212         if (t.master.isActiveMaster()) {
213           t.master.shutdown();
214         } else {
215           t.master.stopMaster();
216         }
217       }
218     }
219     // regionServerThreads can never be null because they are initialized when
220     // the class is constructed.
221       for(Thread t: regionservers) {
222         if (t.isAlive()) {
223           try {
224             t.join();
225           } catch (InterruptedException e) {
226             // continue
227           }
228         }
229       }
230     if (masters != null) {
231       for (JVMClusterUtil.MasterThread t : masters) {
232         while (t.master.isAlive()) {
233           try {
234             // The below has been replaced to debug sometime hangs on end of
235             // tests.
236             // this.master.join():
237             Threads.threadDumpingIsAlive(t.master);
238           } catch(InterruptedException e) {
239             // continue
240           }
241         }
242       }
243     }
244     LOG.info("Shutdown of " +
245       ((masters != null) ? masters.size() : "0") + " master(s) and " +
246       ((regionservers != null) ? regionservers.size() : "0") +
247       " regionserver(s) complete");
248   }
249 }