View Javadoc

1   /*
2    *
3    * Licensed to the Apache Software Foundation (ASF) under one
4    * or more contributor license agreements.  See the NOTICE file
5    * distributed with this work for additional information
6    * regarding copyright ownership.  The ASF licenses this file
7    * to you under the Apache License, Version 2.0 (the
8    * "License"); you may not use this file except in compliance
9    * with the License.  You may obtain a copy of the License at
10   *
11   *     http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing, software
14   * distributed under the License is distributed on an "AS IS" BASIS,
15   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16   * See the License for the specific language governing permissions and
17   * limitations under the License.
18   */
19  package org.apache.hadoop.hbase.coprocessor;
20  
21  import static org.junit.Assert.assertEquals;
22  import static org.junit.Assert.assertTrue;
23  
24  import java.util.Collections;
25  import java.util.Map;
26  import java.util.TreeMap;
27  
28  import org.apache.hadoop.hbase.client.Admin;
29  import org.apache.hadoop.hbase.client.Table;
30  import org.apache.hadoop.hbase.util.ByteStringer;
31  import org.apache.commons.logging.Log;
32  import org.apache.commons.logging.LogFactory;
33  import org.apache.hadoop.conf.Configuration;
34  import org.apache.hadoop.hbase.HBaseTestingUtility;
35  import org.apache.hadoop.hbase.HColumnDescriptor;
36  import org.apache.hadoop.hbase.HTableDescriptor;
37  import org.apache.hadoop.hbase.testclassification.MediumTests;
38  import org.apache.hadoop.hbase.TableName;
39  import org.apache.hadoop.hbase.client.HBaseAdmin;
40  import org.apache.hadoop.hbase.client.HTable;
41  import org.apache.hadoop.hbase.client.Put;
42  import org.apache.hadoop.hbase.client.coprocessor.Batch;
43  import org.apache.hadoop.hbase.coprocessor.protobuf.generated.ColumnAggregationProtos;
44  import org.apache.hadoop.hbase.coprocessor.protobuf.generated.ColumnAggregationProtos.SumResponse;
45  import org.apache.hadoop.hbase.coprocessor.protobuf.generated.ColumnAggregationWithErrorsProtos;
46  import org.apache.hadoop.hbase.coprocessor.protobuf.generated.ColumnAggregationWithErrorsProtos.ColumnAggregationWithErrorsSumRequest;
47  import org.apache.hadoop.hbase.coprocessor.protobuf.generated.ColumnAggregationWithErrorsProtos.ColumnAggregationWithErrorsSumResponse;
48  import org.apache.hadoop.hbase.coprocessor.protobuf.generated.ColumnAggregationWithNullResponseProtos;
49  import org.apache.hadoop.hbase.coprocessor.protobuf.generated.ColumnAggregationWithNullResponseProtos.ColumnAggregationServiceNullResponse;
50  import org.apache.hadoop.hbase.coprocessor.protobuf.generated.ColumnAggregationWithNullResponseProtos.ColumnAggregationNullResponseSumRequest;
51  import org.apache.hadoop.hbase.coprocessor.protobuf.generated.ColumnAggregationWithNullResponseProtos.ColumnAggregationNullResponseSumResponse;
52  import org.apache.hadoop.hbase.util.Bytes;
53  import org.junit.AfterClass;
54  import org.junit.BeforeClass;
55  import org.junit.Test;
56  import org.junit.experimental.categories.Category;
57  
58  import com.google.protobuf.ServiceException;
59  
60  /**
61   * TestEndpoint: test cases to verify the batch execution of coprocessor Endpoint
62   */
63  @Category(MediumTests.class)
64  public class TestBatchCoprocessorEndpoint {
65    private static final Log LOG = LogFactory.getLog(TestBatchCoprocessorEndpoint.class);
66  
67    private static final TableName TEST_TABLE =
68        TableName.valueOf("TestTable");
69    private static final byte[] TEST_FAMILY = Bytes.toBytes("TestFamily");
70    private static final byte[] TEST_QUALIFIER = Bytes.toBytes("TestQualifier");
71    private static byte[] ROW = Bytes.toBytes("testRow");
72  
73    private static final int ROWSIZE = 20;
74    private static final int rowSeperator1 = 5;
75    private static final int rowSeperator2 = 12;
76    private static byte[][] ROWS = makeN(ROW, ROWSIZE);
77  
78    private static HBaseTestingUtility util = new HBaseTestingUtility();
79  
80    @BeforeClass
81    public static void setupBeforeClass() throws Exception {
82      // set configure to indicate which cp should be loaded
83      Configuration conf = util.getConfiguration();
84      conf.setStrings(CoprocessorHost.REGION_COPROCESSOR_CONF_KEY,
85          org.apache.hadoop.hbase.coprocessor.ColumnAggregationEndpoint.class.getName(),
86          ProtobufCoprocessorService.class.getName(),
87          ColumnAggregationEndpointWithErrors.class.getName(),
88          ColumnAggregationEndpointNullResponse.class.getName());
89      conf.setStrings(CoprocessorHost.MASTER_COPROCESSOR_CONF_KEY,
90          ProtobufCoprocessorService.class.getName());
91      util.startMiniCluster(2);
92      Admin admin = new HBaseAdmin(conf);
93      HTableDescriptor desc = new HTableDescriptor(TEST_TABLE);
94      desc.addFamily(new HColumnDescriptor(TEST_FAMILY));
95      admin.createTable(desc, new byte[][]{ROWS[rowSeperator1], ROWS[rowSeperator2]});
96      util.waitUntilAllRegionsAssigned(TEST_TABLE);
97      admin.close();
98  
99      Table table = new HTable(conf, TEST_TABLE);
100     for (int i = 0; i < ROWSIZE; i++) {
101       Put put = new Put(ROWS[i]);
102       put.add(TEST_FAMILY, TEST_QUALIFIER, Bytes.toBytes(i));
103       table.put(put);
104     }
105     table.close();
106   }
107 
108   @AfterClass
109   public static void tearDownAfterClass() throws Exception {
110     util.shutdownMiniCluster();
111   }
112 
113   @Test
114   public void testAggregationNullResponse() throws Throwable {
115     Table table = new HTable(util.getConfiguration(), TEST_TABLE);
116     ColumnAggregationNullResponseSumRequest.Builder builder =
117         ColumnAggregationNullResponseSumRequest
118         .newBuilder();
119     builder.setFamily(ByteStringer.wrap(TEST_FAMILY));
120     if (TEST_QUALIFIER != null && TEST_QUALIFIER.length > 0) {
121       builder.setQualifier(ByteStringer.wrap(TEST_QUALIFIER));
122     }
123     Map<byte[], ColumnAggregationNullResponseSumResponse> results =
124         table.batchCoprocessorService(
125             ColumnAggregationServiceNullResponse.getDescriptor().findMethodByName("sum"),
126             builder.build(), ROWS[0], ROWS[ROWS.length - 1],
127             ColumnAggregationNullResponseSumResponse.getDefaultInstance());
128 
129     int sumResult = 0;
130     int expectedResult = 0;
131     for (Map.Entry<byte[], ColumnAggregationNullResponseSumResponse> e :
132         results.entrySet()) {
133       LOG.info("Got value " + e.getValue().getSum() + " for region "
134           + Bytes.toStringBinary(e.getKey()));
135       sumResult += e.getValue().getSum();
136     }
137     for (int i = 0; i < rowSeperator2; i++) {
138       expectedResult += i;
139     }
140     assertEquals("Invalid result", expectedResult, sumResult);
141     table.close();
142   }
143 
144   private static byte[][] makeN(byte[] base, int n) {
145     byte[][] ret = new byte[n][];
146     for (int i = 0; i < n; i++) {
147       ret[i] = Bytes.add(base, Bytes.toBytes(String.format("%02d", i)));
148     }
149     return ret;
150   }
151 
152   private Map<byte[], SumResponse> sum(final Table table, final byte[] family,
153       final byte[] qualifier, final byte[] start, final byte[] end) throws ServiceException,
154       Throwable {
155     ColumnAggregationProtos.SumRequest.Builder builder = ColumnAggregationProtos.SumRequest
156         .newBuilder();
157     builder.setFamily(ByteStringer.wrap(family));
158     if (qualifier != null && qualifier.length > 0) {
159       builder.setQualifier(ByteStringer.wrap(qualifier));
160     }
161     return table.batchCoprocessorService(
162         ColumnAggregationProtos.ColumnAggregationService.getDescriptor().findMethodByName("sum"),
163         builder.build(), start, end, ColumnAggregationProtos.SumResponse.getDefaultInstance());
164   }
165 
166   @Test
167   public void testAggregationWithReturnValue() throws Throwable {
168     Table table = new HTable(util.getConfiguration(), TEST_TABLE);
169     Map<byte[], SumResponse> results = sum(table, TEST_FAMILY, TEST_QUALIFIER, ROWS[0],
170         ROWS[ROWS.length - 1]);
171     int sumResult = 0;
172     int expectedResult = 0;
173     for (Map.Entry<byte[], SumResponse> e : results.entrySet()) {
174       LOG.info("Got value " + e.getValue().getSum() + " for region "
175           + Bytes.toStringBinary(e.getKey()));
176       sumResult += e.getValue().getSum();
177     }
178     for (int i = 0; i < ROWSIZE; i++) {
179       expectedResult += i;
180     }
181     assertEquals("Invalid result", expectedResult, sumResult);
182 
183     results.clear();
184 
185     // scan: for region 2 and region 3
186     results = sum(table, TEST_FAMILY, TEST_QUALIFIER, ROWS[rowSeperator1],
187         ROWS[ROWS.length - 1]);
188     sumResult = 0;
189     expectedResult = 0;
190     for (Map.Entry<byte[], SumResponse> e : results.entrySet()) {
191       LOG.info("Got value " + e.getValue().getSum() + " for region "
192           + Bytes.toStringBinary(e.getKey()));
193       sumResult += e.getValue().getSum();
194     }
195     for (int i = rowSeperator1; i < ROWSIZE; i++) {
196       expectedResult += i;
197     }
198     assertEquals("Invalid result", expectedResult, sumResult);
199     table.close();
200   }
201 
202   @Test
203   public void testAggregation() throws Throwable {
204     Table table = new HTable(util.getConfiguration(), TEST_TABLE);
205     Map<byte[], SumResponse> results = sum(table, TEST_FAMILY, TEST_QUALIFIER,
206         ROWS[0], ROWS[ROWS.length - 1]);
207     int sumResult = 0;
208     int expectedResult = 0;
209     for (Map.Entry<byte[], SumResponse> e : results.entrySet()) {
210       LOG.info("Got value " + e.getValue().getSum() + " for region "
211           + Bytes.toStringBinary(e.getKey()));
212       sumResult += e.getValue().getSum();
213     }
214     for (int i = 0; i < ROWSIZE; i++) {
215       expectedResult += i;
216     }
217     assertEquals("Invalid result", expectedResult, sumResult);
218 
219     // scan: for region 2 and region 3
220     results = sum(table, TEST_FAMILY, TEST_QUALIFIER, ROWS[rowSeperator1], ROWS[ROWS.length - 1]);
221     sumResult = 0;
222     expectedResult = 0;
223     for (Map.Entry<byte[], SumResponse> e : results.entrySet()) {
224       LOG.info("Got value " + e.getValue().getSum() + " for region "
225           + Bytes.toStringBinary(e.getKey()));
226       sumResult += e.getValue().getSum();
227     }
228     for (int i = rowSeperator1; i < ROWSIZE; i++) {
229       expectedResult += i;
230     }
231     assertEquals("Invalid result", expectedResult, sumResult);
232     table.close();
233   }
234 
235   @Test
236   public void testAggregationWithErrors() throws Throwable {
237     Table table = new HTable(util.getConfiguration(), TEST_TABLE);
238     final Map<byte[], ColumnAggregationWithErrorsSumResponse> results =
239         Collections.synchronizedMap(
240             new TreeMap<byte[], ColumnAggregationWithErrorsSumResponse>(
241                 Bytes.BYTES_COMPARATOR
242             ));
243     ColumnAggregationWithErrorsSumRequest.Builder builder =
244         ColumnAggregationWithErrorsSumRequest
245         .newBuilder();
246     builder.setFamily(ByteStringer.wrap(TEST_FAMILY));
247     if (TEST_QUALIFIER != null && TEST_QUALIFIER.length > 0) {
248       builder.setQualifier(ByteStringer.wrap(TEST_QUALIFIER));
249     }
250 
251     boolean hasError = false;
252     try {
253       table.batchCoprocessorService(
254           ColumnAggregationWithErrorsProtos.ColumnAggregationServiceWithErrors.getDescriptor()
255               .findMethodByName("sum"),
256           builder.build(), ROWS[0], ROWS[ROWS.length - 1],
257           ColumnAggregationWithErrorsSumResponse.getDefaultInstance(),
258           new Batch.Callback<ColumnAggregationWithErrorsSumResponse>() {
259 
260             @Override
261             public void update(byte[] region, byte[] row,
262                 ColumnAggregationWithErrorsSumResponse result) {
263               results.put(region, result);
264             }
265           });
266     } catch (Throwable t) {
267       LOG.info("Exceptions in coprocessor service", t);
268       hasError = true;
269     }
270 
271     int sumResult = 0;
272     int expectedResult = 0;
273     for (Map.Entry<byte[], ColumnAggregationWithErrorsSumResponse> e : results.entrySet()) {
274       LOG.info("Got value " + e.getValue().getSum() + " for region "
275           + Bytes.toStringBinary(e.getKey()));
276       sumResult += e.getValue().getSum();
277     }
278     for (int i = 0; i < rowSeperator2; i++) {
279       expectedResult += i;
280     }
281     assertEquals("Invalid result", expectedResult, sumResult);
282     assertTrue(hasError);
283     table.close();
284   }
285 }