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.IOException;
21 import java.util.Collection;
22 import java.util.HashSet;
23 import java.util.List;
24 import java.util.Set;
25 import java.util.concurrent.ConcurrentMap;
26 import java.util.concurrent.ExecutorService;
27 import java.util.concurrent.Future;
28 import java.util.concurrent.RejectedExecutionException;
29 import java.util.concurrent.SynchronousQueue;
30 import java.util.concurrent.ThreadPoolExecutor;
31 import java.util.concurrent.TimeUnit;
32
33 import org.apache.commons.logging.Log;
34 import org.apache.commons.logging.LogFactory;
35 import org.apache.hadoop.classification.InterfaceAudience;
36 import org.apache.hadoop.classification.InterfaceStability;
37 import org.apache.hadoop.hbase.DaemonThreadFactory;
38 import org.apache.hadoop.hbase.errorhandling.ForeignException;
39 import org.apache.hadoop.hbase.errorhandling.ForeignExceptionDispatcher;
40
41 import com.google.common.collect.MapMaker;
42
43
44
45
46
47
48
49 @InterfaceAudience.Public
50 @InterfaceStability.Evolving
51 public class ProcedureCoordinator {
52 private static final Log LOG = LogFactory.getLog(ProcedureCoordinator.class);
53
54 final static long TIMEOUT_MILLIS_DEFAULT = 60000;
55 final static long WAKE_MILLIS_DEFAULT = 500;
56
57 private final ProcedureCoordinatorRpcs rpcs;
58 private final ExecutorService pool;
59
60
61 private final ConcurrentMap<String, Procedure> procedures =
62 new MapMaker().concurrencyLevel(4).weakValues().makeMap();
63
64
65
66
67
68
69
70
71
72
73 public ProcedureCoordinator(ProcedureCoordinatorRpcs rpcs, ThreadPoolExecutor pool) {
74 this.rpcs = rpcs;
75 this.pool = pool;
76 this.rpcs.start(this);
77 }
78
79
80
81
82 public static ThreadPoolExecutor defaultPool(String coordName, long keepAliveTime, int opThreads,
83 long wakeFrequency) {
84 return new ThreadPoolExecutor(1, opThreads, keepAliveTime, TimeUnit.SECONDS,
85 new SynchronousQueue<Runnable>(),
86 new DaemonThreadFactory("(" + coordName + ")-proc-coordinator-pool"));
87 }
88
89
90
91
92
93 public void close() throws IOException {
94
95 pool.shutdownNow();
96 rpcs.close();
97 }
98
99
100
101
102
103
104
105
106
107
108 boolean submitProcedure(Procedure proc) {
109
110 if (proc == null) {
111 return false;
112 }
113 String procName = proc.getName();
114
115
116 synchronized (procedures) {
117 Procedure oldProc = procedures.get(procName);
118 if (oldProc != null) {
119
120 if (oldProc.completedLatch.getCount() != 0) {
121 LOG.warn("Procedure " + procName + " currently running. Rejecting new request");
122 return false;
123 }
124 LOG.debug("Procedure " + procName + " was in running list but was completed. Accepting new attempt.");
125 procedures.remove(procName);
126 }
127 }
128
129
130 Future<Void> f = null;
131 try {
132 synchronized (procedures) {
133 f = this.pool.submit(proc);
134
135 this.procedures.put(procName, proc);
136 }
137 return true;
138 } catch (RejectedExecutionException e) {
139 LOG.warn("Procedure " + procName + " rejected by execution pool. Propagating error and " +
140 "cancelling operation.", e);
141
142 proc.receive(new ForeignException(procName, e));
143
144
145 if (f != null) {
146 f.cancel(true);
147 }
148 }
149 return false;
150 }
151
152
153
154
155
156
157
158
159 void rpcConnectionFailure(final String message, final IOException cause) {
160 Collection<Procedure> toNotify = procedures.values();
161
162 for (Procedure proc : toNotify) {
163 if (proc == null) {
164 continue;
165 }
166
167 proc.receive(new ForeignException(proc.getName(), cause));
168 }
169 }
170
171
172
173
174
175
176 public void abortProcedure(String procName, ForeignException reason) {
177
178 synchronized(procedures) {
179 Procedure proc = procedures.get(procName);
180 if (proc == null) {
181 return;
182 }
183 proc.receive(reason);
184 }
185 }
186
187
188
189
190
191
192
193
194 Procedure createProcedure(ForeignExceptionDispatcher fed, String procName, byte[] procArgs,
195 List<String> expectedMembers) {
196
197 return new Procedure(this, fed, WAKE_MILLIS_DEFAULT, TIMEOUT_MILLIS_DEFAULT,
198 procName, procArgs, expectedMembers);
199 }
200
201
202
203
204
205
206
207
208
209 public Procedure startProcedure(ForeignExceptionDispatcher fed, String procName, byte[] procArgs,
210 List<String> expectedMembers) throws RejectedExecutionException {
211 Procedure proc = createProcedure(fed, procName, procArgs, expectedMembers);
212 if (!this.submitProcedure(proc)) {
213 LOG.error("Failed to submit procedure '" + procName + "'");
214 return null;
215 }
216 return proc;
217 }
218
219
220
221
222
223
224
225 void memberAcquiredBarrier(String procName, final String member) {
226 Procedure proc = procedures.get(procName);
227 if (proc != null) {
228 proc.barrierAcquiredByMember(member);
229 }
230 }
231
232
233
234
235
236
237
238 void memberFinishedBarrier(String procName, final String member) {
239 Procedure proc = procedures.get(procName);
240 if (proc != null) {
241 proc.barrierReleasedByMember(member);
242 }
243 }
244
245
246
247
248 ProcedureCoordinatorRpcs getRpcs() {
249 return rpcs;
250 }
251
252
253
254
255
256
257
258 public Procedure getProcedure(String name) {
259 return procedures.get(name);
260 }
261
262
263
264
265 public Set<String> getProcedureNames() {
266 return new HashSet<String>(procedures.keySet());
267 }
268 }