diff --git a/hbase-common/src/main/java/org/apache/hadoop/hbase/CellUtil.java b/hbase-common/src/main/java/org/apache/hadoop/hbase/CellUtil.java index 86c77208dbc..2a48bd11a35 100644 --- a/hbase-common/src/main/java/org/apache/hadoop/hbase/CellUtil.java +++ b/hbase-common/src/main/java/org/apache/hadoop/hbase/CellUtil.java @@ -40,6 +40,7 @@ import org.apache.hadoop.hbase.classification.InterfaceStability; import org.apache.hadoop.hbase.io.HeapSize; import org.apache.hadoop.hbase.io.TagCompressionContext; import org.apache.hadoop.hbase.io.util.Dictionary; +import org.apache.hadoop.hbase.io.util.StreamUtils; import org.apache.hadoop.hbase.util.ByteBufferUtils; import org.apache.hadoop.hbase.util.ByteRange; import org.apache.hadoop.hbase.util.Bytes; @@ -433,6 +434,13 @@ public final class CellUtil { return new TagRewriteCell(cell, tags); } + public static Cell createCell(Cell cell, byte[] value, byte[] tags) { + if (cell instanceof ByteBufferCell) { + return new ValueAndTagRewriteByteBufferCell((ByteBufferCell) cell, value, tags); + } + return new ValueAndTagRewriteCell(cell, value, tags); + } + /** * This can be used when a Cell has to change with addition/removal of one or more tags. This is an * efficient way to do so in which only the tags bytes part need to recreated and copied. All other @@ -556,9 +564,9 @@ public final class CellUtil { @Override public long heapSize() { - long sum = HEAP_SIZE_OVERHEAD + CellUtil.estimatedHeapSizeOf(cell) - cell.getTagsLength(); + long sum = HEAP_SIZE_OVERHEAD + CellUtil.estimatedHeapSizeOf(cell); if (this.tags != null) { - sum += ClassSize.ARRAY + this.tags.length; + sum += ClassSize.sizeOf(this.tags, this.tags.length); } return sum; } @@ -605,7 +613,7 @@ public final class CellUtil { @Override public void write(ByteBuffer buf, int offset) { - offset = KeyValueUtil.appendToByteBuffer(this.cell, buf, offset, false); + offset = KeyValueUtil.appendTo(this.cell, buf, offset, false); int tagsLen = this.tags == null ? 0 : this.tags.length; if (tagsLen > 0) { offset = ByteBufferUtils.putAsShort(buf, offset, tagsLen); @@ -763,9 +771,9 @@ public final class CellUtil { @Override public long heapSize() { - long sum = HEAP_SIZE_OVERHEAD + CellUtil.estimatedHeapSizeOf(cell) - cell.getTagsLength(); + long sum = HEAP_SIZE_OVERHEAD + CellUtil.estimatedHeapSizeOf(cell); if (this.tags != null) { - sum += ClassSize.ARRAY + this.tags.length; + sum += ClassSize.sizeOf(this.tags, this.tags.length); } return sum; } @@ -794,7 +802,7 @@ public final class CellUtil { @Override public void write(ByteBuffer buf, int offset) { - offset = KeyValueUtil.appendToByteBuffer(this.cell, buf, offset, false); + offset = KeyValueUtil.appendTo(this.cell, buf, offset, false); int tagsLen = this.tags == null ? 0 : this.tags.length; if (tagsLen > 0) { offset = ByteBufferUtils.putAsShort(buf, offset, tagsLen); @@ -871,6 +879,184 @@ public final class CellUtil { } } + @InterfaceAudience.Private + private static class ValueAndTagRewriteCell extends TagRewriteCell { + + protected byte[] value; + + public ValueAndTagRewriteCell(Cell cell, byte[] value, byte[] tags) { + super(cell, tags); + this.value = value; + } + + @Override + public byte[] getValueArray() { + return this.value; + } + + @Override + public int getValueOffset() { + return 0; + } + + @Override + public int getValueLength() { + return this.value == null ? 0 : this.value.length; + } + + @Override + public long heapSize() { + long sum = ClassSize.REFERENCE + super.heapSize(); + if (this.value != null) { + sum += ClassSize.sizeOf(this.value, this.value.length); + } + return sum; + } + + @Override + public int write(OutputStream out, boolean withTags) throws IOException { + return write(out, withTags, this.cell, this.value, this.tags); + } + + // Made into a static method so as to reuse the logic within ValueAndTagRewriteByteBufferCell + static int write(OutputStream out, boolean withTags, Cell cell, byte[] value, byte[] tags) + throws IOException { + int valLen = value == null ? 0 : value.length; + ByteBufferUtils.putInt(out, KeyValueUtil.keyLength(cell));// Key length + ByteBufferUtils.putInt(out, valLen);// Value length + int len = 2 * Bytes.SIZEOF_INT; + len += CellUtil.writeFlatKey(cell, out);// Key + if (valLen > 0) out.write(value);// Value + len += valLen; + if (withTags && tags != null) { + // Write the tagsLength 2 bytes + out.write((byte) (0xff & (tags.length >> 8))); + out.write((byte) (0xff & tags.length)); + out.write(tags); + len += KeyValue.TAGS_LENGTH_SIZE + tags.length; + } + return len; + } + + @Override + public int getSerializedSize(boolean withTags) { + return super.getSerializedSize(withTags) - this.cell.getValueLength() + this.value.length; + } + + @Override + public void write(ByteBuffer buf, int offset) { + write(buf, offset, this.cell, this.value, this.tags); + } + + // Made into a static method so as to reuse the logic within ValueAndTagRewriteByteBufferCell + static void write(ByteBuffer buf, int offset, Cell cell, byte[] value, byte[] tags) { + offset = ByteBufferUtils.putInt(buf, offset, KeyValueUtil.keyLength(cell));// Key length + offset = ByteBufferUtils.putInt(buf, offset, value.length);// Value length + offset = KeyValueUtil.appendKeyTo(cell, buf, offset); + ByteBufferUtils.copyFromArrayToBuffer(buf, offset, value, 0, value.length); + offset += value.length; + int tagsLen = tags == null ? 0 : tags.length; + if (tagsLen > 0) { + offset = ByteBufferUtils.putAsShort(buf, offset, tagsLen); + ByteBufferUtils.copyFromArrayToBuffer(buf, offset, tags, 0, tagsLen); + } + } + + @Override + public long heapOverhead() { + long overhead = super.heapOverhead() + ClassSize.REFERENCE; + if (this.value != null) { + overhead += ClassSize.ARRAY; + } + return overhead; + } + + @Override + public Cell deepClone() { + Cell clonedBaseCell = ((ExtendedCell) this.cell).deepClone(); + return new ValueAndTagRewriteCell(clonedBaseCell, this.tags, this.value); + } + } + + @InterfaceAudience.Private + private static class ValueAndTagRewriteByteBufferCell extends TagRewriteByteBufferCell { + + protected byte[] value; + + public ValueAndTagRewriteByteBufferCell(ByteBufferCell cell, byte[] value, byte[] tags) { + super(cell, tags); + this.value = value; + } + + @Override + public byte[] getValueArray() { + return this.value; + } + + @Override + public int getValueOffset() { + return 0; + } + + @Override + public int getValueLength() { + return this.value == null ? 0 : this.value.length; + } + + @Override + public ByteBuffer getValueByteBuffer() { + return ByteBuffer.wrap(this.value); + } + + @Override + public int getValuePosition() { + return 0; + } + + @Override + public long heapSize() { + long sum = ClassSize.REFERENCE + super.heapSize(); + if (this.value != null) { + sum += ClassSize.sizeOf(this.value, this.value.length); + } + return sum; + } + + @Override + public int write(OutputStream out, boolean withTags) throws IOException { + return ValueAndTagRewriteCell.write(out, withTags, this.cell, this.value, this.tags); + } + + @Override + public int getSerializedSize(boolean withTags) { + return super.getSerializedSize(withTags) - this.cell.getValueLength() + this.value.length; + } + + @Override + public void write(ByteBuffer buf, int offset) { + ValueAndTagRewriteCell.write(buf, offset, this.cell, this.value, this.tags); + } + + @Override + public long heapOverhead() { + long overhead = super.heapOverhead() + ClassSize.REFERENCE; + if (this.value != null) { + overhead += ClassSize.ARRAY; + } + return overhead; + } + + @Override + public Cell deepClone() { + Cell clonedBaseCell = ((ExtendedCell) this.cell).deepClone(); + if (clonedBaseCell instanceof ByteBufferCell) { + return new ValueAndTagRewriteByteBufferCell((ByteBufferCell) clonedBaseCell, this.tags, + this.value); + } + return new ValueAndTagRewriteCell(clonedBaseCell, this.tags, this.value); + } + } + /** * @param cellScannerables * @return CellScanner interface over cellIterables @@ -1577,6 +1763,34 @@ public final class CellUtil { out.writeByte(cell.getTypeByte()); } + public static int writeFlatKey(Cell cell, OutputStream out) throws IOException { + short rowLen = cell.getRowLength(); + byte fLen = cell.getFamilyLength(); + int qLen = cell.getQualifierLength(); + // Using just one if/else loop instead of every time checking before writing every + // component of cell + if (cell instanceof ByteBufferCell) { + StreamUtils.writeShort(out, rowLen); + ByteBufferUtils.copyBufferToStream(out, ((ByteBufferCell) cell).getRowByteBuffer(), + ((ByteBufferCell) cell).getRowPosition(), rowLen); + out.write(fLen); + ByteBufferUtils.copyBufferToStream(out, ((ByteBufferCell) cell).getFamilyByteBuffer(), + ((ByteBufferCell) cell).getFamilyPosition(), fLen); + ByteBufferUtils.copyBufferToStream(out, ((ByteBufferCell) cell).getQualifierByteBuffer(), + ((ByteBufferCell) cell).getQualifierPosition(), qLen); + } else { + StreamUtils.writeShort(out, rowLen); + out.write(cell.getRowArray(), cell.getRowOffset(), rowLen); + out.write(fLen); + out.write(cell.getFamilyArray(), cell.getFamilyOffset(), fLen); + out.write(cell.getQualifierArray(), cell.getQualifierOffset(), qLen); + } + StreamUtils.writeLong(out, cell.getTimestamp()); + out.write(cell.getTypeByte()); + return Bytes.SIZEOF_SHORT + rowLen + Bytes.SIZEOF_BYTE + fLen + qLen + Bytes.SIZEOF_LONG + + Bytes.SIZEOF_BYTE; + } + /** * Writes the row from the given cell to the output stream * @param out The outputstream to which the data has to be written @@ -2018,6 +2232,20 @@ public final class CellUtil { return Bytes.toLong(cell.getValueArray(), cell.getValueOffset()); } + /** + * Converts the value bytes of the given cell into a int value + * + * @param cell + * @return value as int + */ + public static int getValueAsInt(Cell cell) { + if (cell instanceof ByteBufferCell) { + return ByteBufferUtils.toInt(((ByteBufferCell) cell).getValueByteBuffer(), + ((ByteBufferCell) cell).getValuePosition()); + } + return Bytes.toInt(cell.getValueArray(), cell.getValueOffset()); + } + /** * Converts the value bytes of the given cell into a double value * @@ -2958,7 +3186,7 @@ public final class CellUtil { // Normally all Cell impls within Server will be of type ExtendedCell. Just considering the // other case also. The data fragments within Cell is copied into buf as in KeyValue // serialization format only. - KeyValueUtil.appendToByteBuffer(cell, buf, offset, true); + KeyValueUtil.appendTo(cell, buf, offset, true); } if (buf.hasArray()) { KeyValue newKv; diff --git a/hbase-common/src/main/java/org/apache/hadoop/hbase/ExtendedCell.java b/hbase-common/src/main/java/org/apache/hadoop/hbase/ExtendedCell.java index 61b99900c4e..23d22435328 100644 --- a/hbase-common/src/main/java/org/apache/hadoop/hbase/ExtendedCell.java +++ b/hbase-common/src/main/java/org/apache/hadoop/hbase/ExtendedCell.java @@ -62,7 +62,7 @@ public interface ExtendedCell extends Cell, SettableSequenceId, SettableTimestam int getSerializedSize(boolean withTags); /** - * Write the given Cell into the given buf's offset. + * Write this Cell into the given buf's offset in a {@link KeyValue} format. * @param buf The buffer where to write the Cell. * @param offset The offset within buffer, to write the Cell. */ diff --git a/hbase-common/src/main/java/org/apache/hadoop/hbase/KeyValueUtil.java b/hbase-common/src/main/java/org/apache/hadoop/hbase/KeyValueUtil.java index d4c047c6f66..ca990cf5c4a 100644 --- a/hbase-common/src/main/java/org/apache/hadoop/hbase/KeyValueUtil.java +++ b/hbase-common/src/main/java/org/apache/hadoop/hbase/KeyValueUtil.java @@ -171,9 +171,20 @@ public class KeyValueUtil { /** * Copy the Cell content into the passed buf in KeyValue serialization format. */ - public static int appendToByteBuffer(Cell cell, ByteBuffer buf, int offset, boolean withTags) { + public static int appendTo(Cell cell, ByteBuffer buf, int offset, boolean withTags) { offset = ByteBufferUtils.putInt(buf, offset, keyLength(cell));// Key length offset = ByteBufferUtils.putInt(buf, offset, cell.getValueLength());// Value length + offset = appendKeyTo(cell, buf, offset); + offset = CellUtil.copyValueTo(cell, buf, offset);// Value bytes + int tagsLength = cell.getTagsLength(); + if (withTags && (tagsLength > 0)) { + offset = ByteBufferUtils.putAsShort(buf, offset, tagsLength);// Tags length + offset = CellUtil.copyTagTo(cell, buf, offset);// Tags bytes + } + return offset; + } + + public static int appendKeyTo(Cell cell, ByteBuffer buf, int offset) { offset = ByteBufferUtils.putShort(buf, offset, cell.getRowLength());// RK length offset = CellUtil.copyRowTo(cell, buf, offset);// Row bytes offset = ByteBufferUtils.putByte(buf, offset, cell.getFamilyLength());// CF length @@ -181,12 +192,6 @@ public class KeyValueUtil { offset = CellUtil.copyQualifierTo(cell, buf, offset);// Qualifier bytes offset = ByteBufferUtils.putLong(buf, offset, cell.getTimestamp());// TS offset = ByteBufferUtils.putByte(buf, offset, cell.getTypeByte());// Type - offset = CellUtil.copyValueTo(cell, buf, offset);// Value bytes - int tagsLength = cell.getTagsLength(); - if (withTags && (tagsLength > 0)) { - offset = ByteBufferUtils.putAsShort(buf, offset, tagsLength);// Tags length - offset = CellUtil.copyTagTo(cell, buf, offset);// Tags bytes - } return offset; } diff --git a/hbase-common/src/main/java/org/apache/hadoop/hbase/TagUtil.java b/hbase-common/src/main/java/org/apache/hadoop/hbase/TagUtil.java index 2c8809b60a8..642444f816f 100644 --- a/hbase-common/src/main/java/org/apache/hadoop/hbase/TagUtil.java +++ b/hbase-common/src/main/java/org/apache/hadoop/hbase/TagUtil.java @@ -247,6 +247,23 @@ public final class TagUtil { return tags; } + public static byte[] concatTags(byte[] tags, Cell cell) { + int cellTagsLen = cell.getTagsLength(); + if (cellTagsLen == 0) { + // If no Tags, return early. + return tags; + } + byte[] b = new byte[tags.length + cellTagsLen]; + int pos = Bytes.putBytes(b, 0, tags, 0, tags.length); + if (cell instanceof ByteBufferCell) { + ByteBufferUtils.copyFromBufferToArray(b, ((ByteBufferCell) cell).getTagsByteBuffer(), + ((ByteBufferCell) cell).getTagsPosition(), pos, cellTagsLen); + } else { + Bytes.putBytes(b, pos, cell.getTagsArray(), cell.getTagsOffset(), cellTagsLen); + } + return b; + } + /** * @return Carry forward the TTL tag. */ diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/mob/DefaultMobStoreCompactor.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/mob/DefaultMobStoreCompactor.java index d75e4481671..04ce4f91181 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/mob/DefaultMobStoreCompactor.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/mob/DefaultMobStoreCompactor.java @@ -26,13 +26,10 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.Path; -import org.apache.hadoop.hbase.ArrayBackedTag; import org.apache.hadoop.hbase.Cell; import org.apache.hadoop.hbase.CellUtil; import org.apache.hadoop.hbase.KeyValue; import org.apache.hadoop.hbase.KeyValueUtil; -import org.apache.hadoop.hbase.Tag; -import org.apache.hadoop.hbase.TagType; import org.apache.hadoop.hbase.classification.InterfaceAudience; import org.apache.hadoop.hbase.client.Scan; import org.apache.hadoop.hbase.regionserver.CellSink; @@ -184,8 +181,6 @@ public class DefaultMobStoreCompactor extends DefaultCompactor { byte[] fileName = null; StoreFileWriter mobFileWriter = null, delFileWriter = null; long mobCells = 0, deleteMarkersCount = 0; - Tag tableNameTag = new ArrayBackedTag(TagType.MOB_TABLE_NAME_TAG_TYPE, - store.getTableName().getName()); long cellsCountCompactedToMob = 0, cellsCountCompactedFromMob = 0; long cellsSizeCompactedToMob = 0, cellsSizeCompactedFromMob = 0; try { @@ -250,7 +245,8 @@ public class DefaultMobStoreCompactor extends DefaultCompactor { mobCells++; // append the original keyValue in the mob file. mobFileWriter.append(c); - KeyValue reference = MobUtils.createMobRefKeyValue(c, fileName, tableNameTag); + Cell reference = MobUtils.createMobRefCell(c, fileName, + this.mobStore.getRefCellTags()); // write the cell whose value is the path of a mob file to the store file. writer.append(reference); cellsCountCompactedToMob++; diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/mob/DefaultMobStoreFlusher.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/mob/DefaultMobStoreFlusher.java index a5229b1a897..77f167e889e 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/mob/DefaultMobStoreFlusher.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/mob/DefaultMobStoreFlusher.java @@ -27,12 +27,9 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.Path; -import org.apache.hadoop.hbase.ArrayBackedTag; import org.apache.hadoop.hbase.Cell; import org.apache.hadoop.hbase.HConstants; import org.apache.hadoop.hbase.KeyValue; -import org.apache.hadoop.hbase.Tag; -import org.apache.hadoop.hbase.TagType; import org.apache.hadoop.hbase.classification.InterfaceAudience; import org.apache.hadoop.hbase.monitoring.MonitoredTask; import org.apache.hadoop.hbase.regionserver.DefaultStoreFlusher; @@ -167,8 +164,6 @@ public class DefaultMobStoreFlusher extends DefaultStoreFlusher { // the relative path is mobFiles byte[] fileName = Bytes.toBytes(mobFileWriter.getPath().getName()); try { - Tag tableNameTag = new ArrayBackedTag(TagType.MOB_TABLE_NAME_TAG_TYPE, - store.getTableName().getName()); List cells = new ArrayList(); boolean hasMore; ScannerContext scannerContext = @@ -192,7 +187,8 @@ public class DefaultMobStoreFlusher extends DefaultStoreFlusher { // append the tags to the KeyValue. // The key is same, the value is the filename of the mob file - KeyValue reference = MobUtils.createMobRefKeyValue(c, fileName, tableNameTag); + Cell reference = MobUtils.createMobRefCell(c, fileName, + this.mobStore.getRefCellTags()); writer.append(reference); } } diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/mob/MobUtils.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/mob/MobUtils.java index ecd24159689..770c0693ed0 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/mob/MobUtils.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/mob/MobUtils.java @@ -48,10 +48,10 @@ import org.apache.hadoop.hbase.HColumnDescriptor; import org.apache.hadoop.hbase.HConstants; import org.apache.hadoop.hbase.HRegionInfo; import org.apache.hadoop.hbase.HTableDescriptor; -import org.apache.hadoop.hbase.KeyValue; import org.apache.hadoop.hbase.TableName; import org.apache.hadoop.hbase.Tag; import org.apache.hadoop.hbase.TagType; +import org.apache.hadoop.hbase.TagUtil; import org.apache.hadoop.hbase.backup.HFileArchiver; import org.apache.hadoop.hbase.classification.InterfaceAudience; import org.apache.hadoop.hbase.client.Scan; @@ -424,7 +424,7 @@ public final class MobUtils { * cloning the snapshot. * @return The mob reference KeyValue. */ - public static KeyValue createMobRefKeyValue(Cell cell, byte[] fileName, Tag tableNameTag) { + public static Cell createMobRefCell(Cell cell, byte[] fileName, Tag tableNameTag) { // Append the tags to the KeyValue. // The key is same, the value is the filename of the mob file List tags = new ArrayList(); @@ -437,15 +437,13 @@ public final class MobUtils { // snapshot for mob files. tags.add(tableNameTag); // Add the existing tags. - tags.addAll(CellUtil.getTags(cell)); - int valueLength = cell.getValueLength(); - byte[] refValue = Bytes.add(Bytes.toBytes(valueLength), fileName); - KeyValue reference = new KeyValue(cell.getRowArray(), cell.getRowOffset(), cell.getRowLength(), - cell.getFamilyArray(), cell.getFamilyOffset(), cell.getFamilyLength(), - cell.getQualifierArray(), cell.getQualifierOffset(), cell.getQualifierLength(), - cell.getTimestamp(), KeyValue.Type.Put, refValue, 0, refValue.length, tags); - reference.setSequenceId(cell.getSequenceId()); - return reference; + TagUtil.carryForwardTags(tags, cell); + return createMobRefCell(cell, fileName, TagUtil.fromList(tags)); + } + + public static Cell createMobRefCell(Cell cell, byte[] fileName, byte[] refCellTags) { + byte[] refValue = Bytes.add(Bytes.toBytes(cell.getValueLength()), fileName); + return CellUtil.createCell(cell, refValue, TagUtil.concatTags(refCellTags, cell)); } /** @@ -666,7 +664,7 @@ public final class MobUtils { * @return The real mob value length. */ public static int getMobValueLength(Cell cell) { - return Bytes.toInt(cell.getValueArray(), cell.getValueOffset(), Bytes.SIZEOF_INT); + return CellUtil.getValueAsInt(cell); } /** diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/mob/compactions/PartitionedMobCompactor.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/mob/compactions/PartitionedMobCompactor.java index 33aecc0b294..731fb456f5b 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/mob/compactions/PartitionedMobCompactor.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/mob/compactions/PartitionedMobCompactor.java @@ -43,10 +43,10 @@ import org.apache.hadoop.hbase.Cell; import org.apache.hadoop.hbase.CellComparator; import org.apache.hadoop.hbase.HColumnDescriptor; import org.apache.hadoop.hbase.HConstants; -import org.apache.hadoop.hbase.KeyValue; import org.apache.hadoop.hbase.TableName; import org.apache.hadoop.hbase.Tag; import org.apache.hadoop.hbase.TagType; +import org.apache.hadoop.hbase.TagUtil; import org.apache.hadoop.hbase.classification.InterfaceAudience; import org.apache.hadoop.hbase.client.Connection; import org.apache.hadoop.hbase.client.ConnectionFactory; @@ -92,7 +92,7 @@ public class PartitionedMobCompactor extends MobCompactor { private final Path tempPath; private final Path bulkloadPath; private final CacheConfig compactionCacheConfig; - private final Tag tableNameTag; + private final byte[] refCellTags; private Encryption.Context cryptoContext = Encryption.Context.NONE; public PartitionedMobCompactor(Configuration conf, FileSystem fs, TableName tableName, @@ -113,7 +113,11 @@ public class PartitionedMobCompactor extends MobCompactor { Configuration copyOfConf = new Configuration(conf); copyOfConf.setFloat(HConstants.HFILE_BLOCK_CACHE_SIZE_KEY, 0f); compactionCacheConfig = new CacheConfig(copyOfConf); - tableNameTag = new ArrayBackedTag(TagType.MOB_TABLE_NAME_TAG_TYPE, tableName.getName()); + List tags = new ArrayList<>(2); + tags.add(MobConstants.MOB_REF_TAG); + Tag tableNameTag = new ArrayBackedTag(TagType.MOB_TABLE_NAME_TAG_TYPE, tableName.getName()); + tags.add(tableNameTag); + this.refCellTags = TagUtil.fromList(tags); cryptoContext = EncryptionUtil.createEncryptionContext(copyOfConf, column); } @@ -421,7 +425,7 @@ public class PartitionedMobCompactor extends MobCompactor { // write the mob cell to the mob file. writer.append(cell); // write the new reference cell to the store file. - KeyValue reference = MobUtils.createMobRefKeyValue(cell, fileName, tableNameTag); + Cell reference = MobUtils.createMobRefCell(cell, fileName, this.refCellTags); refFileWriter.append(reference); mobCells++; } diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/HMobStore.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/HMobStore.java index a4b3427b80c..929309e535e 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/HMobStore.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/HMobStore.java @@ -32,6 +32,7 @@ import org.apache.commons.logging.LogFactory; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.FileSystem; import org.apache.hadoop.fs.Path; +import org.apache.hadoop.hbase.ArrayBackedTag; import org.apache.hadoop.hbase.Cell; import org.apache.hadoop.hbase.CellComparator; import org.apache.hadoop.hbase.HColumnDescriptor; @@ -40,6 +41,7 @@ import org.apache.hadoop.hbase.KeyValue; import org.apache.hadoop.hbase.KeyValue.Type; import org.apache.hadoop.hbase.TableName; import org.apache.hadoop.hbase.Tag; +import org.apache.hadoop.hbase.TagType; import org.apache.hadoop.hbase.TagUtil; import org.apache.hadoop.hbase.classification.InterfaceAudience; import org.apache.hadoop.hbase.client.Scan; @@ -101,6 +103,13 @@ public class HMobStore extends HStore { private TableName tableLockName; private Map> map = new ConcurrentHashMap>(); private final IdLock keyLock = new IdLock(); + // When we add a MOB reference cell to the HFile, we will add 2 tags along with it + // 1. A ref tag with type TagType.MOB_REFERENCE_TAG_TYPE. This just denote this this cell is not + // original one but a ref to another MOB Cell. + // 2. Table name tag. It's very useful in cloning the snapshot. When reading from the cloning + // table, we need to find the original mob files by this table name. For details please see + // cloning snapshot for mob files. + private final byte[] refCellTags; public HMobStore(final HRegion region, final HColumnDescriptor family, final Configuration confParam) throws IOException { @@ -120,6 +129,12 @@ public class HMobStore extends HStore { tableLockManager = region.getRegionServerServices().getTableLockManager(); tableLockName = MobUtils.getTableLockName(getTableName()); } + List tags = new ArrayList<>(2); + tags.add(MobConstants.MOB_REF_TAG); + Tag tableNameTag = new ArrayBackedTag(TagType.MOB_TABLE_NAME_TAG_TYPE, + getTableName().getName()); + tags.add(tableNameTag); + this.refCellTags = TagUtil.fromList(tags); } /** @@ -583,4 +598,8 @@ public class HMobStore extends HStore { public long getMobScanCellsSize() { return mobScanCellsSize; } + + public byte[] getRefCellTags() { + return this.refCellTags; + } } diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/regionserver/TestHMobStore.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/regionserver/TestHMobStore.java index 283ae7c1a87..41879e92f7f 100644 --- a/hbase-server/src/test/java/org/apache/hadoop/hbase/regionserver/TestHMobStore.java +++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/regionserver/TestHMobStore.java @@ -97,9 +97,9 @@ public class TestHMobStore { private byte[] value2 = Bytes.toBytes("value2"); private Path mobFilePath; private Date currentDate = new Date(); - private KeyValue seekKey1; - private KeyValue seekKey2; - private KeyValue seekKey3; + private Cell seekKey1; + private Cell seekKey2; + private Cell seekKey3; private NavigableSet qualifiers = new ConcurrentSkipListSet(Bytes.BYTES_COMPARATOR); private List expected = new ArrayList(); @@ -195,9 +195,9 @@ public class TestHMobStore { KeyValue kv1 = new KeyValue(row, family, qf1, Long.MAX_VALUE, referenceValue); KeyValue kv2 = new KeyValue(row, family, qf2, Long.MAX_VALUE, referenceValue); KeyValue kv3 = new KeyValue(row2, family, qf3, Long.MAX_VALUE, referenceValue); - seekKey1 = MobUtils.createMobRefKeyValue(kv1, referenceValue, tableNameTag); - seekKey2 = MobUtils.createMobRefKeyValue(kv2, referenceValue, tableNameTag); - seekKey3 = MobUtils.createMobRefKeyValue(kv3, referenceValue, tableNameTag); + seekKey1 = MobUtils.createMobRefCell(kv1, referenceValue, tableNameTag); + seekKey2 = MobUtils.createMobRefCell(kv2, referenceValue, tableNameTag); + seekKey3 = MobUtils.createMobRefCell(kv3, referenceValue, tableNameTag); } /** diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/util/HFileTestUtil.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/util/HFileTestUtil.java index fbd79c31198..dd3e631ad11 100644 --- a/hbase-server/src/test/java/org/apache/hadoop/hbase/util/HFileTestUtil.java +++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/util/HFileTestUtil.java @@ -115,11 +115,11 @@ public class HFileTestUtil { try { // subtract 2 since iterateOnSplits doesn't include boundary keys for (byte[] key : Bytes.iterateOnSplits(startKey, endKey, numRows - 2)) { - KeyValue kv = new KeyValue(key, family, qualifier, now, key); + Cell kv = new KeyValue(key, family, qualifier, now, key); if (withTag) { // add a tag. Arbitrarily chose mob tag since we have a helper already. Tag tableNameTag = new ArrayBackedTag(TagType.MOB_TABLE_NAME_TAG_TYPE, key); - kv = MobUtils.createMobRefKeyValue(kv, key, tableNameTag); + kv = MobUtils.createMobRefCell(kv, key, tableNameTag); // verify that the kv has the tag. Tag t = CellUtil.getTag(kv, TagType.MOB_TABLE_NAME_TAG_TYPE);