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.security.PrivilegedExceptionAction;
24  import java.util.List;
25  import com.google.common.base.Throwables;
26  
27  import org.apache.commons.logging.Log;
28  import org.apache.commons.logging.LogFactory;
29  import org.apache.hadoop.conf.Configuration;
30  import org.apache.hadoop.fs.FileSystem;
31  import org.apache.hadoop.hbase.master.HMaster;
32  import org.apache.hadoop.hbase.regionserver.HRegionServer;
33  import org.apache.hadoop.hdfs.DistributedFileSystem;
34  import org.apache.hadoop.security.UserGroupInformation;
35  
36  /**
37   * Utility used running a cluster all in the one JVM.
38   */
39  public class JVMClusterUtil {
40    private static final Log LOG = LogFactory.getLog(JVMClusterUtil.class);
41  
42    private final static UserGroupInformation UGI;
43    static {
44      try {
45        UGI = UserGroupInformation.getCurrentUser();
46      } catch (IOException ioe) {
47        throw new RuntimeException("Error getting current user", ioe);
48      }
49    }
50  
51    private static UserGroupInformation getDifferentUser(final Configuration c,
52        int index)
53    throws IOException {
54      FileSystem currentfs = FileSystem.get(c);
55      if (!(currentfs instanceof DistributedFileSystem)) return UGI;
56      // Else distributed filesystem.  Make a new instance per daemon.  Below
57      // code is taken from the AppendTestUtil over in hdfs.
58      String username = UGI.getShortUserName() + ".hrs." + index;
59      return UserGroupInformation.createUserForTesting(username,
60          new String[]{"supergroup"});
61    }
62  
63    /**
64     * Datastructure to hold RegionServer Thread and RegionServer instance
65     */
66    public static class RegionServerThread extends Thread {
67      private final HRegionServer regionServer;
68      private final UserGroupInformation serverUser;
69  
70      public RegionServerThread(final HRegionServer r,
71          final UserGroupInformation ugi, final int index) {
72        super(r, "RegionServer:" + index);
73        this.regionServer = r;
74        this.serverUser = ugi;
75      }
76  
77      /** @return the region server */
78      public HRegionServer getRegionServer() {
79        return this.regionServer;
80      }
81  
82      /**
83       * Block until the region server has come online, indicating it is ready
84       * to be used.
85       */
86      public void waitForServerOnline() {
87        // The server is marked online after the init method completes inside of
88        // the HRS#run method.  HRS#init can fail for whatever region.  In those
89        // cases, we'll jump out of the run without setting online flag.  Check
90        // stopRequested so we don't wait here a flag that will never be flipped.
91        while (!this.regionServer.isOnline() &&
92            !this.regionServer.isStopRequested()) {
93          try {
94            Thread.sleep(1000);
95          } catch (InterruptedException e) {
96            // continue waiting
97          }
98        }
99      }
100   }
101 
102   /**
103    * Creates a {@link RegionServerThread}.
104    * Call 'start' on the returned thread to make it run.
105    * @param c Configuration to use.
106    * @param hrsc Class to create.
107    * @param index Used distingushing the object returned.
108    * @throws IOException
109    * @return Region server added.
110    */
111   public static JVMClusterUtil.RegionServerThread createRegionServerThread(final Configuration c,
112     final Class<? extends HRegionServer> hrsc, final int index)
113   throws IOException {
114     HRegionServer server;
115     UserGroupInformation serverUser;
116     if (UserGroupInformation.isSecurityEnabled()) {
117       serverUser = HRegionServer.loginFromKeytab(c);
118     } else {
119       serverUser = getDifferentUser(c, index);
120     }
121 
122     try {
123       server = serverUser.doAs( new PrivilegedExceptionAction<HRegionServer>(){
124         public HRegionServer run() throws Exception {
125           return hrsc.getConstructor(Configuration.class).newInstance(c);
126         }
127       });
128     } catch (Exception e) {
129       IOException ioe = new IOException();
130       ioe.initCause(e);
131       throw ioe;
132     }
133     return new JVMClusterUtil.RegionServerThread(server, serverUser, index);
134   }
135 
136   /**
137    * Start the cluster.
138    * @param m
139    * @param regionServers
140    * @return Address to use contacting master.
141    */
142   public static String startup(final HMaster m,
143       final List<JVMClusterUtil.RegionServerThread> regionservers) {
144     if (m != null) m.start();
145     if (regionservers != null) {
146       for (JVMClusterUtil.RegionServerThread t: regionservers) {
147         t.start();
148       }
149     }
150     return m == null? null: m.getMasterAddress().toString();
151   }
152 
153   /**
154    * @param master
155    * @param regionservers
156    */
157   public static void shutdown(final HMaster master,
158       final List<RegionServerThread> regionservers) {
159     LOG.debug("Shutting down HBase Cluster");
160     if (master != null) {
161       master.shutdown();
162     }
163     // regionServerThreads can never be null because they are initialized when
164     // the class is constructed.
165       for(Thread t: regionservers) {
166         if (t.isAlive()) {
167           try {
168             t.join();
169           } catch (InterruptedException e) {
170             // continue
171           }
172         }
173       }
174     if (master != null) {
175       while (master.isAlive()) {
176         try {
177           // The below has been replaced to debug sometime hangs on end of
178           // tests.
179           // this.master.join():
180           Threads.threadDumpingIsAlive(master);
181         } catch(InterruptedException e) {
182           // continue
183         }
184       }
185     }
186     LOG.info("Shutdown " +
187       ((regionservers != null)? master.getName(): "0 masters") +
188       " " + regionservers.size() + " region server(s)");
189   }
190 }