下面列出了org.apache.hadoop.hbase.Cell#getTimestamp ( ) 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。
@Override
public Cell transformCell(Cell cell) throws IOException {
// Convert Tephra deletes back into HBase deletes
if (tx.getVisibilityLevel() == Transaction.VisibilityLevel.SNAPSHOT_ALL) {
if (DeleteTracker.isFamilyDelete(cell)) {
return new KeyValue(CellUtil.cloneRow(cell), CellUtil.cloneFamily(cell), null, cell.getTimestamp(),
KeyValue.Type.DeleteFamily);
} else if (isColumnDelete(cell)) {
// Note: in some cases KeyValue.Type.Delete is used in Delete object,
// and in some other cases KeyValue.Type.DeleteColumn is used.
// Since Tephra cannot distinguish between the two, we return KeyValue.Type.DeleteColumn.
// KeyValue.Type.DeleteColumn makes both CellUtil.isDelete and CellUtil.isDeleteColumns return true, and will
// work in both cases.
return new KeyValue(CellUtil.cloneRow(cell), CellUtil.cloneFamily(cell), CellUtil.cloneQualifier(cell),
cell.getTimestamp(), KeyValue.Type.DeleteColumn);
}
}
return cell;
}
/**
* Gets a list of {@link RegionPruneInfo} for given regions. Returns all regions if the given regions set is null.
*
* @param regions a set of regions
* @return list of {@link RegionPruneInfo}s.
* @throws IOException when not able to read the data from HBase
*/
public List<RegionPruneInfo> getPruneInfoForRegions(@Nullable SortedSet<byte[]> regions) throws IOException {
List<RegionPruneInfo> regionPruneInfos = new ArrayList<>();
try (Table stateTable = stateTableSupplier.get()) {
byte[] startRow = makeRegionKey(EMPTY_BYTE_ARRAY);
Scan scan = new Scan(startRow, REGION_KEY_PREFIX_STOP);
scan.addColumn(FAMILY, PRUNE_UPPER_BOUND_COL);
try (ResultScanner scanner = stateTable.getScanner(scan)) {
Result next;
while ((next = scanner.next()) != null) {
byte[] region = getRegionFromKey(next.getRow());
if (regions == null || regions.contains(region)) {
Cell cell = next.getColumnLatestCell(FAMILY, PRUNE_UPPER_BOUND_COL);
if (cell != null) {
byte[] pruneUpperBoundBytes = CellUtil.cloneValue(cell);
long timestamp = cell.getTimestamp();
regionPruneInfos.add(new RegionPruneInfo(region, Bytes.toStringBinary(region),
Bytes.toLong(pruneUpperBoundBytes), timestamp));
}
}
}
}
}
return Collections.unmodifiableList(regionPruneInfos);
}
/**
* Gets a list of {@link RegionPruneInfo} for given regions. Returns all regions if the given regions set is null.
*
* @param regions a set of regions
* @return list of {@link RegionPruneInfo}s.
* @throws IOException when not able to read the data from HBase
*/
public List<RegionPruneInfo> getPruneInfoForRegions(@Nullable SortedSet<byte[]> regions) throws IOException {
List<RegionPruneInfo> regionPruneInfos = new ArrayList<>();
try (Table stateTable = stateTableSupplier.get()) {
byte[] startRow = makeRegionKey(EMPTY_BYTE_ARRAY);
Scan scan = new Scan(startRow, REGION_KEY_PREFIX_STOP);
scan.addColumn(FAMILY, PRUNE_UPPER_BOUND_COL);
try (ResultScanner scanner = stateTable.getScanner(scan)) {
Result next;
while ((next = scanner.next()) != null) {
byte[] region = getRegionFromKey(next.getRow());
if (regions == null || regions.contains(region)) {
Cell cell = next.getColumnLatestCell(FAMILY, PRUNE_UPPER_BOUND_COL);
if (cell != null) {
byte[] pruneUpperBoundBytes = CellUtil.cloneValue(cell);
long timestamp = cell.getTimestamp();
regionPruneInfos.add(new RegionPruneInfo(region, Bytes.toStringBinary(region),
Bytes.toLong(pruneUpperBoundBytes), timestamp));
}
}
}
}
}
return Collections.unmodifiableList(regionPruneInfos);
}
@Override
public Cell transformCell(Cell cell) throws IOException {
// Convert Tephra deletes back into HBase deletes
if (tx.getVisibilityLevel() == Transaction.VisibilityLevel.SNAPSHOT_ALL) {
if (DeleteTracker.isFamilyDelete(cell)) {
return new KeyValue(CellUtil.cloneRow(cell), CellUtil.cloneFamily(cell), null, cell.getTimestamp(),
KeyValue.Type.DeleteFamily);
} else if (isColumnDelete(cell)) {
// Note: in some cases KeyValue.Type.Delete is used in Delete object,
// and in some other cases KeyValue.Type.DeleteColumn is used.
// Since Tephra cannot distinguish between the two, we return KeyValue.Type.DeleteColumn.
// KeyValue.Type.DeleteColumn makes both CellUtil.isDelete and CellUtil.isDeleteColumns return true, and will
// work in both cases.
return new KeyValue(CellUtil.cloneRow(cell), CellUtil.cloneFamily(cell), CellUtil.cloneQualifier(cell),
cell.getTimestamp(), KeyValue.Type.DeleteColumn);
}
}
return cell;
}
public static Map<String, Map<String, String>> versionedRegionMap(HBaseAdmin admin, long timestamp)
throws IOException {
Map<String, Map<String, String>> regionLocationMap = new HashMap<>();
try (HTable metaTable = new HTable(admin.getConfiguration(), metaTableName())) {
Scan scan = new Scan();
scan.setSmall(true);
scan.setCaching(1000);
scan.setMaxVersions();
ResultScanner scanner = metaTable.getScanner(scan);
for (Result result : scanner) {
List<Cell> columnCells = result.getColumnCells("info".getBytes(), "server".getBytes());
for (Cell cell : columnCells) {
if (cell.getTimestamp() <= timestamp) {
String tableName = Bytes.toString(HRegionInfo.getTableName(cell.getRow()));
String encodeRegionName = HRegionInfo.encodeRegionName(cell.getRow());
String regionServer = Bytes.toString(cell.getValue()).replaceAll(":", ",");
Map<String, String> innerMap = regionLocationMap.get(tableName);
if (innerMap == null) {
innerMap = new HashMap<>();
regionLocationMap.put(tableName, innerMap);
}
if (innerMap.get(encodeRegionName) == null)
innerMap.put(encodeRegionName, regionServer);
}
}
}
}
return regionLocationMap;
}
@SuppressWarnings("deprecation")
private static KeyValue addSaltByte(Cell keyValue, int nSaltBuckets) {
byte[] buf = keyValue.getRowArray();
int length = keyValue.getRowLength();
int offset = keyValue.getRowOffset();
boolean isViewSeq = length > SEQ_PREFIX_BYTES.length && Bytes.compareTo(SEQ_PREFIX_BYTES, 0, SEQ_PREFIX_BYTES.length, buf, offset, SEQ_PREFIX_BYTES.length) == 0;
if (!isViewSeq && nSaltBuckets == 0) {
return null;
}
byte[] newBuf;
if (isViewSeq) { // We messed up the name for the sequences for view indexes so we'll take this opportunity to fix it
if (buf[length-1] == 0) { // Global indexes on views have trailing null byte
length--;
}
byte[][] rowKeyMetaData = new byte[3][];
SchemaUtil.getVarChars(buf, offset, length, 0, rowKeyMetaData);
byte[] schemaName = rowKeyMetaData[PhoenixDatabaseMetaData.SCHEMA_NAME_INDEX];
byte[] unprefixedSchemaName = new byte[schemaName.length - MetaDataUtil.VIEW_INDEX_SEQUENCE_PREFIX_BYTES.length];
System.arraycopy(schemaName, MetaDataUtil.VIEW_INDEX_SEQUENCE_PREFIX_BYTES.length, unprefixedSchemaName, 0, unprefixedSchemaName.length);
byte[] tableName = rowKeyMetaData[PhoenixDatabaseMetaData.TABLE_NAME_INDEX];
PName physicalName = PNameFactory.newName(unprefixedSchemaName);
// Reformulate key based on correct data
newBuf = MetaDataUtil.getViewIndexSequenceKey(tableName == null ? null : Bytes.toString(tableName),
physicalName, nSaltBuckets, false).getKey();
} else {
newBuf = new byte[length + 1];
System.arraycopy(buf, offset, newBuf, SaltingUtil.NUM_SALTING_BYTES, length);
newBuf[0] = SaltingUtil.getSaltingByte(newBuf, SaltingUtil.NUM_SALTING_BYTES, length, nSaltBuckets);
}
return new KeyValue(newBuf, 0, newBuf.length,
buf, keyValue.getFamilyOffset(), keyValue.getFamilyLength(),
buf, keyValue.getQualifierOffset(), keyValue.getQualifierLength(),
keyValue.getTimestamp(), KeyValue.Type.codeToType(keyValue.getTypeByte()),
buf, keyValue.getValueOffset(), keyValue.getValueLength());
}
protected final void trackDelete(Cell cell) {
// If keepDeletedCells is true, then we only remove cells by versions or TTL during
// compaction, so we do not need to track delete here.
// If keepDeletedCells is TTL and the delete marker is expired, then we can make sure that the
// minVerions is larger than 0(otherwise we will just return at preCheck). So here we still
// need to track the delete marker to see if it masks some cells.
if (keepDeletedCells == KeepDeletedCells.FALSE
|| (keepDeletedCells == KeepDeletedCells.TTL && cell.getTimestamp() < oldestUnexpiredTS)) {
deletes.add(cell);
}
}
public long getTimestampForKey(String key, byte[] column) throws IOException {
Cell cell = getCell(key, column);
if (cell != null) {
return cell.getTimestamp();
} else {
throw new IOException("Cannot retrieve string from hbase");
}
}
@Override
public ReturnCode filterKeyValue(Cell cell) throws IOException {
// include all cells visible to in-progress transactions, except for those already
// marked as invalid
long ts = cell.getTimestamp();
if (ts > visibilityUpperBound) {
// include everything that could still be in-progress except invalids
if (invalidIds.contains(ts)) {
return ReturnCode.SKIP;
}
return ReturnCode.INCLUDE;
}
return txFilter.filterKeyValue(cell);
}
public static long getTimestamp(Mutation m) {
for (List<Cell> cells : m.getFamilyCellMap().values()) {
for (Cell cell : cells) {
return cell.getTimestamp();
}
}
throw new IllegalStateException("No cell found");
}
public long createSequence(Result result, long minValue, long maxValue, boolean cycle) throws SQLException {
Cell statusKV = result.rawCells()[0];
long timestamp = statusKV.getTimestamp();
int statusCode = PInteger.INSTANCE.getCodec().decodeInt(statusKV.getValueArray(), statusKV.getValueOffset(), SortOrder.getDefault());
if (statusCode == 0) { // Success - add sequence value and return timestamp
SequenceValue value = new SequenceValue(timestamp, minValue, maxValue, cycle);
insertSequenceValue(value);
return timestamp;
}
SQLExceptionCode code = SQLExceptionCode.fromErrorCode(statusCode);
throw new SQLExceptionInfo.Builder(code)
.setSchemaName(key.getSchemaName())
.setTableName(key.getSequenceName())
.build().buildException();
}
@Override
public ReturnCode filterKeyValue(Cell cell) throws IOException {
// include all cells visible to in-progress transactions, except for those already marked as invalid
long ts = cell.getTimestamp();
if (ts > visibilityUpperBound) {
// include everything that could still be in-progress except invalids
if (invalidIds.contains(ts)) {
return ReturnCode.SKIP;
}
return ReturnCode.INCLUDE;
}
return txFilter.filterKeyValue(cell);
}
public static long getMaxTimestamp(Mutation m) {
long ts = 0;
for (List<Cell> cells : m.getFamilyCellMap().values()) {
if (cells == null) {
continue;
}
for (Cell cell : cells) {
if (ts < cell.getTimestamp()) {
ts = cell.getTimestamp();
}
}
}
return ts;
}
@Override
public ReturnCode filterKeyValue(Cell v) {
long timestamp = v.getTimestamp();
if (timestamp > ts) {
this.column.setTs(timestamp);
return ReturnCode.SKIP;
}
return ReturnCode.INCLUDE;
}
@Override
public ReturnCode filterKeyValue(Cell cell) throws IOException {
if (!CellUtil.matchingFamily(cell, currentFamily.get(), currentFamily.getOffset(), currentFamily.getLength())) {
// column family changed
currentFamily.set(cell.getFamilyArray(), cell.getFamilyOffset(), cell.getFamilyLength());
Long familyOldestTs = oldestTsByFamily.get(currentFamily);
currentOldestTs = familyOldestTs != null ? familyOldestTs : 0;
deleteTracker.reset();
}
// need to apply TTL for the column family here
long kvTimestamp = cell.getTimestamp();
if (TxUtils.getTimestampForTTL(kvTimestamp) < currentOldestTs) {
// passed TTL for this column, seek to next
return ReturnCode.NEXT_COL;
} else if (tx.isVisible(kvTimestamp)) {
// Return all writes done by current transaction (including deletes) for VisibilityLevel.SNAPSHOT_ALL
if (tx.getVisibilityLevel() == Transaction.VisibilityLevel.SNAPSHOT_ALL && tx.isCurrentWrite(kvTimestamp)) {
// cell is visible
// visibility SNAPSHOT_ALL needs all matches
return runSubFilter(ReturnCode.INCLUDE, cell);
}
if (DeleteTracker.isFamilyDelete(cell)) {
deleteTracker.addFamilyDelete(cell);
if (clearDeletes) {
return ReturnCode.NEXT_COL;
} else {
// cell is visible
// as soon as we find a KV to include we can move to the next column
return runSubFilter(ReturnCode.INCLUDE_AND_NEXT_COL, cell);
}
}
// check if masked by family delete
if (deleteTracker.isDeleted(cell)) {
return ReturnCode.NEXT_COL;
}
// check for column delete
if (isColumnDelete(cell)) {
if (clearDeletes) {
// skip "deleted" cell
return ReturnCode.NEXT_COL;
} else {
// keep the marker but skip any remaining versions
return runSubFilter(ReturnCode.INCLUDE_AND_NEXT_COL, cell);
}
}
// cell is visible
// as soon as we find a KV to include we can move to the next column
return runSubFilter(ReturnCode.INCLUDE_AND_NEXT_COL, cell);
} else {
return ReturnCode.SKIP;
}
}
public void run(Connection connection, List<String> args) throws InvalidArgsException, IOException {
if (args.size() < 1 || args.size() > 2) {
throw new InvalidArgsException(args);
}
String tableName = args.get(0);
String filterVal = null;
if (args.size() > 1) {
filterVal = args.get(1);
}
Table table = connection.getTable(TableName.valueOf(tableName));
// Create a new Scan instance.
Scan scan = new Scan();
// This command supports using a columnvalue filter.
// The filter takes the form of <columnfamily>:<column><operator><value>
// An example would be cf:col>=10
if (filterVal != null) {
String splitVal = "=";
CompareFilter.CompareOp op = CompareFilter.CompareOp.EQUAL;
if (filterVal.contains(">=")) {
op = CompareFilter.CompareOp.GREATER_OR_EQUAL;
splitVal = ">=";
} else if (filterVal.contains("<=")) {
op = CompareFilter.CompareOp.LESS_OR_EQUAL;
splitVal = "<=";
} else if (filterVal.contains(">")) {
op = CompareFilter.CompareOp.GREATER;
splitVal = ">";
} else if (filterVal.contains("<")) {
op = CompareFilter.CompareOp.LESS;
splitVal = "<";
}
String[] filter = filterVal.split(splitVal);
String[] filterCol = filter[0].split(":");
scan.setFilter(new SingleColumnValueFilter(filterCol[0].getBytes(), filterCol[1].getBytes(), op, filter[1].getBytes()));
}
ResultScanner resultScanner = table.getScanner(scan);
for (Result result : resultScanner) {
for (Cell cell : result.listCells()) {
String row = new String(CellUtil.cloneRow(cell));
String family = new String(CellUtil.cloneFamily(cell));
String column = new String(CellUtil.cloneQualifier(cell));
String value = new String(CellUtil.cloneValue(cell));
long timestamp = cell.getTimestamp();
System.out.printf("%-20s column=%s:%s, timestamp=%s, value=%s\n", row, family, column, timestamp, value);
}
}
}
/**
* Pretend we have done a seek but don't do it yet, if possible. The hope is
* that we find requested columns in more recent files and won't have to seek
* in older files. Creates a fake key/value with the given row/column and the
* highest (most recent) possible timestamp we might get from this file. When
* users of such "lazy scanner" need to know the next KV precisely (e.g. when
* this scanner is at the top of the heap), they run {@link #enforceSeek()}.
* <p>
* Note that this function does guarantee that the current KV of this scanner
* will be advanced to at least the given KV. Because of this, it does have
* to do a real seek in cases when the seek timestamp is older than the
* highest timestamp of the file, e.g. when we are trying to seek to the next
* row/column and use OLDEST_TIMESTAMP in the seek key.
*/
@Override
public boolean requestSeek(Cell kv, boolean forward, boolean useBloom)
throws IOException {
if (kv.getFamilyLength() == 0) {
useBloom = false;
}
boolean haveToSeek = true;
if (useBloom) {
// check ROWCOL Bloom filter first.
if (reader.getBloomFilterType() == BloomType.ROWCOL) {
haveToSeek = reader.passesGeneralRowColBloomFilter(kv);
} else if (canOptimizeForNonNullColumn
&& ((PrivateCellUtil.isDeleteFamily(kv)
|| PrivateCellUtil.isDeleteFamilyVersion(kv)))) {
// if there is no such delete family kv in the store file,
// then no need to seek.
haveToSeek = reader.passesDeleteFamilyBloomFilter(kv.getRowArray(), kv.getRowOffset(),
kv.getRowLength());
}
}
delayedReseek = forward;
delayedSeekKV = kv;
if (haveToSeek) {
// This row/column might be in this store file (or we did not use the
// Bloom filter), so we still need to seek.
realSeekDone = false;
long maxTimestampInFile = reader.getMaxTimestamp();
long seekTimestamp = kv.getTimestamp();
if (seekTimestamp > maxTimestampInFile) {
// Create a fake key that is not greater than the real next key.
// (Lower timestamps correspond to higher KVs.)
// To understand this better, consider that we are asked to seek to
// a higher timestamp than the max timestamp in this file. We know that
// the next point when we have to consider this file again is when we
// pass the max timestamp of this file (with the same row/column).
setCurrentCell(PrivateCellUtil.createFirstOnRowColTS(kv, maxTimestampInFile));
} else {
// This will be the case e.g. when we need to seek to the next
// row/column, and we don't know exactly what they are, so we set the
// seek key's timestamp to OLDEST_TIMESTAMP to skip the rest of this
// row/column.
enforceSeek();
}
return cur != null;
}
// Multi-column Bloom filter optimization.
// Create a fake key/value, so that this scanner only bubbles up to the top
// of the KeyValueHeap in StoreScanner after we scanned this row/column in
// all other store files. The query matcher will then just skip this fake
// key/value and the store scanner will progress to the next column. This
// is obviously not a "real real" seek, but unlike the fake KV earlier in
// this method, we want this to be propagated to ScanQueryMatcher.
setCurrentCell(PrivateCellUtil.createLastOnRowCol(kv));
realSeekDone = true;
return true;
}
@Override
public ReturnCode filterKeyValue(Cell cell) throws IOException {
if (!CellUtil.matchingFamily(cell, currentFamily.get(), currentFamily.getOffset(), currentFamily.getLength())) {
// column family changed
currentFamily.set(cell.getFamilyArray(), cell.getFamilyOffset(), cell.getFamilyLength());
Long familyOldestTs = oldestTsByFamily.get(currentFamily);
currentOldestTs = familyOldestTs != null ? familyOldestTs : 0;
deleteTracker.reset();
}
// need to apply TTL for the column family here
long kvTimestamp = cell.getTimestamp();
if (TxUtils.getTimestampForTTL(kvTimestamp) < currentOldestTs) {
// passed TTL for this column, seek to next
return ReturnCode.NEXT_COL;
} else if (tx.isVisible(kvTimestamp)) {
// Return all writes done by current transaction (including deletes) for VisibilityLevel.SNAPSHOT_ALL
if (tx.getVisibilityLevel() == Transaction.VisibilityLevel.SNAPSHOT_ALL && tx.isCurrentWrite(kvTimestamp)) {
// cell is visible
// visibility SNAPSHOT_ALL needs all matches
return runSubFilter(ReturnCode.INCLUDE, cell);
}
if (DeleteTracker.isFamilyDelete(cell)) {
deleteTracker.addFamilyDelete(cell);
if (clearDeletes) {
return ReturnCode.NEXT_COL;
} else {
// cell is visible
// as soon as we find a KV to include we can move to the next column
return runSubFilter(ReturnCode.INCLUDE_AND_NEXT_COL, cell);
}
}
// check if masked by family delete
if (deleteTracker.isDeleted(cell)) {
return ReturnCode.NEXT_COL;
}
// check for column delete
if (isColumnDelete(cell)) {
if (clearDeletes) {
// skip "deleted" cell
return ReturnCode.NEXT_COL;
} else {
// keep the marker but skip any remaining versions
return runSubFilter(ReturnCode.INCLUDE_AND_NEXT_COL, cell);
}
}
// cell is visible
// as soon as we find a KV to include we can move to the next column
return runSubFilter(ReturnCode.INCLUDE_AND_NEXT_COL, cell);
} else {
return ReturnCode.SKIP;
}
}
public void splitStats(HRegion p, HRegion l, HRegion r, StatisticsCollector tracker, ImmutableBytesPtr cfKey,
List<Mutation> mutations) throws IOException {
if (tracker == null) { return; }
boolean useMaxTimeStamp = clientTimeStamp == StatisticsCollector.NO_TIMESTAMP;
if (!useMaxTimeStamp) {
mutations.add(getLastStatsUpdatedTimePut(clientTimeStamp));
}
long readTimeStamp = useMaxTimeStamp ? HConstants.LATEST_TIMESTAMP : clientTimeStamp;
Result result = StatisticsUtil.readRegionStatistics(statsReaderTable, tableName, cfKey, p.getRegionName(),
readTimeStamp);
if (result != null && !result.isEmpty()) {
Cell cell = result.getColumnLatestCell(QueryConstants.DEFAULT_COLUMN_FAMILY_BYTES, PhoenixDatabaseMetaData.GUIDE_POSTS_BYTES);
Cell rowCountCell = result.getColumnLatestCell(QueryConstants.DEFAULT_COLUMN_FAMILY_BYTES, PhoenixDatabaseMetaData.GUIDE_POSTS_ROW_COUNT_BYTES);
long rowCount = 0;
if (cell != null) {
long writeTimeStamp = useMaxTimeStamp ? cell.getTimestamp() : clientTimeStamp;
GuidePostsInfo guidePostsRegionInfo = GuidePostsInfo.deserializeGuidePostsInfo(cell.getValueArray(),
cell.getValueOffset(), cell.getValueLength(), rowCount);
byte[] pPrefix = StatisticsUtil.getRowKey(tableName, cfKey, p.getRegionName());
mutations.add(new Delete(pPrefix, writeTimeStamp));
long byteSize = 0;
Cell byteSizeCell = result.getColumnLatestCell(QueryConstants.DEFAULT_COLUMN_FAMILY_BYTES,
PhoenixDatabaseMetaData.GUIDE_POSTS_WIDTH_BYTES);
int index = Collections.binarySearch(guidePostsRegionInfo.getGuidePosts(), r.getStartKey(),
Bytes.BYTES_COMPARATOR);
int size = guidePostsRegionInfo.getGuidePosts().size();
int midEndIndex, midStartIndex;
if (index < 0) {
midEndIndex = midStartIndex = -(index + 1);
} else {
// For an exact match, we want to get rid of the exact match guidepost,
// since it's replaced by the region boundary.
midEndIndex = index;
midStartIndex = index + 1;
}
double per = (double)(midEndIndex) / size;
long leftRowCount = 0;
long rightRowCount = 0;
long leftByteCount = 0;
long rightByteCount = 0;
if (rowCountCell != null) {
rowCount = PLong.INSTANCE.getCodec().decodeLong(rowCountCell.getValueArray(),
rowCountCell.getValueOffset(), SortOrder.getDefault());
leftRowCount = (long)(per * rowCount);
rightRowCount = (long)((1 - per) * rowCount);
}
if (byteSizeCell != null) {
byteSize = PLong.INSTANCE.getCodec().decodeLong(byteSizeCell.getValueArray(),
byteSizeCell.getValueOffset(), SortOrder.getDefault());
leftByteCount = (long)(per * byteSize);
rightByteCount = (long)((1 - per) * byteSize);
}
if (midEndIndex > 0) {
GuidePostsInfo lguidePosts = new GuidePostsInfo(leftByteCount, guidePostsRegionInfo
.getGuidePosts().subList(0, midEndIndex), leftRowCount);
tracker.clear();
tracker.addGuidePost(cfKey, lguidePosts, leftByteCount, cell.getTimestamp());
addStats(l.getRegionName(), tracker, cfKey, mutations);
}
if (midStartIndex < size) {
GuidePostsInfo rguidePosts = new GuidePostsInfo(rightByteCount, guidePostsRegionInfo
.getGuidePosts().subList(midStartIndex, size),
rightRowCount);
tracker.clear();
tracker.addGuidePost(cfKey, rguidePosts, rightByteCount, cell.getTimestamp());
addStats(r.getRegionName(), tracker, cfKey, mutations);
}
}
}
}
@Override
public ReturnCode filterKeyValue(Cell cell) throws IOException {
if (!CellUtil.matchingFamily(cell, currentFamily)) {
// column family changed
currentFamily = CellUtil.cloneFamily(cell);
Long familyOldestTs = oldestTsByFamily.get(currentFamily);
currentOldestTs = familyOldestTs != null ? familyOldestTs : 0;
deleteTracker.reset();
}
// need to apply TTL for the column family here
long kvTimestamp = cell.getTimestamp();
if (TxUtils.getTimestampForTTL(kvTimestamp) < currentOldestTs) {
// passed TTL for this column, seek to next
return ReturnCode.NEXT_COL;
} else if (tx.isVisible(kvTimestamp)) {
// Return all writes done by current transaction (including deletes) for VisibilityLevel.SNAPSHOT_ALL
if (tx.getVisibilityLevel() == Transaction.VisibilityLevel.SNAPSHOT_ALL && tx.isCurrentWrite(kvTimestamp)) {
// cell is visible
// visibility SNAPSHOT_ALL needs all matches
return runSubFilter(ReturnCode.INCLUDE, cell);
}
if (DeleteTracker.isFamilyDelete(cell)) {
deleteTracker.addFamilyDelete(cell);
if (clearDeletes) {
return ReturnCode.NEXT_COL;
} else {
// cell is visible
// as soon as we find a KV to include we can move to the next column
return runSubFilter(ReturnCode.INCLUDE_AND_NEXT_COL, cell);
}
}
// check if masked by family delete
if (deleteTracker.isDeleted(cell)) {
return ReturnCode.NEXT_COL;
}
// check for column delete
if (isColumnDelete(cell)) {
if (clearDeletes) {
// skip "deleted" cell
return ReturnCode.NEXT_COL;
} else {
// keep the marker but skip any remaining versions
return runSubFilter(ReturnCode.INCLUDE_AND_NEXT_COL, cell);
}
}
// cell is visible
// as soon as we find a KV to include we can move to the next column
return runSubFilter(ReturnCode.INCLUDE_AND_NEXT_COL, cell);
} else {
return ReturnCode.SKIP;
}
}