You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hbase.apache.org by an...@apache.org on 2013/11/06 04:11:59 UTC
svn commit: r1539224 - in /hbase/trunk:
hbase-client/src/main/java/org/apache/hadoop/hbase/protobuf/
hbase-common/src/main/java/org/apache/hadoop/hbase/
hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/
hbase-server/src/main/java/org/apac...
Author: anoopsamjohn
Date: Wed Nov 6 03:11:58 2013
New Revision: 1539224
URL: http://svn.apache.org/r1539224
Log:
HBASE-9874 Append and Increment operation drops Tags
Modified:
hbase/trunk/hbase-client/src/main/java/org/apache/hadoop/hbase/protobuf/ProtobufUtil.java
hbase/trunk/hbase-common/src/main/java/org/apache/hadoop/hbase/CellUtil.java
hbase/trunk/hbase-common/src/main/java/org/apache/hadoop/hbase/KeyValue.java
hbase/trunk/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/BaseRegionObserver.java
hbase/trunk/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/RegionObserver.java
hbase/trunk/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/HRegion.java
hbase/trunk/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/RegionCoprocessorHost.java
hbase/trunk/hbase-server/src/test/java/org/apache/hadoop/hbase/regionserver/TestTags.java
Modified: hbase/trunk/hbase-client/src/main/java/org/apache/hadoop/hbase/protobuf/ProtobufUtil.java
URL: http://svn.apache.org/viewvc/hbase/trunk/hbase-client/src/main/java/org/apache/hadoop/hbase/protobuf/ProtobufUtil.java?rev=1539224&r1=1539223&r2=1539224&view=diff
==============================================================================
--- hbase/trunk/hbase-client/src/main/java/org/apache/hadoop/hbase/protobuf/ProtobufUtil.java (original)
+++ hbase/trunk/hbase-client/src/main/java/org/apache/hadoop/hbase/protobuf/ProtobufUtil.java Wed Nov 6 03:11:58 2013
@@ -627,7 +627,9 @@ public final class ProtobufUtil {
"Missing required field: qualifer value");
}
byte[] value = qv.getValue().toByteArray();
- append.add(family, qualifier, value);
+ byte[] tags = qv.getTags().toByteArray();
+ append.add(CellUtil.createCell(row, family, qualifier, append.getTimeStamp(),
+ KeyValue.Type.Put, value, tags));
}
}
}
@@ -699,8 +701,10 @@ public final class ProtobufUtil {
if (!qv.hasValue()) {
throw new DoNotRetryIOException("Missing required field: qualifer value");
}
- long value = Bytes.toLong(qv.getValue().toByteArray());
- increment.addColumn(family, qualifier, value);
+ byte[] value = qv.getValue().toByteArray();
+ byte[] tags = qv.getTags().toByteArray();
+ increment.add(CellUtil.createCell(row, family, qualifier, increment.getTimeStamp(),
+ KeyValue.Type.Put, value, tags));
}
}
}
@@ -973,6 +977,10 @@ public final class ProtobufUtil {
kv.getQualifierArray(), kv.getQualifierOffset(), kv.getQualifierLength()));
valueBuilder.setValue(ZeroCopyLiteralByteString.wrap(
kv.getValueArray(), kv.getValueOffset(), kv.getValueLength()));
+ if (kv.getTagsLength() > 0) {
+ valueBuilder.setTags(ZeroCopyLiteralByteString.wrap(kv.getTagsArray(),
+ kv.getTagsOffset(), kv.getTagsLength()));
+ }
columnBuilder.addQualifierValue(valueBuilder.build());
}
}
Modified: hbase/trunk/hbase-common/src/main/java/org/apache/hadoop/hbase/CellUtil.java
URL: http://svn.apache.org/viewvc/hbase/trunk/hbase-common/src/main/java/org/apache/hadoop/hbase/CellUtil.java?rev=1539224&r1=1539223&r2=1539224&view=diff
==============================================================================
--- hbase/trunk/hbase-common/src/main/java/org/apache/hadoop/hbase/CellUtil.java (original)
+++ hbase/trunk/hbase-common/src/main/java/org/apache/hadoop/hbase/CellUtil.java Wed Nov 6 03:11:58 2013
@@ -172,6 +172,12 @@ public final class CellUtil {
return keyValue;
}
+ public static Cell createCell(final byte[] row, final byte[] family, final byte[] qualifier,
+ final long timestamp, Type type, final byte[] value, byte[] tags) {
+ KeyValue keyValue = new KeyValue(row, family, qualifier, timestamp, type, value, tags);
+ return keyValue;
+ }
+
/**
* @param cellScannerables
* @return CellScanner interface over <code>cellIterables</code>
Modified: hbase/trunk/hbase-common/src/main/java/org/apache/hadoop/hbase/KeyValue.java
URL: http://svn.apache.org/viewvc/hbase/trunk/hbase-common/src/main/java/org/apache/hadoop/hbase/KeyValue.java?rev=1539224&r1=1539223&r2=1539224&view=diff
==============================================================================
--- hbase/trunk/hbase-common/src/main/java/org/apache/hadoop/hbase/KeyValue.java (original)
+++ hbase/trunk/hbase-common/src/main/java/org/apache/hadoop/hbase/KeyValue.java Wed Nov 6 03:11:58 2013
@@ -809,7 +809,7 @@ public class KeyValue implements Cell, H
pos += flength + qlength;
pos = Bytes.putLong(bytes, pos, timestamp);
pos = Bytes.putByte(bytes, pos, type.getCode());
- pos += keylength + vlength;
+ pos += vlength;
if (tagsLength > 0) {
pos = Bytes.putShort(bytes, pos, (short)(tagsLength & 0x0000ffff));
}
Modified: hbase/trunk/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/BaseRegionObserver.java
URL: http://svn.apache.org/viewvc/hbase/trunk/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/BaseRegionObserver.java?rev=1539224&r1=1539223&r2=1539224&view=diff
==============================================================================
--- hbase/trunk/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/BaseRegionObserver.java (original)
+++ hbase/trunk/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/BaseRegionObserver.java Wed Nov 6 03:11:58 2013
@@ -477,4 +477,10 @@ public abstract class BaseRegionObserver
DataBlockEncoding preferredEncodingInCache, Reference r, Reader reader) throws IOException {
return reader;
}
+
+ @Override
+ public Cell postMutationBeforeWAL(ObserverContext<RegionCoprocessorEnvironment> ctx,
+ MutationType opType, Mutation mutation, Cell oldCell, Cell newCell) throws IOException {
+ return newCell;
+ }
}
Modified: hbase/trunk/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/RegionObserver.java
URL: http://svn.apache.org/viewvc/hbase/trunk/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/RegionObserver.java?rev=1539224&r1=1539223&r2=1539224&view=diff
==============================================================================
--- hbase/trunk/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/RegionObserver.java (original)
+++ hbase/trunk/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/RegionObserver.java Wed Nov 6 03:11:58 2013
@@ -67,6 +67,11 @@ import org.apache.hadoop.hbase.util.Pair
@InterfaceStability.Evolving
public interface RegionObserver extends Coprocessor {
+ /** Mutation type for postMutationBeforeWAL hook */
+ public enum MutationType {
+ APPEND, INCREMENT
+ }
+
/**
* Called before the region is reported as open to the master.
* @param c the environment provided by the region server
@@ -1052,4 +1057,20 @@ public interface RegionObserver extends
final FileSystem fs, final Path p, final FSDataInputStreamWrapper in, long size,
final CacheConfig cacheConf, final DataBlockEncoding preferredEncodingInCache,
final Reference r, StoreFile.Reader reader) throws IOException;
+
+ /**
+ * Called after a new cell has been created during an increment operation, but before
+ * it is committed to the WAL or memstore.
+ * Calling {@link org.apache.hadoop.hbase.coprocessor.ObserverContext#bypass()} has no
+ * effect in this hook.
+ * @param ctx the environment provided by the region server
+ * @param opType the operation type
+ * @param mutation the current mutation
+ * @param oldCell old cell containing previous value
+ * @param newCell the new cell containing the computed value
+ * @return the new cell, possibly changed
+ * @throws IOException
+ */
+ Cell postMutationBeforeWAL(ObserverContext<RegionCoprocessorEnvironment> ctx,
+ MutationType opType, Mutation mutation, Cell oldCell, Cell newCell) throws IOException;
}
Modified: hbase/trunk/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/HRegion.java
URL: http://svn.apache.org/viewvc/hbase/trunk/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/HRegion.java?rev=1539224&r1=1539223&r2=1539224&view=diff
==============================================================================
--- hbase/trunk/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/HRegion.java (original)
+++ hbase/trunk/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/HRegion.java Wed Nov 6 03:11:58 2013
@@ -94,6 +94,7 @@ import org.apache.hadoop.hbase.client.Pu
import org.apache.hadoop.hbase.client.Result;
import org.apache.hadoop.hbase.client.RowMutations;
import org.apache.hadoop.hbase.client.Scan;
+import org.apache.hadoop.hbase.coprocessor.RegionObserver;
import org.apache.hadoop.hbase.errorhandling.ForeignExceptionSnare;
import org.apache.hadoop.hbase.exceptions.FailedSanityCheckException;
import org.apache.hadoop.hbase.exceptions.RegionInRecoveryException;
@@ -4667,13 +4668,15 @@ public class HRegion implements HeapSize
for (Cell cell : family.getValue()) {
KeyValue kv = KeyValueUtil.ensureKeyValue(cell);
KeyValue newKV;
+ KeyValue oldKv = null;
if (idx < results.size()
&& CellUtil.matchingQualifier(results.get(idx),kv)) {
- KeyValue oldKv = KeyValueUtil.ensureKeyValue(results.get(idx));
+ oldKv = KeyValueUtil.ensureKeyValue(results.get(idx));
// allocate an empty kv once
newKV = new KeyValue(row.length, kv.getFamilyLength(),
kv.getQualifierLength(), now, KeyValue.Type.Put,
- oldKv.getValueLength() + kv.getValueLength());
+ oldKv.getValueLength() + kv.getValueLength(),
+ oldKv.getTagsLength() + kv.getTagsLength());
// copy in the value
System.arraycopy(oldKv.getBuffer(), oldKv.getValueOffset(),
newKV.getBuffer(), newKV.getValueOffset(),
@@ -4682,16 +4685,24 @@ public class HRegion implements HeapSize
newKV.getBuffer(),
newKV.getValueOffset() + oldKv.getValueLength(),
kv.getValueLength());
+ // copy in the tags
+ System.arraycopy(oldKv.getBuffer(), oldKv.getTagsOffset(), newKV.getBuffer(),
+ newKV.getTagsOffset(), oldKv.getTagsLength());
+ System.arraycopy(kv.getBuffer(), kv.getTagsOffset(), newKV.getBuffer(),
+ newKV.getTagsOffset() + oldKv.getTagsLength(), kv.getTagsLength());
idx++;
} else {
// allocate an empty kv once
newKV = new KeyValue(row.length, kv.getFamilyLength(),
kv.getQualifierLength(), now, KeyValue.Type.Put,
- kv.getValueLength());
+ kv.getValueLength(), kv.getTagsLength());
// copy in the value
System.arraycopy(kv.getBuffer(), kv.getValueOffset(),
newKV.getBuffer(), newKV.getValueOffset(),
kv.getValueLength());
+ // copy in tags
+ System.arraycopy(kv.getBuffer(), kv.getTagsOffset(), newKV.getBuffer(),
+ newKV.getTagsOffset(), kv.getTagsLength());
}
// copy in row, family, and qualifier
System.arraycopy(kv.getBuffer(), kv.getRowOffset(),
@@ -4704,6 +4715,11 @@ public class HRegion implements HeapSize
kv.getQualifierLength());
newKV.setMvccVersion(w.getWriteNumber());
+ // Give coprocessors a chance to update the new cell
+ if (coprocessorHost != null) {
+ newKV = KeyValueUtil.ensureKeyValue(coprocessorHost.postMutationBeforeWAL(
+ RegionObserver.MutationType.APPEND, append, oldKv, (Cell) newKV));
+ }
kvs.add(newKV);
// Append update to WAL
@@ -4837,8 +4853,9 @@ public class HRegion implements HeapSize
int idx = 0;
for (Cell kv: family.getValue()) {
long amount = Bytes.toLong(CellUtil.cloneValue(kv));
+ Cell c = null;
if (idx < results.size() && CellUtil.matchingQualifier(results.get(idx), kv)) {
- Cell c = results.get(idx);
+ c = results.get(idx);
if(c.getValueLength() == Bytes.SIZEOF_LONG) {
amount += Bytes.toLong(c.getValueArray(), c.getValueOffset(), Bytes.SIZEOF_LONG);
} else {
@@ -4850,9 +4867,33 @@ public class HRegion implements HeapSize
}
// Append new incremented KeyValue to list
- KeyValue newKV =
- new KeyValue(row, family.getKey(), CellUtil.cloneQualifier(kv), now, Bytes.toBytes(amount));
+ byte[] q = CellUtil.cloneQualifier(kv);
+ byte[] val = Bytes.toBytes(amount);
+ int oldCellTagsLen = (c == null) ? 0 : c.getTagsLength();
+ int incCellTagsLen = kv.getTagsLength();
+ KeyValue newKV = new KeyValue(row.length, family.getKey().length, q.length, now,
+ KeyValue.Type.Put, val.length, oldCellTagsLen + incCellTagsLen);
+ System.arraycopy(row, 0, newKV.getBuffer(), newKV.getRowOffset(), row.length);
+ System.arraycopy(family.getKey(), 0, newKV.getBuffer(), newKV.getFamilyOffset(),
+ family.getKey().length);
+ System.arraycopy(q, 0, newKV.getBuffer(), newKV.getQualifierOffset(), q.length);
+ // copy in the value
+ System.arraycopy(val, 0, newKV.getBuffer(), newKV.getValueOffset(), val.length);
+ // copy tags
+ if (oldCellTagsLen > 0) {
+ System.arraycopy(c.getTagsArray(), c.getTagsOffset(), newKV.getBuffer(),
+ newKV.getTagsOffset(), oldCellTagsLen);
+ }
+ if (incCellTagsLen > 0) {
+ System.arraycopy(kv.getTagsArray(), kv.getTagsOffset(), newKV.getBuffer(),
+ newKV.getTagsOffset() + oldCellTagsLen, incCellTagsLen);
+ }
newKV.setMvccVersion(w.getWriteNumber());
+ // Give coprocessors a chance to update the new cell
+ if (coprocessorHost != null) {
+ newKV = KeyValueUtil.ensureKeyValue(coprocessorHost.postMutationBeforeWAL(
+ RegionObserver.MutationType.INCREMENT, increment, c, (Cell) newKV));
+ }
kvs.add(newKV);
// Prepare WAL updates
Modified: hbase/trunk/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/RegionCoprocessorHost.java
URL: http://svn.apache.org/viewvc/hbase/trunk/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/RegionCoprocessorHost.java?rev=1539224&r1=1539223&r2=1539224&view=diff
==============================================================================
--- hbase/trunk/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/RegionCoprocessorHost.java (original)
+++ hbase/trunk/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/RegionCoprocessorHost.java Wed Nov 6 03:11:58 2013
@@ -55,6 +55,7 @@ import org.apache.hadoop.hbase.coprocess
import org.apache.hadoop.hbase.coprocessor.ObserverContext;
import org.apache.hadoop.hbase.coprocessor.RegionCoprocessorEnvironment;
import org.apache.hadoop.hbase.coprocessor.RegionObserver;
+import org.apache.hadoop.hbase.coprocessor.RegionObserver.MutationType;
import org.apache.hadoop.hbase.filter.ByteArrayComparable;
import org.apache.hadoop.hbase.filter.CompareFilter.CompareOp;
import org.apache.hadoop.hbase.io.FSDataInputStreamWrapper;
@@ -1708,4 +1709,24 @@ public class RegionCoprocessorHost
}
return reader;
}
+
+ public Cell postMutationBeforeWAL(MutationType opType, Mutation mutation, Cell oldCell,
+ Cell newCell) throws IOException {
+ ObserverContext<RegionCoprocessorEnvironment> ctx = null;
+ for (RegionEnvironment env : coprocessors) {
+ if (env.getInstance() instanceof RegionObserver) {
+ ctx = ObserverContext.createAndPrepare(env, ctx);
+ try {
+ newCell = ((RegionObserver) env.getInstance()).postMutationBeforeWAL(ctx, opType,
+ mutation, oldCell, newCell);
+ } catch (Throwable e) {
+ handleCoprocessorThrowable(env, e);
+ }
+ if (ctx.shouldComplete()) {
+ break;
+ }
+ }
+ }
+ return newCell;
+ }
}
Modified: hbase/trunk/hbase-server/src/test/java/org/apache/hadoop/hbase/regionserver/TestTags.java
URL: http://svn.apache.org/viewvc/hbase/trunk/hbase-server/src/test/java/org/apache/hadoop/hbase/regionserver/TestTags.java?rev=1539224&r1=1539223&r2=1539224&view=diff
==============================================================================
--- hbase/trunk/hbase-server/src/test/java/org/apache/hadoop/hbase/regionserver/TestTags.java (original)
+++ hbase/trunk/hbase-server/src/test/java/org/apache/hadoop/hbase/regionserver/TestTags.java Wed Nov 6 03:11:58 2013
@@ -17,13 +17,12 @@
*/
package org.apache.hadoop.hbase.regionserver;
+import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
-import java.util.NavigableMap;
-import java.util.TreeMap;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.Cell;
@@ -37,9 +36,11 @@ import org.apache.hadoop.hbase.KeyValueU
import org.apache.hadoop.hbase.MediumTests;
import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.Tag;
+import org.apache.hadoop.hbase.client.Append;
import org.apache.hadoop.hbase.client.Durability;
import org.apache.hadoop.hbase.client.HBaseAdmin;
import org.apache.hadoop.hbase.client.HTable;
+import org.apache.hadoop.hbase.client.Increment;
import org.apache.hadoop.hbase.client.Put;
import org.apache.hadoop.hbase.client.Result;
import org.apache.hadoop.hbase.client.ResultScanner;
@@ -55,8 +56,10 @@ import org.apache.hadoop.hbase.util.Byte
import org.junit.After;
import org.junit.AfterClass;
import org.junit.BeforeClass;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.experimental.categories.Category;
+import org.junit.rules.TestName;
/**
* Class that test tags
@@ -67,6 +70,9 @@ public class TestTags {
private final static HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
+ @Rule
+ public final TestName TEST_NAME = new TestName();
+
@BeforeClass
public static void setUpBeforeClass() throws Exception {
Configuration conf = TEST_UTIL.getConfiguration();
@@ -90,7 +96,7 @@ public class TestTags {
public void testTags() throws Exception {
HTable table = null;
try {
- TableName tableName = TableName.valueOf("testTags");
+ TableName tableName = TableName.valueOf(TEST_NAME.getMethodName());
byte[] fam = Bytes.toBytes("info");
byte[] row = Bytes.toBytes("rowa");
// column names
@@ -168,7 +174,7 @@ public class TestTags {
public void testFlushAndCompactionWithoutTags() throws Exception {
HTable table = null;
try {
- TableName tableName = TableName.valueOf("testFlushAndCompactionWithoutTags");
+ TableName tableName = TableName.valueOf(TEST_NAME.getMethodName());
byte[] fam = Bytes.toBytes("info");
byte[] row = Bytes.toBytes("rowa");
// column names
@@ -270,7 +276,7 @@ public class TestTags {
public void testFlushAndCompactionwithCombinations() throws Exception {
HTable table = null;
try {
- TableName tableName = TableName.valueOf("testFlushAndCompactionwithCombinations");
+ TableName tableName = TableName.valueOf(TEST_NAME.getMethodName());
byte[] fam = Bytes.toBytes("info");
byte[] row = Bytes.toBytes("rowa");
// column names
@@ -394,6 +400,114 @@ public class TestTags {
}
}
+ @Test
+ public void testTagsWithAppendAndIncrement() throws Exception {
+ TableName tableName = TableName.valueOf(TEST_NAME.getMethodName());
+ byte[] f = Bytes.toBytes("f");
+ byte[] q = Bytes.toBytes("q");
+ byte[] row1 = Bytes.toBytes("r1");
+ byte[] row2 = Bytes.toBytes("r2");
+
+ HTableDescriptor desc = new HTableDescriptor(tableName);
+ HColumnDescriptor colDesc = new HColumnDescriptor(f);
+ desc.addFamily(colDesc);
+ TEST_UTIL.getHBaseAdmin().createTable(desc);
+
+ HTable table = null;
+ try {
+ table = new HTable(TEST_UTIL.getConfiguration(), tableName);
+ Put put = new Put(row1);
+ byte[] v = Bytes.toBytes(2L);
+ put.add(f, q, v, new Tag[] { new Tag((byte) 1, "tag1") });
+ table.put(put);
+ Increment increment = new Increment(row1);
+ increment.addColumn(f, q, 1L);
+ table.increment(increment);
+ ResultScanner scanner = table.getScanner(new Scan());
+ Result result = scanner.next();
+ KeyValue kv = KeyValueUtil.ensureKeyValue(result.getColumnLatestCell(f, q));
+ List<Tag> tags = kv.getTags();
+ assertEquals(3L, Bytes.toLong(kv.getValueArray(), kv.getValueOffset(), kv.getValueLength()));
+ assertEquals(1, tags.size());
+ assertEquals("tag1", Bytes.toString(tags.get(0).getValue()));
+ increment = new Increment(row1);
+ increment.add(new KeyValue(row1, f, q, 1234L, v, new Tag[] { new Tag((byte) 1, "tag2") }));
+ table.increment(increment);
+ scanner = table.getScanner(new Scan());
+ result = scanner.next();
+ kv = KeyValueUtil.ensureKeyValue(result.getColumnLatestCell(f, q));
+ tags = kv.getTags();
+ assertEquals(5L, Bytes.toLong(kv.getValueArray(), kv.getValueOffset(), kv.getValueLength()));
+ assertEquals(2, tags.size());
+ assertEquals("tag1", Bytes.toString(tags.get(0).getValue()));
+ assertEquals("tag2", Bytes.toString(tags.get(1).getValue()));
+
+ put = new Put(row2);
+ v = Bytes.toBytes(2L);
+ put.add(f, q, v);
+ table.put(put);
+ increment = new Increment(row2);
+ increment.add(new KeyValue(row2, f, q, 1234L, v, new Tag[] { new Tag((byte) 1, "tag2") }));
+ table.increment(increment);
+ Scan scan = new Scan();
+ scan.setStartRow(row2);
+ scanner = table.getScanner(scan);
+ result = scanner.next();
+ kv = KeyValueUtil.ensureKeyValue(result.getColumnLatestCell(f, q));
+ tags = kv.getTags();
+ assertEquals(4L, Bytes.toLong(kv.getValueArray(), kv.getValueOffset(), kv.getValueLength()));
+ assertEquals(1, tags.size());
+ assertEquals("tag2", Bytes.toString(tags.get(0).getValue()));
+
+ // Test Append
+ byte[] row3 = Bytes.toBytes("r3");
+ put = new Put(row3);
+ put.add(f, q, Bytes.toBytes("a"), new Tag[] { new Tag((byte) 1, "tag1") });
+ table.put(put);
+ Append append = new Append(row3);
+ append.add(f, q, Bytes.toBytes("b"));
+ table.append(append);
+ scan = new Scan();
+ scan.setStartRow(row3);
+ scanner = table.getScanner(scan);
+ result = scanner.next();
+ kv = KeyValueUtil.ensureKeyValue(result.getColumnLatestCell(f, q));
+ tags = kv.getTags();
+ assertEquals(1, tags.size());
+ assertEquals("tag1", Bytes.toString(tags.get(0).getValue()));
+ append = new Append(row3);
+ append.add(new KeyValue(row3, f, q, 1234L, v, new Tag[] { new Tag((byte) 1, "tag2") }));
+ table.append(append);
+ scanner = table.getScanner(scan);
+ result = scanner.next();
+ kv = KeyValueUtil.ensureKeyValue(result.getColumnLatestCell(f, q));
+ tags = kv.getTags();
+ assertEquals(2, tags.size());
+ assertEquals("tag1", Bytes.toString(tags.get(0).getValue()));
+ assertEquals("tag2", Bytes.toString(tags.get(1).getValue()));
+
+ byte[] row4 = Bytes.toBytes("r4");
+ put = new Put(row4);
+ put.add(f, q, Bytes.toBytes("a"));
+ table.put(put);
+ append = new Append(row4);
+ append.add(new KeyValue(row4, f, q, 1234L, v, new Tag[] { new Tag((byte) 1, "tag2") }));
+ table.append(append);
+ scan = new Scan();
+ scan.setStartRow(row4);
+ scanner = table.getScanner(scan);
+ result = scanner.next();
+ kv = KeyValueUtil.ensureKeyValue(result.getColumnLatestCell(f, q));
+ tags = kv.getTags();
+ assertEquals(1, tags.size());
+ assertEquals("tag2", Bytes.toString(tags.get(0).getValue()));
+ } finally {
+ if (table != null) {
+ table.close();
+ }
+ }
+ }
+
private void result(byte[] fam, byte[] row, byte[] qual, byte[] row2, HTable table, byte[] value,
byte[] value2, byte[] row1, byte[] value1) throws IOException {
Scan s = new Scan(row);