HBase-11315: Keeping MVCC for configurable longer time
This commit is contained in:
parent
738bf63f12
commit
cc4f54770b
|
@ -143,6 +143,12 @@ public class TestPayloadCarryingRpcController {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getSequenceId() {
|
||||||
|
// unused
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public byte[] getValueArray() {
|
public byte[] getValueArray() {
|
||||||
return Bytes.toBytes(this.i);
|
return Bytes.toBytes(this.i);
|
||||||
|
|
|
@ -142,14 +142,25 @@ public interface Cell {
|
||||||
//6) MvccVersion
|
//6) MvccVersion
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* @deprecated as of 1.0, use {@link Cell#getSequenceId()}
|
||||||
|
*
|
||||||
* Internal use only. A region-specific sequence ID given to each operation. It always exists for
|
* Internal use only. A region-specific sequence ID given to each operation. It always exists for
|
||||||
* cells in the memstore but is not retained forever. It may survive several flushes, but
|
* cells in the memstore but is not retained forever. It may survive several flushes, but
|
||||||
* generally becomes irrelevant after the cell's row is no longer involved in any operations that
|
* generally becomes irrelevant after the cell's row is no longer involved in any operations that
|
||||||
* require strict consistency.
|
* require strict consistency.
|
||||||
* @return mvccVersion (always >= 0 if exists), or 0 if it no longer exists
|
* @return mvccVersion (always >= 0 if exists), or 0 if it no longer exists
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
long getMvccVersion();
|
long getMvccVersion();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A region-specific unique monotonically increasing sequence ID given to each Cell. It always
|
||||||
|
* exists for cells in the memstore but is not retained forever. It will be kept for
|
||||||
|
* {@link HConstants#KEEP_SEQID_PERIOD} days, but generally becomes irrelevant after the cell's
|
||||||
|
* row is no longer involved in any operations that require strict consistency.
|
||||||
|
* @return seqId (always > 0 if exists), or 0 if it no longer exists
|
||||||
|
*/
|
||||||
|
long getSequenceId();
|
||||||
|
|
||||||
//7) Value
|
//7) Value
|
||||||
|
|
||||||
|
|
|
@ -167,7 +167,7 @@ public final class CellUtil {
|
||||||
final long timestamp, final byte type, final byte[] value, final long memstoreTS) {
|
final long timestamp, final byte type, final byte[] value, final long memstoreTS) {
|
||||||
KeyValue keyValue = new KeyValue(row, family, qualifier, timestamp,
|
KeyValue keyValue = new KeyValue(row, family, qualifier, timestamp,
|
||||||
KeyValue.Type.codeToType(type), value);
|
KeyValue.Type.codeToType(type), value);
|
||||||
keyValue.setMvccVersion(memstoreTS);
|
keyValue.setSequenceId(memstoreTS);
|
||||||
return keyValue;
|
return keyValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -175,7 +175,7 @@ public final class CellUtil {
|
||||||
final long timestamp, final byte type, final byte[] value, byte[] tags, final long memstoreTS) {
|
final long timestamp, final byte type, final byte[] value, byte[] tags, final long memstoreTS) {
|
||||||
KeyValue keyValue = new KeyValue(row, family, qualifier, timestamp,
|
KeyValue keyValue = new KeyValue(row, family, qualifier, timestamp,
|
||||||
KeyValue.Type.codeToType(type), value, tags);
|
KeyValue.Type.codeToType(type), value, tags);
|
||||||
keyValue.setMvccVersion(memstoreTS);
|
keyValue.setSequenceId(memstoreTS);
|
||||||
return keyValue;
|
return keyValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -353,6 +353,11 @@ public final class HConstants {
|
||||||
|
|
||||||
/** Default value for cluster ID */
|
/** Default value for cluster ID */
|
||||||
public static final String CLUSTER_ID_DEFAULT = "default-cluster";
|
public static final String CLUSTER_ID_DEFAULT = "default-cluster";
|
||||||
|
|
||||||
|
/** Parameter name for # days to keep MVCC values during a major compaction */
|
||||||
|
public static final String KEEP_SEQID_PERIOD = "hbase.hstore.compaction.keep.seqId.period";
|
||||||
|
/** At least to keep MVCC values in hfiles for 5 days */
|
||||||
|
public static final int MIN_KEEP_SEQID_PERIOD = 5;
|
||||||
|
|
||||||
// Always store the location of the root table's HRegion.
|
// Always store the location of the root table's HRegion.
|
||||||
// This HRegion is never split.
|
// This HRegion is never split.
|
||||||
|
|
|
@ -284,15 +284,23 @@ public class KeyValue implements Cell, HeapSize, Cloneable {
|
||||||
// used to achieve atomic operations in the memstore.
|
// used to achieve atomic operations in the memstore.
|
||||||
@Override
|
@Override
|
||||||
public long getMvccVersion() {
|
public long getMvccVersion() {
|
||||||
return mvcc;
|
return this.getSequenceId();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setMvccVersion(long mvccVersion){
|
/**
|
||||||
this.mvcc = mvccVersion;
|
* used to achieve atomic operations in the memstore.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public long getSequenceId() {
|
||||||
|
return seqId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSequenceId(long seqId) {
|
||||||
|
this.seqId = seqId;
|
||||||
}
|
}
|
||||||
|
|
||||||
// multi-version concurrency control version. default value is 0, aka do not care.
|
// multi-version concurrency control version. default value is 0, aka do not care.
|
||||||
private long mvcc = 0; // this value is not part of a serialized KeyValue (not in HFiles)
|
private long seqId = 0;
|
||||||
|
|
||||||
/** Dragon time over, return to normal business */
|
/** Dragon time over, return to normal business */
|
||||||
|
|
||||||
|
@ -1083,7 +1091,7 @@ public class KeyValue implements Cell, HeapSize, Cloneable {
|
||||||
// Important to clone the memstoreTS as well - otherwise memstore's
|
// Important to clone the memstoreTS as well - otherwise memstore's
|
||||||
// update-in-place methods (eg increment) will end up creating
|
// update-in-place methods (eg increment) will end up creating
|
||||||
// new entries
|
// new entries
|
||||||
ret.setMvccVersion(mvcc);
|
ret.setSequenceId(seqId);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1094,7 +1102,7 @@ public class KeyValue implements Cell, HeapSize, Cloneable {
|
||||||
*/
|
*/
|
||||||
public KeyValue shallowCopy() {
|
public KeyValue shallowCopy() {
|
||||||
KeyValue shallowCopy = new KeyValue(this.bytes, this.offset, this.length);
|
KeyValue shallowCopy = new KeyValue(this.bytes, this.offset, this.length);
|
||||||
shallowCopy.setMvccVersion(this.mvcc);
|
shallowCopy.setSequenceId(this.seqId);
|
||||||
return shallowCopy;
|
return shallowCopy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1108,8 +1116,8 @@ public class KeyValue implements Cell, HeapSize, Cloneable {
|
||||||
if (this.bytes == null || this.bytes.length == 0) {
|
if (this.bytes == null || this.bytes.length == 0) {
|
||||||
return "empty";
|
return "empty";
|
||||||
}
|
}
|
||||||
return keyToString(this.bytes, this.offset + ROW_OFFSET, getKeyLength()) +
|
return keyToString(this.bytes, this.offset + ROW_OFFSET, getKeyLength()) + "/vlen="
|
||||||
"/vlen=" + getValueLength() + "/mvcc=" + mvcc;
|
+ getValueLength() + "/seqid=" + seqId;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -75,7 +75,7 @@ public class KeyValueUtil {
|
||||||
public static KeyValue copyToNewKeyValue(final Cell cell) {
|
public static KeyValue copyToNewKeyValue(final Cell cell) {
|
||||||
byte[] bytes = copyToNewByteArray(cell);
|
byte[] bytes = copyToNewByteArray(cell);
|
||||||
KeyValue kvCell = new KeyValue(bytes, 0, bytes.length);
|
KeyValue kvCell = new KeyValue(bytes, 0, bytes.length);
|
||||||
kvCell.setMvccVersion(cell.getMvccVersion());
|
kvCell.setSequenceId(cell.getMvccVersion());
|
||||||
return kvCell;
|
return kvCell;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -175,7 +175,7 @@ public class KeyValueUtil {
|
||||||
keyValue = new KeyValue(bb.array(), underlyingArrayOffset, kvLength);
|
keyValue = new KeyValue(bb.array(), underlyingArrayOffset, kvLength);
|
||||||
if (includesMvccVersion) {
|
if (includesMvccVersion) {
|
||||||
long mvccVersion = ByteBufferUtils.readVLong(bb);
|
long mvccVersion = ByteBufferUtils.readVLong(bb);
|
||||||
keyValue.setMvccVersion(mvccVersion);
|
keyValue.setSequenceId(mvccVersion);
|
||||||
}
|
}
|
||||||
return keyValue;
|
return keyValue;
|
||||||
}
|
}
|
||||||
|
|
|
@ -231,6 +231,11 @@ abstract class BufferedDataBlockEncoder implements DataBlockEncoder {
|
||||||
return memstoreTS;
|
return memstoreTS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getSequenceId() {
|
||||||
|
return memstoreTS;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public byte[] getValueArray() {
|
public byte[] getValueArray() {
|
||||||
return currentBuffer.array();
|
return currentBuffer.array();
|
||||||
|
@ -421,6 +426,11 @@ abstract class BufferedDataBlockEncoder implements DataBlockEncoder {
|
||||||
return memstoreTS;
|
return memstoreTS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getSequenceId() {
|
||||||
|
return memstoreTS;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public byte[] getValueArray() {
|
public byte[] getValueArray() {
|
||||||
return currentBuffer.array();
|
return currentBuffer.array();
|
||||||
|
|
|
@ -125,7 +125,7 @@ public class EncodedDataBlock {
|
||||||
(int) KeyValue.getKeyValueDataStructureSize(klen, vlen, tagsLen));
|
(int) KeyValue.getKeyValueDataStructureSize(klen, vlen, tagsLen));
|
||||||
if (meta.isIncludesMvcc()) {
|
if (meta.isIncludesMvcc()) {
|
||||||
long mvccVersion = ByteBufferUtils.readVLong(decompressedData);
|
long mvccVersion = ByteBufferUtils.readVLong(decompressedData);
|
||||||
kv.setMvccVersion(mvccVersion);
|
kv.setSequenceId(mvccVersion);
|
||||||
}
|
}
|
||||||
return kv;
|
return kv;
|
||||||
}
|
}
|
||||||
|
@ -244,7 +244,7 @@ public class EncodedDataBlock {
|
||||||
}
|
}
|
||||||
kv = new KeyValue(in.array(), kvOffset, (int) KeyValue.getKeyValueDataStructureSize(
|
kv = new KeyValue(in.array(), kvOffset, (int) KeyValue.getKeyValueDataStructureSize(
|
||||||
klength, vlength, tagsLength));
|
klength, vlength, tagsLength));
|
||||||
kv.setMvccVersion(memstoreTS);
|
kv.setSequenceId(memstoreTS);
|
||||||
this.dataBlockEncoder.encode(kv, encodingCtx, out);
|
this.dataBlockEncoder.encode(kv, encodingCtx, out);
|
||||||
}
|
}
|
||||||
BufferGrabbingByteArrayOutputStream stream = new BufferGrabbingByteArrayOutputStream();
|
BufferGrabbingByteArrayOutputStream stream = new BufferGrabbingByteArrayOutputStream();
|
||||||
|
|
|
@ -70,7 +70,7 @@ public class TestCellCodec {
|
||||||
Codec.Encoder encoder = codec.getEncoder(dos);
|
Codec.Encoder encoder = codec.getEncoder(dos);
|
||||||
final KeyValue kv =
|
final KeyValue kv =
|
||||||
new KeyValue(Bytes.toBytes("r"), Bytes.toBytes("f"), Bytes.toBytes("q"), Bytes.toBytes("v"));
|
new KeyValue(Bytes.toBytes("r"), Bytes.toBytes("f"), Bytes.toBytes("q"), Bytes.toBytes("v"));
|
||||||
kv.setMvccVersion(Long.MAX_VALUE);
|
kv.setSequenceId(Long.MAX_VALUE);
|
||||||
encoder.write(kv);
|
encoder.write(kv);
|
||||||
encoder.flush();
|
encoder.flush();
|
||||||
dos.close();
|
dos.close();
|
||||||
|
|
|
@ -50,7 +50,7 @@ public class TestByteRangeWithKVSerialization {
|
||||||
long mvcc = pbr.getVLong();
|
long mvcc = pbr.getVLong();
|
||||||
KeyValue kv = new KeyValue(pbr.getBytes(), kvStartPos,
|
KeyValue kv = new KeyValue(pbr.getBytes(), kvStartPos,
|
||||||
(int) KeyValue.getKeyValueDataStructureSize(keyLen, valLen, tagsLen));
|
(int) KeyValue.getKeyValueDataStructureSize(keyLen, valLen, tagsLen));
|
||||||
kv.setMvccVersion(mvcc);
|
kv.setSequenceId(mvcc);
|
||||||
return kv;
|
return kv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,7 +65,7 @@ public class TestByteRangeWithKVSerialization {
|
||||||
Tag[] tags = new Tag[] { new Tag((byte) 1, "tag1") };
|
Tag[] tags = new Tag[] { new Tag((byte) 1, "tag1") };
|
||||||
for (int i = 0; i < kvCount; i++) {
|
for (int i = 0; i < kvCount; i++) {
|
||||||
KeyValue kv = new KeyValue(Bytes.toBytes(i), FAMILY, QUALIFIER, i, VALUE, tags);
|
KeyValue kv = new KeyValue(Bytes.toBytes(i), FAMILY, QUALIFIER, i, VALUE, tags);
|
||||||
kv.setMvccVersion(i);
|
kv.setSequenceId(i);
|
||||||
kvs.add(kv);
|
kvs.add(kv);
|
||||||
totalSize += kv.getLength() + Bytes.SIZEOF_LONG;
|
totalSize += kv.getLength() + Bytes.SIZEOF_LONG;
|
||||||
}
|
}
|
||||||
|
|
|
@ -122,6 +122,11 @@ public class PrefixTreeCell implements Cell, Comparable<Cell> {
|
||||||
return mvccVersion;
|
return mvccVersion;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getSequenceId() {
|
||||||
|
return getMvccVersion();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getValueLength() {
|
public int getValueLength() {
|
||||||
return valueLength;
|
return valueLength;
|
||||||
|
|
|
@ -44,21 +44,21 @@ public class TestRowDataDifferentTimestamps extends BaseTestRowData{
|
||||||
static List<KeyValue> d = Lists.newArrayList();
|
static List<KeyValue> d = Lists.newArrayList();
|
||||||
static{
|
static{
|
||||||
KeyValue kv0 = new KeyValue(Arow, cf, cq0, 0L, v0);
|
KeyValue kv0 = new KeyValue(Arow, cf, cq0, 0L, v0);
|
||||||
kv0.setMvccVersion(123456789L);
|
kv0.setSequenceId(123456789L);
|
||||||
d.add(kv0);
|
d.add(kv0);
|
||||||
|
|
||||||
KeyValue kv1 = new KeyValue(Arow, cf, cq1, 1L, v0);
|
KeyValue kv1 = new KeyValue(Arow, cf, cq1, 1L, v0);
|
||||||
kv1.setMvccVersion(3L);
|
kv1.setSequenceId(3L);
|
||||||
d.add(kv1);
|
d.add(kv1);
|
||||||
|
|
||||||
KeyValue kv2 = new KeyValue(Brow, cf, cq0, 12345678L, v0);
|
KeyValue kv2 = new KeyValue(Brow, cf, cq0, 12345678L, v0);
|
||||||
kv2.setMvccVersion(65537L);
|
kv2.setSequenceId(65537L);
|
||||||
d.add(kv2);
|
d.add(kv2);
|
||||||
|
|
||||||
//watch out... Long.MAX_VALUE comes back as 1332221664203, even with other encoders
|
//watch out... Long.MAX_VALUE comes back as 1332221664203, even with other encoders
|
||||||
// d.add(new KeyValue(Brow, cf, cq1, Long.MAX_VALUE, v0));
|
// d.add(new KeyValue(Brow, cf, cq1, Long.MAX_VALUE, v0));
|
||||||
KeyValue kv3 = new KeyValue(Brow, cf, cq1, Long.MAX_VALUE-1, v0);
|
KeyValue kv3 = new KeyValue(Brow, cf, cq1, Long.MAX_VALUE-1, v0);
|
||||||
kv3.setMvccVersion(1L);
|
kv3.setSequenceId(1L);
|
||||||
d.add(kv3);
|
d.add(kv3);
|
||||||
|
|
||||||
KeyValue kv4 = new KeyValue(Brow, cf, cq1, 999999999, v0);
|
KeyValue kv4 = new KeyValue(Brow, cf, cq1, 999999999, v0);
|
||||||
|
@ -66,7 +66,7 @@ public class TestRowDataDifferentTimestamps extends BaseTestRowData{
|
||||||
d.add(kv4);
|
d.add(kv4);
|
||||||
|
|
||||||
KeyValue kv5 = new KeyValue(Brow, cf, cq1, 12345, v0);
|
KeyValue kv5 = new KeyValue(Brow, cf, cq1, 12345, v0);
|
||||||
kv5.setMvccVersion(0L);
|
kv5.setSequenceId(0L);
|
||||||
d.add(kv5);
|
d.add(kv5);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -897,6 +897,16 @@ public final class WALProtos {
|
||||||
* <code>optional uint64 nonce = 10;</code>
|
* <code>optional uint64 nonce = 10;</code>
|
||||||
*/
|
*/
|
||||||
long getNonce();
|
long getNonce();
|
||||||
|
|
||||||
|
// optional uint64 orig_sequence_number = 11;
|
||||||
|
/**
|
||||||
|
* <code>optional uint64 orig_sequence_number = 11;</code>
|
||||||
|
*/
|
||||||
|
boolean hasOrigSequenceNumber();
|
||||||
|
/**
|
||||||
|
* <code>optional uint64 orig_sequence_number = 11;</code>
|
||||||
|
*/
|
||||||
|
long getOrigSequenceNumber();
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Protobuf type {@code WALKey}
|
* Protobuf type {@code WALKey}
|
||||||
|
@ -1017,6 +1027,11 @@ public final class WALProtos {
|
||||||
nonce_ = input.readUInt64();
|
nonce_ = input.readUInt64();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case 88: {
|
||||||
|
bitField0_ |= 0x00000100;
|
||||||
|
origSequenceNumber_ = input.readUInt64();
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (com.google.protobuf.InvalidProtocolBufferException e) {
|
} catch (com.google.protobuf.InvalidProtocolBufferException e) {
|
||||||
|
@ -1323,6 +1338,22 @@ public final class WALProtos {
|
||||||
return nonce_;
|
return nonce_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// optional uint64 orig_sequence_number = 11;
|
||||||
|
public static final int ORIG_SEQUENCE_NUMBER_FIELD_NUMBER = 11;
|
||||||
|
private long origSequenceNumber_;
|
||||||
|
/**
|
||||||
|
* <code>optional uint64 orig_sequence_number = 11;</code>
|
||||||
|
*/
|
||||||
|
public boolean hasOrigSequenceNumber() {
|
||||||
|
return ((bitField0_ & 0x00000100) == 0x00000100);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* <code>optional uint64 orig_sequence_number = 11;</code>
|
||||||
|
*/
|
||||||
|
public long getOrigSequenceNumber() {
|
||||||
|
return origSequenceNumber_;
|
||||||
|
}
|
||||||
|
|
||||||
private void initFields() {
|
private void initFields() {
|
||||||
encodedRegionName_ = com.google.protobuf.ByteString.EMPTY;
|
encodedRegionName_ = com.google.protobuf.ByteString.EMPTY;
|
||||||
tableName_ = com.google.protobuf.ByteString.EMPTY;
|
tableName_ = com.google.protobuf.ByteString.EMPTY;
|
||||||
|
@ -1334,6 +1365,7 @@ public final class WALProtos {
|
||||||
clusterIds_ = java.util.Collections.emptyList();
|
clusterIds_ = java.util.Collections.emptyList();
|
||||||
nonceGroup_ = 0L;
|
nonceGroup_ = 0L;
|
||||||
nonce_ = 0L;
|
nonce_ = 0L;
|
||||||
|
origSequenceNumber_ = 0L;
|
||||||
}
|
}
|
||||||
private byte memoizedIsInitialized = -1;
|
private byte memoizedIsInitialized = -1;
|
||||||
public final boolean isInitialized() {
|
public final boolean isInitialized() {
|
||||||
|
@ -1411,6 +1443,9 @@ public final class WALProtos {
|
||||||
if (((bitField0_ & 0x00000080) == 0x00000080)) {
|
if (((bitField0_ & 0x00000080) == 0x00000080)) {
|
||||||
output.writeUInt64(10, nonce_);
|
output.writeUInt64(10, nonce_);
|
||||||
}
|
}
|
||||||
|
if (((bitField0_ & 0x00000100) == 0x00000100)) {
|
||||||
|
output.writeUInt64(11, origSequenceNumber_);
|
||||||
|
}
|
||||||
getUnknownFields().writeTo(output);
|
getUnknownFields().writeTo(output);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1460,6 +1495,10 @@ public final class WALProtos {
|
||||||
size += com.google.protobuf.CodedOutputStream
|
size += com.google.protobuf.CodedOutputStream
|
||||||
.computeUInt64Size(10, nonce_);
|
.computeUInt64Size(10, nonce_);
|
||||||
}
|
}
|
||||||
|
if (((bitField0_ & 0x00000100) == 0x00000100)) {
|
||||||
|
size += com.google.protobuf.CodedOutputStream
|
||||||
|
.computeUInt64Size(11, origSequenceNumber_);
|
||||||
|
}
|
||||||
size += getUnknownFields().getSerializedSize();
|
size += getUnknownFields().getSerializedSize();
|
||||||
memoizedSerializedSize = size;
|
memoizedSerializedSize = size;
|
||||||
return size;
|
return size;
|
||||||
|
@ -1527,6 +1566,11 @@ public final class WALProtos {
|
||||||
result = result && (getNonce()
|
result = result && (getNonce()
|
||||||
== other.getNonce());
|
== other.getNonce());
|
||||||
}
|
}
|
||||||
|
result = result && (hasOrigSequenceNumber() == other.hasOrigSequenceNumber());
|
||||||
|
if (hasOrigSequenceNumber()) {
|
||||||
|
result = result && (getOrigSequenceNumber()
|
||||||
|
== other.getOrigSequenceNumber());
|
||||||
|
}
|
||||||
result = result &&
|
result = result &&
|
||||||
getUnknownFields().equals(other.getUnknownFields());
|
getUnknownFields().equals(other.getUnknownFields());
|
||||||
return result;
|
return result;
|
||||||
|
@ -1580,6 +1624,10 @@ public final class WALProtos {
|
||||||
hash = (37 * hash) + NONCE_FIELD_NUMBER;
|
hash = (37 * hash) + NONCE_FIELD_NUMBER;
|
||||||
hash = (53 * hash) + hashLong(getNonce());
|
hash = (53 * hash) + hashLong(getNonce());
|
||||||
}
|
}
|
||||||
|
if (hasOrigSequenceNumber()) {
|
||||||
|
hash = (37 * hash) + ORIG_SEQUENCE_NUMBER_FIELD_NUMBER;
|
||||||
|
hash = (53 * hash) + hashLong(getOrigSequenceNumber());
|
||||||
|
}
|
||||||
hash = (29 * hash) + getUnknownFields().hashCode();
|
hash = (29 * hash) + getUnknownFields().hashCode();
|
||||||
memoizedHashCode = hash;
|
memoizedHashCode = hash;
|
||||||
return hash;
|
return hash;
|
||||||
|
@ -1728,6 +1776,8 @@ public final class WALProtos {
|
||||||
bitField0_ = (bitField0_ & ~0x00000100);
|
bitField0_ = (bitField0_ & ~0x00000100);
|
||||||
nonce_ = 0L;
|
nonce_ = 0L;
|
||||||
bitField0_ = (bitField0_ & ~0x00000200);
|
bitField0_ = (bitField0_ & ~0x00000200);
|
||||||
|
origSequenceNumber_ = 0L;
|
||||||
|
bitField0_ = (bitField0_ & ~0x00000400);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1810,6 +1860,10 @@ public final class WALProtos {
|
||||||
to_bitField0_ |= 0x00000080;
|
to_bitField0_ |= 0x00000080;
|
||||||
}
|
}
|
||||||
result.nonce_ = nonce_;
|
result.nonce_ = nonce_;
|
||||||
|
if (((from_bitField0_ & 0x00000400) == 0x00000400)) {
|
||||||
|
to_bitField0_ |= 0x00000100;
|
||||||
|
}
|
||||||
|
result.origSequenceNumber_ = origSequenceNumber_;
|
||||||
result.bitField0_ = to_bitField0_;
|
result.bitField0_ = to_bitField0_;
|
||||||
onBuilt();
|
onBuilt();
|
||||||
return result;
|
return result;
|
||||||
|
@ -1902,6 +1956,9 @@ public final class WALProtos {
|
||||||
if (other.hasNonce()) {
|
if (other.hasNonce()) {
|
||||||
setNonce(other.getNonce());
|
setNonce(other.getNonce());
|
||||||
}
|
}
|
||||||
|
if (other.hasOrigSequenceNumber()) {
|
||||||
|
setOrigSequenceNumber(other.getOrigSequenceNumber());
|
||||||
|
}
|
||||||
this.mergeUnknownFields(other.getUnknownFields());
|
this.mergeUnknownFields(other.getUnknownFields());
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
@ -2977,6 +3034,39 @@ public final class WALProtos {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// optional uint64 orig_sequence_number = 11;
|
||||||
|
private long origSequenceNumber_ ;
|
||||||
|
/**
|
||||||
|
* <code>optional uint64 orig_sequence_number = 11;</code>
|
||||||
|
*/
|
||||||
|
public boolean hasOrigSequenceNumber() {
|
||||||
|
return ((bitField0_ & 0x00000400) == 0x00000400);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* <code>optional uint64 orig_sequence_number = 11;</code>
|
||||||
|
*/
|
||||||
|
public long getOrigSequenceNumber() {
|
||||||
|
return origSequenceNumber_;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* <code>optional uint64 orig_sequence_number = 11;</code>
|
||||||
|
*/
|
||||||
|
public Builder setOrigSequenceNumber(long value) {
|
||||||
|
bitField0_ |= 0x00000400;
|
||||||
|
origSequenceNumber_ = value;
|
||||||
|
onChanged();
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* <code>optional uint64 orig_sequence_number = 11;</code>
|
||||||
|
*/
|
||||||
|
public Builder clearOrigSequenceNumber() {
|
||||||
|
bitField0_ = (bitField0_ & ~0x00000400);
|
||||||
|
origSequenceNumber_ = 0L;
|
||||||
|
onChanged();
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
// @@protoc_insertion_point(builder_scope:WALKey)
|
// @@protoc_insertion_point(builder_scope:WALKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5176,24 +5266,24 @@ public final class WALProtos {
|
||||||
java.lang.String[] descriptorData = {
|
java.lang.String[] descriptorData = {
|
||||||
"\n\tWAL.proto\032\013HBase.proto\"Y\n\tWALHeader\022\027\n" +
|
"\n\tWAL.proto\032\013HBase.proto\"Y\n\tWALHeader\022\027\n" +
|
||||||
"\017has_compression\030\001 \001(\010\022\026\n\016encryption_key" +
|
"\017has_compression\030\001 \001(\010\022\026\n\016encryption_key" +
|
||||||
"\030\002 \001(\014\022\033\n\023has_tag_compression\030\003 \001(\010\"\202\002\n\006" +
|
"\030\002 \001(\014\022\033\n\023has_tag_compression\030\003 \001(\010\"\240\002\n\006" +
|
||||||
"WALKey\022\033\n\023encoded_region_name\030\001 \002(\014\022\022\n\nt" +
|
"WALKey\022\033\n\023encoded_region_name\030\001 \002(\014\022\022\n\nt" +
|
||||||
"able_name\030\002 \002(\014\022\033\n\023log_sequence_number\030\003" +
|
"able_name\030\002 \002(\014\022\033\n\023log_sequence_number\030\003" +
|
||||||
" \002(\004\022\022\n\nwrite_time\030\004 \002(\004\022\035\n\ncluster_id\030\005" +
|
" \002(\004\022\022\n\nwrite_time\030\004 \002(\004\022\035\n\ncluster_id\030\005" +
|
||||||
" \001(\0132\005.UUIDB\002\030\001\022\034\n\006scopes\030\006 \003(\0132\014.Family" +
|
" \001(\0132\005.UUIDB\002\030\001\022\034\n\006scopes\030\006 \003(\0132\014.Family" +
|
||||||
"Scope\022\032\n\022following_kv_count\030\007 \001(\r\022\032\n\013clu" +
|
"Scope\022\032\n\022following_kv_count\030\007 \001(\r\022\032\n\013clu" +
|
||||||
"ster_ids\030\010 \003(\0132\005.UUID\022\022\n\nnonceGroup\030\t \001(" +
|
"ster_ids\030\010 \003(\0132\005.UUID\022\022\n\nnonceGroup\030\t \001(" +
|
||||||
"\004\022\r\n\005nonce\030\n \001(\004\"=\n\013FamilyScope\022\016\n\006famil",
|
"\004\022\r\n\005nonce\030\n \001(\004\022\034\n\024orig_sequence_number",
|
||||||
"y\030\001 \002(\014\022\036\n\nscope_type\030\002 \002(\0162\n.ScopeType\"" +
|
"\030\013 \001(\004\"=\n\013FamilyScope\022\016\n\006family\030\001 \002(\014\022\036\n" +
|
||||||
"\251\001\n\024CompactionDescriptor\022\022\n\ntable_name\030\001" +
|
"\nscope_type\030\002 \002(\0162\n.ScopeType\"\251\001\n\024Compac" +
|
||||||
" \002(\014\022\033\n\023encoded_region_name\030\002 \002(\014\022\023\n\013fam" +
|
"tionDescriptor\022\022\n\ntable_name\030\001 \002(\014\022\033\n\023en" +
|
||||||
"ily_name\030\003 \002(\014\022\030\n\020compaction_input\030\004 \003(\t" +
|
"coded_region_name\030\002 \002(\014\022\023\n\013family_name\030\003" +
|
||||||
"\022\031\n\021compaction_output\030\005 \003(\t\022\026\n\016store_hom" +
|
" \002(\014\022\030\n\020compaction_input\030\004 \003(\t\022\031\n\021compac" +
|
||||||
"e_dir\030\006 \002(\t\"\014\n\nWALTrailer*F\n\tScopeType\022\033" +
|
"tion_output\030\005 \003(\t\022\026\n\016store_home_dir\030\006 \002(" +
|
||||||
"\n\027REPLICATION_SCOPE_LOCAL\020\000\022\034\n\030REPLICATI" +
|
"\t\"\014\n\nWALTrailer*F\n\tScopeType\022\033\n\027REPLICAT" +
|
||||||
"ON_SCOPE_GLOBAL\020\001B?\n*org.apache.hadoop.h" +
|
"ION_SCOPE_LOCAL\020\000\022\034\n\030REPLICATION_SCOPE_G" +
|
||||||
"base.protobuf.generatedB\tWALProtosH\001\210\001\000\240" +
|
"LOBAL\020\001B?\n*org.apache.hadoop.hbase.proto" +
|
||||||
"\001\001"
|
"buf.generatedB\tWALProtosH\001\210\001\000\240\001\001"
|
||||||
};
|
};
|
||||||
com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner =
|
com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner =
|
||||||
new com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner() {
|
new com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner() {
|
||||||
|
@ -5211,7 +5301,7 @@ public final class WALProtos {
|
||||||
internal_static_WALKey_fieldAccessorTable = new
|
internal_static_WALKey_fieldAccessorTable = new
|
||||||
com.google.protobuf.GeneratedMessage.FieldAccessorTable(
|
com.google.protobuf.GeneratedMessage.FieldAccessorTable(
|
||||||
internal_static_WALKey_descriptor,
|
internal_static_WALKey_descriptor,
|
||||||
new java.lang.String[] { "EncodedRegionName", "TableName", "LogSequenceNumber", "WriteTime", "ClusterId", "Scopes", "FollowingKvCount", "ClusterIds", "NonceGroup", "Nonce", });
|
new java.lang.String[] { "EncodedRegionName", "TableName", "LogSequenceNumber", "WriteTime", "ClusterId", "Scopes", "FollowingKvCount", "ClusterIds", "NonceGroup", "Nonce", "OrigSequenceNumber", });
|
||||||
internal_static_FamilyScope_descriptor =
|
internal_static_FamilyScope_descriptor =
|
||||||
getDescriptor().getMessageTypes().get(2);
|
getDescriptor().getMessageTypes().get(2);
|
||||||
internal_static_FamilyScope_fieldAccessorTable = new
|
internal_static_FamilyScope_fieldAccessorTable = new
|
||||||
|
|
|
@ -54,6 +54,7 @@ message WALKey {
|
||||||
|
|
||||||
optional uint64 nonceGroup = 9;
|
optional uint64 nonceGroup = 9;
|
||||||
optional uint64 nonce = 10;
|
optional uint64 nonce = 10;
|
||||||
|
optional uint64 orig_sequence_number = 11;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
optional CustomEntryType custom_entry_type = 9;
|
optional CustomEntryType custom_entry_type = 9;
|
||||||
|
|
|
@ -765,7 +765,7 @@ public class HFileReaderV2 extends AbstractHFileReader {
|
||||||
KeyValue ret = new KeyValue(blockBuffer.array(), blockBuffer.arrayOffset()
|
KeyValue ret = new KeyValue(blockBuffer.array(), blockBuffer.arrayOffset()
|
||||||
+ blockBuffer.position(), getCellBufSize());
|
+ blockBuffer.position(), getCellBufSize());
|
||||||
if (this.reader.shouldIncludeMemstoreTS()) {
|
if (this.reader.shouldIncludeMemstoreTS()) {
|
||||||
ret.setMvccVersion(currMemstoreTS);
|
ret.setSequenceId(currMemstoreTS);
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
@ -106,6 +106,9 @@ public class ReplicationProtbufUtil {
|
||||||
uuidBuilder.setMostSigBits(clusterId.getMostSignificantBits());
|
uuidBuilder.setMostSigBits(clusterId.getMostSignificantBits());
|
||||||
keyBuilder.addClusterIds(uuidBuilder.build());
|
keyBuilder.addClusterIds(uuidBuilder.build());
|
||||||
}
|
}
|
||||||
|
if(key.getOrigLogSeqNum() > 0) {
|
||||||
|
keyBuilder.setOrigSequenceNumber(key.getOrigLogSeqNum());
|
||||||
|
}
|
||||||
WALEdit edit = entry.getEdit();
|
WALEdit edit = entry.getEdit();
|
||||||
NavigableMap<byte[], Integer> scopes = key.getScopes();
|
NavigableMap<byte[], Integer> scopes = key.getScopes();
|
||||||
if (scopes != null && !scopes.isEmpty()) {
|
if (scopes != null && !scopes.isEmpty()) {
|
||||||
|
|
|
@ -271,7 +271,7 @@ public class DefaultMemStore implements MemStore {
|
||||||
assert alloc.getBytes() != null;
|
assert alloc.getBytes() != null;
|
||||||
alloc.put(0, kv.getBuffer(), kv.getOffset(), len);
|
alloc.put(0, kv.getBuffer(), kv.getOffset(), len);
|
||||||
KeyValue newKv = new KeyValue(alloc.getBytes(), alloc.getOffset(), len);
|
KeyValue newKv = new KeyValue(alloc.getBytes(), alloc.getOffset(), len);
|
||||||
newKv.setMvccVersion(kv.getMvccVersion());
|
newKv.setSequenceId(kv.getMvccVersion());
|
||||||
return newKv;
|
return newKv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2155,6 +2155,7 @@ public class HRegion implements HeapSize { // , Writable{
|
||||||
/** This method is potentially expensive and should only be used for non-replay CP path. */
|
/** This method is potentially expensive and should only be used for non-replay CP path. */
|
||||||
public abstract Mutation[] getMutationsForCoprocs();
|
public abstract Mutation[] getMutationsForCoprocs();
|
||||||
public abstract boolean isInReplay();
|
public abstract boolean isInReplay();
|
||||||
|
public abstract long getReplaySequenceId();
|
||||||
|
|
||||||
public boolean isDone() {
|
public boolean isDone() {
|
||||||
return nextIndexToProcess == operations.length;
|
return nextIndexToProcess == operations.length;
|
||||||
|
@ -2194,11 +2195,18 @@ public class HRegion implements HeapSize { // , Writable{
|
||||||
public boolean isInReplay() {
|
public boolean isInReplay() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getReplaySequenceId() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class ReplayBatch extends BatchOperationInProgress<HLogSplitter.MutationReplay> {
|
private static class ReplayBatch extends BatchOperationInProgress<HLogSplitter.MutationReplay> {
|
||||||
public ReplayBatch(MutationReplay[] operations) {
|
private long replaySeqId = 0;
|
||||||
|
public ReplayBatch(MutationReplay[] operations, long seqId) {
|
||||||
super(operations);
|
super(operations);
|
||||||
|
this.replaySeqId = seqId;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -2226,6 +2234,11 @@ public class HRegion implements HeapSize { // , Writable{
|
||||||
public boolean isInReplay() {
|
public boolean isInReplay() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getReplaySequenceId() {
|
||||||
|
return this.replaySeqId;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -2252,13 +2265,14 @@ public class HRegion implements HeapSize { // , Writable{
|
||||||
/**
|
/**
|
||||||
* Replay a batch of mutations.
|
* Replay a batch of mutations.
|
||||||
* @param mutations mutations to replay.
|
* @param mutations mutations to replay.
|
||||||
|
* @param replaySeqId SeqId for current mutations
|
||||||
* @return an array of OperationStatus which internally contains the
|
* @return an array of OperationStatus which internally contains the
|
||||||
* OperationStatusCode and the exceptionMessage if any.
|
* OperationStatusCode and the exceptionMessage if any.
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
public OperationStatus[] batchReplay(HLogSplitter.MutationReplay[] mutations)
|
public OperationStatus[] batchReplay(HLogSplitter.MutationReplay[] mutations, long replaySeqId)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
return batchMutate(new ReplayBatch(mutations));
|
return batchMutate(new ReplayBatch(mutations, replaySeqId));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -2475,7 +2489,7 @@ public class HRegion implements HeapSize { // , Writable{
|
||||||
// ------------------------------------
|
// ------------------------------------
|
||||||
// STEP 2. Update any LATEST_TIMESTAMP timestamps
|
// STEP 2. Update any LATEST_TIMESTAMP timestamps
|
||||||
// ----------------------------------
|
// ----------------------------------
|
||||||
for (int i = firstIndex; i < lastIndexExclusive; i++) {
|
for (int i = firstIndex; !isInReplay && i < lastIndexExclusive; i++) {
|
||||||
// skip invalid
|
// skip invalid
|
||||||
if (batchOp.retCodeDetails[i].getOperationStatusCode()
|
if (batchOp.retCodeDetails[i].getOperationStatusCode()
|
||||||
!= OperationStatusCode.NOT_RUN) continue;
|
!= OperationStatusCode.NOT_RUN) continue;
|
||||||
|
@ -2485,16 +2499,18 @@ public class HRegion implements HeapSize { // , Writable{
|
||||||
updateKVTimestamps(familyMaps[i].values(), byteNow);
|
updateKVTimestamps(familyMaps[i].values(), byteNow);
|
||||||
noOfPuts++;
|
noOfPuts++;
|
||||||
} else {
|
} else {
|
||||||
if (!isInReplay) {
|
prepareDeleteTimestamps(mutation, familyMaps[i], byteNow);
|
||||||
prepareDeleteTimestamps(mutation, familyMaps[i], byteNow);
|
|
||||||
}
|
|
||||||
noOfDeletes++;
|
noOfDeletes++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
lock(this.updatesLock.readLock(), numReadyToWrite);
|
lock(this.updatesLock.readLock(), numReadyToWrite);
|
||||||
locked = true;
|
locked = true;
|
||||||
mvccNum = MultiVersionConsistencyControl.getPreAssignedWriteNumber(this.sequenceId);
|
if(isInReplay) {
|
||||||
|
mvccNum = batchOp.getReplaySequenceId();
|
||||||
|
} else {
|
||||||
|
mvccNum = MultiVersionConsistencyControl.getPreAssignedWriteNumber(this.sequenceId);
|
||||||
|
}
|
||||||
//
|
//
|
||||||
// ------------------------------------
|
// ------------------------------------
|
||||||
// Acquire the latest mvcc number
|
// Acquire the latest mvcc number
|
||||||
|
@ -2591,6 +2607,9 @@ public class HRegion implements HeapSize { // , Writable{
|
||||||
walKey = new HLogKey(this.getRegionInfo().getEncodedNameAsBytes(),
|
walKey = new HLogKey(this.getRegionInfo().getEncodedNameAsBytes(),
|
||||||
this.htableDescriptor.getTableName(), HLog.NO_SEQUENCE_ID, now,
|
this.htableDescriptor.getTableName(), HLog.NO_SEQUENCE_ID, now,
|
||||||
mutation.getClusterIds(), currentNonceGroup, currentNonce);
|
mutation.getClusterIds(), currentNonceGroup, currentNonce);
|
||||||
|
if(isInReplay) {
|
||||||
|
walKey.setOrigLogSeqNum(batchOp.getReplaySequenceId());
|
||||||
|
}
|
||||||
txid = this.log.appendNoSync(this.htableDescriptor, this.getRegionInfo(), walKey, walEdit,
|
txid = this.log.appendNoSync(this.htableDescriptor, this.getRegionInfo(), walKey, walEdit,
|
||||||
getSequenceId(), true, memstoreCells);
|
getSequenceId(), true, memstoreCells);
|
||||||
}
|
}
|
||||||
|
@ -2952,7 +2971,7 @@ public class HRegion implements HeapSize { // , Writable{
|
||||||
Store store = getStore(family);
|
Store store = getStore(family);
|
||||||
for (Cell cell: cells) {
|
for (Cell cell: cells) {
|
||||||
KeyValue kv = KeyValueUtil.ensureKeyValue(cell);
|
KeyValue kv = KeyValueUtil.ensureKeyValue(cell);
|
||||||
kv.setMvccVersion(mvccNum);
|
kv.setSequenceId(mvccNum);
|
||||||
Pair<Long, Cell> ret = store.add(kv);
|
Pair<Long, Cell> ret = store.add(kv);
|
||||||
size += ret.getFirst();
|
size += ret.getFirst();
|
||||||
memstoreCells.add(KeyValueUtil.ensureKeyValue(ret.getSecond()));
|
memstoreCells.add(KeyValueUtil.ensureKeyValue(ret.getSecond()));
|
||||||
|
@ -3213,6 +3232,7 @@ public class HRegion implements HeapSize { // , Writable{
|
||||||
try {
|
try {
|
||||||
reader = HLogFactory.createReader(fs, edits, conf);
|
reader = HLogFactory.createReader(fs, edits, conf);
|
||||||
long currentEditSeqId = -1;
|
long currentEditSeqId = -1;
|
||||||
|
long currentReplaySeqId = -1;
|
||||||
long firstSeqIdInLog = -1;
|
long firstSeqIdInLog = -1;
|
||||||
long skippedEdits = 0;
|
long skippedEdits = 0;
|
||||||
long editsCount = 0;
|
long editsCount = 0;
|
||||||
|
@ -3275,6 +3295,8 @@ public class HRegion implements HeapSize { // , Writable{
|
||||||
firstSeqIdInLog = key.getLogSeqNum();
|
firstSeqIdInLog = key.getLogSeqNum();
|
||||||
}
|
}
|
||||||
currentEditSeqId = key.getLogSeqNum();
|
currentEditSeqId = key.getLogSeqNum();
|
||||||
|
currentReplaySeqId = (key.getOrigLogSeqNum() > 0) ?
|
||||||
|
key.getOrigLogSeqNum() : currentEditSeqId;
|
||||||
boolean flush = false;
|
boolean flush = false;
|
||||||
for (KeyValue kv: val.getKeyValues()) {
|
for (KeyValue kv: val.getKeyValues()) {
|
||||||
// Check this edit is for me. Also, guard against writing the special
|
// Check this edit is for me. Also, guard against writing the special
|
||||||
|
@ -3309,6 +3331,7 @@ public class HRegion implements HeapSize { // , Writable{
|
||||||
skippedEdits++;
|
skippedEdits++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
kv.setSequenceId(currentReplaySeqId);
|
||||||
// Once we are over the limit, restoreEdit will keep returning true to
|
// Once we are over the limit, restoreEdit will keep returning true to
|
||||||
// flush -- but don't flush until we've played all the kvs that make up
|
// flush -- but don't flush until we've played all the kvs that make up
|
||||||
// the WALEdit.
|
// the WALEdit.
|
||||||
|
@ -4922,7 +4945,7 @@ public class HRegion implements HeapSize { // , Writable{
|
||||||
writeEntry = mvcc.beginMemstoreInsertWithSeqNum(mvccNum);
|
writeEntry = mvcc.beginMemstoreInsertWithSeqNum(mvccNum);
|
||||||
// 6. Apply to memstore
|
// 6. Apply to memstore
|
||||||
for (KeyValue kv : mutations) {
|
for (KeyValue kv : mutations) {
|
||||||
kv.setMvccVersion(mvccNum);
|
kv.setSequenceId(mvccNum);
|
||||||
Store store = getStore(kv);
|
Store store = getStore(kv);
|
||||||
if (store == null) {
|
if (store == null) {
|
||||||
checkFamily(CellUtil.cloneFamily(kv));
|
checkFamily(CellUtil.cloneFamily(kv));
|
||||||
|
@ -5168,7 +5191,7 @@ public class HRegion implements HeapSize { // , Writable{
|
||||||
// so only need to update the timestamp to 'now'
|
// so only need to update the timestamp to 'now'
|
||||||
newKV.updateLatestStamp(Bytes.toBytes(now));
|
newKV.updateLatestStamp(Bytes.toBytes(now));
|
||||||
}
|
}
|
||||||
newKV.setMvccVersion(mvccNum);
|
newKV.setSequenceId(mvccNum);
|
||||||
// Give coprocessors a chance to update the new cell
|
// Give coprocessors a chance to update the new cell
|
||||||
if (coprocessorHost != null) {
|
if (coprocessorHost != null) {
|
||||||
newKV = KeyValueUtil.ensureKeyValue(coprocessorHost.postMutationBeforeWAL(
|
newKV = KeyValueUtil.ensureKeyValue(coprocessorHost.postMutationBeforeWAL(
|
||||||
|
@ -5382,7 +5405,7 @@ public class HRegion implements HeapSize { // , Writable{
|
||||||
System.arraycopy(kv.getTagsArray(), kv.getTagsOffset(), newKV.getTagsArray(),
|
System.arraycopy(kv.getTagsArray(), kv.getTagsOffset(), newKV.getTagsArray(),
|
||||||
newKV.getTagsOffset() + oldCellTagsLen, incCellTagsLen);
|
newKV.getTagsOffset() + oldCellTagsLen, incCellTagsLen);
|
||||||
}
|
}
|
||||||
newKV.setMvccVersion(mvccNum);
|
newKV.setSequenceId(mvccNum);
|
||||||
// Give coprocessors a chance to update the new cell
|
// Give coprocessors a chance to update the new cell
|
||||||
if (coprocessorHost != null) {
|
if (coprocessorHost != null) {
|
||||||
newKV = KeyValueUtil.ensureKeyValue(coprocessorHost.postMutationBeforeWAL(
|
newKV = KeyValueUtil.ensureKeyValue(coprocessorHost.postMutationBeforeWAL(
|
||||||
|
@ -6220,4 +6243,14 @@ public class HRegion implements HeapSize { // , Writable{
|
||||||
WALEdit.EMPTY_WALEDIT, this.sequenceId, false, cells);
|
WALEdit.EMPTY_WALEDIT, this.sequenceId, false, cells);
|
||||||
return key;
|
return key;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Explictly sync wal
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
public void syncWal() throws IOException {
|
||||||
|
if(this.log != null) {
|
||||||
|
this.log.sync();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -246,7 +246,7 @@ public class MultiVersionConsistencyControl {
|
||||||
|
|
||||||
public static class WriteEntry {
|
public static class WriteEntry {
|
||||||
private long writeNumber;
|
private long writeNumber;
|
||||||
private boolean completed = false;
|
private volatile boolean completed = false;
|
||||||
|
|
||||||
WriteEntry(long writeNumber) {
|
WriteEntry(long writeNumber) {
|
||||||
this.writeNumber = writeNumber;
|
this.writeNumber = writeNumber;
|
||||||
|
|
|
@ -633,12 +633,13 @@ public class RSRpcServices implements HBaseRPCErrorHandler,
|
||||||
* constructing MultiResponse to save a possible loop if caller doesn't need MultiResponse.
|
* constructing MultiResponse to save a possible loop if caller doesn't need MultiResponse.
|
||||||
* @param region
|
* @param region
|
||||||
* @param mutations
|
* @param mutations
|
||||||
|
* @param replaySeqId
|
||||||
* @return an array of OperationStatus which internally contains the OperationStatusCode and the
|
* @return an array of OperationStatus which internally contains the OperationStatusCode and the
|
||||||
* exceptionMessage if any
|
* exceptionMessage if any
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
private OperationStatus [] doReplayBatchOp(final HRegion region,
|
private OperationStatus [] doReplayBatchOp(final HRegion region,
|
||||||
final List<HLogSplitter.MutationReplay> mutations) throws IOException {
|
final List<HLogSplitter.MutationReplay> mutations, long replaySeqId) throws IOException {
|
||||||
HLogSplitter.MutationReplay[] mArray = new HLogSplitter.MutationReplay[mutations.size()];
|
HLogSplitter.MutationReplay[] mArray = new HLogSplitter.MutationReplay[mutations.size()];
|
||||||
|
|
||||||
long before = EnvironmentEdgeManager.currentTimeMillis();
|
long before = EnvironmentEdgeManager.currentTimeMillis();
|
||||||
|
@ -657,7 +658,7 @@ public class RSRpcServices implements HBaseRPCErrorHandler,
|
||||||
if (!region.getRegionInfo().isMetaTable()) {
|
if (!region.getRegionInfo().isMetaTable()) {
|
||||||
regionServer.cacheFlusher.reclaimMemStoreMemory();
|
regionServer.cacheFlusher.reclaimMemStoreMemory();
|
||||||
}
|
}
|
||||||
return region.batchReplay(mArray);
|
return region.batchReplay(mArray, replaySeqId);
|
||||||
} finally {
|
} finally {
|
||||||
if (regionServer.metricsRegionServer != null) {
|
if (regionServer.metricsRegionServer != null) {
|
||||||
long after = EnvironmentEdgeManager.currentTimeMillis();
|
long after = EnvironmentEdgeManager.currentTimeMillis();
|
||||||
|
@ -1330,7 +1331,6 @@ public class RSRpcServices implements HBaseRPCErrorHandler,
|
||||||
entries.get(0).getKey().getEncodedRegionName().toStringUtf8());
|
entries.get(0).getKey().getEncodedRegionName().toStringUtf8());
|
||||||
RegionCoprocessorHost coprocessorHost = region.getCoprocessorHost();
|
RegionCoprocessorHost coprocessorHost = region.getCoprocessorHost();
|
||||||
List<Pair<HLogKey, WALEdit>> walEntries = new ArrayList<Pair<HLogKey, WALEdit>>();
|
List<Pair<HLogKey, WALEdit>> walEntries = new ArrayList<Pair<HLogKey, WALEdit>>();
|
||||||
List<HLogSplitter.MutationReplay> mutations = new ArrayList<HLogSplitter.MutationReplay>();
|
|
||||||
// when tag is enabled, we need tag replay edits with log sequence number
|
// when tag is enabled, we need tag replay edits with log sequence number
|
||||||
boolean needAddReplayTag = (HFile.getFormatVersion(regionServer.conf) >= 3);
|
boolean needAddReplayTag = (HFile.getFormatVersion(regionServer.conf) >= 3);
|
||||||
for (WALEntry entry : entries) {
|
for (WALEntry entry : entries) {
|
||||||
|
@ -1354,18 +1354,22 @@ public class RSRpcServices implements HBaseRPCErrorHandler,
|
||||||
}
|
}
|
||||||
walEntries.add(walEntry);
|
walEntries.add(walEntry);
|
||||||
}
|
}
|
||||||
mutations.addAll(edits);
|
if(edits!=null && !edits.isEmpty()) {
|
||||||
}
|
long replaySeqId = (entry.getKey().hasOrigSequenceNumber()) ?
|
||||||
|
entry.getKey().getOrigSequenceNumber() : entry.getKey().getLogSequenceNumber();
|
||||||
if (!mutations.isEmpty()) {
|
OperationStatus[] result = doReplayBatchOp(region, edits, replaySeqId);
|
||||||
OperationStatus[] result = doReplayBatchOp(region, mutations);
|
// check if it's a partial success
|
||||||
// check if it's a partial success
|
for (int i = 0; result != null && i < result.length; i++) {
|
||||||
for (int i = 0; result != null && i < result.length; i++) {
|
if (result[i] != OperationStatus.SUCCESS) {
|
||||||
if (result[i] != OperationStatus.SUCCESS) {
|
throw new IOException(result[i].getExceptionMsg());
|
||||||
throw new IOException(result[i].getExceptionMsg());
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//sync wal at the end because ASYNC_WAL is used above
|
||||||
|
region.syncWal();
|
||||||
|
|
||||||
if (coprocessorHost != null) {
|
if (coprocessorHost != null) {
|
||||||
for (Pair<HLogKey, WALEdit> wal : walEntries) {
|
for (Pair<HLogKey, WALEdit> wal : walEntries) {
|
||||||
coprocessorHost.postWALRestore(region.getRegionInfo(), wal.getFirst(),
|
coprocessorHost.postWALRestore(region.getRegionInfo(), wal.getFirst(),
|
||||||
|
|
|
@ -211,15 +211,6 @@ public class StoreFileScanner implements KeyValueScanner {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// For the optimisation in HBASE-4346, we set the KV's memstoreTS to
|
|
||||||
// 0, if it is older than all the scanners' read points. It is possible
|
|
||||||
// that a newer KV's memstoreTS was reset to 0. But, there is an
|
|
||||||
// older KV which was not reset to 0 (because it was
|
|
||||||
// not old enough during flush). Make sure that we set it correctly now,
|
|
||||||
// so that the comparision order does not change.
|
|
||||||
if (cur.getMvccVersion() <= readPt) {
|
|
||||||
KeyValueUtil.ensureKeyValue(cur).setMvccVersion(0);
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -58,6 +58,9 @@ public abstract class Compactor {
|
||||||
|
|
||||||
private int compactionKVMax;
|
private int compactionKVMax;
|
||||||
protected Compression.Algorithm compactionCompression;
|
protected Compression.Algorithm compactionCompression;
|
||||||
|
|
||||||
|
/** specify how many days to keep MVCC values during major compaction **/
|
||||||
|
protected int keepSeqIdPeriod;
|
||||||
|
|
||||||
//TODO: depending on Store is not good but, realistically, all compactors currently do.
|
//TODO: depending on Store is not good but, realistically, all compactors currently do.
|
||||||
Compactor(final Configuration conf, final Store store) {
|
Compactor(final Configuration conf, final Store store) {
|
||||||
|
@ -67,6 +70,8 @@ public abstract class Compactor {
|
||||||
this.conf.getInt(HConstants.COMPACTION_KV_MAX, HConstants.COMPACTION_KV_MAX_DEFAULT);
|
this.conf.getInt(HConstants.COMPACTION_KV_MAX, HConstants.COMPACTION_KV_MAX_DEFAULT);
|
||||||
this.compactionCompression = (this.store.getFamily() == null) ?
|
this.compactionCompression = (this.store.getFamily() == null) ?
|
||||||
Compression.Algorithm.NONE : this.store.getFamily().getCompactionCompression();
|
Compression.Algorithm.NONE : this.store.getFamily().getCompactionCompression();
|
||||||
|
this.keepSeqIdPeriod = Math.max(this.conf.getInt(HConstants.KEEP_SEQID_PERIOD,
|
||||||
|
HConstants.MIN_KEEP_SEQID_PERIOD), HConstants.MIN_KEEP_SEQID_PERIOD);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -92,19 +97,30 @@ public abstract class Compactor {
|
||||||
public long maxMVCCReadpoint = 0;
|
public long maxMVCCReadpoint = 0;
|
||||||
/** Max tags length**/
|
/** Max tags length**/
|
||||||
public int maxTagsLength = 0;
|
public int maxTagsLength = 0;
|
||||||
|
/** Min SeqId to keep during a major compaction **/
|
||||||
|
public long minSeqIdToKeep = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extracts some details about the files to compact that are commonly needed by compactors.
|
* Extracts some details about the files to compact that are commonly needed by compactors.
|
||||||
* @param filesToCompact Files.
|
* @param filesToCompact Files.
|
||||||
* @param calculatePutTs Whether earliest put TS is needed.
|
* @param allFiles Whether all files are included for compaction
|
||||||
* @return The result.
|
* @return The result.
|
||||||
*/
|
*/
|
||||||
protected FileDetails getFileDetails(
|
protected FileDetails getFileDetails(
|
||||||
Collection<StoreFile> filesToCompact, boolean calculatePutTs) throws IOException {
|
Collection<StoreFile> filesToCompact, boolean allFiles) throws IOException {
|
||||||
FileDetails fd = new FileDetails();
|
FileDetails fd = new FileDetails();
|
||||||
|
long oldestHFileTimeStampToKeepMVCC = System.currentTimeMillis() -
|
||||||
|
(1000L * 60 * 60 * 24 * this.keepSeqIdPeriod);
|
||||||
|
|
||||||
for (StoreFile file : filesToCompact) {
|
for (StoreFile file : filesToCompact) {
|
||||||
|
if(allFiles && (file.getModificationTimeStamp() < oldestHFileTimeStampToKeepMVCC)) {
|
||||||
|
// when isAllFiles is true, all files are compacted so we can calculate the smallest
|
||||||
|
// MVCC value to keep
|
||||||
|
if(fd.minSeqIdToKeep < file.getMaxMemstoreTS()) {
|
||||||
|
fd.minSeqIdToKeep = file.getMaxMemstoreTS();
|
||||||
|
}
|
||||||
|
}
|
||||||
long seqNum = file.getMaxSequenceId();
|
long seqNum = file.getMaxSequenceId();
|
||||||
fd.maxSeqId = Math.max(fd.maxSeqId, seqNum);
|
fd.maxSeqId = Math.max(fd.maxSeqId, seqNum);
|
||||||
StoreFile.Reader r = file.getReader();
|
StoreFile.Reader r = file.getReader();
|
||||||
|
@ -130,7 +146,7 @@ public abstract class Compactor {
|
||||||
// If required, calculate the earliest put timestamp of all involved storefiles.
|
// If required, calculate the earliest put timestamp of all involved storefiles.
|
||||||
// This is used to remove family delete marker during compaction.
|
// This is used to remove family delete marker during compaction.
|
||||||
long earliestPutTs = 0;
|
long earliestPutTs = 0;
|
||||||
if (calculatePutTs) {
|
if (allFiles) {
|
||||||
tmp = fileInfo.get(StoreFile.EARLIEST_PUT_TS);
|
tmp = fileInfo.get(StoreFile.EARLIEST_PUT_TS);
|
||||||
if (tmp == null) {
|
if (tmp == null) {
|
||||||
// There's a file with no information, must be an old one
|
// There's a file with no information, must be an old one
|
||||||
|
@ -148,7 +164,7 @@ public abstract class Compactor {
|
||||||
", size=" + StringUtils.humanReadableInt(r.length()) +
|
", size=" + StringUtils.humanReadableInt(r.length()) +
|
||||||
", encoding=" + r.getHFileReader().getDataBlockEncoding() +
|
", encoding=" + r.getHFileReader().getDataBlockEncoding() +
|
||||||
", seqNum=" + seqNum +
|
", seqNum=" + seqNum +
|
||||||
(calculatePutTs ? ", earliestPutTs=" + earliestPutTs: ""));
|
(allFiles ? ", earliestPutTs=" + earliestPutTs: ""));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return fd;
|
return fd;
|
||||||
|
@ -202,10 +218,11 @@ public abstract class Compactor {
|
||||||
* @param scanner Where to read from.
|
* @param scanner Where to read from.
|
||||||
* @param writer Where to write to.
|
* @param writer Where to write to.
|
||||||
* @param smallestReadPoint Smallest read point.
|
* @param smallestReadPoint Smallest read point.
|
||||||
|
* @param cleanSeqId When true, remove seqId(used to be mvcc) value which is <= smallestReadPoint
|
||||||
* @return Whether compaction ended; false if it was interrupted for some reason.
|
* @return Whether compaction ended; false if it was interrupted for some reason.
|
||||||
*/
|
*/
|
||||||
protected boolean performCompaction(InternalScanner scanner,
|
protected boolean performCompaction(InternalScanner scanner,
|
||||||
CellSink writer, long smallestReadPoint) throws IOException {
|
CellSink writer, long smallestReadPoint, boolean cleanSeqId) throws IOException {
|
||||||
int bytesWritten = 0;
|
int bytesWritten = 0;
|
||||||
// Since scanner.next() can return 'false' but still be delivering data,
|
// Since scanner.next() can return 'false' but still be delivering data,
|
||||||
// we have to use a do/while loop.
|
// we have to use a do/while loop.
|
||||||
|
@ -218,8 +235,8 @@ public abstract class Compactor {
|
||||||
// output to writer:
|
// output to writer:
|
||||||
for (Cell c : kvs) {
|
for (Cell c : kvs) {
|
||||||
KeyValue kv = KeyValueUtil.ensureKeyValue(c);
|
KeyValue kv = KeyValueUtil.ensureKeyValue(c);
|
||||||
if (kv.getMvccVersion() <= smallestReadPoint) {
|
if (cleanSeqId && kv.getSequenceId() <= smallestReadPoint) {
|
||||||
kv.setMvccVersion(0);
|
kv.setSequenceId(0);
|
||||||
}
|
}
|
||||||
writer.append(kv);
|
writer.append(kv);
|
||||||
++progress.currentCompactedKVs;
|
++progress.currentCompactedKVs;
|
||||||
|
|
|
@ -54,6 +54,7 @@ public class DefaultCompactor extends Compactor {
|
||||||
|
|
||||||
StoreFile.Writer writer = null;
|
StoreFile.Writer writer = null;
|
||||||
List<Path> newFiles = new ArrayList<Path>();
|
List<Path> newFiles = new ArrayList<Path>();
|
||||||
|
boolean cleanSeqId = false;
|
||||||
try {
|
try {
|
||||||
InternalScanner scanner = null;
|
InternalScanner scanner = null;
|
||||||
try {
|
try {
|
||||||
|
@ -71,9 +72,13 @@ public class DefaultCompactor extends Compactor {
|
||||||
}
|
}
|
||||||
// Create the writer even if no kv(Empty store file is also ok),
|
// Create the writer even if no kv(Empty store file is also ok),
|
||||||
// because we need record the max seq id for the store file, see HBASE-6059
|
// because we need record the max seq id for the store file, see HBASE-6059
|
||||||
|
if(fd.minSeqIdToKeep > 0) {
|
||||||
|
smallestReadPoint = Math.min(fd.minSeqIdToKeep, smallestReadPoint);
|
||||||
|
cleanSeqId = true;
|
||||||
|
}
|
||||||
writer = store.createWriterInTmp(fd.maxKeyCount, this.compactionCompression, true,
|
writer = store.createWriterInTmp(fd.maxKeyCount, this.compactionCompression, true,
|
||||||
fd.maxMVCCReadpoint >= smallestReadPoint, fd.maxTagsLength > 0);
|
fd.maxMVCCReadpoint >= smallestReadPoint, fd.maxTagsLength > 0);
|
||||||
boolean finished = performCompaction(scanner, writer, smallestReadPoint);
|
boolean finished = performCompaction(scanner, writer, smallestReadPoint, cleanSeqId);
|
||||||
if (!finished) {
|
if (!finished) {
|
||||||
writer.close();
|
writer.close();
|
||||||
store.getFileSystem().delete(writer.getPath(), false);
|
store.getFileSystem().delete(writer.getPath(), false);
|
||||||
|
|
|
@ -90,6 +90,7 @@ public class StripeCompactor extends Compactor {
|
||||||
|
|
||||||
boolean finished = false;
|
boolean finished = false;
|
||||||
InternalScanner scanner = null;
|
InternalScanner scanner = null;
|
||||||
|
boolean cleanSeqId = false;
|
||||||
try {
|
try {
|
||||||
// Get scanner to use.
|
// Get scanner to use.
|
||||||
ScanType coprocScanType = ScanType.COMPACT_RETAIN_DELETES;
|
ScanType coprocScanType = ScanType.COMPACT_RETAIN_DELETES;
|
||||||
|
@ -108,6 +109,10 @@ public class StripeCompactor extends Compactor {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the writer factory for compactions.
|
// Create the writer factory for compactions.
|
||||||
|
if(fd.minSeqIdToKeep > 0) {
|
||||||
|
smallestReadPoint = Math.min(fd.minSeqIdToKeep, smallestReadPoint);
|
||||||
|
cleanSeqId = true;
|
||||||
|
}
|
||||||
final boolean needMvcc = fd.maxMVCCReadpoint >= smallestReadPoint;
|
final boolean needMvcc = fd.maxMVCCReadpoint >= smallestReadPoint;
|
||||||
final Compression.Algorithm compression = store.getFamily().getCompactionCompression();
|
final Compression.Algorithm compression = store.getFamily().getCompactionCompression();
|
||||||
StripeMultiFileWriter.WriterFactory factory = new StripeMultiFileWriter.WriterFactory() {
|
StripeMultiFileWriter.WriterFactory factory = new StripeMultiFileWriter.WriterFactory() {
|
||||||
|
@ -122,7 +127,7 @@ public class StripeCompactor extends Compactor {
|
||||||
// It is ok here if storeScanner is null.
|
// It is ok here if storeScanner is null.
|
||||||
StoreScanner storeScanner = (scanner instanceof StoreScanner) ? (StoreScanner)scanner : null;
|
StoreScanner storeScanner = (scanner instanceof StoreScanner) ? (StoreScanner)scanner : null;
|
||||||
mw.init(storeScanner, factory, store.getComparator());
|
mw.init(storeScanner, factory, store.getComparator());
|
||||||
finished = performCompaction(scanner, mw, smallestReadPoint);
|
finished = performCompaction(scanner, mw, smallestReadPoint, cleanSeqId);
|
||||||
if (!finished) {
|
if (!finished) {
|
||||||
throw new InterruptedIOException( "Aborting compaction of store " + store +
|
throw new InterruptedIOException( "Aborting compaction of store " + store +
|
||||||
" in region " + store.getRegionInfo().getRegionNameAsString() +
|
" in region " + store.getRegionInfo().getRegionNameAsString() +
|
||||||
|
|
|
@ -91,9 +91,9 @@ class FSWALEntry extends HLog.Entry {
|
||||||
*/
|
*/
|
||||||
long stampRegionSequenceId() {
|
long stampRegionSequenceId() {
|
||||||
long regionSequenceId = this.regionSequenceIdReference.incrementAndGet();
|
long regionSequenceId = this.regionSequenceIdReference.incrementAndGet();
|
||||||
if(memstoreKVs != null && !memstoreKVs.isEmpty()) {
|
if (!this.getEdit().isReplay() && memstoreKVs != null && !memstoreKVs.isEmpty()) {
|
||||||
for(KeyValue kv : this.memstoreKVs){
|
for(KeyValue kv : this.memstoreKVs){
|
||||||
kv.setMvccVersion(regionSequenceId);
|
kv.setSequenceId(regionSequenceId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
HLogKey key = getKey();
|
HLogKey key = getKey();
|
||||||
|
|
|
@ -119,6 +119,7 @@ public class HLogKey implements WritableComparable<HLogKey>, SequenceNumber {
|
||||||
private byte [] encodedRegionName;
|
private byte [] encodedRegionName;
|
||||||
private TableName tablename;
|
private TableName tablename;
|
||||||
private long logSeqNum;
|
private long logSeqNum;
|
||||||
|
private long origLogSeqNum = 0;
|
||||||
private CountDownLatch seqNumAssignedLatch = new CountDownLatch(1);
|
private CountDownLatch seqNumAssignedLatch = new CountDownLatch(1);
|
||||||
// Time at which this edit was written.
|
// Time at which this edit was written.
|
||||||
private long writeTime;
|
private long writeTime;
|
||||||
|
@ -255,6 +256,22 @@ public class HLogKey implements WritableComparable<HLogKey>, SequenceNumber {
|
||||||
this.seqNumAssignedLatch.countDown();
|
this.seqNumAssignedLatch.countDown();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to set original seq Id for HLogKey during wal replay
|
||||||
|
* @param seqId
|
||||||
|
*/
|
||||||
|
public void setOrigLogSeqNum(final long seqId) {
|
||||||
|
this.origLogSeqNum = seqId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a positive long if current HLogKey is created from a replay edit
|
||||||
|
* @return original sequence number of the WALEdit
|
||||||
|
*/
|
||||||
|
public long getOrigLogSeqNum() {
|
||||||
|
return this.origLogSeqNum;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wait for sequence number is assigned & return the assigned value
|
* Wait for sequence number is assigned & return the assigned value
|
||||||
* @return long the new assigned sequence number
|
* @return long the new assigned sequence number
|
||||||
|
@ -536,6 +553,9 @@ public class HLogKey implements WritableComparable<HLogKey>, SequenceNumber {
|
||||||
}
|
}
|
||||||
builder.setLogSequenceNumber(this.logSeqNum);
|
builder.setLogSequenceNumber(this.logSeqNum);
|
||||||
builder.setWriteTime(writeTime);
|
builder.setWriteTime(writeTime);
|
||||||
|
if(this.origLogSeqNum > 0) {
|
||||||
|
builder.setOrigSequenceNumber(this.origLogSeqNum);
|
||||||
|
}
|
||||||
if (this.nonce != HConstants.NO_NONCE) {
|
if (this.nonce != HConstants.NO_NONCE) {
|
||||||
builder.setNonce(nonce);
|
builder.setNonce(nonce);
|
||||||
}
|
}
|
||||||
|
@ -599,5 +619,8 @@ public class HLogKey implements WritableComparable<HLogKey>, SequenceNumber {
|
||||||
}
|
}
|
||||||
this.logSeqNum = walKey.getLogSequenceNumber();
|
this.logSeqNum = walKey.getLogSequenceNumber();
|
||||||
this.writeTime = walKey.getWriteTime();
|
this.writeTime = walKey.getWriteTime();
|
||||||
|
if(walKey.hasOrigSequenceNumber()) {
|
||||||
|
this.origLogSeqNum = walKey.getOrigSequenceNumber();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,6 +73,7 @@ import org.apache.hadoop.hbase.Tag;
|
||||||
import org.apache.hadoop.hbase.TagType;
|
import org.apache.hadoop.hbase.TagType;
|
||||||
import org.apache.hadoop.hbase.client.ConnectionUtils;
|
import org.apache.hadoop.hbase.client.ConnectionUtils;
|
||||||
import org.apache.hadoop.hbase.client.Delete;
|
import org.apache.hadoop.hbase.client.Delete;
|
||||||
|
import org.apache.hadoop.hbase.client.Durability;
|
||||||
import org.apache.hadoop.hbase.client.HConnection;
|
import org.apache.hadoop.hbase.client.HConnection;
|
||||||
import org.apache.hadoop.hbase.client.HConnectionManager;
|
import org.apache.hadoop.hbase.client.HConnectionManager;
|
||||||
import org.apache.hadoop.hbase.client.Mutation;
|
import org.apache.hadoop.hbase.client.Mutation;
|
||||||
|
@ -1863,6 +1864,10 @@ public class HLogSplitter {
|
||||||
public MutationReplay(MutationType type, Mutation mutation, long nonceGroup, long nonce) {
|
public MutationReplay(MutationType type, Mutation mutation, long nonceGroup, long nonce) {
|
||||||
this.type = type;
|
this.type = type;
|
||||||
this.mutation = mutation;
|
this.mutation = mutation;
|
||||||
|
if(this.mutation.getDurability() != Durability.SKIP_WAL) {
|
||||||
|
// using ASYNC_WAL for relay
|
||||||
|
this.mutation.setDurability(Durability.ASYNC_WAL);
|
||||||
|
}
|
||||||
this.nonceGroup = nonceGroup;
|
this.nonceGroup = nonceGroup;
|
||||||
this.nonce = nonce;
|
this.nonce = nonce;
|
||||||
}
|
}
|
||||||
|
@ -1875,10 +1880,10 @@ public class HLogSplitter {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tag original sequence number for each edit to be replayed
|
* Tag original sequence number for each edit to be replayed
|
||||||
* @param entry
|
* @param seqId
|
||||||
* @param cell
|
* @param cell
|
||||||
*/
|
*/
|
||||||
private static Cell tagReplayLogSequenceNumber(WALEntry entry, Cell cell) {
|
private static Cell tagReplayLogSequenceNumber(long seqId, Cell cell) {
|
||||||
// Tag puts with original sequence number if there is no LOG_REPLAY_TAG yet
|
// Tag puts with original sequence number if there is no LOG_REPLAY_TAG yet
|
||||||
boolean needAddRecoveryTag = true;
|
boolean needAddRecoveryTag = true;
|
||||||
if (cell.getTagsLength() > 0) {
|
if (cell.getTagsLength() > 0) {
|
||||||
|
@ -1891,8 +1896,7 @@ public class HLogSplitter {
|
||||||
}
|
}
|
||||||
if (needAddRecoveryTag) {
|
if (needAddRecoveryTag) {
|
||||||
List<Tag> newTags = new ArrayList<Tag>();
|
List<Tag> newTags = new ArrayList<Tag>();
|
||||||
Tag replayTag = new Tag(TagType.LOG_REPLAY_TAG_TYPE, Bytes.toBytes(entry.getKey()
|
Tag replayTag = new Tag(TagType.LOG_REPLAY_TAG_TYPE, Bytes.toBytes(seqId));
|
||||||
.getLogSequenceNumber()));
|
|
||||||
newTags.add(replayTag);
|
newTags.add(replayTag);
|
||||||
return KeyValue.cloneAndAddTags(cell, newTags);
|
return KeyValue.cloneAndAddTags(cell, newTags);
|
||||||
}
|
}
|
||||||
|
@ -1918,6 +1922,8 @@ public class HLogSplitter {
|
||||||
return new ArrayList<MutationReplay>();
|
return new ArrayList<MutationReplay>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
long replaySeqId = (entry.getKey().hasOrigSequenceNumber()) ?
|
||||||
|
entry.getKey().getOrigSequenceNumber() : entry.getKey().getLogSequenceNumber();
|
||||||
int count = entry.getAssociatedCellCount();
|
int count = entry.getAssociatedCellCount();
|
||||||
List<MutationReplay> mutations = new ArrayList<MutationReplay>();
|
List<MutationReplay> mutations = new ArrayList<MutationReplay>();
|
||||||
Cell previousCell = null;
|
Cell previousCell = null;
|
||||||
|
@ -1958,7 +1964,7 @@ public class HLogSplitter {
|
||||||
} else {
|
} else {
|
||||||
Cell tmpNewCell = cell;
|
Cell tmpNewCell = cell;
|
||||||
if (addLogReplayTag) {
|
if (addLogReplayTag) {
|
||||||
tmpNewCell = tagReplayLogSequenceNumber(entry, cell);
|
tmpNewCell = tagReplayLogSequenceNumber(replaySeqId, cell);
|
||||||
}
|
}
|
||||||
((Put) m).add(KeyValueUtil.ensureKeyValue(tmpNewCell));
|
((Put) m).add(KeyValueUtil.ensureKeyValue(tmpNewCell));
|
||||||
}
|
}
|
||||||
|
@ -1973,8 +1979,8 @@ public class HLogSplitter {
|
||||||
clusterIds.add(new UUID(uuid.getMostSigBits(), uuid.getLeastSigBits()));
|
clusterIds.add(new UUID(uuid.getMostSigBits(), uuid.getLeastSigBits()));
|
||||||
}
|
}
|
||||||
key = new HLogKey(walKey.getEncodedRegionName().toByteArray(), TableName.valueOf(walKey
|
key = new HLogKey(walKey.getEncodedRegionName().toByteArray(), TableName.valueOf(walKey
|
||||||
.getTableName().toByteArray()), walKey.getLogSequenceNumber(),
|
.getTableName().toByteArray()), replaySeqId, walKey.getWriteTime(), clusterIds,
|
||||||
walKey.getWriteTime(), clusterIds, walKey.getNonceGroup(), walKey.getNonce());
|
walKey.getNonceGroup(), walKey.getNonce());
|
||||||
logEntry.setFirst(key);
|
logEntry.setFirst(key);
|
||||||
logEntry.setSecond(val);
|
logEntry.setSecond(val);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1906,7 +1906,7 @@ public class AccessController extends BaseRegionObserver
|
||||||
newKv.getValueArray(), newKv.getValueOffset(), newKv.getValueLength(),
|
newKv.getValueArray(), newKv.getValueOffset(), newKv.getValueLength(),
|
||||||
tags);
|
tags);
|
||||||
// Preserve mvcc data
|
// Preserve mvcc data
|
||||||
rewriteKv.setMvccVersion(newKv.getMvccVersion());
|
rewriteKv.setSequenceId(newKv.getMvccVersion());
|
||||||
return rewriteKv;
|
return rewriteKv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1255,7 +1255,7 @@ public class VisibilityController extends BaseRegionObserver implements MasterOb
|
||||||
newKv.getTimestamp(), KeyValue.Type.codeToType(newKv.getTypeByte()),
|
newKv.getTimestamp(), KeyValue.Type.codeToType(newKv.getTypeByte()),
|
||||||
newKv.getValueArray(), newKv.getValueOffset(), newKv.getValueLength(), tags);
|
newKv.getValueArray(), newKv.getValueOffset(), newKv.getValueLength(), tags);
|
||||||
// Preserve mvcc data
|
// Preserve mvcc data
|
||||||
rewriteKv.setMvccVersion(newKv.getMvccVersion());
|
rewriteKv.setSequenceId(newKv.getMvccVersion());
|
||||||
return rewriteKv;
|
return rewriteKv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3055,7 +3055,7 @@ public class HBaseTestingUtility extends HBaseCommonTestingUtility {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static <T> String safeGetAsStr(List<T> lst, int i) {
|
public static <T> String safeGetAsStr(List<T> lst, int i) {
|
||||||
if (0 <= i && i < lst.size()) {
|
if (0 <= i && i < lst.size()) {
|
||||||
return lst.get(i).toString();
|
return lst.get(i).toString();
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -176,7 +176,7 @@ public class TestHFileBlock {
|
||||||
totalSize += kv.getLength();
|
totalSize += kv.getLength();
|
||||||
if (includesMemstoreTS) {
|
if (includesMemstoreTS) {
|
||||||
long memstoreTS = randomizer.nextLong();
|
long memstoreTS = randomizer.nextLong();
|
||||||
kv.setMvccVersion(memstoreTS);
|
kv.setSequenceId(memstoreTS);
|
||||||
totalSize += WritableUtils.getVIntSize(memstoreTS);
|
totalSize += WritableUtils.getVIntSize(memstoreTS);
|
||||||
}
|
}
|
||||||
hbw.write(kv);
|
hbw.write(kv);
|
||||||
|
|
|
@ -241,7 +241,7 @@ public class TestDefaultMemStore extends TestCase {
|
||||||
mvcc.beginMemstoreInsertWithSeqNum(this.startSeqNum.incrementAndGet());
|
mvcc.beginMemstoreInsertWithSeqNum(this.startSeqNum.incrementAndGet());
|
||||||
|
|
||||||
KeyValue kv1 = new KeyValue(row, f, q1, v);
|
KeyValue kv1 = new KeyValue(row, f, q1, v);
|
||||||
kv1.setMvccVersion(w.getWriteNumber());
|
kv1.setSequenceId(w.getWriteNumber());
|
||||||
memstore.add(kv1);
|
memstore.add(kv1);
|
||||||
|
|
||||||
KeyValueScanner s = this.memstore.getScanners(mvcc.memstoreReadPoint()).get(0);
|
KeyValueScanner s = this.memstore.getScanners(mvcc.memstoreReadPoint()).get(0);
|
||||||
|
@ -254,7 +254,7 @@ public class TestDefaultMemStore extends TestCase {
|
||||||
|
|
||||||
w = mvcc.beginMemstoreInsertWithSeqNum(this.startSeqNum.incrementAndGet());
|
w = mvcc.beginMemstoreInsertWithSeqNum(this.startSeqNum.incrementAndGet());
|
||||||
KeyValue kv2 = new KeyValue(row, f, q2, v);
|
KeyValue kv2 = new KeyValue(row, f, q2, v);
|
||||||
kv2.setMvccVersion(w.getWriteNumber());
|
kv2.setSequenceId(w.getWriteNumber());
|
||||||
memstore.add(kv2);
|
memstore.add(kv2);
|
||||||
|
|
||||||
s = this.memstore.getScanners(mvcc.memstoreReadPoint()).get(0);
|
s = this.memstore.getScanners(mvcc.memstoreReadPoint()).get(0);
|
||||||
|
@ -285,11 +285,11 @@ public class TestDefaultMemStore extends TestCase {
|
||||||
mvcc.beginMemstoreInsertWithSeqNum(this.startSeqNum.incrementAndGet());
|
mvcc.beginMemstoreInsertWithSeqNum(this.startSeqNum.incrementAndGet());
|
||||||
|
|
||||||
KeyValue kv11 = new KeyValue(row, f, q1, v1);
|
KeyValue kv11 = new KeyValue(row, f, q1, v1);
|
||||||
kv11.setMvccVersion(w.getWriteNumber());
|
kv11.setSequenceId(w.getWriteNumber());
|
||||||
memstore.add(kv11);
|
memstore.add(kv11);
|
||||||
|
|
||||||
KeyValue kv12 = new KeyValue(row, f, q2, v1);
|
KeyValue kv12 = new KeyValue(row, f, q2, v1);
|
||||||
kv12.setMvccVersion(w.getWriteNumber());
|
kv12.setSequenceId(w.getWriteNumber());
|
||||||
memstore.add(kv12);
|
memstore.add(kv12);
|
||||||
mvcc.completeMemstoreInsert(w);
|
mvcc.completeMemstoreInsert(w);
|
||||||
|
|
||||||
|
@ -300,11 +300,11 @@ public class TestDefaultMemStore extends TestCase {
|
||||||
// START INSERT 2: Write both columns val2
|
// START INSERT 2: Write both columns val2
|
||||||
w = mvcc.beginMemstoreInsertWithSeqNum(this.startSeqNum.incrementAndGet());
|
w = mvcc.beginMemstoreInsertWithSeqNum(this.startSeqNum.incrementAndGet());
|
||||||
KeyValue kv21 = new KeyValue(row, f, q1, v2);
|
KeyValue kv21 = new KeyValue(row, f, q1, v2);
|
||||||
kv21.setMvccVersion(w.getWriteNumber());
|
kv21.setSequenceId(w.getWriteNumber());
|
||||||
memstore.add(kv21);
|
memstore.add(kv21);
|
||||||
|
|
||||||
KeyValue kv22 = new KeyValue(row, f, q2, v2);
|
KeyValue kv22 = new KeyValue(row, f, q2, v2);
|
||||||
kv22.setMvccVersion(w.getWriteNumber());
|
kv22.setSequenceId(w.getWriteNumber());
|
||||||
memstore.add(kv22);
|
memstore.add(kv22);
|
||||||
|
|
||||||
// BEFORE COMPLETING INSERT 2, SEE FIRST KVS
|
// BEFORE COMPLETING INSERT 2, SEE FIRST KVS
|
||||||
|
@ -337,11 +337,11 @@ public class TestDefaultMemStore extends TestCase {
|
||||||
mvcc.beginMemstoreInsertWithSeqNum(this.startSeqNum.incrementAndGet());
|
mvcc.beginMemstoreInsertWithSeqNum(this.startSeqNum.incrementAndGet());
|
||||||
|
|
||||||
KeyValue kv11 = new KeyValue(row, f, q1, v1);
|
KeyValue kv11 = new KeyValue(row, f, q1, v1);
|
||||||
kv11.setMvccVersion(w.getWriteNumber());
|
kv11.setSequenceId(w.getWriteNumber());
|
||||||
memstore.add(kv11);
|
memstore.add(kv11);
|
||||||
|
|
||||||
KeyValue kv12 = new KeyValue(row, f, q2, v1);
|
KeyValue kv12 = new KeyValue(row, f, q2, v1);
|
||||||
kv12.setMvccVersion(w.getWriteNumber());
|
kv12.setSequenceId(w.getWriteNumber());
|
||||||
memstore.add(kv12);
|
memstore.add(kv12);
|
||||||
mvcc.completeMemstoreInsert(w);
|
mvcc.completeMemstoreInsert(w);
|
||||||
|
|
||||||
|
@ -353,7 +353,7 @@ public class TestDefaultMemStore extends TestCase {
|
||||||
w = mvcc.beginMemstoreInsertWithSeqNum(this.startSeqNum.incrementAndGet());
|
w = mvcc.beginMemstoreInsertWithSeqNum(this.startSeqNum.incrementAndGet());
|
||||||
KeyValue kvDel = new KeyValue(row, f, q2, kv11.getTimestamp(),
|
KeyValue kvDel = new KeyValue(row, f, q2, kv11.getTimestamp(),
|
||||||
KeyValue.Type.DeleteColumn);
|
KeyValue.Type.DeleteColumn);
|
||||||
kvDel.setMvccVersion(w.getWriteNumber());
|
kvDel.setSequenceId(w.getWriteNumber());
|
||||||
memstore.add(kvDel);
|
memstore.add(kvDel);
|
||||||
|
|
||||||
// BEFORE COMPLETING DELETE, SEE FIRST KVS
|
// BEFORE COMPLETING DELETE, SEE FIRST KVS
|
||||||
|
@ -414,7 +414,7 @@ public class TestDefaultMemStore extends TestCase {
|
||||||
byte[] v = Bytes.toBytes(i);
|
byte[] v = Bytes.toBytes(i);
|
||||||
|
|
||||||
KeyValue kv = new KeyValue(row, f, q1, i, v);
|
KeyValue kv = new KeyValue(row, f, q1, i, v);
|
||||||
kv.setMvccVersion(w.getWriteNumber());
|
kv.setSequenceId(w.getWriteNumber());
|
||||||
memstore.add(kv);
|
memstore.add(kv);
|
||||||
mvcc.completeMemstoreInsert(w);
|
mvcc.completeMemstoreInsert(w);
|
||||||
|
|
||||||
|
@ -827,7 +827,7 @@ public class TestDefaultMemStore extends TestCase {
|
||||||
KeyValue kv2 = KeyValueTestUtil.create("r", "f", "q", 101, "v");
|
KeyValue kv2 = KeyValueTestUtil.create("r", "f", "q", 101, "v");
|
||||||
KeyValue kv3 = KeyValueTestUtil.create("r", "f", "q", 102, "v");
|
KeyValue kv3 = KeyValueTestUtil.create("r", "f", "q", 102, "v");
|
||||||
|
|
||||||
kv1.setMvccVersion(1); kv2.setMvccVersion(1);kv3.setMvccVersion(1);
|
kv1.setSequenceId(1); kv2.setSequenceId(1);kv3.setSequenceId(1);
|
||||||
l.add(kv1); l.add(kv2); l.add(kv3);
|
l.add(kv1); l.add(kv2); l.add(kv3);
|
||||||
|
|
||||||
this.memstore.upsert(l, 2);// readpoint is 2
|
this.memstore.upsert(l, 2);// readpoint is 2
|
||||||
|
@ -835,7 +835,7 @@ public class TestDefaultMemStore extends TestCase {
|
||||||
assert(newSize > oldSize);
|
assert(newSize > oldSize);
|
||||||
|
|
||||||
KeyValue kv4 = KeyValueTestUtil.create("r", "f", "q", 104, "v");
|
KeyValue kv4 = KeyValueTestUtil.create("r", "f", "q", 104, "v");
|
||||||
kv4.setMvccVersion(1);
|
kv4.setSequenceId(1);
|
||||||
l.clear(); l.add(kv4);
|
l.clear(); l.add(kv4);
|
||||||
this.memstore.upsert(l, 3);
|
this.memstore.upsert(l, 3);
|
||||||
assertEquals(newSize, this.memstore.size.get());
|
assertEquals(newSize, this.memstore.size.get());
|
||||||
|
@ -877,7 +877,7 @@ public class TestDefaultMemStore extends TestCase {
|
||||||
// test the case that the timeOfOldestEdit is updated after a KV upsert
|
// test the case that the timeOfOldestEdit is updated after a KV upsert
|
||||||
List<Cell> l = new ArrayList<Cell>();
|
List<Cell> l = new ArrayList<Cell>();
|
||||||
KeyValue kv1 = KeyValueTestUtil.create("r", "f", "q", 100, "v");
|
KeyValue kv1 = KeyValueTestUtil.create("r", "f", "q", 100, "v");
|
||||||
kv1.setMvccVersion(100);
|
kv1.setSequenceId(100);
|
||||||
l.add(kv1);
|
l.add(kv1);
|
||||||
memstore.upsert(l, 1000);
|
memstore.upsert(l, 1000);
|
||||||
t = memstore.timeOfOldestEdit();
|
t = memstore.timeOfOldestEdit();
|
||||||
|
|
|
@ -528,6 +528,7 @@ public class TestHRegion {
|
||||||
}
|
}
|
||||||
long seqId = region.replayRecoveredEditsIfAny(regiondir, maxSeqIdInStores, null, status);
|
long seqId = region.replayRecoveredEditsIfAny(regiondir, maxSeqIdInStores, null, status);
|
||||||
assertEquals(maxSeqId, seqId);
|
assertEquals(maxSeqId, seqId);
|
||||||
|
region.getMVCC().initialize(seqId);
|
||||||
Get get = new Get(row);
|
Get get = new Get(row);
|
||||||
Result result = region.get(get);
|
Result result = region.get(get);
|
||||||
for (long i = minSeqId; i <= maxSeqId; i += 10) {
|
for (long i = minSeqId; i <= maxSeqId; i += 10) {
|
||||||
|
@ -579,6 +580,7 @@ public class TestHRegion {
|
||||||
}
|
}
|
||||||
long seqId = region.replayRecoveredEditsIfAny(regiondir, maxSeqIdInStores, null, status);
|
long seqId = region.replayRecoveredEditsIfAny(regiondir, maxSeqIdInStores, null, status);
|
||||||
assertEquals(maxSeqId, seqId);
|
assertEquals(maxSeqId, seqId);
|
||||||
|
region.getMVCC().initialize(seqId);
|
||||||
Get get = new Get(row);
|
Get get = new Get(row);
|
||||||
Result result = region.get(get);
|
Result result = region.get(get);
|
||||||
for (long i = minSeqId; i <= maxSeqId; i += 10) {
|
for (long i = minSeqId; i <= maxSeqId; i += 10) {
|
||||||
|
|
|
@ -689,7 +689,7 @@ public class TestReversibleScanners {
|
||||||
private static KeyValue makeKV(int rowNum, int cqNum, byte[] familyName) {
|
private static KeyValue makeKV(int rowNum, int cqNum, byte[] familyName) {
|
||||||
KeyValue kv = new KeyValue(ROWS[rowNum], familyName, QUALS[cqNum], TS,
|
KeyValue kv = new KeyValue(ROWS[rowNum], familyName, QUALS[cqNum], TS,
|
||||||
VALUES[rowNum % VALUESIZE]);
|
VALUES[rowNum % VALUESIZE]);
|
||||||
kv.setMvccVersion(makeMVCC(rowNum, cqNum));
|
kv.setSequenceId(makeMVCC(rowNum, cqNum));
|
||||||
return kv;
|
return kv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,6 @@
|
||||||
*/
|
*/
|
||||||
package org.apache.hadoop.hbase.regionserver;
|
package org.apache.hadoop.hbase.regionserver;
|
||||||
|
|
||||||
import static org.apache.hadoop.hbase.HBaseTestingUtility.assertKVListsEqual;
|
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
@ -449,5 +448,32 @@ public class TestSeekOptimizations {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void assertKVListsEqual(String additionalMsg,
|
||||||
|
final List<? extends Cell> expected,
|
||||||
|
final List<? extends Cell> actual) {
|
||||||
|
final int eLen = expected.size();
|
||||||
|
final int aLen = actual.size();
|
||||||
|
final int minLen = Math.min(eLen, aLen);
|
||||||
|
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < minLen
|
||||||
|
&& KeyValue.COMPARATOR.compareOnlyKeyPortion(expected.get(i), actual.get(i)) == 0;
|
||||||
|
++i) {}
|
||||||
|
|
||||||
|
if (additionalMsg == null) {
|
||||||
|
additionalMsg = "";
|
||||||
|
}
|
||||||
|
if (!additionalMsg.isEmpty()) {
|
||||||
|
additionalMsg = ". " + additionalMsg;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (eLen != aLen || i != minLen) {
|
||||||
|
throw new AssertionError(
|
||||||
|
"Expected and actual KV arrays differ at position " + i + ": " +
|
||||||
|
HBaseTestingUtility.safeGetAsStr(expected, i) + " (length " + eLen +") vs. " +
|
||||||
|
HBaseTestingUtility.safeGetAsStr(actual, i) + " (length " + aLen + ")" + additionalMsg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue