private boolean isEndOfColumnRange(byte[] lastCol, byte[] endCol) { return RangeRequests.isLastRowName(lastCol) || Arrays.equals(RangeRequests.nextLexicographicName(lastCol), endCol); }
@Override public boolean hasNext(byte[] lastToken) { if (RangeRequests.isTerminalRow(range.isReverse(), lastToken)) { return false; } else { byte[] nextStartRow = RangeRequests.getNextStartRow(range.isReverse(), lastToken); return !Arrays.equals(nextStartRow, range.getEndExclusive()); } }
public RangeVisitor setRangePrefix(byte[] prefix) { this.startRow = prefix; this.endRow = RangeRequests.createEndNameForPrefixScan(prefix); return this; }
public static boolean isTerminalRow(boolean reverse, @Nonnull byte[] rowName) { if (reverse) { return isFirstRowName(rowName); } else { return isLastRowName(rowName); } }
public static byte[] getNextStartRow(boolean reverse, @Nonnull byte[] rowName) { if (reverse) { return previousLexicographicName(rowName); } else { return nextLexicographicName(rowName); } }
@Nullable public static byte[] getNextStartRowUnlessTerminal(boolean reverse, @Nonnull byte[] rowName) { if (reverse) { if (isFirstRowName(rowName)) { return null; } else { return previousLexicographicName(rowName); } } else { return nextLexicographicNameInternal(rowName); } } }
private byte[] getNextColumnRangeColumn(boolean completedCell, byte[] lastCol) { if (!completedCell) { return lastCol; } else { return RangeRequests.nextLexicographicName(lastCol); } }
private void doTestGetRangePagingLastRowEdgeCase(int numColumnsInMetadata, int batchSizeHint, boolean reverse) { TableReference tableRef = createTableWithNamedColumns(numColumnsInMetadata); byte[] last = reverse ? RangeRequests.getFirstRowName() : RangeRequests.getLastRowName(); Map<Cell, byte[]> values = ImmutableMap.of( Cell.create(last, PtBytes.toBytes("c1")), PtBytes.toBytes("a"), Cell.create(last, last), PtBytes.toBytes("b")); keyValueService.put(tableRef, values, TEST_TIMESTAMP); RangeRequest request = RangeRequest.builder(reverse).batchHint(batchSizeHint).build(); try (ClosableIterator<RowResult<Value>> iter = keyValueService.getRange(tableRef, request, Long.MAX_VALUE)) { List<RowResult<Value>> results = ImmutableList.copyOf(iter); List<RowResult<Value>> expected = ImmutableList.of( RowResult.create(last, ImmutableSortedMap.<byte[], Value>orderedBy(UnsignedBytes.lexicographicalComparator()) .put(PtBytes.toBytes("c1"), Value.create(PtBytes.toBytes("a"), TEST_TIMESTAMP)) .put(last, Value.create(PtBytes.toBytes("b"), TEST_TIMESTAMP)) .build())); assertEquals(expected, results); } }
private boolean isRangeDone(byte[] row) { return row == null || RangeRequests.isLastRowName(row); }
/** * This will return a start and end row that will exactly contain all rows for this prefix in * reverse. * <p> * start will be on the left hand side and will be greater lexicographically */ private static Pair<byte[], byte[]> createNamesForReversePrefixScan(@Nonnull byte[] name) { Preconditions.checkNotNull(name, "name cannot be null"); Preconditions.checkArgument(name.length <= Cell.MAX_NAME_LENGTH, "name is too long"); if (name.length == 0) { return Pair.create(name, name); } byte[] startName = new byte[Cell.MAX_NAME_LENGTH]; System.arraycopy(name, 0, startName, 0, name.length); for (int i = name.length; i < startName.length; i++) { startName[i] = (byte) 0xff; } byte[] endName = RangeRequests.previousLexicographicName(name); return Pair.create(startName, endName); }
@Override public ClosableIterator<RowResult<Value>> getBatch(int batchSize, @Nullable byte[] lastToken) { RangeRequest.Builder newRange = range.getBuilder(); if (lastToken != null) { newRange.startRowInclusive(RangeRequests.getNextStartRow(range.isReverse(), lastToken)); } newRange.batchHint(batchSize); return keyValueService.getRange(tableRef, newRange.build(), timestamp); }
/** * This is a replacement for startRow when doing reverse range request. */ public static byte[] startRowInclusiveOrLargestRow(RangeRequest rangeRequest) { Preconditions.checkArgument(rangeRequest.isReverse()); if (rangeRequest.getStartInclusive().length == 0) { return getLastRowName(); } return rangeRequest.getStartInclusive(); }
@Test public void examinedCellLimit() { List<BatchOfCellsToSweep> batches = partition( ImmutableList.of( batchWithThreeTssPerCell(0, 20, 30), batchWithThreeTssPerCell(20, 20, 30), batchWithThreeTssPerCell(40, 20, 30)), // A large timestamp batch size. Without the examined cell limit, we would // combine all three input batches in one. 100000, RangeRequests.getFirstRowName(), 50); // The first input batch examines 30 cells and is not sufficient to satisfy the limit (50). // However, the first two batches combined together examine 60 cells, which covers the limit. // Hence we expect one output batch which is the concatenation of the first two input batches. assertThat(batches).containsExactly(batchWithThreeTssPerCell(0, 40, 60)); }
private static boolean isForSingleRow(byte[] startInclusive, byte[] endExclusive) { if (startInclusive.length == 0 || endExclusive.length == 0) { return false; } return Arrays.equals(endExclusive, RangeRequests.nextLexicographicName(startInclusive)); }
private void assertNextPrevEqualsOrig(byte[] value) { Assert.assertTrue(Arrays.equals(value, RangeRequests.nextLexicographicName(RangeRequests.previousLexicographicName(value)))); Assert.assertTrue(Arrays.equals(value, RangeRequests.previousLexicographicName(RangeRequests.nextLexicographicName(value)))); } }
public static boolean isFirstRowName(boolean reverse, @Nonnull byte[] name) { return reverse ? isLastRowName(name) : isFirstRowName(name); }
@Test public void testEmpty() { RangeRequest request = RangeRequest.builder().endRowExclusive(RangeRequests.getFirstRowName()).build(); Assert.assertTrue(request.isEmptyRange()); request = RangeRequest.reverseBuilder().endRowExclusive(RangeRequests.getLastRowName()).build(); Assert.assertTrue(request.isEmptyRange()); }
private boolean isRangeDone(byte[] row) { return row == null || RangeRequests.isLastRowName(row); }
private Range createColumnRange(byte[] startColOrEmpty, byte[] endColExlusiveOrEmpty, long startTs) { ByteBuffer start = startColOrEmpty.length == 0 ? Range.UNBOUND_START : Range.startOfColumn(startColOrEmpty, startTs); ByteBuffer end = endColExlusiveOrEmpty.length == 0 ? Range.UNBOUND_END : Range.endOfColumnIncludingSentinels(RangeRequests.previousLexicographicName(endColExlusiveOrEmpty)); return Range.of(start, end); }
@Nullable public static byte[] getNextStartRowUnlessTerminal(boolean reverse, @Nonnull byte[] rowName) { if (reverse) { if (isFirstRowName(rowName)) { return null; } else { return previousLexicographicName(rowName); } } else { return nextLexicographicNameInternal(rowName); } } }