HBASE-24030 Add necessary validations to HRegion.checkAndMutate() and HRegion.checkAndRowMutate() (#1315)

Signed-off-by: Viraj Jasani <vjasani@apache.org>
Signed-off-by: Jan Hentschel <janh@apache.org>
This commit is contained in:
Toshihiro Suzuki 2020-03-22 11:55:52 +09:00 committed by GitHub
parent b53fa3c51f
commit 9b4e75a7f6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 86 additions and 3 deletions

View File

@ -115,6 +115,7 @@ import org.apache.hadoop.hbase.client.RegionInfo;
import org.apache.hadoop.hbase.client.RegionInfoBuilder; import org.apache.hadoop.hbase.client.RegionInfoBuilder;
import org.apache.hadoop.hbase.client.RegionReplicaUtil; import org.apache.hadoop.hbase.client.RegionReplicaUtil;
import org.apache.hadoop.hbase.client.Result; import org.apache.hadoop.hbase.client.Result;
import org.apache.hadoop.hbase.client.Row;
import org.apache.hadoop.hbase.client.RowMutations; import org.apache.hadoop.hbase.client.RowMutations;
import org.apache.hadoop.hbase.client.Scan; import org.apache.hadoop.hbase.client.Scan;
import org.apache.hadoop.hbase.client.TableDescriptor; import org.apache.hadoop.hbase.client.TableDescriptor;
@ -4207,7 +4208,6 @@ public class HRegion implements HeapSize, PropagatingConfigurationObserver, Regi
@Override @Override
public boolean checkAndMutate(byte[] row, byte[] family, byte[] qualifier, CompareOperator op, public boolean checkAndMutate(byte[] row, byte[] family, byte[] qualifier, CompareOperator op,
ByteArrayComparable comparator, TimeRange timeRange, Mutation mutation) throws IOException { ByteArrayComparable comparator, TimeRange timeRange, Mutation mutation) throws IOException {
checkMutationType(mutation, row);
return doCheckAndRowMutate(row, family, qualifier, op, comparator, null, timeRange, null, return doCheckAndRowMutate(row, family, qualifier, op, comparator, null, timeRange, null,
mutation); mutation);
} }
@ -4243,6 +4243,12 @@ public class HRegion implements HeapSize, PropagatingConfigurationObserver, Regi
// need these commented out checks. // need these commented out checks.
// if (rowMutations == null && mutation == null) throw new DoNotRetryIOException("Both null"); // if (rowMutations == null && mutation == null) throw new DoNotRetryIOException("Both null");
// if (rowMutations != null && mutation != null) throw new DoNotRetryIOException("Both set"); // if (rowMutations != null && mutation != null) throw new DoNotRetryIOException("Both set");
if (mutation != null) {
checkMutationType(mutation);
checkRow(mutation, row);
} else {
checkRow(rowMutations, row);
}
checkReadOnly(); checkReadOnly();
// TODO, add check for value length also move this check to the client // TODO, add check for value length also move this check to the client
checkResources(); checkResources();
@ -4358,13 +4364,17 @@ public class HRegion implements HeapSize, PropagatingConfigurationObserver, Regi
} }
} }
private void checkMutationType(final Mutation mutation, final byte [] row) private void checkMutationType(final Mutation mutation)
throws DoNotRetryIOException { throws DoNotRetryIOException {
boolean isPut = mutation instanceof Put; boolean isPut = mutation instanceof Put;
if (!isPut && !(mutation instanceof Delete)) { if (!isPut && !(mutation instanceof Delete)) {
throw new org.apache.hadoop.hbase.DoNotRetryIOException("Action must be Put or Delete"); throw new org.apache.hadoop.hbase.DoNotRetryIOException("Action must be Put or Delete");
} }
if (!Bytes.equals(row, mutation.getRow())) { }
private void checkRow(final Row action, final byte[] row)
throws DoNotRetryIOException {
if (!Bytes.equals(row, action.getRow())) {
throw new org.apache.hadoop.hbase.DoNotRetryIOException("Action's getRow must match"); throw new org.apache.hadoop.hbase.DoNotRetryIOException("Action's getRow must match");
} }
} }

View File

@ -74,6 +74,7 @@ import org.apache.hadoop.hbase.CellBuilderType;
import org.apache.hadoop.hbase.CellUtil; import org.apache.hadoop.hbase.CellUtil;
import org.apache.hadoop.hbase.CompareOperator; import org.apache.hadoop.hbase.CompareOperator;
import org.apache.hadoop.hbase.CompatibilitySingletonFactory; import org.apache.hadoop.hbase.CompatibilitySingletonFactory;
import org.apache.hadoop.hbase.DoNotRetryIOException;
import org.apache.hadoop.hbase.DroppedSnapshotException; import org.apache.hadoop.hbase.DroppedSnapshotException;
import org.apache.hadoop.hbase.ExtendedCellBuilderFactory; import org.apache.hadoop.hbase.ExtendedCellBuilderFactory;
import org.apache.hadoop.hbase.HBaseClassTestRule; import org.apache.hadoop.hbase.HBaseClassTestRule;
@ -2268,6 +2269,78 @@ public class TestHRegion {
assertTrue(region.get(new Get(row).addColumn(FAMILY, Bytes.toBytes("A"))).isEmpty()); assertTrue(region.get(new Get(row).addColumn(FAMILY, Bytes.toBytes("A"))).isEmpty());
} }
@Test
public void testCheckAndMutate_wrongMutationType() throws Throwable {
// Setting up region
this.region = initHRegion(tableName, method, CONF, fam1);
try {
region.checkAndMutate(row, fam1, qual1, CompareOperator.EQUAL, new BinaryComparator(value1),
new Increment(row).addColumn(fam1, qual1, 1));
fail("should throw DoNotRetryIOException");
} catch (DoNotRetryIOException e) {
assertEquals("Action must be Put or Delete", e.getMessage());
}
try {
region.checkAndMutate(row,
new SingleColumnValueFilter(fam1, qual1, CompareOperator.EQUAL, value1),
new Increment(row).addColumn(fam1, qual1, 1));
fail("should throw DoNotRetryIOException");
} catch (DoNotRetryIOException e) {
assertEquals("Action must be Put or Delete", e.getMessage());
}
}
@Test
public void testCheckAndMutate_wrongRow() throws Throwable {
final byte[] wrongRow = Bytes.toBytes("wrongRow");
// Setting up region
this.region = initHRegion(tableName, method, CONF, fam1);
try {
region.checkAndMutate(row, fam1, qual1, CompareOperator.EQUAL, new BinaryComparator(value1),
new Put(wrongRow).addColumn(fam1, qual1, value1));
fail("should throw DoNotRetryIOException");
} catch (DoNotRetryIOException e) {
assertEquals("Action's getRow must match", e.getMessage());
}
try {
region.checkAndMutate(row,
new SingleColumnValueFilter(fam1, qual1, CompareOperator.EQUAL, value1),
new Put(wrongRow).addColumn(fam1, qual1, value1));
fail("should throw DoNotRetryIOException");
} catch (DoNotRetryIOException e) {
assertEquals("Action's getRow must match", e.getMessage());
}
try {
region.checkAndRowMutate(row, fam1, qual1, CompareOperator.EQUAL,
new BinaryComparator(value1),
new RowMutations(wrongRow)
.add((Mutation) new Put(wrongRow)
.addColumn(fam1, qual1, value1))
.add((Mutation) new Delete(wrongRow).addColumns(fam1, qual2)));
fail("should throw DoNotRetryIOException");
} catch (DoNotRetryIOException e) {
assertEquals("Action's getRow must match", e.getMessage());
}
try {
region.checkAndRowMutate(row,
new SingleColumnValueFilter(fam1, qual1, CompareOperator.EQUAL, value1),
new RowMutations(wrongRow)
.add((Mutation) new Put(wrongRow)
.addColumn(fam1, qual1, value1))
.add((Mutation) new Delete(wrongRow).addColumns(fam1, qual2)));
fail("should throw DoNotRetryIOException");
} catch (DoNotRetryIOException e) {
assertEquals("Action's getRow must match", e.getMessage());
}
}
// //////////////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////////////////
// Delete tests // Delete tests
// //////////////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////////////////