HBASE-19897 RowMutations should follow the fluent pattern

This commit is contained in:
Chia-Ping Tsai 2018-02-01 13:58:54 +08:00
parent 7fe215db5f
commit 6a1ed25581
2 changed files with 61 additions and 29 deletions

View File

@ -22,9 +22,9 @@ import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import org.apache.yetus.audience.InterfaceAudience;
import org.apache.hadoop.hbase.util.Bytes; import org.apache.hadoop.hbase.util.Bytes;
import org.apache.hadoop.hbase.util.CollectionUtils;
import org.apache.yetus.audience.InterfaceAudience;
/** /**
* Performs multiple mutations atomically on a single row. * Performs multiple mutations atomically on a single row.
@ -38,6 +38,21 @@ import org.apache.hadoop.hbase.util.Bytes;
*/ */
@InterfaceAudience.Public @InterfaceAudience.Public
public class RowMutations implements Row { public class RowMutations implements Row {
/**
* Create a {@link RowMutations} with the specified mutations.
* @param mutations the mutations to send
* @return RowMutations
* @throws IOException if any row in mutations is different to another
*/
public static RowMutations of(List<? extends Mutation> mutations) throws IOException {
if (CollectionUtils.isEmpty(mutations)) {
throw new IllegalArgumentException("Can't instantiate a RowMutations by empty list");
}
return new RowMutations(mutations.get(0).getRow(), mutations.size())
.add(mutations);
}
private final List<Mutation> mutations; private final List<Mutation> mutations;
private final byte [] row; private final byte [] row;
@ -50,8 +65,7 @@ public class RowMutations implements Row {
* @param initialCapacity the initial capacity of the RowMutations * @param initialCapacity the initial capacity of the RowMutations
*/ */
public RowMutations(byte [] row, int initialCapacity) { public RowMutations(byte [] row, int initialCapacity) {
Mutation.checkRow(row); this.row = Bytes.copy(Mutation.checkRow(row));
this.row = Bytes.copy(row);
if (initialCapacity <= 0) { if (initialCapacity <= 0) {
this.mutations = new ArrayList<>(); this.mutations = new ArrayList<>();
} else { } else {
@ -62,29 +76,53 @@ public class RowMutations implements Row {
/** /**
* Add a {@link Put} operation to the list of mutations * Add a {@link Put} operation to the list of mutations
* @param p The {@link Put} to add * @param p The {@link Put} to add
* @throws IOException * @throws IOException if the row of added mutation doesn't match the original row
* @deprecated since 2.0 version and will be removed in 3.0 version.
* use {@link #add(Mutation)}
*/ */
@Deprecated
public void add(Put p) throws IOException { public void add(Put p) throws IOException {
internalAdd(p); add((Mutation) p);
} }
/** /**
* Add a {@link Delete} operation to the list of mutations * Add a {@link Delete} operation to the list of mutations
* @param d The {@link Delete} to add * @param d The {@link Delete} to add
* @throws IOException * @throws IOException if the row of added mutation doesn't match the original row
* @deprecated since 2.0 version and will be removed in 3.0 version.
* use {@link #add(Mutation)}
*/ */
@Deprecated
public void add(Delete d) throws IOException { public void add(Delete d) throws IOException {
internalAdd(d); add((Mutation) d);
} }
private void internalAdd(Mutation m) throws IOException { /**
int res = Bytes.compareTo(this.row, m.getRow()); * Currently only supports {@link Put} and {@link Delete} mutations.
if (res != 0) { *
throw new WrongRowIOException("The row in the recently added Put/Delete <" + * @param mutation The data to send.
Bytes.toStringBinary(m.getRow()) + "> doesn't match the original one <" + * @throws IOException if the row of added mutation doesn't match the original row
*/
public RowMutations add(Mutation mutation) throws IOException {
return add(Collections.singletonList(mutation));
}
/**
* Currently only supports {@link Put} and {@link Delete} mutations.
*
* @param mutations The data to send.
* @throws IOException if the row of added mutation doesn't match the original row
*/
public RowMutations add(List<? extends Mutation> mutations) throws IOException {
for (Mutation mutation : mutations) {
if (!Bytes.equals(row, mutation.getRow())) {
throw new WrongRowIOException("The row in the recently added Put/Delete <" +
Bytes.toStringBinary(mutation.getRow()) + "> doesn't match the original one <" +
Bytes.toStringBinary(this.row) + ">"); Bytes.toStringBinary(this.row) + ">");
}
} }
mutations.add(m); this.mutations.addAll(mutations);
return this;
} }
/** /**

View File

@ -26,6 +26,7 @@ import static org.junit.Assert.fail;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.Random; import java.util.Random;
@ -452,10 +453,9 @@ public class TestFromClientSide3 {
byte [][] QUALIFIERS = new byte [][] { byte [][] QUALIFIERS = new byte [][] {
Bytes.toBytes("a"), Bytes.toBytes("b") Bytes.toBytes("a"), Bytes.toBytes("b")
}; };
RowMutations arm = new RowMutations(ROW);
Put p = new Put(ROW); RowMutations arm = RowMutations.of(Collections.singletonList(
p.addColumn(FAMILY, QUALIFIERS[0], VALUE); new Put(ROW).addColumn(FAMILY, QUALIFIERS[0], VALUE)));
arm.add(p);
Object[] batchResult = new Object[1]; Object[] batchResult = new Object[1];
t.batch(Arrays.asList(arm), batchResult); t.batch(Arrays.asList(arm), batchResult);
@ -463,13 +463,9 @@ public class TestFromClientSide3 {
Result r = t.get(g); Result r = t.get(g);
assertEquals(0, Bytes.compareTo(VALUE, r.getValue(FAMILY, QUALIFIERS[0]))); assertEquals(0, Bytes.compareTo(VALUE, r.getValue(FAMILY, QUALIFIERS[0])));
arm = new RowMutations(ROW); arm = RowMutations.of(Arrays.asList(
p = new Put(ROW); new Put(ROW).addColumn(FAMILY, QUALIFIERS[1], VALUE),
p.addColumn(FAMILY, QUALIFIERS[1], VALUE); new Delete(ROW).addColumns(FAMILY, QUALIFIERS[0])));
arm.add(p);
Delete d = new Delete(ROW);
d.addColumns(FAMILY, QUALIFIERS[0]);
arm.add(d);
t.batch(Arrays.asList(arm), batchResult); t.batch(Arrays.asList(arm), batchResult);
r = t.get(g); r = t.get(g);
assertEquals(0, Bytes.compareTo(VALUE, r.getValue(FAMILY, QUALIFIERS[1]))); assertEquals(0, Bytes.compareTo(VALUE, r.getValue(FAMILY, QUALIFIERS[1])));
@ -477,10 +473,8 @@ public class TestFromClientSide3 {
// Test that we get the correct remote exception for RowMutations from batch() // Test that we get the correct remote exception for RowMutations from batch()
try { try {
arm = new RowMutations(ROW); arm = RowMutations.of(Collections.singletonList(
p = new Put(ROW); new Put(ROW).addColumn(new byte[]{'b', 'o', 'g', 'u', 's'}, QUALIFIERS[0], VALUE)));
p.addColumn(new byte[]{'b', 'o', 'g', 'u', 's'}, QUALIFIERS[0], VALUE);
arm.add(p);
t.batch(Arrays.asList(arm), batchResult); t.batch(Arrays.asList(arm), batchResult);
fail("Expected RetriesExhaustedWithDetailsException with NoSuchColumnFamilyException"); fail("Expected RetriesExhaustedWithDetailsException with NoSuchColumnFamilyException");
} catch(RetriesExhaustedWithDetailsException e) { } catch(RetriesExhaustedWithDetailsException e) {