001/*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018package org.apache.hadoop.hbase.client;
019
020import static org.junit.jupiter.api.Assertions.assertEquals;
021import static org.junit.jupiter.api.Assertions.assertFalse;
022import static org.junit.jupiter.api.Assertions.assertTrue;
023
024import java.util.Arrays;
025import org.apache.hadoop.hbase.CompareOperator;
026import org.apache.hadoop.hbase.filter.FilterList;
027import org.apache.hadoop.hbase.filter.SingleColumnValueFilter;
028import org.apache.hadoop.hbase.ipc.CoprocessorRpcChannel;
029import org.apache.hadoop.hbase.util.Bytes;
030import org.junit.jupiter.api.TestTemplate;
031
032import org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil;
033import org.apache.hadoop.hbase.shaded.protobuf.generated.ClientProtos.MutationProto;
034import org.apache.hadoop.hbase.shaded.protobuf.generated.ClientProtos.MutationProto.MutationType;
035import org.apache.hadoop.hbase.shaded.protobuf.generated.MultiRowMutationProtos.MultiRowMutationService;
036import org.apache.hadoop.hbase.shaded.protobuf.generated.MultiRowMutationProtos.MutateRowsRequest;
037import org.apache.hadoop.hbase.shaded.protobuf.generated.MultiRowMutationProtos.MutateRowsResponse;
038
039public class FromClientSideTestMultiRowMutation extends FromClientSideTestBase {
040
041  protected FromClientSideTestMultiRowMutation(Class<? extends ConnectionRegistry> registryImpl,
042    int numHedgedReqs) {
043    super(registryImpl, numHedgedReqs);
044  }
045
046  @TestTemplate
047  public void testMultiRowMutation() throws Exception {
048    final byte[] ROW1 = Bytes.toBytes("testRow1");
049    final byte[] ROW2 = Bytes.toBytes("testRow2");
050    final byte[] ROW3 = Bytes.toBytes("testRow3");
051    TEST_UTIL.createTable(tableName, FAMILY);
052    try (Connection conn = getConnection(); Table t = conn.getTable(tableName)) {
053      // Add initial data
054      t.batch(Arrays.asList(new Put(ROW1).addColumn(FAMILY, QUALIFIER, VALUE),
055        new Put(ROW2).addColumn(FAMILY, QUALIFIER, Bytes.toBytes(1L)),
056        new Put(ROW3).addColumn(FAMILY, QUALIFIER, VALUE)), new Object[3]);
057
058      // Execute MultiRowMutation
059      Put put = new Put(ROW).addColumn(FAMILY, QUALIFIER, VALUE);
060      MutationProto m1 = ProtobufUtil.toMutation(MutationType.PUT, put);
061
062      Delete delete = new Delete(ROW1);
063      MutationProto m2 = ProtobufUtil.toMutation(MutationType.DELETE, delete);
064
065      Increment increment = new Increment(ROW2).addColumn(FAMILY, QUALIFIER, 1L);
066      MutationProto m3 = ProtobufUtil.toMutation(MutationType.INCREMENT, increment);
067
068      Append append = new Append(ROW3).addColumn(FAMILY, QUALIFIER, VALUE);
069      MutationProto m4 = ProtobufUtil.toMutation(MutationType.APPEND, append);
070
071      MutateRowsRequest.Builder mrmBuilder = MutateRowsRequest.newBuilder();
072      mrmBuilder.addMutationRequest(m1);
073      mrmBuilder.addMutationRequest(m2);
074      mrmBuilder.addMutationRequest(m3);
075      mrmBuilder.addMutationRequest(m4);
076
077      CoprocessorRpcChannel channel = t.coprocessorService(ROW);
078      MultiRowMutationService.BlockingInterface service =
079        MultiRowMutationService.newBlockingStub(channel);
080      MutateRowsResponse response = service.mutateRows(null, mrmBuilder.build());
081
082      // Assert
083      assertTrue(response.getProcessed());
084
085      Result r = t.get(new Get(ROW));
086      assertEquals(Bytes.toString(VALUE), Bytes.toString(r.getValue(FAMILY, QUALIFIER)));
087
088      r = t.get(new Get(ROW1));
089      assertTrue(r.isEmpty());
090
091      r = t.get(new Get(ROW2));
092      assertEquals(2L, Bytes.toLong(r.getValue(FAMILY, QUALIFIER)));
093
094      r = t.get(new Get(ROW3));
095      assertEquals(Bytes.toString(VALUE) + Bytes.toString(VALUE),
096        Bytes.toString(r.getValue(FAMILY, QUALIFIER)));
097    }
098  }
099
100  @TestTemplate
101  public void testMultiRowMutationWithSingleConditionWhenConditionMatches() throws Exception {
102    final byte[] ROW1 = Bytes.toBytes("testRow1");
103    final byte[] ROW2 = Bytes.toBytes("testRow2");
104    final byte[] VALUE1 = Bytes.toBytes("testValue1");
105    final byte[] VALUE2 = Bytes.toBytes("testValue2");
106    TEST_UTIL.createTable(tableName, FAMILY);
107    try (Connection conn = getConnection(); Table t = conn.getTable(tableName)) {
108      // Add initial data
109      t.put(new Put(ROW2).addColumn(FAMILY, QUALIFIER, VALUE2));
110
111      // Execute MultiRowMutation with conditions
112      Put put1 = new Put(ROW).addColumn(FAMILY, QUALIFIER, VALUE);
113      MutationProto m1 = ProtobufUtil.toMutation(MutationType.PUT, put1);
114      Put put2 = new Put(ROW1).addColumn(FAMILY, QUALIFIER, VALUE1);
115      MutationProto m2 = ProtobufUtil.toMutation(MutationType.PUT, put2);
116      Delete delete = new Delete(ROW2);
117      MutationProto m3 = ProtobufUtil.toMutation(MutationType.DELETE, delete);
118
119      MutateRowsRequest.Builder mrmBuilder = MutateRowsRequest.newBuilder();
120      mrmBuilder.addMutationRequest(m1);
121      mrmBuilder.addMutationRequest(m2);
122      mrmBuilder.addMutationRequest(m3);
123      mrmBuilder.addCondition(
124        ProtobufUtil.toCondition(ROW2, FAMILY, QUALIFIER, CompareOperator.EQUAL, VALUE2, null));
125
126      CoprocessorRpcChannel channel = t.coprocessorService(ROW);
127      MultiRowMutationService.BlockingInterface service =
128        MultiRowMutationService.newBlockingStub(channel);
129      MutateRowsResponse response = service.mutateRows(null, mrmBuilder.build());
130
131      // Assert
132      assertTrue(response.getProcessed());
133
134      Result r = t.get(new Get(ROW));
135      assertEquals(Bytes.toString(VALUE), Bytes.toString(r.getValue(FAMILY, QUALIFIER)));
136
137      r = t.get(new Get(ROW1));
138      assertEquals(Bytes.toString(VALUE1), Bytes.toString(r.getValue(FAMILY, QUALIFIER)));
139
140      r = t.get(new Get(ROW2));
141      assertTrue(r.isEmpty());
142    }
143  }
144
145  @TestTemplate
146  public void testMultiRowMutationWithSingleConditionWhenConditionNotMatch() throws Exception {
147    final byte[] ROW1 = Bytes.toBytes("testRow1");
148    final byte[] ROW2 = Bytes.toBytes("testRow2");
149    final byte[] VALUE1 = Bytes.toBytes("testValue1");
150    final byte[] VALUE2 = Bytes.toBytes("testValue2");
151    TEST_UTIL.createTable(tableName, FAMILY);
152    try (Connection conn = getConnection(); Table t = conn.getTable(tableName)) {
153      // Add initial data
154      t.put(new Put(ROW2).addColumn(FAMILY, QUALIFIER, VALUE2));
155
156      // Execute MultiRowMutation with conditions
157      Put put1 = new Put(ROW).addColumn(FAMILY, QUALIFIER, VALUE);
158      MutationProto m1 = ProtobufUtil.toMutation(MutationType.PUT, put1);
159      Put put2 = new Put(ROW1).addColumn(FAMILY, QUALIFIER, VALUE1);
160      MutationProto m2 = ProtobufUtil.toMutation(MutationType.PUT, put2);
161      Delete delete = new Delete(ROW2);
162      MutationProto m3 = ProtobufUtil.toMutation(MutationType.DELETE, delete);
163
164      MutateRowsRequest.Builder mrmBuilder = MutateRowsRequest.newBuilder();
165      mrmBuilder.addMutationRequest(m1);
166      mrmBuilder.addMutationRequest(m2);
167      mrmBuilder.addMutationRequest(m3);
168      mrmBuilder.addCondition(
169        ProtobufUtil.toCondition(ROW2, FAMILY, QUALIFIER, CompareOperator.EQUAL, VALUE1, null));
170
171      CoprocessorRpcChannel channel = t.coprocessorService(ROW);
172      MultiRowMutationService.BlockingInterface service =
173        MultiRowMutationService.newBlockingStub(channel);
174      MutateRowsResponse response = service.mutateRows(null, mrmBuilder.build());
175
176      // Assert
177      assertFalse(response.getProcessed());
178
179      Result r = t.get(new Get(ROW));
180      assertTrue(r.isEmpty());
181
182      r = t.get(new Get(ROW1));
183      assertTrue(r.isEmpty());
184
185      r = t.get(new Get(ROW2));
186      assertEquals(Bytes.toString(VALUE2), Bytes.toString(r.getValue(FAMILY, QUALIFIER)));
187    }
188  }
189
190  @TestTemplate
191  public void testMultiRowMutationWithMultipleConditionsWhenConditionsMatch() throws Exception {
192    final byte[] ROW1 = Bytes.toBytes("testRow1");
193    final byte[] ROW2 = Bytes.toBytes("testRow2");
194    final byte[] VALUE1 = Bytes.toBytes("testValue1");
195    final byte[] VALUE2 = Bytes.toBytes("testValue2");
196    TEST_UTIL.createTable(tableName, FAMILY);
197    try (Connection conn = getConnection(); Table t = conn.getTable(tableName)) {
198      // Add initial data
199      t.put(new Put(ROW2).addColumn(FAMILY, QUALIFIER, VALUE2));
200
201      // Execute MultiRowMutation with conditions
202      Put put1 = new Put(ROW).addColumn(FAMILY, QUALIFIER, VALUE);
203      MutationProto m1 = ProtobufUtil.toMutation(MutationType.PUT, put1);
204      Put put2 = new Put(ROW1).addColumn(FAMILY, QUALIFIER, VALUE1);
205      MutationProto m2 = ProtobufUtil.toMutation(MutationType.PUT, put2);
206      Delete delete = new Delete(ROW2);
207      MutationProto m3 = ProtobufUtil.toMutation(MutationType.DELETE, delete);
208
209      MutateRowsRequest.Builder mrmBuilder = MutateRowsRequest.newBuilder();
210      mrmBuilder.addMutationRequest(m1);
211      mrmBuilder.addMutationRequest(m2);
212      mrmBuilder.addMutationRequest(m3);
213      mrmBuilder.addCondition(
214        ProtobufUtil.toCondition(ROW, FAMILY, QUALIFIER, CompareOperator.EQUAL, null, null));
215      mrmBuilder.addCondition(
216        ProtobufUtil.toCondition(ROW2, FAMILY, QUALIFIER, CompareOperator.EQUAL, VALUE2, null));
217
218      CoprocessorRpcChannel channel = t.coprocessorService(ROW);
219      MultiRowMutationService.BlockingInterface service =
220        MultiRowMutationService.newBlockingStub(channel);
221      MutateRowsResponse response = service.mutateRows(null, mrmBuilder.build());
222
223      // Assert
224      assertTrue(response.getProcessed());
225
226      Result r = t.get(new Get(ROW));
227      assertEquals(Bytes.toString(VALUE), Bytes.toString(r.getValue(FAMILY, QUALIFIER)));
228
229      r = t.get(new Get(ROW1));
230      assertEquals(Bytes.toString(VALUE1), Bytes.toString(r.getValue(FAMILY, QUALIFIER)));
231
232      r = t.get(new Get(ROW2));
233      assertTrue(r.isEmpty());
234    }
235  }
236
237  @TestTemplate
238  public void testMultiRowMutationWithMultipleConditionsWhenConditionsNotMatch() throws Exception {
239    final byte[] ROW1 = Bytes.toBytes("testRow1");
240    final byte[] ROW2 = Bytes.toBytes("testRow2");
241    final byte[] VALUE1 = Bytes.toBytes("testValue1");
242    final byte[] VALUE2 = Bytes.toBytes("testValue2");
243    TEST_UTIL.createTable(tableName, FAMILY);
244    try (Connection conn = getConnection(); Table t = conn.getTable(tableName)) {
245      // Add initial data
246      t.put(new Put(ROW2).addColumn(FAMILY, QUALIFIER, VALUE2));
247
248      // Execute MultiRowMutation with conditions
249      Put put1 = new Put(ROW).addColumn(FAMILY, QUALIFIER, VALUE);
250      MutationProto m1 = ProtobufUtil.toMutation(MutationType.PUT, put1);
251      Put put2 = new Put(ROW1).addColumn(FAMILY, QUALIFIER, VALUE1);
252      MutationProto m2 = ProtobufUtil.toMutation(MutationType.PUT, put2);
253      Delete delete = new Delete(ROW2);
254      MutationProto m3 = ProtobufUtil.toMutation(MutationType.DELETE, delete);
255
256      MutateRowsRequest.Builder mrmBuilder = MutateRowsRequest.newBuilder();
257      mrmBuilder.addMutationRequest(m1);
258      mrmBuilder.addMutationRequest(m2);
259      mrmBuilder.addMutationRequest(m3);
260      mrmBuilder.addCondition(
261        ProtobufUtil.toCondition(ROW1, FAMILY, QUALIFIER, CompareOperator.EQUAL, null, null));
262      mrmBuilder.addCondition(
263        ProtobufUtil.toCondition(ROW2, FAMILY, QUALIFIER, CompareOperator.EQUAL, VALUE1, null));
264
265      CoprocessorRpcChannel channel = t.coprocessorService(ROW);
266      MultiRowMutationService.BlockingInterface service =
267        MultiRowMutationService.newBlockingStub(channel);
268      MutateRowsResponse response = service.mutateRows(null, mrmBuilder.build());
269
270      // Assert
271      assertFalse(response.getProcessed());
272
273      Result r = t.get(new Get(ROW));
274      assertTrue(r.isEmpty());
275
276      r = t.get(new Get(ROW1));
277      assertTrue(r.isEmpty());
278
279      r = t.get(new Get(ROW2));
280      assertEquals(Bytes.toString(VALUE2), Bytes.toString(r.getValue(FAMILY, QUALIFIER)));
281    }
282  }
283
284  @TestTemplate
285  public void testMultiRowMutationWithFilterConditionWhenConditionMatches() throws Exception {
286    final byte[] ROW1 = Bytes.toBytes("testRow1");
287    final byte[] ROW2 = Bytes.toBytes("testRow2");
288    final byte[] QUALIFIER2 = Bytes.toBytes("testQualifier2");
289    final byte[] VALUE1 = Bytes.toBytes("testValue1");
290    final byte[] VALUE2 = Bytes.toBytes("testValue2");
291    final byte[] VALUE3 = Bytes.toBytes("testValue3");
292    TEST_UTIL.createTable(tableName, FAMILY);
293    try (Connection conn = getConnection(); Table t = conn.getTable(tableName)) {
294      // Add initial data
295      t.put(
296        new Put(ROW2).addColumn(FAMILY, QUALIFIER, VALUE2).addColumn(FAMILY, QUALIFIER2, VALUE3));
297
298      // Execute MultiRowMutation with conditions
299      Put put1 = new Put(ROW).addColumn(FAMILY, QUALIFIER, VALUE);
300      MutationProto m1 = ProtobufUtil.toMutation(MutationType.PUT, put1);
301      Put put2 = new Put(ROW1).addColumn(FAMILY, QUALIFIER, VALUE1);
302      MutationProto m2 = ProtobufUtil.toMutation(MutationType.PUT, put2);
303      Delete delete = new Delete(ROW2);
304      MutationProto m3 = ProtobufUtil.toMutation(MutationType.DELETE, delete);
305
306      MutateRowsRequest.Builder mrmBuilder = MutateRowsRequest.newBuilder();
307      mrmBuilder.addMutationRequest(m1);
308      mrmBuilder.addMutationRequest(m2);
309      mrmBuilder.addMutationRequest(m3);
310      mrmBuilder.addCondition(ProtobufUtil.toCondition(ROW2,
311        new FilterList(
312          new SingleColumnValueFilter(FAMILY, QUALIFIER, CompareOperator.EQUAL, VALUE2),
313          new SingleColumnValueFilter(FAMILY, QUALIFIER2, CompareOperator.EQUAL, VALUE3)),
314        null));
315
316      CoprocessorRpcChannel channel = t.coprocessorService(ROW);
317      MultiRowMutationService.BlockingInterface service =
318        MultiRowMutationService.newBlockingStub(channel);
319      MutateRowsResponse response = service.mutateRows(null, mrmBuilder.build());
320
321      // Assert
322      assertTrue(response.getProcessed());
323
324      Result r = t.get(new Get(ROW));
325      assertEquals(Bytes.toString(VALUE), Bytes.toString(r.getValue(FAMILY, QUALIFIER)));
326
327      r = t.get(new Get(ROW1));
328      assertEquals(Bytes.toString(VALUE1), Bytes.toString(r.getValue(FAMILY, QUALIFIER)));
329
330      r = t.get(new Get(ROW2));
331      assertTrue(r.isEmpty());
332    }
333  }
334
335  @TestTemplate
336  public void testMultiRowMutationWithFilterConditionWhenConditionNotMatch() throws Exception {
337    final byte[] ROW1 = Bytes.toBytes("testRow1");
338    final byte[] ROW2 = Bytes.toBytes("testRow2");
339    final byte[] QUALIFIER2 = Bytes.toBytes("testQualifier2");
340    final byte[] VALUE1 = Bytes.toBytes("testValue1");
341    final byte[] VALUE2 = Bytes.toBytes("testValue2");
342    final byte[] VALUE3 = Bytes.toBytes("testValue3");
343    TEST_UTIL.createTable(tableName, FAMILY);
344    try (Connection conn = getConnection(); Table t = conn.getTable(tableName)) {
345      // Add initial data
346      t.put(
347        new Put(ROW2).addColumn(FAMILY, QUALIFIER, VALUE2).addColumn(FAMILY, QUALIFIER2, VALUE3));
348
349      // Execute MultiRowMutation with conditions
350      Put put1 = new Put(ROW).addColumn(FAMILY, QUALIFIER, VALUE);
351      MutationProto m1 = ProtobufUtil.toMutation(MutationType.PUT, put1);
352      Put put2 = new Put(ROW1).addColumn(FAMILY, QUALIFIER, VALUE1);
353      MutationProto m2 = ProtobufUtil.toMutation(MutationType.PUT, put2);
354      Delete delete = new Delete(ROW2);
355      MutationProto m3 = ProtobufUtil.toMutation(MutationType.DELETE, delete);
356
357      MutateRowsRequest.Builder mrmBuilder = MutateRowsRequest.newBuilder();
358      mrmBuilder.addMutationRequest(m1);
359      mrmBuilder.addMutationRequest(m2);
360      mrmBuilder.addMutationRequest(m3);
361      mrmBuilder.addCondition(ProtobufUtil.toCondition(ROW2,
362        new FilterList(
363          new SingleColumnValueFilter(FAMILY, QUALIFIER, CompareOperator.EQUAL, VALUE2),
364          new SingleColumnValueFilter(FAMILY, QUALIFIER2, CompareOperator.EQUAL, VALUE2)),
365        null));
366
367      CoprocessorRpcChannel channel = t.coprocessorService(ROW);
368      MultiRowMutationService.BlockingInterface service =
369        MultiRowMutationService.newBlockingStub(channel);
370      MutateRowsResponse response = service.mutateRows(null, mrmBuilder.build());
371
372      // Assert
373      assertFalse(response.getProcessed());
374
375      Result r = t.get(new Get(ROW));
376      assertTrue(r.isEmpty());
377
378      r = t.get(new Get(ROW1));
379      assertTrue(r.isEmpty());
380
381      r = t.get(new Get(ROW2));
382      assertEquals(Bytes.toString(VALUE2), Bytes.toString(r.getValue(FAMILY, QUALIFIER)));
383    }
384  }
385}