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.client;
19  
20  import java.io.IOException;
21  import java.util.ArrayList;
22  import java.util.List;
23  import java.util.Map;
24  
25  import org.apache.hadoop.hbase.CellScannable;
26  import org.apache.hadoop.hbase.TableName;
27  import org.apache.hadoop.hbase.HRegionLocation;
28  import org.apache.hadoop.hbase.ipc.PayloadCarryingRpcController;
29  import org.apache.hadoop.hbase.protobuf.ProtobufUtil;
30  import org.apache.hadoop.hbase.protobuf.RequestConverter;
31  import org.apache.hadoop.hbase.protobuf.ResponseConverter;
32  import org.apache.hadoop.hbase.protobuf.generated.ClientProtos;
33  import org.apache.hadoop.hbase.protobuf.generated.ClientProtos.MultiRequest;
34  
35  import com.google.protobuf.ServiceException;
36  
37  /**
38   * Callable that handles the <code>multi</code> method call going against a single
39   * regionserver; i.e. A {@link RegionServerCallable} for the multi call (It is not a
40   * {@link RegionServerCallable} that goes against multiple regions.
41   * @param <R>
42   */
43  class MultiServerCallable<R> extends RegionServerCallable<MultiResponse> {
44    private final MultiAction<R> multi;
45  
46    MultiServerCallable(final HConnection connection, final TableName tableName,
47        final HRegionLocation location, final MultiAction<R> multi) {
48      super(connection, tableName, null);
49      this.multi = multi;
50      setLocation(location);
51    }
52  
53    MultiAction<R> getMulti() {
54      return this.multi;
55    }
56  
57    @Override
58    public MultiResponse call() throws IOException {
59      MultiResponse response = new MultiResponse();
60      // The multi object is a list of Actions by region.
61      for (Map.Entry<byte[], List<Action<R>>> e: this.multi.actions.entrySet()) {
62        byte[] regionName = e.getKey();
63        int rowMutations = 0;
64        List<Action<R>> actions = e.getValue();
65        for (Action<R> action : actions) {
66          Row row = action.getAction();
67          // Row Mutations are a set of Puts and/or Deletes all to be applied atomically
68          // on the one row.  We do these a row at a time.
69          if (row instanceof RowMutations) {
70            try {
71              RowMutations rms = (RowMutations)row;
72              // Stick all Cells for all RowMutations in here into 'cells'.  Populated when we call
73              // buildNoDataMultiRequest in the below.
74              List<CellScannable> cells = new ArrayList<CellScannable>(rms.getMutations().size());
75              // Build a multi request absent its Cell payload (this is the 'nodata' in the below).
76              MultiRequest multiRequest =
77                  RequestConverter.buildNoDataMultiRequest(regionName, rms, cells);
78              // Carry the cells over the proxy/pb Service interface using the payload carrying
79              // rpc controller.
80              getStub().multi(new PayloadCarryingRpcController(cells), multiRequest);
81              // This multi call does not return results.
82              response.add(regionName, action.getOriginalIndex(), Result.EMPTY_RESULT);
83            } catch (ServiceException se) {
84              response.add(regionName, action.getOriginalIndex(),
85                ProtobufUtil.getRemoteException(se));
86            }
87            rowMutations++;
88          }
89        }
90        // Are there any non-RowMutation actions to send for this region?
91        if (actions.size() > rowMutations) {
92          Exception ex = null;
93          List<Object> results = null;
94          // Stick all Cells for the multiRequest in here into 'cells'.  Gets filled in when we
95          // call buildNoDataMultiRequest
96          List<CellScannable> cells = new ArrayList<CellScannable>(actions.size() - rowMutations);
97          try {
98            // The call to buildNoDataMultiRequest will skip RowMutations.  They have
99            // already been handled above.
100           MultiRequest multiRequest =
101               RequestConverter.buildNoDataMultiRequest(regionName, actions, cells);
102           // Controller optionally carries cell data over the proxy/service boundary and also
103           // optionally ferries cell response data back out again.
104           PayloadCarryingRpcController controller = new PayloadCarryingRpcController(cells);
105           ClientProtos.MultiResponse responseProto = getStub().multi(controller, multiRequest);
106           results = ResponseConverter.getResults(responseProto, controller.cellScanner());
107         } catch (ServiceException se) {
108           ex = ProtobufUtil.getRemoteException(se);
109         }
110         for (int i = 0, n = actions.size(); i < n; i++) {
111           int originalIndex = actions.get(i).getOriginalIndex();
112           response.add(regionName, originalIndex, results == null ? ex : results.get(i));
113         }
114       }
115     }
116     return response;
117   }
118 
119   @Override
120   public void prepare(boolean reload) throws IOException {
121     // Use the location we were given in the constructor rather than go look it up.
122     setStub(getConnection().getClient(getLocation().getServerName()));
123   }
124 }