@Test public void thoroughSweepDeletesLowerValue() { enqueueWriteCommitted(TABLE_THOR, LOW_TS); enqueueWriteCommitted(TABLE_THOR, LOW_TS2); assertTestValueEnqueuedAtGivenTimestampStillPresent(TABLE_THOR, LOW_TS); assertTestValueEnqueuedAtGivenTimestampStillPresent(TABLE_THOR, LOW_TS2); sweepQueue.sweepNextBatch(ShardAndStrategy.thorough(THOR_SHARD)); assertReadAtTimestampReturnsNothing(TABLE_THOR, LOW_TS + 1); assertTestValueEnqueuedAtGivenTimestampStillPresent(TABLE_THOR, LOW_TS2); }
@Test public void conservativeSweepDeletesLowerValue() { enqueueWriteCommitted(TABLE_CONS, LOW_TS); enqueueWriteCommitted(TABLE_CONS, LOW_TS2); assertTestValueEnqueuedAtGivenTimestampStillPresent(TABLE_CONS, LOW_TS); assertTestValueEnqueuedAtGivenTimestampStillPresent(TABLE_CONS, LOW_TS2); sweepQueue.sweepNextBatch(ShardAndStrategy.conservative(CONS_SHARD)); assertReadAtTimestampReturnsSentinel(TABLE_CONS, LOW_TS + 1); assertTestValueEnqueuedAtGivenTimestampStillPresent(TABLE_CONS, LOW_TS2); }
private void writeValuesAroundSweepTimestampAndSweepAndCheck(long sweepTimestamp, int sweepIterations) { enqueueWriteCommitted(TABLE_CONS, sweepTimestamp - 10); enqueueWriteCommitted(TABLE_CONS, sweepTimestamp - 5); enqueueWriteCommitted(TABLE_CONS, sweepTimestamp + 5); IntStream.range(0, sweepIterations) .forEach(unused -> sweepQueue.sweepNextBatch(ShardAndStrategy.conservative(CONS_SHARD))); assertReadAtTimestampReturnsSentinel(TABLE_CONS, sweepTimestamp - 5); assertTestValueEnqueuedAtGivenTimestampStillPresent(TABLE_CONS, sweepTimestamp - 5); assertTestValueEnqueuedAtGivenTimestampStillPresent(TABLE_CONS, sweepTimestamp + 5); }
@Test public void conservativeSweepDeletesAllButLatestWithSingleDeleteAllTimestamps() { long lastWriteTs = TS_FINE_GRANULARITY - 1; for (long i = 1; i <= lastWriteTs; i++) { enqueueWriteCommitted(TABLE_CONS, i); } sweepQueue.sweepNextBatch(ShardAndStrategy.conservative(CONS_SHARD)); assertReadAtTimestampReturnsSentinel(TABLE_CONS, lastWriteTs); assertTestValueEnqueuedAtGivenTimestampStillPresent(TABLE_CONS, lastWriteTs); verify(spiedKvs, times(1)).deleteAllTimestamps(any(TableReference.class), anyMap(), eq(false)); }
@Test public void thoroughSweepDeletesAllButLatestWithSingleDeleteAllTimestampsIncludingSentinels() { long lastWriteTs = TS_FINE_GRANULARITY - 1; for (long i = 1; i <= lastWriteTs; i++) { enqueueWriteCommitted(TABLE_THOR, i); } sweepQueue.sweepNextBatch(ShardAndStrategy.thorough(THOR_SHARD)); assertReadAtTimestampReturnsNothing(TABLE_THOR, lastWriteTs); assertTestValueEnqueuedAtGivenTimestampStillPresent(TABLE_THOR, lastWriteTs); verify(spiedKvs, times(1)).deleteAllTimestamps(any(TableReference.class), anyMap(), eq(true)); }
@Test public void onlySweepsOneBatchAtATime() { enqueueWriteCommitted(TABLE_CONS, LOW_TS); enqueueWriteCommitted(TABLE_CONS, LOW_TS2); enqueueWriteCommitted(TABLE_CONS, TS_FINE_GRANULARITY); sweepQueue.sweepNextBatch(ShardAndStrategy.conservative(CONS_SHARD)); assertReadAtTimestampReturnsSentinel(TABLE_CONS, LOW_TS + 1); assertTestValueEnqueuedAtGivenTimestampStillPresent(TABLE_CONS, LOW_TS2); assertTestValueEnqueuedAtGivenTimestampStillPresent(TABLE_CONS, TS_FINE_GRANULARITY); }
@Test public void sweepDeletesTombstonesWhenWriteHasHigherTimestamp() { enqueueTombstone(TABLE_CONS, LOW_TS); enqueueWriteCommitted(TABLE_CONS, LOW_TS2); assertReadAtTimestampReturnsTombstoneAtTimestamp(TABLE_CONS, LOW_TS + 1, LOW_TS); assertTestValueEnqueuedAtGivenTimestampStillPresent(TABLE_CONS, LOW_TS2); sweepQueue.sweepNextBatch(ShardAndStrategy.conservative(CONS_SHARD)); assertReadAtTimestampReturnsSentinel(TABLE_CONS, LOW_TS + 1); assertTestValueEnqueuedAtGivenTimestampStillPresent(TABLE_CONS, LOW_TS2); }
@Test public void doesNotGoBackwardsEvenIfSweepTimestampRegressesWithinBucket() { enqueueWriteCommitted(TABLE_CONS, LOW_TS); enqueueWriteCommitted(TABLE_CONS, LOW_TS2); enqueueWriteCommitted(TABLE_CONS, LOW_TS3); runConservativeSweepAtTimestamp(LOW_TS2 + 5); assertReadAtTimestampReturnsSentinel(TABLE_CONS, LOW_TS2); assertTestValueEnqueuedAtGivenTimestampStillPresent(TABLE_CONS, LOW_TS2); verify(spiedKvs, times(1)).deleteAllTimestamps(any(TableReference.class), anyMap(), eq(false)); assertProgressUpdatedToTimestamp(LOW_TS2 + 5 - 1); runConservativeSweepAtTimestamp(LOW_TS2 - 5); verify(spiedKvs, times(1)).deleteAllTimestamps(any(TableReference.class), anyMap(), eq(false)); assertProgressUpdatedToTimestamp(LOW_TS2 + 5 - 1); }
@Test public void remembersProgressWhenSweepTimestampAdvances() { long baseSweepTs = getSweepTsCons(); long oldPartitionTs = baseSweepTs - 5; long newPartitionFirstTs = baseSweepTs + 5; long newPartitionSecondTs = baseSweepTs + 10; enqueueWriteCommitted(TABLE_CONS, oldPartitionTs); enqueueWriteCommitted(TABLE_CONS, newPartitionFirstTs); enqueueWriteCommitted(TABLE_CONS, newPartitionSecondTs); assertReadAtTimestampReturnsNothing(TABLE_CONS, oldPartitionTs); runConservativeSweepAtTimestamp(baseSweepTs + 7); runConservativeSweepAtTimestamp(baseSweepTs + 7); assertReadAtTimestampReturnsSentinel(TABLE_CONS, oldPartitionTs + 1); assertTestValueEnqueuedAtGivenTimestampStillPresent(TABLE_CONS, newPartitionFirstTs); assertTestValueEnqueuedAtGivenTimestampStillPresent(TABLE_CONS, newPartitionSecondTs); runConservativeSweepAtTimestamp(newPartitionSecondTs + 1); assertReadAtTimestampReturnsSentinel(TABLE_CONS, newPartitionSecondTs); assertTestValueEnqueuedAtGivenTimestampStillPresent(TABLE_CONS, newPartitionSecondTs); }
@Test public void conservativeSweepAddsSentinelAndLeavesSingleValue() { enqueueWriteCommitted(TABLE_CONS, LOW_TS); assertReadAtTimestampReturnsNothing(TABLE_CONS, LOW_TS); sweepQueue.sweepNextBatch(ShardAndStrategy.conservative(CONS_SHARD)); assertReadAtTimestampReturnsSentinel(TABLE_CONS, LOW_TS); assertTestValueEnqueuedAtGivenTimestampStillPresent(TABLE_CONS, LOW_TS); }
@Test public void canSweepAtMinimumTime() { enqueueWriteCommitted(TABLE_CONS, LOW_TS); enqueueWriteCommitted(TABLE_CONS, LOW_TS2); enqueueWriteCommitted(TABLE_CONS, LOW_TS3); runConservativeSweepAtTimestamp(Long.MIN_VALUE); assertTestValueEnqueuedAtGivenTimestampStillPresent(TABLE_CONS, LOW_TS); assertProgressUpdatedToTimestamp(SweepQueueUtils.INITIAL_TIMESTAMP); }
@Test public void canSweepAtMaximumTime() { enqueueWriteCommitted(TABLE_CONS, LOW_TS); enqueueWriteCommitted(TABLE_CONS, LOW_TS2); enqueueWriteCommitted(TABLE_CONS, LOW_TS3); runConservativeSweepAtTimestamp(Long.MAX_VALUE); assertReadAtTimestampReturnsSentinel(TABLE_CONS, LOW_TS3); assertTestValueEnqueuedAtGivenTimestampStillPresent(TABLE_CONS, LOW_TS3); }
@Test public void thoroughSweepDoesNotAddSentinelAndLeavesSingleValue() { enqueueWriteCommitted(TABLE_THOR, LOW_TS); assertReadAtTimestampReturnsNothing(TABLE_THOR, LOW_TS); sweepQueue.sweepNextBatch(ShardAndStrategy.thorough(THOR_SHARD)); assertReadAtTimestampReturnsNothing(TABLE_THOR, LOW_TS); assertTestValueEnqueuedAtGivenTimestampStillPresent(TABLE_THOR, LOW_TS); }
@Test public void doesNotGoBackwardsEvenIfSweepTimestampRegressesAcrossBoundary() { long coarseBoundary = TS_COARSE_GRANULARITY; enqueueWriteCommitted(TABLE_CONS, coarseBoundary - 5); enqueueWriteCommitted(TABLE_CONS, coarseBoundary + 5); enqueueWriteCommitted(TABLE_CONS, coarseBoundary + 15); // Need 2 sweeps to get through the first coarse bucket runConservativeSweepAtTimestamp(coarseBoundary + 8); assertThat(metricsManager).hasSweepTimestampConservativeEqualTo( coarseBoundary + 8); runConservativeSweepAtTimestamp(coarseBoundary + 8); assertReadAtTimestampReturnsSentinel(TABLE_CONS, coarseBoundary - 5 + 1); assertTestValueEnqueuedAtGivenTimestampStillPresent(TABLE_CONS, coarseBoundary + 5); assertTestValueEnqueuedAtGivenTimestampStillPresent(TABLE_CONS, coarseBoundary + 15); // Now regresses (e.g. clock drift on unreadable) runConservativeSweepAtTimestamp(coarseBoundary - 3); assertThat(metricsManager).hasSweepTimestampConservativeEqualTo( coarseBoundary - 3); // And advances again runConservativeSweepAtTimestamp(coarseBoundary + 18); assertThat(metricsManager).hasSweepTimestampConservativeEqualTo( coarseBoundary + 18); assertReadAtTimestampReturnsSentinel(TABLE_CONS, coarseBoundary - 5 + 1); assertReadAtTimestampReturnsSentinel(TABLE_CONS, coarseBoundary + 5 + 1); assertTestValueEnqueuedAtGivenTimestampStillPresent(TABLE_CONS, coarseBoundary + 15); }
@Test public void sweepDeletesWritesWhenTombstoneHasHigherTimestamp() { enqueueWriteCommitted(TABLE_CONS, LOW_TS); enqueueTombstone(TABLE_CONS, LOW_TS2); assertTestValueEnqueuedAtGivenTimestampStillPresent(TABLE_CONS, LOW_TS); assertReadAtTimestampReturnsTombstoneAtTimestamp(TABLE_CONS, LOW_TS2 + 1, LOW_TS2); sweepQueue.sweepNextBatch(ShardAndStrategy.conservative(CONS_SHARD)); assertReadAtTimestampReturnsSentinel(TABLE_CONS, LOW_TS + 1); assertReadAtTimestampReturnsTombstoneAtTimestamp(TABLE_CONS, LOW_TS2 + 1, LOW_TS2); }
@Test public void sweepProgressesAcrossCoarsePartitions() { long tsCoarseTwo = LOW_TS + TS_FINE_GRANULARITY + TS_COARSE_GRANULARITY; long tsCoarseFour = LOW_TS + 3 * TS_COARSE_GRANULARITY; enqueueWriteCommitted(TABLE_CONS, LOW_TS); enqueueWriteCommitted(TABLE_CONS, tsCoarseTwo); enqueueWriteCommitted(TABLE_CONS, tsCoarseFour); enqueueWriteCommitted(TABLE_CONS, tsCoarseFour + 1L); sweepQueue.sweepNextBatch(ShardAndStrategy.conservative(CONS_SHARD)); assertReadAtTimestampReturnsSentinel(TABLE_CONS, LOW_TS); assertTestValueEnqueuedAtGivenTimestampStillPresent(TABLE_CONS, LOW_TS); sweepQueue.sweepNextBatch(ShardAndStrategy.conservative(CONS_SHARD)); assertReadAtTimestampReturnsSentinel(TABLE_CONS, tsCoarseTwo); assertTestValueEnqueuedAtGivenTimestampStillPresent(TABLE_CONS, tsCoarseTwo); sweepQueue.sweepNextBatch(ShardAndStrategy.conservative(CONS_SHARD)); assertReadAtTimestampReturnsSentinel(TABLE_CONS, tsCoarseFour + 1); assertReadAtTimestampReturnsValue(TABLE_CONS, tsCoarseFour + 2, tsCoarseFour + 1); }
@Test public void doesNotTransitivelyRetainWritesFromBeforeSweepTimestamp() { long sweepTimestamp = getSweepTsCons(); enqueueWriteCommitted(TABLE_CONS, sweepTimestamp - 10); enqueueTombstone(TABLE_CONS, sweepTimestamp - 5); enqueueWriteCommitted(TABLE_CONS, sweepTimestamp + 5); sweepQueue.sweepNextBatch(ShardAndStrategy.conservative(CONS_SHARD)); assertReadAtTimestampReturnsSentinel(TABLE_CONS, sweepTimestamp - 5); assertReadAtTimestampReturnsTombstoneAtTimestamp(TABLE_CONS, sweepTimestamp - 5 + 1, sweepTimestamp - 5); assertTestValueEnqueuedAtGivenTimestampStillPresent(TABLE_CONS, sweepTimestamp + 5); assertThat(metricsManager).hasTombstonesPutConservativeEqualTo(1); assertThat(metricsManager).hasLastSweptTimestampConservativeEqualTo( sweepTimestamp - 1); }
assertTestValueEnqueuedAtGivenTimestampStillPresent(TABLE_CONS, LOW_TS); assertThat(metricsManager).hasTombstonesPutConservativeEqualTo(1); assertTestValueEnqueuedAtGivenTimestampStillPresent(TABLE_CONS, tsFineTwo); assertThat(metricsManager).hasTombstonesPutConservativeEqualTo(2); assertTestValueEnqueuedAtGivenTimestampStillPresent(TABLE_CONS, tsFineFour + 1); assertThat(metricsManager).hasTombstonesPutConservativeEqualTo(3); assertThat(metricsManager).hasEntriesReadConservativeEqualTo(4);