SnapshotTransactionManager extends AbstractLockAwareTransactionManager { @Override public List<OpenTransaction> startTransactions(List<? extends PreCommitCondition> conditions) { if (conditions.isEmpty()) { return ImmutableList.of(); } List<StartIdentifiedAtlasDbTransactionResponse> responses = timelockService.startIdentifiedAtlasDbTransactionBatch(conditions.size()); Preconditions.checkState(conditions.size() == responses.size(), "Different number of responses and conditions"); try { long immutableTs = responses.stream() .mapToLong(response -> response.immutableTimestamp().getImmutableTimestamp()) .max().getAsLong(); recordImmutableTimestamp(immutableTs); cleaner.punch(responses.get(0).startTimestampAndPartition().timestamp()); return Streams.zip( responses.stream(), conditions.stream(), (response, condition) -> { LockToken immutableTsLock = response.immutableTimestamp().getLock(); Supplier<Long> startTimestampSupplier = Suppliers.ofInstance( response.startTimestampAndPartition().timestamp()); Transaction transaction = createTransaction( immutableTs, startTimestampSupplier, immutableTsLock, condition); return new OpenTransactionImpl(transaction, immutableTsLock); }).collect(Collectors.toList()); } catch (Throwable t) { timelockService.tryUnlock( responses.stream() .map(response -> response.immutableTimestamp().getLock()) .collect(Collectors.toSet())); responses.forEach(response -> lockWatchEventCache.removeTransactionStateFromCache( response.startTimestampAndPartition().timestamp())); throw Throwables.rewrapAndThrowUncheckedException(t); } } protected  SnapshotTransactionManager(
            MetricsManager metricsManager,
            KeyValueService keyValueService,
            TimelockService timelockService,
            LockWatchManager lockWatchManager,
            LockWatchEventCache lockWatchEventCache,
            TimestampManagementService timestampManagementService,
            LockService lockService,
            @NotNull TransactionService transactionService,
            Supplier<AtlasDbConstraintCheckingMode> constraintModeSupplier,
            ConflictDetectionManager conflictDetectionManager,
            SweepStrategyManager sweepStrategyManager,
            Cleaner cleaner,
            boolean allowHiddenTableAccess,
            int concurrentGetRangesThreadPoolSize,
            int defaultGetRangesConcurrency,
            TimestampCache timestampCache,
            MultiTableSweepQueueWriter sweepQueueWriter,
            ExecutorService deleteExecutor,
            boolean validateLocksOnReads,
            Supplier<TransactionConfig> transactionConfig,
            ConflictTracer conflictTracer,
            MetricsFilterEvaluationContext metricsFilterEvaluationContext); @Override T runTaskWithConditionThrowOnConflict(
            C condition, ConditionAwareTransactionTask<T, C, E> task); @Override List<OpenTransaction> startTransactions(List<? extends PreCommitCondition> conditions); @Override T runTaskWithConditionReadOnly(
            C condition, ConditionAwareTransactionTask<T, C, E> task); @Override void registerClosingCallback(Runnable closingCallback); @Override void close(); @Override void clearTimestampCache(); @Override LockService getLockService(); @Override TimelockService getTimelockService(); @Override LockWatchManager getLockWatchManager(); @Override long getImmutableTimestamp(); @Override long getUnreadableTimestamp(); @Override Cleaner getCleaner(); @Override KeyValueService getKeyValueService(); @Override TimestampService getTimestampService(); @Override TimestampManagementService getTimestampManagementService(); @Override TransactionService getTransactionService(); @Override KeyValueServiceStatus getKeyValueServiceStatus();  }
@Test public void startEmptyBatchOfTransactionsDoesNotCallTimelockService() { TimelockService timelockService = spy(new LegacyTimelockService(timestampService, closeableLockService, LockClient.of("lock"))); SnapshotTransactionManager transactionManager = createSnapshotTransactionManager(timelockService, false); List<OpenTransaction> transactions = transactionManager.startTransactions(ImmutableList.of()); assertThat(transactions).isEmpty(); verify(timelockService, never()).startIdentifiedAtlasDbTransactionBatch(anyInt()); }