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