1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.hadoop.hbase.procedure2;
20
21 import java.io.IOException;
22 import java.io.InputStream;
23 import java.io.OutputStream;
24 import java.lang.reflect.Constructor;
25 import java.lang.reflect.Modifier;
26 import java.util.Arrays;
27 import java.util.List;
28 import java.util.Map;
29
30 import org.apache.hadoop.hbase.ProcedureInfo;
31 import org.apache.hadoop.hbase.classification.InterfaceAudience;
32 import org.apache.hadoop.hbase.classification.InterfaceStability;
33 import org.apache.hadoop.hbase.exceptions.TimeoutIOException;
34 import org.apache.hadoop.hbase.procedure2.util.StringUtils;
35 import org.apache.hadoop.hbase.protobuf.generated.ProcedureProtos;
36 import org.apache.hadoop.hbase.protobuf.generated.ProcedureProtos.ProcedureState;
37 import org.apache.hadoop.hbase.util.ByteStringer;
38 import org.apache.hadoop.hbase.util.EnvironmentEdgeManager;
39
40 import com.google.common.annotations.VisibleForTesting;
41 import com.google.common.base.Preconditions;
42 import com.google.protobuf.ByteString;
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63 @InterfaceAudience.Private
64 @InterfaceStability.Evolving
65 public abstract class Procedure<TEnvironment> implements Comparable<Procedure> {
66
67 private String owner = null;
68 private Long parentProcId = null;
69 private Long procId = null;
70 private long startTime;
71
72
73 private ProcedureState state = ProcedureState.INITIALIZING;
74 private Integer timeout = null;
75 private int[] stackIndexes = null;
76 private int childrenLatch = 0;
77 private long lastUpdate;
78
79 private RemoteProcedureException exception = null;
80 private byte[] result = null;
81
82
83
84
85
86
87
88 protected abstract Procedure[] execute(TEnvironment env)
89 throws ProcedureYieldException;
90
91
92
93
94
95
96
97
98
99
100 protected abstract void rollback(TEnvironment env)
101 throws IOException;
102
103
104
105
106
107
108
109
110
111
112
113
114
115 protected abstract boolean abort(TEnvironment env);
116
117
118
119
120
121
122 protected abstract void serializeStateData(final OutputStream stream)
123 throws IOException;
124
125
126
127
128
129
130 protected abstract void deserializeStateData(final InputStream stream)
131 throws IOException;
132
133
134
135
136
137
138
139
140
141
142 protected boolean acquireLock(final TEnvironment env) {
143 return true;
144 }
145
146
147
148
149 protected void releaseLock(final TEnvironment env) {
150
151 }
152
153
154
155
156
157
158
159 protected void beforeReplay(final TEnvironment env) {
160
161 }
162
163
164
165
166
167
168 protected void completionCleanup(final TEnvironment env) {
169
170 }
171
172 @Override
173 public String toString() {
174
175 return toStringSimpleSB().toString();
176 }
177
178
179
180
181
182
183 protected StringBuilder toStringSimpleSB() {
184 StringBuilder sb = new StringBuilder();
185 toStringClassDetails(sb);
186
187 if (procId != null) {
188 sb.append(" id=");
189 sb.append(getProcId());
190 }
191
192 if (hasParent()) {
193 sb.append(" parent=");
194 sb.append(getParentProcId());
195 }
196
197 if (hasOwner()) {
198 sb.append(" owner=");
199 sb.append(getOwner());
200 }
201
202 sb.append(" state=");
203 sb.append(getState());
204
205 return sb;
206 }
207
208
209
210
211
212 public String toStringDetails() {
213 StringBuilder sb = toStringSimpleSB();
214
215 sb.append(" startTime=");
216 sb.append(getStartTime());
217
218 sb.append(" lastUpdate=");
219 sb.append(getLastUpdate());
220
221 if (stackIndexes != null) {
222 sb.append("\n");
223 sb.append("stackIndexes=");
224 sb.append(Arrays.toString(getStackIndexes()));
225 }
226
227 return sb.toString();
228 }
229
230 protected String toStringClass() {
231 StringBuilder sb = new StringBuilder();
232 toStringClassDetails(sb);
233
234 return sb.toString();
235 }
236
237
238
239
240
241
242 protected void toStringClassDetails(StringBuilder builder) {
243 builder.append(getClass().getName());
244 }
245
246
247
248
249 public byte[] getResult() {
250 return result;
251 }
252
253
254
255
256
257 protected void setResult(final byte[] result) {
258 this.result = result;
259 }
260
261 public long getProcId() {
262 return procId;
263 }
264
265 public boolean hasParent() {
266 return parentProcId != null;
267 }
268
269 public boolean hasException() {
270 return exception != null;
271 }
272
273 public boolean hasTimeout() {
274 return timeout != null;
275 }
276
277 public long getParentProcId() {
278 return parentProcId;
279 }
280
281
282
283
284
285 public synchronized boolean isFailed() {
286 return exception != null || state == ProcedureState.ROLLEDBACK;
287 }
288
289
290
291
292 public synchronized boolean isSuccess() {
293 return state == ProcedureState.FINISHED && exception == null;
294 }
295
296
297
298
299
300 public synchronized boolean isFinished() {
301 switch (state) {
302 case ROLLEDBACK:
303 return true;
304 case FINISHED:
305 return exception == null;
306 default:
307 break;
308 }
309 return false;
310 }
311
312
313
314
315 public synchronized boolean isWaiting() {
316 switch (state) {
317 case WAITING:
318 case WAITING_TIMEOUT:
319 return true;
320 default:
321 break;
322 }
323 return false;
324 }
325
326 public synchronized RemoteProcedureException getException() {
327 return exception;
328 }
329
330 public long getStartTime() {
331 return startTime;
332 }
333
334 public synchronized long getLastUpdate() {
335 return lastUpdate;
336 }
337
338 public synchronized long elapsedTime() {
339 return lastUpdate - startTime;
340 }
341
342
343
344
345 protected void setTimeout(final int timeout) {
346 this.timeout = timeout;
347 }
348
349
350
351
352 public int getTimeout() {
353 return timeout;
354 }
355
356
357
358
359 public long getTimeRemaining() {
360 return Math.max(0, timeout - (EnvironmentEdgeManager.currentTime() - startTime));
361 }
362
363 @VisibleForTesting
364 @InterfaceAudience.Private
365 public void setOwner(final String owner) {
366 this.owner = StringUtils.isEmpty(owner) ? null : owner;
367 }
368
369 public String getOwner() {
370 return owner;
371 }
372
373 public boolean hasOwner() {
374 return owner != null;
375 }
376
377 @VisibleForTesting
378 @InterfaceAudience.Private
379 protected synchronized void setState(final ProcedureState state) {
380 this.state = state;
381 updateTimestamp();
382 }
383
384 @InterfaceAudience.Private
385 protected synchronized ProcedureState getState() {
386 return state;
387 }
388
389 protected void setFailure(final String source, final Throwable cause) {
390 setFailure(new RemoteProcedureException(source, cause));
391 }
392
393 protected synchronized void setFailure(final RemoteProcedureException exception) {
394 this.exception = exception;
395 if (!isFinished()) {
396 setState(ProcedureState.FINISHED);
397 }
398 }
399
400 protected void setAbortFailure(final String source, final String msg) {
401 setFailure(source, new ProcedureAbortedException(msg));
402 }
403
404 @InterfaceAudience.Private
405 protected synchronized boolean setTimeoutFailure() {
406 if (state == ProcedureState.WAITING_TIMEOUT) {
407 long timeDiff = EnvironmentEdgeManager.currentTime() - lastUpdate;
408 setFailure("ProcedureExecutor", new TimeoutIOException(
409 "Operation timed out after " + StringUtils.humanTimeDiff(timeDiff)));
410 return true;
411 }
412 return false;
413 }
414
415
416
417
418 @VisibleForTesting
419 @InterfaceAudience.Private
420 protected void setProcId(final long procId) {
421 this.procId = procId;
422 this.startTime = EnvironmentEdgeManager.currentTime();
423 setState(ProcedureState.RUNNABLE);
424 }
425
426
427
428
429 @InterfaceAudience.Private
430 protected void setParentProcId(final long parentProcId) {
431 this.parentProcId = parentProcId;
432 }
433
434
435
436
437
438 @InterfaceAudience.Private
439 protected Procedure[] doExecute(final TEnvironment env)
440 throws ProcedureYieldException {
441 try {
442 updateTimestamp();
443 return execute(env);
444 } finally {
445 updateTimestamp();
446 }
447 }
448
449
450
451
452
453 @InterfaceAudience.Private
454 protected void doRollback(final TEnvironment env) throws IOException {
455 try {
456 updateTimestamp();
457 rollback(env);
458 } finally {
459 updateTimestamp();
460 }
461 }
462
463
464
465
466
467 @InterfaceAudience.Private
468 protected void setStartTime(final long startTime) {
469 this.startTime = startTime;
470 }
471
472
473
474
475
476 private synchronized void setLastUpdate(final long lastUpdate) {
477 this.lastUpdate = lastUpdate;
478 }
479
480 protected synchronized void updateTimestamp() {
481 this.lastUpdate = EnvironmentEdgeManager.currentTime();
482 }
483
484
485
486
487 @InterfaceAudience.Private
488 protected synchronized void setChildrenLatch(final int numChildren) {
489 this.childrenLatch = numChildren;
490 }
491
492
493
494
495 @InterfaceAudience.Private
496 protected synchronized void incChildrenLatch() {
497
498 this.childrenLatch++;
499 }
500
501
502
503
504
505 @InterfaceAudience.Private
506 protected synchronized boolean childrenCountDown() {
507 assert childrenLatch > 0;
508 return --childrenLatch == 0;
509 }
510
511
512
513
514
515 @InterfaceAudience.Private
516 protected synchronized void addStackIndex(final int index) {
517 if (stackIndexes == null) {
518 stackIndexes = new int[] { index };
519 } else {
520 int count = stackIndexes.length;
521 stackIndexes = Arrays.copyOf(stackIndexes, count + 1);
522 stackIndexes[count] = index;
523 }
524 }
525
526 @InterfaceAudience.Private
527 protected synchronized boolean removeStackIndex() {
528 if (stackIndexes.length > 1) {
529 stackIndexes = Arrays.copyOf(stackIndexes, stackIndexes.length - 1);
530 return false;
531 } else {
532 stackIndexes = null;
533 return true;
534 }
535 }
536
537
538
539
540
541 @InterfaceAudience.Private
542 protected synchronized void setStackIndexes(final List<Integer> stackIndexes) {
543 this.stackIndexes = new int[stackIndexes.size()];
544 for (int i = 0; i < this.stackIndexes.length; ++i) {
545 this.stackIndexes[i] = stackIndexes.get(i);
546 }
547 }
548
549 @InterfaceAudience.Private
550 protected synchronized boolean wasExecuted() {
551 return stackIndexes != null;
552 }
553
554 @InterfaceAudience.Private
555 protected synchronized int[] getStackIndexes() {
556 return stackIndexes;
557 }
558
559 @Override
560 public int compareTo(final Procedure other) {
561 long diff = getProcId() - other.getProcId();
562 return (diff < 0) ? -1 : (diff > 0) ? 1 : 0;
563 }
564
565
566
567
568 @InterfaceAudience.Private
569 protected static Long getRootProcedureId(final Map<Long, Procedure> procedures, Procedure proc) {
570 while (proc.hasParent()) {
571 proc = procedures.get(proc.getParentProcId());
572 if (proc == null) return null;
573 }
574 return proc.getProcId();
575 }
576
577 protected static Procedure newInstance(final String className) throws IOException {
578 try {
579 Class<?> clazz = Class.forName(className);
580 if (!Modifier.isPublic(clazz.getModifiers())) {
581 throw new Exception("the " + clazz + " class is not public");
582 }
583
584 Constructor<?> ctor = clazz.getConstructor();
585 assert ctor != null : "no constructor found";
586 if (!Modifier.isPublic(ctor.getModifiers())) {
587 throw new Exception("the " + clazz + " constructor is not public");
588 }
589 return (Procedure)ctor.newInstance();
590 } catch (Exception e) {
591 throw new IOException("The procedure class " + className +
592 " must be accessible and have an empty constructor", e);
593 }
594 }
595
596 protected static void validateClass(final Procedure proc) throws IOException {
597 try {
598 Class<?> clazz = proc.getClass();
599 if (!Modifier.isPublic(clazz.getModifiers())) {
600 throw new Exception("the " + clazz + " class is not public");
601 }
602
603 Constructor<?> ctor = clazz.getConstructor();
604 assert ctor != null;
605 if (!Modifier.isPublic(ctor.getModifiers())) {
606 throw new Exception("the " + clazz + " constructor is not public");
607 }
608 } catch (Exception e) {
609 throw new IOException("The procedure class " + proc.getClass().getName() +
610 " must be accessible and have an empty constructor", e);
611 }
612 }
613
614
615
616
617 @InterfaceAudience.Private
618 public static ProcedureInfo createProcedureInfo(final Procedure proc) {
619 RemoteProcedureException exception = proc.hasException() ? proc.getException() : null;
620 return new ProcedureInfo(
621 proc.getProcId(),
622 proc.toStringClass(),
623 proc.getOwner(),
624 proc.getState(),
625 proc.hasParent() ? proc.getParentProcId() : -1,
626 exception != null ?
627 RemoteProcedureException.toProto(exception.getSource(), exception.getCause()) : null,
628 proc.getLastUpdate(),
629 proc.getStartTime(),
630 proc.getResult());
631 }
632
633
634
635
636
637 @InterfaceAudience.Private
638 public static ProcedureProtos.Procedure convert(final Procedure proc)
639 throws IOException {
640 Preconditions.checkArgument(proc != null);
641 validateClass(proc);
642
643 ProcedureProtos.Procedure.Builder builder = ProcedureProtos.Procedure.newBuilder()
644 .setClassName(proc.getClass().getName())
645 .setProcId(proc.getProcId())
646 .setState(proc.getState())
647 .setStartTime(proc.getStartTime())
648 .setLastUpdate(proc.getLastUpdate());
649
650 if (proc.hasParent()) {
651 builder.setParentId(proc.getParentProcId());
652 }
653
654 if (proc.hasTimeout()) {
655 builder.setTimeout(proc.getTimeout());
656 }
657
658 if (proc.hasOwner()) {
659 builder.setOwner(proc.getOwner());
660 }
661
662 int[] stackIds = proc.getStackIndexes();
663 if (stackIds != null) {
664 for (int i = 0; i < stackIds.length; ++i) {
665 builder.addStackId(stackIds[i]);
666 }
667 }
668
669 if (proc.hasException()) {
670 RemoteProcedureException exception = proc.getException();
671 builder.setException(
672 RemoteProcedureException.toProto(exception.getSource(), exception.getCause()));
673 }
674
675 byte[] result = proc.getResult();
676 if (result != null) {
677 builder.setResult(ByteStringer.wrap(result));
678 }
679
680 ByteString.Output stateStream = ByteString.newOutput();
681 proc.serializeStateData(stateStream);
682 if (stateStream.size() > 0) {
683 builder.setStateData(stateStream.toByteString());
684 }
685
686 return builder.build();
687 }
688
689
690
691
692
693
694
695
696
697
698 @InterfaceAudience.Private
699 public static Procedure convert(final ProcedureProtos.Procedure proto)
700 throws IOException {
701
702 Procedure proc = Procedure.newInstance(proto.getClassName());
703
704
705 proc.setProcId(proto.getProcId());
706 proc.setState(proto.getState());
707 proc.setStartTime(proto.getStartTime());
708 proc.setLastUpdate(proto.getLastUpdate());
709
710 if (proto.hasParentId()) {
711 proc.setParentProcId(proto.getParentId());
712 }
713
714 if (proto.hasOwner()) {
715 proc.setOwner(proto.getOwner());
716 }
717
718 if (proto.hasTimeout()) {
719 proc.setTimeout(proto.getTimeout());
720 }
721
722 if (proto.getStackIdCount() > 0) {
723 proc.setStackIndexes(proto.getStackIdList());
724 }
725
726 if (proto.hasException()) {
727 assert proc.getState() == ProcedureState.FINISHED ||
728 proc.getState() == ProcedureState.ROLLEDBACK :
729 "The procedure must be failed (waiting to rollback) or rolledback";
730 proc.setFailure(RemoteProcedureException.fromProto(proto.getException()));
731 }
732
733 if (proto.hasResult()) {
734 proc.setResult(proto.getResult().toByteArray());
735 }
736
737
738 proc.deserializeStateData(proto.getStateData().newInput());
739
740 return proc;
741 }
742 }