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