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.util.ArrayList;
25 import java.util.Arrays;
26
27 import org.apache.hadoop.hbase.classification.InterfaceAudience;
28 import org.apache.hadoop.hbase.classification.InterfaceStability;
29 import org.apache.hadoop.hbase.protobuf.generated.ProcedureProtos.StateMachineProcedureData;
30
31
32
33
34
35
36
37
38
39
40
41
42 @InterfaceAudience.Private
43 @InterfaceStability.Evolving
44 public abstract class StateMachineProcedure<TEnvironment, TState>
45 extends Procedure<TEnvironment> {
46 private Flow stateFlow = Flow.HAS_MORE_STATE;
47 private int stateCount = 0;
48 private int[] states = null;
49
50 private ArrayList<Procedure> subProcList = null;
51
52 protected enum Flow {
53 HAS_MORE_STATE,
54 NO_MORE_STATE,
55 }
56
57
58
59
60
61
62
63 protected abstract Flow executeFromState(TEnvironment env, TState state)
64 throws ProcedureYieldException, InterruptedException;
65
66
67
68
69
70
71 protected abstract void rollbackState(TEnvironment env, TState state)
72 throws IOException, InterruptedException;
73
74
75
76
77
78
79 protected abstract TState getState(int stateId);
80
81
82
83
84
85
86 protected abstract int getStateId(TState state);
87
88
89
90
91
92 protected abstract TState getInitialState();
93
94
95
96
97
98 protected void setNextState(final TState state) {
99 setNextState(getStateId(state));
100 }
101
102
103
104
105
106
107
108
109
110 protected boolean isYieldBeforeExecuteFromState(TEnvironment env, TState state) {
111 return false;
112 }
113
114
115
116
117
118 protected void addChildProcedure(Procedure... subProcedure) {
119 if (subProcList == null) {
120 subProcList = new ArrayList<Procedure>(subProcedure.length);
121 }
122 for (int i = 0; i < subProcedure.length; ++i) {
123 subProcList.add(subProcedure[i]);
124 }
125 }
126
127 @Override
128 protected Procedure[] execute(final TEnvironment env)
129 throws ProcedureYieldException, InterruptedException {
130 updateTimestamp();
131 try {
132 if (!hasMoreState()) return null;
133
134 TState state = getCurrentState();
135 if (stateCount == 0) {
136 setNextState(getStateId(state));
137 }
138
139 stateFlow = executeFromState(env, state);
140
141 if (subProcList != null && subProcList.size() != 0) {
142 Procedure[] subProcedures = subProcList.toArray(new Procedure[subProcList.size()]);
143 subProcList = null;
144 return subProcedures;
145 }
146
147 return (isWaiting() || isFailed() || !hasMoreState()) ? null : new Procedure[] {this};
148 } finally {
149 updateTimestamp();
150 }
151 }
152
153 @Override
154 protected void rollback(final TEnvironment env)
155 throws IOException, InterruptedException {
156 try {
157 updateTimestamp();
158 rollbackState(env, getCurrentState());
159 stateCount--;
160 } finally {
161 updateTimestamp();
162 }
163 }
164
165 @Override
166 protected boolean isYieldAfterExecutionStep(final TEnvironment env) {
167 return isYieldBeforeExecuteFromState(env, getCurrentState());
168 }
169
170 private boolean hasMoreState() {
171 return stateFlow != Flow.NO_MORE_STATE;
172 }
173
174 private TState getCurrentState() {
175 return stateCount > 0 ? getState(states[stateCount-1]) : getInitialState();
176 }
177
178
179
180
181
182 private void setNextState(final int stateId) {
183 if (states == null || states.length == stateCount) {
184 int newCapacity = stateCount + 8;
185 if (states != null) {
186 states = Arrays.copyOf(states, newCapacity);
187 } else {
188 states = new int[newCapacity];
189 }
190 }
191 states[stateCount++] = stateId;
192 }
193
194 @Override
195 protected void toStringState(StringBuilder builder) {
196 super.toStringState(builder);
197 if (!isFinished() && getCurrentState() != null) {
198 builder.append(":").append(getCurrentState());
199 }
200 }
201
202 @Override
203 protected void serializeStateData(final OutputStream stream) throws IOException {
204 StateMachineProcedureData.Builder data = StateMachineProcedureData.newBuilder();
205 for (int i = 0; i < stateCount; ++i) {
206 data.addState(states[i]);
207 }
208 data.build().writeDelimitedTo(stream);
209 }
210
211 @Override
212 protected void deserializeStateData(final InputStream stream) throws IOException {
213 StateMachineProcedureData data = StateMachineProcedureData.parseDelimitedFrom(stream);
214 stateCount = data.getStateCount();
215 if (stateCount > 0) {
216 states = new int[stateCount];
217 for (int i = 0; i < stateCount; ++i) {
218 states[i] = data.getState(i);
219 }
220 } else {
221 states = null;
222 }
223 }
224 }