@VisibleForTesting HeldLocks(LockLog lockLog, Collection<AsyncLock> acquiredLocks, UUID requestId, LeaseExpirationTimer expirationTimer) { this.lockLog = lockLog; this.acquiredLocks = acquiredLocks; this.token = LockToken.of(requestId); this.expirationTimer = expirationTimer; }
private static LockToken randomLockToken() { return LockToken.of(UUID.randomUUID()); }
static LockToken toTokenV2(LockRefreshToken legacyToken) { return LockToken.of(toUuid(legacyToken.getTokenId())); }
private static List<LockToken> createLockTokenList(int size) { return IntStream.range(0, size) .boxed() .map(unused -> LockToken.of(UUID.randomUUID())) .collect(Collectors.toList()); }
@Test public void clientWithSynchronousUnlockerDelegatesToUnlock() { try (TimeLockClient client = TimeLockClient.withSynchronousUnlocker(timelock)) { UUID uuid = UUID.randomUUID(); client.tryUnlock(ImmutableSet.of(LockToken.of(uuid))); verify(timelock, times(1)).unlock(ImmutableSet.of(LockToken.of(uuid))); } } }
@Test public void profilingIsSharedAcrossTransactions() { SnapshotTransaction tx1 = snapshotTransactionManager.createTransaction(1, () -> 2L, LockToken.of( UUID.randomUUID()), PreCommitConditions.NO_OP); SnapshotTransaction tx2 = snapshotTransactionManager.createTransaction(1, () -> 2L, LockToken.of( UUID.randomUUID()), PreCommitConditions.NO_OP); assertThat(tx1.commitProfileProcessor).isSameAs(tx2.commitProfileProcessor); } }
/** * Creates a mock of a LockService that only gives out a lock once per unique request and never releases it, even * if unlock is called. The returned tokens are monotonically increasing in the tokenId. */ private TimelockService createStickyLockService() { AtomicLong lockToken = new AtomicLong(0); Set<LockDescriptor> requestedLocks = new ConcurrentHashSet<>(); TimelockService stickyLockService = mock(TimelockService.class); doAnswer(invocation -> { LockRequest request = invocation.getArgument(0); if (requestedLocks.add(Iterables.getOnlyElement(request.getLockDescriptors()))) { return (LockResponse) () -> Optional.of(LockToken.of(new UUID(lockToken.getAndIncrement(), 0L))); } else { return (LockResponse) Optional::empty; } }).when(stickyLockService).lock(any()); return stickyLockService; }
private LockToken mockHeldLocksForNewRequest(Consumer<HeldLocks> mockApplier) { LockToken request = LockToken.of(UUID.randomUUID()); HeldLocks heldLocks = mock(HeldLocks.class); mockApplier.accept(heldLocks); AsyncResult<HeldLocks> completedResult = new AsyncResult<>(); completedResult.complete(heldLocks); heldLocksCollection.getExistingOrAcquire(request.getRequestId(), () -> completedResult); return request; }
@Test public void successfulLockAndUnlock() throws InterruptedException { LockToken lockToken = LockToken.of(UUID.randomUUID()); when(mockLockService.lock(any())) .thenReturn(() -> Optional.of(lockToken)); Optional<TargetedSweeperLock> maybeLock = TargetedSweeperLock .tryAcquire(1, TableMetadataPersistence.SweepStrategy.CONSERVATIVE, mockLockService); assertThat(maybeLock).isPresent(); TargetedSweeperLock lock = maybeLock.get(); assertThat(lock.getShardAndStrategy()).isEqualTo(ShardAndStrategy.conservative(1)); lock.unlock(); verify(mockLockService, times(1)).unlock(ImmutableSet.of(lockToken)); verify(mockLockService, times(1)).lock(any()); verifyNoMoreInteractions(mockLockService); }
private LockToken mockFailedRequest() { LockToken request = LockToken.of(UUID.randomUUID()); AsyncResult failedLocks = new AsyncResult(); failedLocks.fail(new RuntimeException()); heldLocksCollection.getExistingOrAcquire(request.getRequestId(), () -> failedLocks); return request; }
private LockToken mockTimedOutRequest() { LockToken request = LockToken.of(UUID.randomUUID()); AsyncResult timedOutResult = new AsyncResult(); timedOutResult.timeout(); heldLocksCollection.getExistingOrAcquire(request.getRequestId(), () -> timedOutResult); return request; }
@Test public void multipleSweepersSweepDifferentShardsAndCallUnlockAfterwards() throws InterruptedException { int shards = 128; int sweepers = 8; int threads = shards / sweepers; TimelockService stickyLockService = createStickyLockService(); createAndInitializeSweepersAndWaitForOneBackgroundIteration(sweepers, shards, threads, stickyLockService); for (int i = 0; i < shards; i++) { assertProgressUpdatedToTimestamp(maxTsForFinePartition(tsPartitionFine(unreadableTs - 1)), i); verify(stickyLockService, times(1)).unlock(ImmutableSet.of(LockToken.of(new UUID(i, 0L)))); } // minimum: all threads on one host succeed, then on another, etc: // threads + threads * 2 + ... + threads * swepers verify(stickyLockService, atLeast(threads * sweepers * (sweepers - 1) / 2)) .lock(any(LockRequest.class)); // maximum: all but one succeed on each host, and only then those succeed: // shards + shards - 1 + ... + shards - (sweepers - 1) verify(stickyLockService, atMost(sweepers * shards - sweepers * (sweepers - 1) / 2)) .lock(any(LockRequest.class)); }
@VisibleForTesting HeldLocks(LockLog lockLog, Collection<AsyncLock> acquiredLocks, UUID requestId, LeaseExpirationTimer expirationTimer) { this.lockLog = lockLog; this.acquiredLocks = acquiredLocks; this.token = LockToken.of(requestId); this.expirationTimer = expirationTimer; }