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  package org.apache.hadoop.hbase.protobuf;
19  
20  import java.io.IOException;
21  import java.util.ArrayList;
22  import java.util.List;
23  
24  import org.apache.commons.logging.Log;
25  import org.apache.commons.logging.LogFactory;
26  import org.apache.hadoop.classification.InterfaceAudience;
27  import org.apache.hadoop.hbase.Cell;
28  import org.apache.hadoop.hbase.CellScanner;
29  import org.apache.hadoop.hbase.DoNotRetryIOException;
30  import org.apache.hadoop.hbase.HRegionInfo;
31  import org.apache.hadoop.hbase.ServerName;
32  import org.apache.hadoop.hbase.client.Result;
33  import org.apache.hadoop.hbase.ipc.ServerRpcController;
34  import org.apache.hadoop.hbase.protobuf.generated.AccessControlProtos.UserPermissionsResponse;
35  import org.apache.hadoop.hbase.protobuf.generated.AdminProtos.CloseRegionResponse;
36  import org.apache.hadoop.hbase.protobuf.generated.AdminProtos.GetOnlineRegionResponse;
37  import org.apache.hadoop.hbase.protobuf.generated.AdminProtos.GetServerInfoResponse;
38  import org.apache.hadoop.hbase.protobuf.generated.AdminProtos.OpenRegionResponse;
39  import org.apache.hadoop.hbase.protobuf.generated.AdminProtos.RollWALWriterResponse;
40  import org.apache.hadoop.hbase.protobuf.generated.AdminProtos.ServerInfo;
41  import org.apache.hadoop.hbase.protobuf.generated.ClientProtos;
42  import org.apache.hadoop.hbase.protobuf.generated.ClientProtos.ActionResult;
43  import org.apache.hadoop.hbase.protobuf.generated.ClientProtos.ResultCellMeta;
44  import org.apache.hadoop.hbase.protobuf.generated.ClientProtos.ScanResponse;
45  import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.NameBytesPair;
46  import org.apache.hadoop.hbase.protobuf.generated.MasterAdminProtos.CatalogScanResponse;
47  import org.apache.hadoop.hbase.protobuf.generated.MasterAdminProtos.EnableCatalogJanitorResponse;
48  import org.apache.hadoop.hbase.protobuf.generated.RegionServerStatusProtos.GetLastFlushedSequenceIdResponse;
49  import org.apache.hadoop.hbase.regionserver.RegionOpeningState;
50  import org.apache.hadoop.hbase.security.access.UserPermission;
51  import org.apache.hadoop.util.StringUtils;
52  
53  import com.google.protobuf.ByteString;
54  import com.google.protobuf.RpcController;
55  
56  /**
57   * Helper utility to build protocol buffer responses,
58   * or retrieve data from protocol buffer responses.
59   */
60  @InterfaceAudience.Private
61  public final class ResponseConverter {
62    public static final Log LOG = LogFactory.getLog(ResponseConverter.class);
63  
64    private ResponseConverter() {
65    }
66  
67  // Start utilities for Client
68  
69    /**
70     * Get the results from a protocol buffer MultiResponse
71     *
72     * @param proto the protocol buffer MultiResponse to convert
73     * @param cells Cells to go with the passed in <code>proto</code>.  Can be null.
74     * @return the results that were in the MultiResponse (a Result or an Exception).
75     * @throws IOException
76     */
77    public static List<Object> getResults(final ClientProtos.MultiResponse proto,
78        final CellScanner cells)
79    throws IOException {
80      List<Object> results = new ArrayList<Object>();
81      List<ActionResult> resultList = proto.getResultList();
82      for (int i = 0, n = resultList.size(); i < n; i++) {
83        ActionResult result = resultList.get(i);
84        if (result.hasException()) {
85          results.add(ProtobufUtil.toException(result.getException()));
86        } else if (result.hasValue()) {
87          ClientProtos.Result value = result.getValue();
88          results.add(ProtobufUtil.toResult(value, cells));
89        } else {
90          results.add(new Result());
91        }
92      }
93      return results;
94    }
95  
96    /**
97     * Wrap a throwable to an action result.
98     *
99     * @param t
100    * @return an action result
101    */
102   public static ActionResult buildActionResult(final Throwable t) {
103     ActionResult.Builder builder = ActionResult.newBuilder();
104     NameBytesPair.Builder parameterBuilder = NameBytesPair.newBuilder();
105     parameterBuilder.setName(t.getClass().getName());
106     parameterBuilder.setValue(
107       ByteString.copyFromUtf8(StringUtils.stringifyException(t)));
108     builder.setException(parameterBuilder.build());
109     return builder.build();
110   }
111 
112   /**
113    * Converts the permissions list into a protocol buffer UserPermissionsResponse
114    */
115   public static UserPermissionsResponse buildUserPermissionsResponse(
116       final List<UserPermission> permissions) {
117     UserPermissionsResponse.Builder builder = UserPermissionsResponse.newBuilder();
118     for (UserPermission perm : permissions) {
119       builder.addUserPermission(ProtobufUtil.toUserPermission(perm));
120     }
121     return builder.build();
122   }
123 
124 // End utilities for Client
125 // Start utilities for Admin
126 
127   /**
128    * Get the list of regions to flush from a RollLogWriterResponse
129    *
130    * @param proto the RollLogWriterResponse
131    * @return the the list of regions to flush
132    */
133   public static byte[][] getRegions(final RollWALWriterResponse proto) {
134     if (proto == null || proto.getRegionToFlushCount() == 0) return null;
135     List<byte[]> regions = new ArrayList<byte[]>();
136     for (ByteString region: proto.getRegionToFlushList()) {
137       regions.add(region.toByteArray());
138     }
139     return (byte[][])regions.toArray();
140   }
141 
142   /**
143    * Get the list of region info from a GetOnlineRegionResponse
144    *
145    * @param proto the GetOnlineRegionResponse
146    * @return the list of region info
147    */
148   public static List<HRegionInfo> getRegionInfos(final GetOnlineRegionResponse proto) {
149     if (proto == null || proto.getRegionInfoCount() == 0) return null;
150     return ProtobufUtil.getRegionInfos(proto);
151   }
152 
153   /**
154    * Get the region opening state from a OpenRegionResponse
155    *
156    * @param proto the OpenRegionResponse
157    * @return the region opening state
158    */
159   public static RegionOpeningState getRegionOpeningState
160       (final OpenRegionResponse proto) {
161     if (proto == null || proto.getOpeningStateCount() != 1) return null;
162     return RegionOpeningState.valueOf(
163       proto.getOpeningState(0).name());
164   }
165 
166   /**
167    * Get a list of region opening state from a OpenRegionResponse
168    * 
169    * @param proto the OpenRegionResponse
170    * @return the list of region opening state
171    */
172   public static List<RegionOpeningState> getRegionOpeningStateList(
173       final OpenRegionResponse proto) {
174     if (proto == null) return null;
175     List<RegionOpeningState> regionOpeningStates = new ArrayList<RegionOpeningState>();
176     for (int i = 0; i < proto.getOpeningStateCount(); i++) {
177       regionOpeningStates.add(RegionOpeningState.valueOf(
178           proto.getOpeningState(i).name()));
179     }
180     return regionOpeningStates;
181   }
182 
183   /**
184    * Check if the region is closed from a CloseRegionResponse
185    *
186    * @param proto the CloseRegionResponse
187    * @return the region close state
188    */
189   public static boolean isClosed
190       (final CloseRegionResponse proto) {
191     if (proto == null || !proto.hasClosed()) return false;
192     return proto.getClosed();
193   }
194 
195   /**
196    * A utility to build a GetServerInfoResponse.
197    *
198    * @param serverName
199    * @param webuiPort
200    * @return the response
201    */
202   public static GetServerInfoResponse buildGetServerInfoResponse(
203       final ServerName serverName, final int webuiPort) {
204     GetServerInfoResponse.Builder builder = GetServerInfoResponse.newBuilder();
205     ServerInfo.Builder serverInfoBuilder = ServerInfo.newBuilder();
206     serverInfoBuilder.setServerName(ProtobufUtil.toServerName(serverName));
207     if (webuiPort >= 0) {
208       serverInfoBuilder.setWebuiPort(webuiPort);
209     }
210     builder.setServerInfo(serverInfoBuilder.build());
211     return builder.build();
212   }
213 
214   /**
215    * A utility to build a GetOnlineRegionResponse.
216    *
217    * @param regions
218    * @return the response
219    */
220   public static GetOnlineRegionResponse buildGetOnlineRegionResponse(
221       final List<HRegionInfo> regions) {
222     GetOnlineRegionResponse.Builder builder = GetOnlineRegionResponse.newBuilder();
223     for (HRegionInfo region: regions) {
224       builder.addRegionInfo(HRegionInfo.convert(region));
225     }
226     return builder.build();
227   }
228 
229   /**
230    * Creates a response for the catalog scan request
231    * @return A CatalogScanResponse
232    */
233   public static CatalogScanResponse buildCatalogScanResponse(int numCleaned) {
234     return CatalogScanResponse.newBuilder().setScanResult(numCleaned).build();
235   }
236 
237   /**
238    * Creates a response for the catalog scan request
239    * @return A EnableCatalogJanitorResponse
240    */
241   public static EnableCatalogJanitorResponse buildEnableCatalogJanitorResponse(boolean prevValue) {
242     return EnableCatalogJanitorResponse.newBuilder().setPrevValue(prevValue).build();
243   }
244 
245 // End utilities for Admin
246 
247   /**
248    * Creates a response for the last flushed sequence Id request
249    * @return A GetLastFlushedSequenceIdResponse
250    */
251   public static GetLastFlushedSequenceIdResponse buildGetLastFlushedSequenceIdResponse(
252       long seqId) {
253     return GetLastFlushedSequenceIdResponse.newBuilder().setLastFlushedSequenceId(seqId).build();
254   }
255 
256   /**
257    * Stores an exception encountered during RPC invocation so it can be passed back
258    * through to the client.
259    * @param controller the controller instance provided by the client when calling the service
260    * @param ioe the exception encountered
261    */
262   public static void setControllerException(RpcController controller, IOException ioe) {
263     if (controller != null) {
264       if (controller instanceof ServerRpcController) {
265         ((ServerRpcController)controller).setFailedOn(ioe);
266       } else {
267         controller.setFailed(StringUtils.stringifyException(ioe));
268       }
269     }
270   }
271 
272   /**
273    * Create Results from the cells using the cells meta data. 
274    * @param cellScanner
275    * @param response
276    * @return results
277    */
278   public static Result[] getResults(CellScanner cellScanner, ScanResponse response)
279       throws IOException {
280     if (response == null || cellScanner == null) return null;
281     ResultCellMeta resultCellMeta = response.getResultCellMeta();
282     if (resultCellMeta == null) return null;
283     int noOfResults = resultCellMeta.getCellsLengthCount();
284     Result[] results = new Result[noOfResults];
285     for (int i = 0; i < noOfResults; i++) {
286       int noOfCells = resultCellMeta.getCellsLength(i);
287       List<Cell> cells = new ArrayList<Cell>(noOfCells);
288       for (int j = 0; j < noOfCells; j++) {
289         try {
290           if (cellScanner.advance() == false) {
291             // We are not able to retrieve the exact number of cells which ResultCellMeta says us.
292             // We have to scan for the same results again. Throwing DNRIOE as a client retry on the
293             // same scanner will result in OutOfOrderScannerNextException
294             String msg = "Results sent from server=" + noOfResults + ". But only got " + i
295                 + " results completely at client. Resetting the scanner to scan again.";
296             LOG.error(msg);
297             throw new DoNotRetryIOException(msg);
298           }
299         } catch (IOException ioe) {
300           // We are getting IOE while retrieving the cells for Results.
301           // We have to scan for the same results again. Throwing DNRIOE as a client retry on the
302           // same scanner will result in OutOfOrderScannerNextException
303           LOG.error("Exception while reading cells from result."
304               + "Resetting the scanner to scan again.", ioe);
305           throw new DoNotRetryIOException("Resetting the scanner.", ioe);
306         }
307         cells.add(cellScanner.current());
308       }
309       results[i] = new Result(cells);
310     }
311     return results;
312   }
313 }