1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.hadoop.hbase.util;
21
22 import java.util.concurrent.atomic.AtomicLong;
23
24
25
26
27
28 public class DrainBarrier {
29
30
31
32
33
34
35
36
37 private final AtomicLong valueAndFlags = new AtomicLong(inc(0));
38 private final static long DRAINING_FLAG = 0x1;
39 private final static int FLAG_BIT_COUNT = 1;
40
41
42
43
44
45 public boolean beginOp() {
46 long oldValAndFlags;
47 do {
48 oldValAndFlags = valueAndFlags.get();
49 if (isDraining(oldValAndFlags)) return false;
50 } while (!valueAndFlags.compareAndSet(oldValAndFlags, inc(oldValAndFlags)));
51 return true;
52 }
53
54
55
56
57 @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="NN_NAKED_NOTIFY",
58 justification="First, we do change the state before notify, 2nd, it doesn't even matter")
59 public void endOp() {
60 long oldValAndFlags;
61 do {
62 oldValAndFlags = valueAndFlags.get();
63 long unacceptableCount = isDraining(oldValAndFlags) ? 0 : 1;
64 if (getValue(oldValAndFlags) == unacceptableCount) {
65 throw new AssertionError("endOp called without corresponding beginOp call ("
66 + "the current count is " + unacceptableCount + ")");
67 }
68 } while (!valueAndFlags.compareAndSet(oldValAndFlags, dec(oldValAndFlags)));
69 if (getValue(oldValAndFlags) == 1) {
70 synchronized (this) { this.notifyAll(); }
71 }
72 }
73
74
75
76
77
78
79
80
81 public void stopAndDrainOps() throws InterruptedException {
82 stopAndDrainOps(true);
83 }
84
85
86
87
88
89
90 public void stopAndDrainOpsOnce() throws InterruptedException {
91 stopAndDrainOps(false);
92 }
93
94
95
96
97
98
99
100
101 @edu.umd.cs.findbugs.annotations.SuppressWarnings({"UW_UNCOND_WAIT", "WA_NOT_IN_LOOP"})
102 private void stopAndDrainOps(boolean ignoreRepeatedCalls) throws InterruptedException {
103 long oldValAndFlags;
104 do {
105 oldValAndFlags = valueAndFlags.get();
106 if (isDraining(oldValAndFlags)) {
107 if (ignoreRepeatedCalls) return;
108 throw new AssertionError("stopAndWaitForOpsOnce called more than once");
109 }
110 } while (!valueAndFlags.compareAndSet(oldValAndFlags, dec(oldValAndFlags) | DRAINING_FLAG));
111 if (getValue(oldValAndFlags) == 1) return;
112 synchronized (this) { this.wait(); }
113 }
114
115
116 private static final boolean isDraining(long valueAndFlags) {
117 return (valueAndFlags & DRAINING_FLAG) == DRAINING_FLAG;
118 }
119
120 private static final long getValue(long valueAndFlags) {
121 return valueAndFlags >> FLAG_BIT_COUNT;
122 }
123
124 private static final long inc(long valueAndFlags) {
125 return valueAndFlags + (1 << FLAG_BIT_COUNT);
126 }
127
128 private static final long dec(long valueAndFlags) {
129 return valueAndFlags - (1 << FLAG_BIT_COUNT);
130 }
131 }