/** * Set the row when there is change in row * @param currentRow */ public void setToNewRow(Cell currentRow) { this.currentRow = currentRow; columns.reset(); reset(); }
@Override public void beforeShipped() throws IOException { if (this.currentRow != null) { this.currentRow = PrivateCellUtil.createFirstOnRow(CellUtil.copyRow(this.currentRow)); } if (columns != null) { columns.beforeShipped(); } }
return columns.getNextRowOrNextColumn(cell); MatchCode matchCode = columns.checkColumn(cell, typeByte); if (matchCode != MatchCode.INCLUDE) { return matchCode; matchCode = columns.checkVersions(cell, timestamp, typeByte, false); switch (matchCode) { case SKIP:
static MatchCode checkColumn(ColumnTracker columnTracker, byte[] bytes, int offset, int length, long ttl, byte type, boolean ignoreCount) throws IOException { KeyValue kv = KeyValueUtil.createFirstOnRow(HConstants.EMPTY_BYTE_ARRAY, 0, 0, HConstants.EMPTY_BYTE_ARRAY, 0, 0, bytes, offset, length); MatchCode matchCode = columnTracker.checkColumn(kv, type); if (matchCode == MatchCode.INCLUDE) { return columnTracker.checkVersions(kv, ttl, type, ignoreCount); } return matchCode; } }
/** * Check before the delete logic. * @return null means continue. */ protected final MatchCode preCheck(Cell cell) { if (currentRow == null) { // Since the curCell is null it means we are already sure that we have moved over to the next // row return MatchCode.DONE; } // if row key is changed, then we know that we have moved over to the next row if (rowComparator.compareRows(currentRow, cell) != 0) { return MatchCode.DONE; } if (this.columns.done()) { return MatchCode.SEEK_NEXT_ROW; } long timestamp = cell.getTimestamp(); // check if this is a fake cell. The fake cell is an optimization, we should make the scanner // seek to next column or next row. See StoreFileScanner.requestSeek for more details. // check for early out based on timestamp alone if (timestamp == HConstants.OLDEST_TIMESTAMP || columns.isDone(timestamp)) { return columns.getNextRowOrNextColumn(cell); } // check if the cell is expired by cell TTL if (isCellTTLExpired(cell, this.oldestUnexpiredTS, this.now)) { return MatchCode.SKIP; } return null; }
case NEXT_COL: if (matchCode == MatchCode.INCLUDE || matchCode == MatchCode.INCLUDE_AND_SEEK_NEXT_COL) { return columns.getNextRowOrNextColumn(cell); } else if (matchCode == MatchCode.INCLUDE_AND_SEEK_NEXT_ROW) { return MatchCode.SEEK_NEXT_ROW; columns.doneWithColumn(cell);
@Override public MatchCode match(Cell cell) throws IOException { MatchCode returnCode = preCheck(cell); if (returnCode != null) { return returnCode; } long mvccVersion = cell.getSequenceId(); byte typeByte = cell.getTypeByte(); if (PrivateCellUtil.isDelete(typeByte)) { if (mvccVersion > maxReadPointToTrackVersions) { // we should not use this delete marker to mask any cell yet. return MatchCode.INCLUDE; } trackDelete(cell); return MatchCode.INCLUDE; } returnCode = checkDeleted(deletes, cell); if (returnCode != null) { return returnCode; } // Skip checking column since we do not remove column during compaction. return columns.checkVersions(cell, cell.getTimestamp(), typeByte, mvccVersion > maxReadPointToTrackVersions); } }
public Cell getKeyForNextColumn(Cell cell) { // We aren't sure whether any DeleteFamily cells exist, so we can't skip to next column. // TODO: Current way disable us to seek to next column quickly. Is there any better solution? // see HBASE-18471 for more details // see TestFromClientSide3#testScanAfterDeletingSpecifiedRow // see TestFromClientSide3#testScanAfterDeletingSpecifiedRowV2 if (cell.getQualifierLength() == 0) { Cell nextKey = PrivateCellUtil.createNextOnRowCol(cell); if (nextKey != cell) { return nextKey; } // The cell is at the end of row/family/qualifier, so it is impossible to find any DeleteFamily cells. // Let us seek to next column. } ColumnCount nextColumn = columns.getColumnHint(); if (nextColumn == null) { return PrivateCellUtil.createLastOnRowCol(cell); } else { return PrivateCellUtil.createFirstOnRowCol(cell, nextColumn.getBuffer(), nextColumn.getOffset(), nextColumn.getLength()); } }
protected final MatchCode tryDropDelete(Cell cell) { long timestamp = cell.getTimestamp(); // If it is not the time to drop the delete marker, just return if (timeToPurgeDeletes > 0 && now - timestamp <= timeToPurgeDeletes) { return MatchCode.INCLUDE; } if (keepDeletedCells == KeepDeletedCells.TRUE || (keepDeletedCells == KeepDeletedCells.TTL && timestamp >= oldestUnexpiredTS)) { // If keepDeletedCell is true, or the delete marker is not expired yet, we should include it // in version counting to see if we can drop it. The only exception is that, we can make // sure that no put is older than this delete marker. And under this situation, all later // cells of this column(must be delete markers) can be skipped. if (timestamp < earliestPutTs) { return columns.getNextRowOrNextColumn(cell); } else { return null; } } else { return MatchCode.SKIP; } } }
return columns.checkVersions(cell, timestamp, typeByte, mvccVersion > maxReadPointToTrackVersions);
/** * @param nextIndexed the key of the next entry in the block index (if any) * @param currentCell The Cell we're using to calculate the seek key * @return result of the compare between the indexed key and the key portion of the passed cell */ public int compareKeyForNextColumn(Cell nextIndexed, Cell currentCell) { ColumnCount nextColumn = columns.getColumnHint(); if (nextColumn == null) { return PrivateCellUtil.compareKeyBasedOnColHint(rowComparator, nextIndexed, currentCell, 0, 0, null, 0, 0, HConstants.OLDEST_TIMESTAMP, Type.Minimum.getCode()); } else { return PrivateCellUtil.compareKeyBasedOnColHint(rowComparator, nextIndexed, currentCell, currentCell.getFamilyOffset(), currentCell.getFamilyLength(), nextColumn.getBuffer(), nextColumn.getOffset(), nextColumn.getLength(), HConstants.LATEST_TIMESTAMP, Type.Maximum.getCode()); } }
protected final MatchCode checkDeleted(DeleteTracker deletes, Cell cell) { if (deletes.isEmpty() && !(deletes instanceof NewVersionBehaviorTracker)) { return null; } // MvccSensitiveTracker always need check all cells to save some infos. DeleteResult deleteResult = deletes.isDeleted(cell); switch (deleteResult) { case FAMILY_DELETED: case COLUMN_DELETED: if (!(deletes instanceof NewVersionBehaviorTracker)) { // MvccSensitive can not seek to next because the Put with lower ts may have higher mvcc return columns.getNextRowOrNextColumn(cell); } case VERSION_DELETED: case FAMILY_VERSION_DELETED: case VERSION_MASKED: return MatchCode.SKIP; case NOT_DELETED: return null; default: throw new RuntimeException("Unexpected delete result: " + deleteResult); } }
/** * hbase-2259 */ @Test public void testStackOverflow() throws IOException { int maxVersions = 1; TreeSet<byte[]> columns = new TreeSet<>(Bytes.BYTES_COMPARATOR); for (int i = 0; i < 100000; i++) { columns.add(Bytes.toBytes("col" + i)); } ColumnTracker explicit = new ExplicitColumnTracker(columns, 0, maxVersions, Long.MIN_VALUE); for (int i = 0; i < 100000; i += 2) { byte[] col = Bytes.toBytes("col" + i); ScanQueryMatcher.checkColumn(explicit, col, 0, col.length, 1, KeyValue.Type.Put.getCode(), false); } explicit.reset(); for (int i = 1; i < 100000; i += 2) { byte[] col = Bytes.toBytes("col" + i); ScanQueryMatcher.checkColumn(explicit, col, 0, col.length, 1, KeyValue.Type.Put.getCode(), false); } }
return columns.checkVersions(cell, cell.getTimestamp(), typeByte, mvccVersion > maxReadPointToTrackVersions);
/** * hbase-2259 */ @Test public void testStackOverflow() throws IOException { int maxVersions = 1; TreeSet<byte[]> columns = new TreeSet<>(Bytes.BYTES_COMPARATOR); for (int i = 0; i < 100000; i++) { columns.add(Bytes.toBytes("col" + i)); } ColumnTracker explicit = new ExplicitColumnTracker(columns, 0, maxVersions, Long.MIN_VALUE); for (int i = 0; i < 100000; i += 2) { byte[] col = Bytes.toBytes("col" + i); ScanQueryMatcher.checkColumn(explicit, col, 0, col.length, 1, KeyValue.Type.Put.getCode(), false); } explicit.reset(); for (int i = 1; i < 100000; i += 2) { byte[] col = Bytes.toBytes("col" + i); ScanQueryMatcher.checkColumn(explicit, col, 0, col.length, 1, KeyValue.Type.Put.getCode(), false); } }