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 implements Cloneable {
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    @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="CN_IDIOM_NO_SUPER_CALL",
81        justification="Intentional; calling super class clone doesn't make sense here.")
82    public ProcedureInfo clone() {
83      return new ProcedureInfo(procId, procName, procOwner, procState, parentId, nonceKey,
84        exception, lastUpdate, startTime, result);
85    }
86  
87    @Override
88    public String toString() {
89      StringBuilder sb = new StringBuilder();
90      sb.append("Procedure=");
91      sb.append(procName);
92      sb.append(" (id=");
93      sb.append(procId);
94      if (hasParentId()) {
95        sb.append(", parent=");
96        sb.append(parentId);
97      }
98      if (hasOwner()) {
99        sb.append(", owner=");
100       sb.append(procOwner);
101     }
102     sb.append(", state=");
103     sb.append(procState);
104 
105     long now = EnvironmentEdgeManager.currentTime();
106     sb.append(", startTime=");
107     sb.append(StringUtils.formatTime(now - startTime));
108     sb.append(" ago, lastUpdate=");
109     sb.append(StringUtils.formatTime(now - startTime));
110     sb.append(" ago");
111 
112     if (isFailed()) {
113       sb.append(", exception=\"");
114       sb.append(getExceptionMessage());
115       sb.append("\"");
116     }
117     sb.append(")");
118     return sb.toString();
119   }
120 
121   public long getProcId() {
122     return procId;
123   }
124 
125   public String getProcName() {
126     return procName;
127   }
128 
129   private boolean hasOwner() {
130     return procOwner != null;
131   }
132 
133   public String getProcOwner() {
134     return procOwner;
135   }
136 
137   public ProcedureState getProcState() {
138     return procState;
139   }
140 
141   public boolean hasParentId() {
142     return (parentId != -1);
143   }
144 
145   public long getParentId() {
146     return parentId;
147   }
148 
149   public NonceKey getNonceKey() {
150     return nonceKey;
151   }
152 
153   public boolean isFailed() {
154     return exception != null;
155   }
156 
157   public IOException getException() {
158     if (isFailed()) {
159       return ForeignExceptionUtil.toIOException(exception);
160     }
161     return null;
162   }
163 
164   @InterfaceAudience.Private
165   public ForeignExceptionMessage getForeignExceptionMessage() {
166     return exception;
167   }
168 
169   public String getExceptionCause() {
170     assert isFailed();
171     return exception.getGenericException().getClassName();
172   }
173 
174   public String getExceptionMessage() {
175     assert isFailed();
176     return exception.getGenericException().getMessage();
177   }
178 
179   public String getExceptionFullMessage() {
180     assert isFailed();
181     return getExceptionCause() + " - " + getExceptionMessage();
182   }
183 
184   public boolean hasResultData() {
185     return result != null;
186   }
187 
188   public byte[] getResult() {
189     return result;
190   }
191 
192   public long getStartTime() {
193     return startTime;
194   }
195 
196   public long getLastUpdate() {
197     return lastUpdate;
198   }
199 
200   public long executionTime() {
201     return lastUpdate - startTime;
202   }
203 
204   @InterfaceAudience.Private
205   public boolean hasClientAckTime() {
206     return clientAckTime != -1;
207   }
208 
209   @InterfaceAudience.Private
210   public long getClientAckTime() {
211     return clientAckTime;
212   }
213 
214   @InterfaceAudience.Private
215   public void setClientAckTime(final long timestamp) {
216     this.clientAckTime = timestamp;
217   }
218 
219   /**
220    * @return Convert the current {@link ProcedureInfo} into a Protocol Buffers Procedure
221    * instance.
222    */
223   @InterfaceAudience.Private
224   public static ProcedureProtos.Procedure convertToProcedureProto(
225       final ProcedureInfo procInfo) {
226     ProcedureProtos.Procedure.Builder builder = ProcedureProtos.Procedure.newBuilder();
227 
228     builder.setClassName(procInfo.getProcName());
229     builder.setProcId(procInfo.getProcId());
230     builder.setStartTime(procInfo.getStartTime());
231     builder.setState(procInfo.getProcState());
232     builder.setLastUpdate(procInfo.getLastUpdate());
233 
234     if (procInfo.hasParentId()) {
235       builder.setParentId(procInfo.getParentId());
236     }
237 
238     if (procInfo.getProcOwner() != null) {
239        builder.setOwner(procInfo.getProcOwner());
240     }
241 
242     if (procInfo.isFailed()) {
243         builder.setException(procInfo.getForeignExceptionMessage());
244     }
245 
246     if (procInfo.hasResultData()) {
247       builder.setResult(ByteStringer.wrap(procInfo.getResult()));
248     }
249 
250     return builder.build();
251   }
252 
253   /**
254    * Helper to convert the protobuf object.
255    * @return Convert the current Protocol Buffers Procedure to {@link ProcedureInfo}
256    * instance.
257    */
258   @InterfaceAudience.Private
259   public static ProcedureInfo convert(final ProcedureProtos.Procedure procProto) {
260     NonceKey nonceKey = null;
261     if (procProto.getNonce() != HConstants.NO_NONCE) {
262       nonceKey = new NonceKey(procProto.getNonceGroup(), procProto.getNonce());
263     }
264 
265     return new ProcedureInfo(
266       procProto.getProcId(),
267       procProto.getClassName(),
268       procProto.getOwner(),
269       procProto.getState(),
270       procProto.hasParentId() ? procProto.getParentId() : -1,
271       nonceKey,
272       procProto.hasException() ? procProto.getException() : null,
273       procProto.getLastUpdate(),
274       procProto.getStartTime(),
275       procProto.hasResult() ? procProto.getResult().toByteArray() : null);
276   }
277 
278   /**
279   * Check if the user is this procedure's owner
280   * @param owner the owner field of the procedure
281   * @param user the user
282   * @return true if the user is the owner of the procedure,
283   *   false otherwise or the owner is unknown.
284   */
285   @InterfaceAudience.Private
286   public static boolean isProcedureOwner(final ProcedureInfo procInfo, final User user) {
287     if (user == null) {
288       return false;
289     }
290     String procOwner = procInfo.getProcOwner();
291     if (procOwner == null) {
292       return false;
293     }
294     return procOwner.equals(user.getShortName());
295   }
296 }