This is an automated email from the ASF dual-hosted git repository.

brfrn169 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/hbase.git


The following commit(s) were added to refs/heads/master by this push:
     new 5fa15cf  HBASE-25575 Should validate Puts in RowMutations (#2954)
5fa15cf is described below

commit 5fa15cfde3d77e77ffb1f09d60dce4db264f3831
Author: Toshihiro Suzuki <brfrn...@gmail.com>
AuthorDate: Mon Feb 22 10:46:16 2021 +0900

    HBASE-25575 Should validate Puts in RowMutations (#2954)
    
    Signed-off-by: Duo Zhang <zhang...@apache.org>
---
 .../hadoop/hbase/client/ConnectionUtils.java       | 10 ++++-
 .../hadoop/hbase/client/RawAsyncTableImpl.java     | 13 ++++--
 .../apache/hadoop/hbase/client/TestAsyncTable.java | 43 +++++++++++++++++++
 .../hadoop/hbase/client/TestAsyncTableBatch.java   | 50 ++++++++++++++++++++++
 4 files changed, 112 insertions(+), 4 deletions(-)

diff --git 
a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/ConnectionUtils.java
 
b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/ConnectionUtils.java
index 5b8cb84..70312aa 100644
--- 
a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/ConnectionUtils.java
+++ 
b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/ConnectionUtils.java
@@ -482,7 +482,7 @@ public final class ConnectionUtils {
   }
 
   // validate for well-formedness
-  static void validatePut(Put put, int maxKeyValueSize) throws 
IllegalArgumentException {
+  static void validatePut(Put put, int maxKeyValueSize) {
     if (put.isEmpty()) {
       throw new IllegalArgumentException("No columns to insert");
     }
@@ -497,6 +497,14 @@ public final class ConnectionUtils {
     }
   }
 
+  static void validatePutsInRowMutations(RowMutations rowMutations, int 
maxKeyValueSize) {
+    for (Mutation mutation : rowMutations.getMutations()) {
+      if (mutation instanceof Put) {
+        validatePut((Put) mutation, maxKeyValueSize);
+      }
+    }
+  }
+
   /**
    * Select the priority for the rpc call.
    * <p/>
diff --git 
a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/RawAsyncTableImpl.java
 
b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/RawAsyncTableImpl.java
index 3cffad8..187ecf1 100644
--- 
a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/RawAsyncTableImpl.java
+++ 
b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/RawAsyncTableImpl.java
@@ -22,6 +22,7 @@ import static 
org.apache.hadoop.hbase.client.ConnectionUtils.checkHasFamilies;
 import static org.apache.hadoop.hbase.client.ConnectionUtils.isEmptyStopRow;
 import static 
org.apache.hadoop.hbase.client.ConnectionUtils.timelineConsistentRead;
 import static org.apache.hadoop.hbase.client.ConnectionUtils.validatePut;
+import static 
org.apache.hadoop.hbase.client.ConnectionUtils.validatePutsInRowMutations;
 import static org.apache.hadoop.hbase.util.FutureUtils.addListener;
 
 import java.io.IOException;
@@ -343,6 +344,7 @@ class RawAsyncTableImpl implements 
AsyncTable<AdvancedScanResultConsumer> {
     @Override
     public CompletableFuture<Boolean> thenMutate(RowMutations mutation) {
       preCheck();
+      validatePutsInRowMutations(mutation, conn.connConf.getMaxKeyValueSize());
       return RawAsyncTableImpl.this.<Boolean> newCaller(row, 
mutation.getMaxPriority(),
         rpcTimeoutNs)
         .action((controller, loc, stub) -> 
RawAsyncTableImpl.this.mutateRow(controller,
@@ -403,6 +405,7 @@ class RawAsyncTableImpl implements 
AsyncTable<AdvancedScanResultConsumer> {
 
     @Override
     public CompletableFuture<Boolean> thenMutate(RowMutations mutation) {
+      validatePutsInRowMutations(mutation, conn.connConf.getMaxKeyValueSize());
       return RawAsyncTableImpl.this.<Boolean> newCaller(row, 
mutation.getMaxPriority(),
         rpcTimeoutNs)
         .action((controller, loc, stub) -> 
RawAsyncTableImpl.this.mutateRow(controller,
@@ -420,9 +423,6 @@ class RawAsyncTableImpl implements 
AsyncTable<AdvancedScanResultConsumer> {
 
   @Override
   public CompletableFuture<CheckAndMutateResult> checkAndMutate(CheckAndMutate 
checkAndMutate) {
-    if (checkAndMutate.getAction() instanceof Put) {
-      validatePut((Put) checkAndMutate.getAction(), 
conn.connConf.getMaxKeyValueSize());
-    }
     if (checkAndMutate.getAction() instanceof Put || 
checkAndMutate.getAction() instanceof Delete
       || checkAndMutate.getAction() instanceof Increment
       || checkAndMutate.getAction() instanceof Append) {
@@ -442,6 +442,7 @@ class RawAsyncTableImpl implements 
AsyncTable<AdvancedScanResultConsumer> {
         .call();
     } else if (checkAndMutate.getAction() instanceof RowMutations) {
       RowMutations rowMutations = (RowMutations) checkAndMutate.getAction();
+      validatePutsInRowMutations(rowMutations, 
conn.connConf.getMaxKeyValueSize());
       return RawAsyncTableImpl.this.<CheckAndMutateResult> 
newCaller(checkAndMutate.getRow(),
         rowMutations.getMaxPriority(), rpcTimeoutNs)
         .action((controller, loc, stub) ->
@@ -514,6 +515,7 @@ class RawAsyncTableImpl implements 
AsyncTable<AdvancedScanResultConsumer> {
 
   @Override
   public CompletableFuture<Result> mutateRow(RowMutations mutations) {
+    validatePutsInRowMutations(mutations, conn.connConf.getMaxKeyValueSize());
     return this.<Result> newCaller(mutations.getRow(), 
mutations.getMaxPriority(),
       writeRpcTimeoutNs).action((controller, loc, stub) ->
         this.<Result, Result> mutateRow(controller, loc, stub, mutations,
@@ -615,7 +617,12 @@ class RawAsyncTableImpl implements 
AsyncTable<AdvancedScanResultConsumer> {
         CheckAndMutate checkAndMutate = (CheckAndMutate) action;
         if (checkAndMutate.getAction() instanceof Put) {
           validatePut((Put) checkAndMutate.getAction(), 
conn.connConf.getMaxKeyValueSize());
+        } else if (checkAndMutate.getAction() instanceof RowMutations) {
+          validatePutsInRowMutations((RowMutations) checkAndMutate.getAction(),
+            conn.connConf.getMaxKeyValueSize());
         }
+      } else if (action instanceof RowMutations) {
+        validatePutsInRowMutations((RowMutations) action, 
conn.connConf.getMaxKeyValueSize());
       }
     }
     return conn.callerFactory.batch().table(tableName).actions(actions)
diff --git 
a/hbase-server/src/test/java/org/apache/hadoop/hbase/client/TestAsyncTable.java 
b/hbase-server/src/test/java/org/apache/hadoop/hbase/client/TestAsyncTable.java
index f76c923..2952fa3 100644
--- 
a/hbase-server/src/test/java/org/apache/hadoop/hbase/client/TestAsyncTable.java
+++ 
b/hbase-server/src/test/java/org/apache/hadoop/hbase/client/TestAsyncTable.java
@@ -1673,4 +1673,47 @@ public class TestAsyncTable {
       assertThat(e.getMessage(), containsString("KeyValue size too large"));
     }
   }
+
+  @Test
+  public void testInvalidPutInRowMutations() throws IOException {
+    final byte[] row = Bytes.toBytes(0);
+    try {
+      getTable.get().mutateRow(new RowMutations(row).add(new Put(row)));
+      fail("Should fail since the put does not contain any cells");
+    } catch (IllegalArgumentException e) {
+      assertThat(e.getMessage(), containsString("No columns to insert"));
+    }
+
+    try {
+      getTable.get()
+        .mutateRow(new RowMutations(row).add(new Put(row)
+          .addColumn(FAMILY, QUALIFIER, new byte[MAX_KEY_VALUE_SIZE])));
+      fail("Should fail since the put exceeds the max key value size");
+    } catch (IllegalArgumentException e) {
+      assertThat(e.getMessage(), containsString("KeyValue size too large"));
+    }
+  }
+
+  @Test
+  public void testInvalidPutInRowMutationsInCheckAndMutate() throws 
IOException {
+    final byte[] row = Bytes.toBytes(0);
+    try {
+      getTable.get().checkAndMutate(CheckAndMutate.newBuilder(row)
+        .ifNotExists(FAMILY, QUALIFIER)
+        .build(new RowMutations(row).add(new Put(row))));
+      fail("Should fail since the put does not contain any cells");
+    } catch (IllegalArgumentException e) {
+      assertThat(e.getMessage(), containsString("No columns to insert"));
+    }
+
+    try {
+      getTable.get().checkAndMutate(CheckAndMutate.newBuilder(row)
+        .ifNotExists(FAMILY, QUALIFIER)
+        .build(new RowMutations(row).add(new Put(row)
+          .addColumn(FAMILY, QUALIFIER, new byte[MAX_KEY_VALUE_SIZE]))));
+      fail("Should fail since the put exceeds the max key value size");
+    } catch (IllegalArgumentException e) {
+      assertThat(e.getMessage(), containsString("KeyValue size too large"));
+    }
+  }
 }
diff --git 
a/hbase-server/src/test/java/org/apache/hadoop/hbase/client/TestAsyncTableBatch.java
 
b/hbase-server/src/test/java/org/apache/hadoop/hbase/client/TestAsyncTableBatch.java
index 4fb050e..78dbf0b 100644
--- 
a/hbase-server/src/test/java/org/apache/hadoop/hbase/client/TestAsyncTableBatch.java
+++ 
b/hbase-server/src/test/java/org/apache/hadoop/hbase/client/TestAsyncTableBatch.java
@@ -336,6 +336,56 @@ public class TestAsyncTableBatch {
   }
 
   @Test
+  public void testInvalidPutInRowMutations() throws IOException {
+    final byte[] row = Bytes.toBytes(0);
+
+    AsyncTable<?> table = tableGetter.apply(TABLE_NAME);
+    try {
+      table.batch(Arrays.asList(new Delete(row), new RowMutations(row).add(new 
Put(row))));
+      fail("Should fail since the put does not contain any cells");
+    } catch (IllegalArgumentException e) {
+      assertThat(e.getMessage(), containsString("No columns to insert"));
+    }
+
+    try {
+      table.batch(
+        Arrays.asList(new RowMutations(row).add(new Put(row)
+            .addColumn(FAMILY, CQ, new byte[MAX_KEY_VALUE_SIZE])),
+          new Delete(row)));
+      fail("Should fail since the put exceeds the max key value size");
+    } catch (IllegalArgumentException e) {
+      assertThat(e.getMessage(), containsString("KeyValue size too large"));
+    }
+  }
+
+  @Test
+  public void testInvalidPutInRowMutationsInCheckAndMutate() throws 
IOException {
+    final byte[] row = Bytes.toBytes(0);
+
+    AsyncTable<?> table = tableGetter.apply(TABLE_NAME);
+    try {
+      table.batch(Arrays.asList(new Delete(row), CheckAndMutate.newBuilder(row)
+        .ifNotExists(FAMILY, CQ)
+        .build(new RowMutations(row).add(new Put(row)))));
+      fail("Should fail since the put does not contain any cells");
+    } catch (IllegalArgumentException e) {
+      assertThat(e.getMessage(), containsString("No columns to insert"));
+    }
+
+    try {
+      table.batch(
+        Arrays.asList(CheckAndMutate.newBuilder(row)
+            .ifNotExists(FAMILY, CQ)
+            .build(new RowMutations(row).add(new Put(row)
+              .addColumn(FAMILY, CQ, new byte[MAX_KEY_VALUE_SIZE]))),
+          new Delete(row)));
+      fail("Should fail since the put exceeds the max key value size");
+    } catch (IllegalArgumentException e) {
+      assertThat(e.getMessage(), containsString("KeyValue size too large"));
+    }
+  }
+
+  @Test
   public void testWithCheckAndMutate() throws Exception {
     AsyncTable<?> table = tableGetter.apply(TABLE_NAME);
 

Reply via email to