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.client.coprocessor;
20  
21  import static org.apache.hadoop.hbase.HConstants.EMPTY_START_ROW;
22  import static org.apache.hadoop.hbase.HConstants.LAST_ROW;
23  
24  import com.google.protobuf.ByteString;
25  import com.google.protobuf.ZeroCopyLiteralByteString;
26  
27  import org.apache.hadoop.classification.InterfaceAudience;
28  import org.apache.hadoop.fs.Path;
29  import org.apache.hadoop.hbase.TableName;
30  import org.apache.hadoop.hbase.client.HTable;
31  import org.apache.hadoop.hbase.ipc.BlockingRpcCallback;
32  import org.apache.hadoop.hbase.ipc.CoprocessorRpcChannel;
33  import org.apache.hadoop.hbase.ipc.ServerRpcController;
34  import org.apache.hadoop.hbase.protobuf.ProtobufUtil;
35  import org.apache.hadoop.hbase.protobuf.generated.ClientProtos;
36  import org.apache.hadoop.hbase.protobuf.generated.SecureBulkLoadProtos;
37  import org.apache.hadoop.hbase.security.SecureBulkLoadUtil;
38  import org.apache.hadoop.hbase.util.Pair;
39  import org.apache.hadoop.security.token.Token;
40  
41  import java.io.IOException;
42  import java.util.ArrayList;
43  import java.util.List;
44  
45  /**
46   * Client proxy for SecureBulkLoadProtocol
47   * used in conjunction with SecureBulkLoadEndpoint
48   */
49  @InterfaceAudience.Private
50  public class SecureBulkLoadClient {
51    private HTable table;
52  
53    public SecureBulkLoadClient(HTable table) {
54      this.table = table;
55    }
56  
57    public String prepareBulkLoad(final TableName tableName) throws IOException {
58      try {
59        return
60          table.coprocessorService(SecureBulkLoadProtos.SecureBulkLoadService.class,
61            EMPTY_START_ROW,
62            LAST_ROW,
63            new Batch.Call<SecureBulkLoadProtos.SecureBulkLoadService,String>() {
64              @Override
65              public String call(SecureBulkLoadProtos.SecureBulkLoadService instance) throws IOException {
66                ServerRpcController controller = new ServerRpcController();
67  
68                BlockingRpcCallback<SecureBulkLoadProtos.PrepareBulkLoadResponse> rpcCallback =
69                    new BlockingRpcCallback<SecureBulkLoadProtos.PrepareBulkLoadResponse>();
70  
71                SecureBulkLoadProtos.PrepareBulkLoadRequest request =
72                    SecureBulkLoadProtos.PrepareBulkLoadRequest.newBuilder()
73                    .setTableName(ProtobufUtil.toProtoTableName(tableName)).build();
74  
75                instance.prepareBulkLoad(controller,
76                    request,
77                    rpcCallback);
78  
79                SecureBulkLoadProtos.PrepareBulkLoadResponse response = rpcCallback.get();
80                if (controller.failedOnException()) {
81                  throw controller.getFailedOn();
82                }
83                return response.getBulkToken();
84              }
85            }).entrySet().iterator().next().getValue();
86      } catch (Throwable throwable) {
87        throw new IOException(throwable);
88      }
89    }
90  
91    public void cleanupBulkLoad(final String bulkToken) throws IOException {
92      try {
93          table.coprocessorService(SecureBulkLoadProtos.SecureBulkLoadService.class,
94              EMPTY_START_ROW,
95              LAST_ROW,
96              new Batch.Call<SecureBulkLoadProtos.SecureBulkLoadService, String>() {
97  
98                @Override
99                public String call(SecureBulkLoadProtos.SecureBulkLoadService instance) throws IOException {
100                 ServerRpcController controller = new ServerRpcController();
101 
102                 BlockingRpcCallback<SecureBulkLoadProtos.CleanupBulkLoadResponse> rpcCallback =
103                     new BlockingRpcCallback<SecureBulkLoadProtos.CleanupBulkLoadResponse>();
104 
105                 SecureBulkLoadProtos.CleanupBulkLoadRequest request =
106                     SecureBulkLoadProtos.CleanupBulkLoadRequest.newBuilder()
107                         .setBulkToken(bulkToken).build();
108 
109                 instance.cleanupBulkLoad(controller,
110                     request,
111                     rpcCallback);
112 
113                 if (controller.failedOnException()) {
114                   throw controller.getFailedOn();
115                 }
116                 return null;
117               }
118             });
119     } catch (Throwable throwable) {
120       throw new IOException(throwable);
121     }
122   }
123 
124   public boolean bulkLoadHFiles(final List<Pair<byte[], String>> familyPaths,
125                          final Token<?> userToken,
126                          final String bulkToken,
127                          final byte[] startRow) throws IOException {
128     // we never want to send a batch of HFiles to all regions, thus cannot call
129     // HTable#coprocessorService methods that take start and end rowkeys; see HBASE-9639
130     try {
131       CoprocessorRpcChannel channel = table.coprocessorService(startRow);
132       SecureBulkLoadProtos.SecureBulkLoadService instance =
133           ProtobufUtil.newServiceStub(SecureBulkLoadProtos.SecureBulkLoadService.class, channel);
134 
135       SecureBulkLoadProtos.DelegationToken protoDT =
136           SecureBulkLoadProtos.DelegationToken.newBuilder().build();
137       if(userToken != null) {
138         protoDT =
139             SecureBulkLoadProtos.DelegationToken.newBuilder()
140               .setIdentifier(ZeroCopyLiteralByteString.wrap(userToken.getIdentifier()))
141               .setPassword(ZeroCopyLiteralByteString.wrap(userToken.getPassword()))
142               .setKind(userToken.getKind().toString())
143               .setService(userToken.getService().toString()).build();
144       }
145 
146       List<ClientProtos.BulkLoadHFileRequest.FamilyPath> protoFamilyPaths =
147           new ArrayList<ClientProtos.BulkLoadHFileRequest.FamilyPath>();
148       for(Pair<byte[], String> el: familyPaths) {
149         protoFamilyPaths.add(ClientProtos.BulkLoadHFileRequest.FamilyPath.newBuilder()
150           .setFamily(ZeroCopyLiteralByteString.wrap(el.getFirst()))
151           .setPath(el.getSecond()).build());
152       }
153 
154       SecureBulkLoadProtos.SecureBulkLoadHFilesRequest request =
155           SecureBulkLoadProtos.SecureBulkLoadHFilesRequest.newBuilder()
156             .setFsToken(protoDT)
157             .addAllFamilyPath(protoFamilyPaths)
158             .setBulkToken(bulkToken).build();
159 
160       ServerRpcController controller = new ServerRpcController();
161       BlockingRpcCallback<SecureBulkLoadProtos.SecureBulkLoadHFilesResponse> rpcCallback =
162           new BlockingRpcCallback<SecureBulkLoadProtos.SecureBulkLoadHFilesResponse>();
163       instance.secureBulkLoadHFiles(controller,
164         request,
165         rpcCallback);
166 
167       SecureBulkLoadProtos.SecureBulkLoadHFilesResponse response = rpcCallback.get();
168       if (controller.failedOnException()) {
169         throw controller.getFailedOn();
170       }
171       return response.getLoaded();
172     } catch (Throwable throwable) {
173       throw new IOException(throwable);
174     }
175   }
176 
177   public Path getStagingPath(String bulkToken, byte[] family) throws IOException {
178     return SecureBulkLoadUtil.getStagingPath(table.getConfiguration(), bulkToken, family);
179   }
180 }