View Javadoc

1   /**
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  
19  package org.apache.hadoop.hbase;
20  
21  import java.io.IOException;
22  
23  import org.apache.hadoop.hbase.classification.InterfaceAudience;
24  import org.apache.hadoop.hbase.classification.InterfaceStability;
25  import org.apache.hadoop.hbase.protobuf.generated.ErrorHandlingProtos.ForeignExceptionMessage;
26  import org.apache.hadoop.hbase.protobuf.generated.ProcedureProtos;
27  import org.apache.hadoop.hbase.protobuf.generated.ProcedureProtos.ProcedureState;
28  import org.apache.hadoop.hbase.security.User;
29  import org.apache.hadoop.hbase.util.ByteStringer;
30  import org.apache.hadoop.hbase.util.EnvironmentEdgeManager;
31  import org.apache.hadoop.hbase.util.ForeignExceptionUtil;
32  import org.apache.hadoop.hbase.util.NonceKey;
33  import org.apache.hadoop.util.StringUtils;
34  
35  /**
36   * Procedure information
37   */
38  @InterfaceAudience.Public
39  @InterfaceStability.Evolving
40  public class ProcedureInfo {
41    private final long procId;
42    private final String procName;
43    private final String procOwner;
44    private final ProcedureState procState;
45    private final long parentId;
46    private final NonceKey nonceKey;
47    private final ForeignExceptionMessage exception;
48    private final long lastUpdate;
49    private final long startTime;
50    private final byte[] result;
51  
52    private long clientAckTime = -1;
53  
54    @InterfaceAudience.Private
55    public ProcedureInfo(
56        final long procId,
57        final String procName,
58        final String procOwner,
59        final ProcedureState procState,
60        final long parentId,
61        final NonceKey nonceKey,
62        final ForeignExceptionMessage exception,
63        final long lastUpdate,
64        final long startTime,
65        final byte[] result) {
66      this.procId = procId;
67      this.procName = procName;
68      this.procOwner = procOwner;
69      this.procState = procState;
70      this.parentId = parentId;
71      this.nonceKey = nonceKey;
72      this.lastUpdate = lastUpdate;
73      this.startTime = startTime;
74  
75      // If the procedure is completed, we should treat exception and result differently
76      this.exception = exception;
77      this.result = result;
78    }
79  
80    public ProcedureInfo clone() {
81      return new ProcedureInfo(procId, procName, procOwner, procState, parentId, nonceKey,
82        exception, lastUpdate, startTime, result);
83    }
84  
85    @Override
86    public String toString() {
87      StringBuilder sb = new StringBuilder();
88      sb.append("Procedure=");
89      sb.append(procName);
90      sb.append(" (id=");
91      sb.append(procId);
92      if (hasParentId()) {
93        sb.append(", parent=");
94        sb.append(parentId);
95      }
96      if (hasOwner()) {
97        sb.append(", owner=");
98        sb.append(procOwner);
99      }
100     sb.append(", state=");
101     sb.append(procState);
102 
103     long now = EnvironmentEdgeManager.currentTime();
104     sb.append(", startTime=");
105     sb.append(StringUtils.formatTime(now - startTime));
106     sb.append(" ago, lastUpdate=");
107     sb.append(StringUtils.formatTime(now - startTime));
108     sb.append(" ago");
109 
110     if (isFailed()) {
111       sb.append(", exception=\"");
112       sb.append(getExceptionMessage());
113       sb.append("\"");
114     }
115     sb.append(")");
116     return sb.toString();
117   }
118 
119   public long getProcId() {
120     return procId;
121   }
122 
123   public String getProcName() {
124     return procName;
125   }
126 
127   private boolean hasOwner() {
128     return procOwner != null;
129   }
130 
131   public String getProcOwner() {
132     return procOwner;
133   }
134 
135   public ProcedureState getProcState() {
136     return procState;
137   }
138 
139   public boolean hasParentId() {
140     return (parentId != -1);
141   }
142 
143   public long getParentId() {
144     return parentId;
145   }
146 
147   public NonceKey getNonceKey() {
148     return nonceKey;
149   }
150 
151   public boolean isFailed() {
152     return exception != null;
153   }
154 
155   public IOException getException() {
156     if (isFailed()) {
157       return ForeignExceptionUtil.toIOException(exception);
158     }
159     return null;
160   }
161 
162   @InterfaceAudience.Private
163   public ForeignExceptionMessage getForeignExceptionMessage() {
164     return exception;
165   }
166 
167   public String getExceptionCause() {
168     assert isFailed();
169     return exception.getGenericException().getClassName();
170   }
171 
172   public String getExceptionMessage() {
173     assert isFailed();
174     return exception.getGenericException().getMessage();
175   }
176 
177   public String getExceptionFullMessage() {
178     assert isFailed();
179     return getExceptionCause() + " - " + getExceptionMessage();
180   }
181 
182   public boolean hasResultData() {
183     return result != null;
184   }
185 
186   public byte[] getResult() {
187     return result;
188   }
189 
190   public long getStartTime() {
191     return startTime;
192   }
193 
194   public long getLastUpdate() {
195     return lastUpdate;
196   }
197 
198   public long executionTime() {
199     return lastUpdate - startTime;
200   }
201 
202   @InterfaceAudience.Private
203   public boolean hasClientAckTime() {
204     return clientAckTime > 0;
205   }
206 
207   @InterfaceAudience.Private
208   public long getClientAckTime() {
209     return clientAckTime;
210   }
211 
212   @InterfaceAudience.Private
213   public void setClientAckTime(final long timestamp) {
214     this.clientAckTime = timestamp;
215   }
216 
217   /**
218    * @return Convert the current {@link ProcedureInfo} into a Protocol Buffers Procedure
219    * instance.
220    */
221   @InterfaceAudience.Private
222   public static ProcedureProtos.Procedure convertToProcedureProto(
223       final ProcedureInfo procInfo) {
224     ProcedureProtos.Procedure.Builder builder = ProcedureProtos.Procedure.newBuilder();
225 
226     builder.setClassName(procInfo.getProcName());
227     builder.setProcId(procInfo.getProcId());
228     builder.setStartTime(procInfo.getStartTime());
229     builder.setState(procInfo.getProcState());
230     builder.setLastUpdate(procInfo.getLastUpdate());
231 
232     if (procInfo.hasParentId()) {
233       builder.setParentId(procInfo.getParentId());
234     }
235 
236     if (procInfo.getProcOwner() != null) {
237        builder.setOwner(procInfo.getProcOwner());
238     }
239 
240     if (procInfo.isFailed()) {
241         builder.setException(procInfo.getForeignExceptionMessage());
242     }
243 
244     if (procInfo.hasResultData()) {
245       builder.setResult(ByteStringer.wrap(procInfo.getResult()));
246     }
247 
248     return builder.build();
249   }
250 
251   /**
252    * Helper to convert the protobuf object.
253    * @return Convert the current Protocol Buffers Procedure to {@link ProcedureInfo}
254    * instance.
255    */
256   @InterfaceAudience.Private
257   public static ProcedureInfo convert(final ProcedureProtos.Procedure procProto) {
258     NonceKey nonceKey = null;
259     if (procProto.getNonce() != HConstants.NO_NONCE) {
260       nonceKey = new NonceKey(procProto.getNonceGroup(), procProto.getNonce());
261     }
262 
263     return new ProcedureInfo(
264       procProto.getProcId(),
265       procProto.getClassName(),
266       procProto.getOwner(),
267       procProto.getState(),
268       procProto.hasParentId() ? procProto.getParentId() : -1,
269       nonceKey,
270       procProto.hasException() ? procProto.getException() : null,
271       procProto.getLastUpdate(),
272       procProto.getStartTime(),
273       procProto.getState() == ProcedureState.FINISHED ? procProto.getResult().toByteArray() : null);
274   }
275 
276   /**
277   * Check if the user is this procedure's owner
278   * @param owner the owner field of the procedure
279   * @param user the user
280   * @return true if the user is the owner of the procedure,
281   *   false otherwise or the owner is unknown.
282   */
283   @InterfaceAudience.Private
284   public static boolean isProcedureOwner(final ProcedureInfo procInfo, final User user) {
285     if (user == null) {
286       return false;
287     }
288     String procOwner = procInfo.getProcOwner();
289     if (procOwner == null) {
290       return false;
291     }
292     return procOwner.equals(user.getShortName());
293   }
294 }