1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.hadoop.hbase.procedure;
19
20 import java.io.Closeable;
21 import java.io.IOException;
22 import java.util.Collection;
23 import java.util.concurrent.ConcurrentMap;
24 import java.util.concurrent.ExecutorService;
25 import java.util.concurrent.Future;
26 import java.util.concurrent.RejectedExecutionException;
27 import java.util.concurrent.SynchronousQueue;
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 import org.apache.hadoop.classification.InterfaceAudience;
34 import org.apache.hadoop.classification.InterfaceStability;
35 import org.apache.hadoop.hbase.DaemonThreadFactory;
36 import org.apache.hadoop.hbase.errorhandling.ForeignException;
37
38 import com.google.common.collect.MapMaker;
39
40
41
42
43
44
45
46
47
48
49 @InterfaceAudience.Public
50 @InterfaceStability.Evolving
51 public class ProcedureMember implements Closeable {
52 private static final Log LOG = LogFactory.getLog(ProcedureMember.class);
53
54 private final SubprocedureFactory builder;
55 private final ProcedureMemberRpcs rpcs;
56
57 private final ConcurrentMap<String,Subprocedure> subprocs =
58 new MapMaker().concurrencyLevel(4).weakValues().makeMap();
59 private final ExecutorService pool;
60
61
62
63
64
65
66
67
68 public ProcedureMember(ProcedureMemberRpcs rpcs, ThreadPoolExecutor pool,
69 SubprocedureFactory factory) {
70 this.pool = pool;
71 this.rpcs = rpcs;
72 this.builder = factory;
73 }
74
75 public static ThreadPoolExecutor defaultPool(long wakeFrequency, long keepAlive,
76 int procThreads, String memberName) {
77 return new ThreadPoolExecutor(1, procThreads, keepAlive, TimeUnit.SECONDS,
78 new SynchronousQueue<Runnable>(),
79 new DaemonThreadFactory("member: '" + memberName + "' subprocedure-pool"));
80 }
81
82
83
84
85
86
87 ProcedureMemberRpcs getRpcs() {
88 return rpcs;
89 }
90
91
92
93
94
95
96
97
98
99
100 public Subprocedure createSubprocedure(String opName, byte[] data) {
101 return builder.buildSubprocedure(opName, data);
102 }
103
104
105
106
107
108
109
110
111 public boolean submitSubprocedure(Subprocedure subproc) {
112
113 if (subproc == null) {
114 LOG.warn("Submitted null subprocedure, nothing to run here.");
115 return false;
116 }
117
118 String procName = subproc.getName();
119 if (procName == null || procName.length() == 0) {
120 LOG.error("Subproc name cannot be null or the empty string");
121 return false;
122 }
123
124
125 Subprocedure rsub;
126 synchronized (subprocs) {
127 rsub = subprocs.get(procName);
128 }
129 if (rsub != null) {
130 if (!rsub.isComplete()) {
131 LOG.error("Subproc '" + procName + "' is already running. Bailing out");
132 return false;
133 }
134 LOG.warn("A completed old subproc " + procName + " is still present, removing");
135 subprocs.remove(procName);
136 }
137
138 LOG.debug("Submitting new Subprocedure:" + procName);
139
140
141 Future<Void> future = null;
142 try {
143 future = this.pool.submit(subproc);
144 synchronized (subprocs) {
145 subprocs.put(procName, subproc);
146 }
147 return true;
148 } catch (RejectedExecutionException e) {
149
150 String msg = "Subprocedure pool is full!";
151 subproc.cancel(msg, e.getCause());
152
153
154 if (future != null) {
155 future.cancel(true);
156 }
157 }
158
159 LOG.error("Failed to start subprocedure '" + procName + "'");
160 return false;
161 }
162
163
164
165
166
167 public void receivedReachedGlobalBarrier(String procName) {
168 Subprocedure subproc = subprocs.get(procName);
169 if (subproc == null) {
170 LOG.warn("Unexpected reached glabal barrier message for Sub-Procedure '" + procName + "'");
171 return;
172 }
173 subproc.receiveReachedGlobalBarrier();
174 }
175
176
177
178
179 @Override
180 public void close() throws IOException {
181
182 pool.shutdownNow();
183 }
184
185
186
187
188
189
190
191 boolean closeAndWait(long timeoutMs) throws InterruptedException {
192 pool.shutdown();
193 return pool.awaitTermination(timeoutMs, TimeUnit.MILLISECONDS);
194 }
195
196
197
198
199
200
201
202
203
204
205
206 public void controllerConnectionFailure(final String message, final IOException cause) {
207 Collection<Subprocedure> toNotify = subprocs.values();
208 LOG.error(message, cause);
209 for (Subprocedure sub : toNotify) {
210
211 sub.cancel(message, cause);
212 }
213 }
214
215
216
217
218
219
220 public void receiveAbortProcedure(String procName, ForeignException ee) {
221 LOG.debug("Request received to abort procedure " + procName, ee);
222
223 Subprocedure sub = subprocs.get(procName);
224 if (sub == null) {
225 LOG.info("Received abort on procedure with no local subprocedure " + procName +
226 ", ignoring it.", ee);
227 return;
228 }
229 LOG.error("Propagating foreign exception to subprocedure " + sub.getName(), ee);
230 sub.monitor.receive(ee);
231 }
232 }