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