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.executor;
21  
22  import java.util.Collections;
23  import java.util.HashMap;
24  import java.util.Map;
25  import java.util.Map.Entry;
26  import java.util.concurrent.BlockingQueue;
27  import java.util.concurrent.LinkedBlockingQueue;
28  import java.util.concurrent.ThreadPoolExecutor;
29  import java.util.concurrent.TimeUnit;
30  
31  import org.apache.commons.logging.Log;
32  import org.apache.commons.logging.LogFactory;
33  
34  /**
35   * This is a generic HBase executor service. This component abstract a
36   * threadpool, a queue to which jobs can be submitted and a Runnable that
37   * handles the object that is added to the queue.
38   *
39   * In order to create a new HBExecutorService, you need to do:
40   *   HBExecutorService.startExecutorService("myService");
41   *
42   * In order to use the service created above, you need to override the
43   * HBEventHandler class and create an event type that submits to this service.
44   *
45   */
46  public class HBaseExecutorService
47  {
48    private static final Log LOG = LogFactory.getLog(HBaseExecutorService.class);
49    // default number of threads in the pool
50    private int corePoolSize = 1;
51    // max number of threads - maximum concurrency
52    private int maximumPoolSize = 5;
53    // how long to retain excess threads
54    private long keepAliveTimeInMillis = 1000;
55    // the thread pool executor that services the requests
56    ThreadPoolExecutor threadPoolExecutor;
57    // work queue to use - unbounded queue
58    BlockingQueue<Runnable> workQueue = new LinkedBlockingQueue<Runnable>();
59    // name for this executor service
60    String name;
61    // hold the all the executors created in a map addressable by their names
62    static Map<String, HBaseExecutorService> executorServicesMap =
63      Collections.synchronizedMap(new HashMap<String, HBaseExecutorService>());
64  
65    
66    /**
67     * The following is a list of names for the various executor services in both 
68     * the master and the region server.
69     */
70    public enum HBaseExecutorServiceType {
71      NONE                       (-1),
72      MASTER_CLOSEREGION         (1),
73      MASTER_OPENREGION          (2);
74      
75      private final int value;
76      
77      HBaseExecutorServiceType(int intValue) {
78        this.value = intValue;
79      }
80      
81      public void startExecutorService(String serverName) {
82        // if this is NONE then there is no executor to start
83        if(value == NONE.value) {
84          throw new RuntimeException("Cannot start NONE executor type.");
85        }
86        String name = getExecutorName(serverName);
87        if(HBaseExecutorService.isExecutorServiceRunning(name)) {
88          LOG.debug("Executor service " + toString() + " already running on " + serverName);
89          return;
90        }
91        HBaseExecutorService.startExecutorService(name);
92      }
93      
94      public HBaseExecutorService getExecutor(String serverName) {
95        // if this is NONE then there is no executor
96        if(value == NONE.value) {
97          return null;
98        }
99        return HBaseExecutorService.getExecutorService(getExecutorName(serverName));
100     }
101     
102     public String getExecutorName(String serverName) {
103       // if this is NONE then there is no executor
104       if(value == NONE.value) {
105         return null;
106       }
107       return (this.toString() + "-" + serverName);
108     }
109   }
110 
111 
112 
113   /**
114    * Start an executor service with a given name. If there was a service already
115    * started with the same name, this throws a RuntimeException.
116    * @param name Name of the service to start.
117    */
118   public static void startExecutorService(String name) {
119     if(executorServicesMap.get(name) != null) {
120       throw new RuntimeException("An executor service with the name " + name + " is already running!");
121     }
122     HBaseExecutorService hbes = new HBaseExecutorService(name);
123     executorServicesMap.put(name, hbes);
124     LOG.debug("Starting executor service: " + name);
125   }
126   
127   public static boolean isExecutorServiceRunning(String name) {
128     return (executorServicesMap.containsKey(name));
129   }
130 
131   /**
132    * This method is an accessor for all the HBExecutorServices running so far
133    * addressable by name. If there is no such service, then it returns null.
134    */
135   public static HBaseExecutorService getExecutorService(String name) {
136     HBaseExecutorService executor = executorServicesMap.get(name);
137     if(executor == null) {
138       LOG.debug("Executor service [" + name + "] not found.");
139     }
140     return executor;
141   }
142   
143   public static void shutdown() {
144     for(Entry<String, HBaseExecutorService> entry : executorServicesMap.entrySet()) {
145       entry.getValue().threadPoolExecutor.shutdown();
146     }
147     executorServicesMap.clear();
148   }
149 
150   protected HBaseExecutorService(String name) {
151     this.name = name;
152     // create the thread pool executor
153     threadPoolExecutor = new ThreadPoolExecutor(
154                                 corePoolSize,
155                                 maximumPoolSize,
156                                 keepAliveTimeInMillis,
157                                 TimeUnit.MILLISECONDS,
158                                 workQueue
159                                 );
160     // name the threads for this threadpool
161     threadPoolExecutor.setThreadFactory(new NamedThreadFactory(name));
162   }
163 
164   /**
165    * Submit the event to the queue for handling.
166    * @param event
167    */
168   public void submit(Runnable event) {
169     threadPoolExecutor.execute(event);
170   }
171 }