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 static org.junit.Assert.assertEquals;
21  import static org.junit.Assert.assertFalse;
22  import static org.junit.Assert.assertTrue;
23  
24  import java.io.IOException;
25  import java.util.ArrayList;
26  import java.util.List;
27  import org.apache.commons.logging.Log;
28  import org.apache.commons.logging.LogFactory;
29  import org.apache.hadoop.hbase.Cell;
30  import org.apache.hadoop.hbase.CellUtil;
31  import org.apache.hadoop.hbase.DoNotRetryIOException;
32  import org.apache.hadoop.hbase.HBaseTestingUtility;
33  import org.apache.hadoop.hbase.HColumnDescriptor;
34  import org.apache.hadoop.hbase.HConstants;
35  import org.apache.hadoop.hbase.HTableDescriptor;
36  import org.apache.hadoop.hbase.TableName;
37  import org.apache.hadoop.hbase.filter.BinaryComparator;
38  import org.apache.hadoop.hbase.ipc.PayloadCarryingRpcController;
39  import org.apache.hadoop.hbase.protobuf.ProtobufUtil;
40  import org.apache.hadoop.hbase.protobuf.RequestConverter;
41  import org.apache.hadoop.hbase.protobuf.generated.ClientProtos;
42  import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos;
43  import org.apache.hadoop.hbase.regionserver.HRegion;
44  import org.apache.hadoop.hbase.regionserver.HRegionServer;
45  import org.apache.hadoop.hbase.testclassification.ClientTests;
46  import org.apache.hadoop.hbase.testclassification.MediumTests;
47  import org.apache.hadoop.hbase.util.Bytes;
48  import org.junit.After;
49  import org.junit.AfterClass;
50  import org.junit.Before;
51  import org.junit.BeforeClass;
52  import org.junit.Test;
53  import org.junit.experimental.categories.Category;
54  import org.mockito.Mockito;
55  
56  /**
57   * The purpose of this test is to ensure whether rs deals with the malformed cells correctly.
58   */
59  @Category({ MediumTests.class, ClientTests.class })
60  public class TestMalformedCellFromClient {
61    private static final Log LOG = LogFactory.getLog(TestMalformedCellFromClient.class);
62    private static final HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
63    private static final byte[] FAMILY = Bytes.toBytes("testFamily");
64    private static final TableName TABLE_NAME = TableName.valueOf("TestMalformedCellFromClient");
65  
66    @BeforeClass
67    public static void setUpBeforeClass() throws Exception {
68      // disable the retry
69      TEST_UTIL.getConfiguration().setInt(HConstants.HBASE_CLIENT_RETRIES_NUMBER, 1);
70      TEST_UTIL.startMiniCluster(1);
71    }
72  
73    @Before
74    public void before() throws Exception {
75      HTableDescriptor desc =
76        new HTableDescriptor(TABLE_NAME).addFamily(new HColumnDescriptor(FAMILY));
77      TEST_UTIL.getConnection().getAdmin().createTable(desc);
78    }
79  
80    @After
81    public void tearDown() throws Exception {
82      for (HTableDescriptor htd : TEST_UTIL.getHBaseAdmin().listTables()) {
83        TEST_UTIL.deleteTable(htd.getTableName());
84      }
85    }
86  
87    @AfterClass
88    public static void tearDownAfterClass() throws Exception {
89      TEST_UTIL.shutdownMiniCluster();
90    }
91  
92    /**
93     * The invalid cells is in rm. The rm should fail but the subsequent mutations should succeed.
94     * Currently, we have no client api to submit the request consisting of condition-rm and mutation.
95     * Hence, this test build the request manually.
96     */
97    @Test
98    public void testAtomicOperations() throws Exception {
99      RowMutations rm = new RowMutations(Bytes.toBytes("fail"));
100     rm.add(new Put(rm.getRow()).addColumn(FAMILY, null, new byte[10]));
101     rm.add(new Put(rm.getRow()).addColumn(FAMILY, null, new byte[10]));
102     Put put = new Put(Bytes.toBytes("good")).addColumn(FAMILY, null, new byte[10]);
103 
104     // build the request
105     HRegion r = TEST_UTIL.getMiniHBaseCluster().getRegions(TABLE_NAME).get(0);
106     ClientProtos.MultiRequest request =
107       ClientProtos.MultiRequest.newBuilder(createRequest(rm, r.getRegionInfo().getRegionName()))
108         .addRegionAction(ClientProtos.RegionAction.newBuilder().setRegion(RequestConverter
109           .buildRegionSpecifier(HBaseProtos.RegionSpecifier.RegionSpecifierType.REGION_NAME,
110             r.getRegionInfo().getRegionName())).addAction(ClientProtos.Action.newBuilder()
111           .setMutation(
112             ProtobufUtil.toMutationNoData(ClientProtos.MutationProto.MutationType.PUT, put))))
113         .build();
114 
115     List<Cell> cells = new ArrayList<>();
116     for (Mutation m : rm.getMutations()) {
117       cells.addAll(m.getCellList(FAMILY));
118     }
119     cells.addAll(put.getCellList(FAMILY));
120     assertEquals(3, cells.size());
121     PayloadCarryingRpcController controller = Mockito.mock(PayloadCarryingRpcController.class);
122     Mockito.when(controller.cellScanner()).thenReturn(CellUtil.createCellScanner(cells));
123     HRegionServer rs = TEST_UTIL.getMiniHBaseCluster().getRegionServer(0);
124     ClientProtos.MultiResponse response = rs.getRSRpcServices().multi(controller, request);
125     assertEquals(2, response.getRegionActionResultCount());
126     assertTrue(response.getRegionActionResultList().get(0).hasException());
127     assertFalse(response.getRegionActionResultList().get(1).hasException());
128     assertEquals(1, response.getRegionActionResultList().get(1).getResultOrExceptionCount());
129     assertTrue(
130       response.getRegionActionResultList().get(1).getResultOrExceptionList().get(0).hasResult());
131     try (Table table = TEST_UTIL.getConnection().getTable(TABLE_NAME)) {
132       Result result = table.get(new Get(Bytes.toBytes("good")));
133       assertEquals(1, result.size());
134       Cell cell = result.getColumnLatestCell(FAMILY, null);
135       assertTrue(Bytes.equals(CellUtil.cloneValue(cell), new byte[10]));
136     }
137   }
138 
139   private static ClientProtos.MultiRequest createRequest(RowMutations rm, byte[] regionName)
140     throws IOException {
141     ClientProtos.RegionAction.Builder builder = RequestConverter
142       .getRegionActionBuilderWithRegion(ClientProtos.RegionAction.newBuilder(), regionName);
143     builder.setAtomic(true);
144     ClientProtos.Action.Builder actionBuilder = ClientProtos.Action.newBuilder();
145     ClientProtos.MutationProto.Builder mutationBuilder = ClientProtos.MutationProto.newBuilder();
146     ClientProtos.Condition condition = RequestConverter
147       .buildCondition(rm.getRow(), FAMILY, FAMILY, new BinaryComparator(new byte[10]),
148         HBaseProtos.CompareType.EQUAL);
149     for (Mutation mutation : rm.getMutations()) {
150       ClientProtos.MutationProto.MutationType mutateType = null;
151       if (mutation instanceof Put) {
152         mutateType = ClientProtos.MutationProto.MutationType.PUT;
153       } else if (mutation instanceof Delete) {
154         mutateType = ClientProtos.MutationProto.MutationType.DELETE;
155       } else {
156         throw new DoNotRetryIOException(
157           "RowMutations supports only put and delete, not " + mutation.getClass().getName());
158       }
159       mutationBuilder.clear();
160       ClientProtos.MutationProto mp =
161         ProtobufUtil.toMutationNoData(mutateType, mutation, mutationBuilder);
162       actionBuilder.clear();
163       actionBuilder.setMutation(mp);
164       // add a get to fail the rm
165       actionBuilder.setGet(ProtobufUtil.toGet(new Get(rm.getRow())));
166       builder.addAction(actionBuilder.build());
167     }
168     ClientProtos.MultiRequest request =
169       ClientProtos.MultiRequest.newBuilder().addRegionAction(builder.build())
170         .setCondition(condition).build();
171     return request;
172   }
173 }