@Override public TimestampAndPartition getFreshTimestampForClient(UUID clientIdentifier) { while (true) { TimestampRange timestampRange = delegate.getFreshTimestamps(NUM_PARTITIONS); int targetResidue = allocator.getRelevantModuli(clientIdentifier).iterator().next(); OptionalLong relevantTimestamp = TimestampRanges.getTimestampMatchingModulus( timestampRange, targetResidue, NUM_PARTITIONS); if (relevantTimestamp.isPresent()) { return TimestampAndPartition.of(relevantTimestamp.getAsLong(), targetResidue); } // Not a bug - getFreshTimestamps is permitted to return less than the number of timestamps asked for, // so this case is possible. log.info("The timestamp range we received from the underlying timestamp service - {} -" + " did not contain a value with residue {} modulo {}. We will try again." + " This is not a bug; but if it happens excessively frequently, please contact support.", SafeArg.of("timestampRange", timestampRange), SafeArg.of("targetResidue", targetResidue), SafeArg.of("modulus", NUM_PARTITIONS)); } }
@Override public StartIdentifiedAtlasDbTransactionResponse startIdentifiedAtlasDbTransaction( StartIdentifiedAtlasDbTransactionRequest request) { return checkAndUpdateLowerBound(() -> delegate.startIdentifiedAtlasDbTransaction(request), r -> r.startTimestampAndPartition().timestamp(), r -> r.startTimestampAndPartition().timestamp()); }
@Override public StartIdentifiedAtlasDbTransactionResponse startIdentifiedAtlasDbTransaction( StartIdentifiedAtlasDbTransactionRequest request) { return StartIdentifiedAtlasDbTransactionResponse.of( lockImmutableTimestamp(ImmutableIdentifiedTimeLockRequest.of(request.requestId())), TimestampAndPartition.of(getFreshTimestamp(), 0)); }
@Override public TransactionAndImmutableTsLock setupRunTaskWithConditionThrowOnConflict(PreCommitCondition condition) { StartIdentifiedAtlasDbTransactionResponse transactionResponse = timelockService.startIdentifiedAtlasDbTransaction( StartIdentifiedAtlasDbTransactionRequest.createForRequestor(clientId)); try { LockToken immutableTsLock = transactionResponse.immutableTimestamp().getLock(); long immutableTs = transactionResponse.immutableTimestamp().getImmutableTimestamp(); recordImmutableTimestamp(immutableTs); cleaner.punch(transactionResponse.startTimestampAndPartition().timestamp()); Supplier<Long> startTimestampSupplier = Suppliers.ofInstance( transactionResponse.startTimestampAndPartition().timestamp()); SnapshotTransaction transaction = createTransaction(immutableTs, startTimestampSupplier, immutableTsLock, condition); return TransactionAndImmutableTsLock.of(transaction, immutableTsLock); } catch (Throwable e) { timelockService.tryUnlock(ImmutableSet.of(transactionResponse.immutableTimestamp().getLock())); throw Throwables.rewrapAndThrowUncheckedException(e); } }
@Test public void startIdentifiedAtlasDbTransactionShouldFail() { StartIdentifiedAtlasDbTransactionResponse startIdentifiedAtlasDbTransactionResponse = StartIdentifiedAtlasDbTransactionResponse.of(LOCK_IMMUTABLE_TIMESTAMP_RESPONSE, TimestampAndPartition.of(1L, 0)); when(rawTimelockService.startIdentifiedAtlasDbTransaction(any())) .thenReturn(startIdentifiedAtlasDbTransactionResponse); assertThrowsOnSecondCall(() -> timelockService.startIdentifiedAtlasDbTransaction( StartIdentifiedAtlasDbTransactionRequest.createForRequestor(UUID.randomUUID()))); }
@Override public StartIdentifiedAtlasDbTransactionResponse startIdentifiedAtlasDbTransaction( StartIdentifiedAtlasDbTransactionRequest request) { return checkAndUpdateLowerBound(() -> delegate.startIdentifiedAtlasDbTransaction(request), r -> r.startTimestampAndPartition().timestamp(), r -> r.startTimestampAndPartition().timestamp()); }
StartIdentifiedAtlasDbTransactionResponse.of( LockImmutableTimestampResponse.of(2L, LockToken.of(UUID.randomUUID())), TimestampAndPartition.of(1L, 1) )); TRM.registerTransactionManager(txnManagerWithMocks);
@Override public TransactionAndImmutableTsLock setupRunTaskWithConditionThrowOnConflict(PreCommitCondition condition) { StartIdentifiedAtlasDbTransactionResponse transactionResponse = timelockService.startIdentifiedAtlasDbTransaction( StartIdentifiedAtlasDbTransactionRequest.createForRequestor(clientId)); try { LockToken immutableTsLock = transactionResponse.immutableTimestamp().getLock(); long immutableTs = transactionResponse.immutableTimestamp().getImmutableTimestamp(); recordImmutableTimestamp(immutableTs); cleaner.punch(transactionResponse.startTimestampAndPartition().timestamp()); Supplier<Long> startTimestampSupplier = Suppliers.ofInstance( transactionResponse.startTimestampAndPartition().timestamp()); SnapshotTransaction transaction = createTransaction(immutableTs, startTimestampSupplier, immutableTsLock, condition); return TransactionAndImmutableTsLock.of(transaction, immutableTsLock); } catch (Throwable e) { timelockService.tryUnlock(ImmutableSet.of(transactionResponse.immutableTimestamp().getLock())); throw Throwables.rewrapAndThrowUncheckedException(e); } }
@Override public TimestampAndPartition getFreshTimestampForClient(UUID clientIdentifier) { while (true) { TimestampRange timestampRange = delegate.getFreshTimestamps(NUM_PARTITIONS); int targetResidue = allocator.getRelevantModuli(clientIdentifier).iterator().next(); OptionalLong relevantTimestamp = TimestampRanges.getTimestampMatchingModulus( timestampRange, targetResidue, NUM_PARTITIONS); if (relevantTimestamp.isPresent()) { return TimestampAndPartition.of(relevantTimestamp.getAsLong(), targetResidue); } // Not a bug - getFreshTimestamps is permitted to return less than the number of timestamps asked for, // so this case is possible. log.info("The timestamp range we received from the underlying timestamp service - {} -" + " did not contain a value with residue {} modulo {}. We will try again." + " This is not a bug; but if it happens excessively frequently, please contact support.", SafeArg.of("timestampRange", timestampRange), SafeArg.of("targetResidue", targetResidue), SafeArg.of("modulus", NUM_PARTITIONS)); } }