@Override public Set<LockRefreshToken> refresh(Set<LockRefreshToken> lockRefreshTokens) throws InterruptedException { return lockService.refreshLockRefreshTokens(lockRefreshTokens); } }
@Override public Set<LockToken> refreshLockLeases(Set<LockToken> tokens) { Set<LockRefreshToken> refreshTokens = tokens.stream() .map(LockTokenConverter::toLegacyToken) .collect(Collectors.toSet()); return lockService.refreshLockRefreshTokens(refreshTokens).stream() .map(LockTokenConverter::toTokenV2) .collect(Collectors.toSet()); }
private void refreshLocks() { ImmutableSet<LockRefreshToken> refreshCopy = ImmutableSet.copyOf(toRefresh); if (refreshCopy.isEmpty()) { return; } Set<LockRefreshToken> refreshedTokens = new HashSet<>(); // We batch refreshes to avoid sending payload of excessive size for (List<LockRefreshToken> tokenBatch : Iterables.partition(refreshCopy, REFRESH_BATCH_SIZE)) { refreshedTokens.addAll(delegate.refreshLockRefreshTokens(tokenBatch)); } for (LockRefreshToken token : refreshCopy) { if (!refreshedTokens.contains(token) && toRefresh.contains(token)) { log.warn("failed to refresh lock: {}", token); toRefresh.remove(token); } } }
@Override public Set<HeldLocksToken> refreshTokens(Iterable<HeldLocksToken> tokens) { Set<LockRefreshToken> refreshTokens = ImmutableSet.copyOf( Iterables.transform(tokens, HeldLocksTokens.getRefreshTokenFun())); Set<LockRefreshToken> goodTokens = delegate().refreshLockRefreshTokens(refreshTokens); Set<HeldLocksToken> ret = Sets.newHashSetWithExpectedSize(refreshTokens.size()); Map<LockRefreshToken, HeldLocksToken> tokenMap = Maps.uniqueIndex(tokens, HeldLocksTokens.getRefreshTokenFun()); for (LockRefreshToken goodToken : goodTokens) { HeldLocksToken lock = tokenMap.get(goodToken); ret.add(goodToken.refreshTokenWithExpriationDate(lock)); } return ret; }
@Override public void throwIfConditionInvalid(long timestamp) { if (lockTokens.isEmpty()) { return; } Set<LockRefreshToken> refreshTokens = lockTokens.stream() .map(HeldLocksToken::getLockRefreshToken) .collect(Collectors.toSet()); Set<LockRefreshToken> refreshedLocks = lockService.refreshLockRefreshTokens(refreshTokens); Set<LockRefreshToken> expiredLocks = Sets.difference(refreshTokens, refreshedLocks); if (!expiredLocks.isEmpty()) { List<HeldLocksToken> expiredHeldLocks = lockTokens.stream() .filter(token -> expiredLocks.contains(token.getLockRefreshToken())) .collect(Collectors.toList()); log.warn("External lock service locks were no longer valid", UnsafeArg.of("invalidLocks", expiredHeldLocks)); throw new TransactionLockTimeoutNonRetriableException("Provided external lock tokens expired. " + "Retry is not possible. Locks: " + expiredHeldLocks); } }
@Override public void throwIfConditionInvalid(long timestamp) { if (lockService.refreshLockRefreshTokens(Collections.singleton(heldLock.getLockRefreshToken())).isEmpty()) { log.warn("Lock service locks were no longer valid", UnsafeArg.of("invalidToken", heldLock.getLockRefreshToken())); throw new TransactionLockTimeoutException("Provided transaction lock expired. Token: " + heldLock.getLockRefreshToken()); } }
@Test public void combinedLocksCondition_checkExternalLocksFirst() { when(lockService.refreshLockRefreshTokens(Collections.singleton(EXTERNAL_LOCK_REFRESH_TOKEN))) .thenReturn(ImmutableSet.of()); when(lockService.refreshLockRefreshTokens(Collections.singleton(TRANSACTION_LOCK_REFRESH_TOKEN))) .thenReturn(ImmutableSet.of()); assertThatThrownBy(() -> combinedLocksCondition.throwIfConditionInvalid(0L)) .isInstanceOf(TransactionLockTimeoutNonRetriableException.class) .hasMessageContaining("Provided external lock tokens expired. Retry is not possible"); }
@Test public void externalLocksCondition_conditionSucceeds() { when(lockService.refreshLockRefreshTokens(ImmutableSet.of(EXTERNAL_LOCK_REFRESH_TOKEN))) .thenReturn(ImmutableSet.of(EXTERNAL_LOCK_REFRESH_TOKEN)); externalLocksCondition.throwIfConditionInvalid(0L); }
@Test public void transactionLocksCondition_conditionSucceeds() { when(lockService.refreshLockRefreshTokens(Collections.singleton(TRANSACTION_LOCK_REFRESH_TOKEN))) .thenReturn(ImmutableSet.of(TRANSACTION_LOCK_REFRESH_TOKEN)); transactionLocksCondition.throwIfConditionInvalid(0L); }
@Test public void refreshLockLeasesDelegatesToLockService() { Set<LockToken> tokens = ImmutableSet.of(LOCK_TOKEN_V2); timelock.refreshLockLeases(tokens); verify(lockService).refreshLockRefreshTokens(ImmutableSet.of(LOCK_REFRESH_TOKEN)); }
@Test public void transactionLocksCondition_conditionFails() { when(lockService.refreshLockRefreshTokens(Collections.singleton(TRANSACTION_LOCK_REFRESH_TOKEN))) .thenReturn(ImmutableSet.of()); assertThatThrownBy(() -> transactionLocksCondition.throwIfConditionInvalid(0L)) .isInstanceOf(TransactionLockTimeoutException.class) .hasMessageContaining("Provided transaction lock expired"); }
@Test public void externalLocksCondition_conditionFails() { when(lockService.refreshLockRefreshTokens(Collections.singleton(EXTERNAL_LOCK_REFRESH_TOKEN))) .thenReturn(ImmutableSet.of()); assertThatThrownBy(() -> externalLocksCondition.throwIfConditionInvalid(0L)) .isInstanceOf(TransactionLockTimeoutNonRetriableException.class) .hasMessageContaining("Provided external lock tokens expired. Retry is not possible"); }
@Test public void refreshSingleReturnsNullIfThereAreNoRefreshTokens() throws InterruptedException { when(LOCK_SERVICE.refreshLockRefreshTokens(any())).thenReturn(Collections.emptySet()); assertNull(LOCK_CLIENT.refreshSingle(TOKEN_1)); } }
@Test public void lockOrRefreshCallsRefreshWhenTokenPresent() throws InterruptedException { LockRefreshToken token = new LockRefreshToken(BigInteger.ONE, 10000000000L); when(mockLockService.lock(anyString(), any())).thenReturn(token); lockService.lockOrRefresh(); verify(mockLockService, atLeastOnce()).lock(any(), any()); lockService.lockOrRefresh(); verify(mockLockService, atLeastOnce()).refreshLockRefreshTokens(ImmutableList.of(token)); verifyNoMoreInteractions(mockLockService); }
@Test public void lockClearedWhenRefreshReturnsEmpty() throws InterruptedException { when(mockLockService.lock(anyString(), any())).thenReturn(new LockRefreshToken(BigInteger.ONE, 10000000000L)); lockService.lockOrRefresh(); when(mockLockService.refreshLockRefreshTokens(any())).thenReturn(ImmutableSet.of()); lockService.lockOrRefresh(); assertFalse(lockService.haveLocks()); }
private void refreshLocks() { ImmutableSet<LockRefreshToken> refreshCopy = ImmutableSet.copyOf(toRefresh); if (refreshCopy.isEmpty()) { return; } Set<LockRefreshToken> refreshedTokens = new HashSet<>(); // We batch refreshes to avoid sending payload of excessive size for (List<LockRefreshToken> tokenBatch : Iterables.partition(refreshCopy, REFRESH_BATCH_SIZE)) { refreshedTokens.addAll(delegate.refreshLockRefreshTokens(tokenBatch)); } for (LockRefreshToken token : refreshCopy) { if (!refreshedTokens.contains(token) && toRefresh.contains(token)) { log.warn("failed to refresh lock: {}", token); toRefresh.remove(token); } } }
@Override public Set<HeldLocksToken> refreshTokens(Iterable<HeldLocksToken> tokens) { Set<LockRefreshToken> refreshTokens = ImmutableSet.copyOf( Iterables.transform(tokens, HeldLocksTokens.getRefreshTokenFun())); Set<LockRefreshToken> goodTokens = delegate().refreshLockRefreshTokens(refreshTokens); Set<HeldLocksToken> ret = Sets.newHashSetWithExpectedSize(refreshTokens.size()); Map<LockRefreshToken, HeldLocksToken> tokenMap = Maps.uniqueIndex(tokens, HeldLocksTokens.getRefreshTokenFun()); for (LockRefreshToken goodToken : goodTokens) { HeldLocksToken lock = tokenMap.get(goodToken); ret.add(goodToken.refreshTokenWithExpriationDate(lock)); } return ret; }
@Override public void throwIfConditionInvalid(long timestamp) { if (lockTokens.isEmpty()) { return; } Set<LockRefreshToken> refreshTokens = lockTokens.stream() .map(HeldLocksToken::getLockRefreshToken) .collect(Collectors.toSet()); Set<LockRefreshToken> refreshedLocks = lockService.refreshLockRefreshTokens(refreshTokens); Set<LockRefreshToken> expiredLocks = Sets.difference(refreshTokens, refreshedLocks); if (!expiredLocks.isEmpty()) { List<HeldLocksToken> expiredHeldLocks = lockTokens.stream() .filter(token -> expiredLocks.contains(token.getLockRefreshToken())) .collect(Collectors.toList()); log.warn("External lock service locks were no longer valid", UnsafeArg.of("invalidLocks", expiredHeldLocks)); throw new TransactionLockTimeoutNonRetriableException("Provided external lock tokens expired. " + "Retry is not possible. Locks: " + expiredHeldLocks); } }
@Override public void throwIfConditionInvalid(long timestamp) { if (lockService.refreshLockRefreshTokens(Collections.singleton(heldLock.getLockRefreshToken())).isEmpty()) { log.warn("Lock service locks were no longer valid", UnsafeArg.of("invalidToken", heldLock.getLockRefreshToken())); throw new TransactionLockTimeoutException("Provided transaction lock expired. Token: " + heldLock.getLockRefreshToken()); } }