/* * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ package com.github.geophile.erdo.systemtest.lockmanagement; import com.github.geophile.erdo.transaction.*; import java.util.Random; import java.util.concurrent.atomic.AtomicLong; import java.util.logging.Level; import java.util.logging.Logger; public class LockManagerTestThread extends Thread { public void run() { int deadlockAborts = 0; int conflictAborts = 0; try { for (int i = 0; i < transactions; i++) { boolean committed = false; do { transaction = transactionManager.currentTransaction(); int from; int to; do { from = random.nextInt(accounts.length); to = random.nextInt(accounts.length); } while (from == to); int amount = MIN_AMOUNT + random.nextInt(MAX_AMOUNT); AccountId fromAccountId = new AccountId(from); AccountId toAccountId = new AccountId(to); try { lock(fromAccountId); lock(toAccountId); accounts[from].set(accounts[from].get() - amount); accounts[to].set(accounts[to].get() + amount); transactionManager.commitTransaction(null, null); committed = true; } catch (DeadlockException e) { LOG.log(Level.INFO, "{0}: deadlock", threadId); deadlockAborts++; } catch (TransactionRolledBackException e) { LOG.log(Level.FINE, "{0}: conflict", threadId); conflictAborts++; } } while (!committed); } } catch (Throwable th) { LOG.log(Level.WARNING, "Test thread ended by exception while working on {0}", transaction); LOG.log(Level.WARNING, "Cause", th); termination = th; } finally { System.out.println( String.format("%s transactions, %s deadlock aborts, %s conflict aborts, termination: %s", transactions, deadlockAborts, conflictAborts, (termination == null ? null : termination.getMessage()))); } } public Throwable termination() { return termination; } public LockManagerTestThread(int threadId, TransactionManager transactionManager, LockManager lockManager, AtomicLong[] accounts, int transactions) { this.threadId = threadId; this.transactionManager = transactionManager; this.lockManager = lockManager; this.accounts = accounts; this.transactions = transactions; this.random = new Random(System.nanoTime()); } private void lock(AccountId accountId) throws DeadlockException, TransactionRolledBackException, InterruptedException { transaction.waitingFor(accountId); try { lockManager.lock(accountId, transaction); } catch (InterruptedException e) { LOG.log(Level.WARNING, "Caught InterruptedException while locking {0}", new Object[]{accountId, e}); } catch (DeadlockException | TransactionRolledBackException e) { transactionManager.rollbackTransaction(); throw e; } finally { transaction.doneWaitingForKey(); } } private static final Logger LOG = Logger.getLogger(LockManagerTestThread.class.getName()); private static final int MIN_AMOUNT = 1; private static final int MAX_AMOUNT = 100; private final int threadId; private final int transactions; private final AtomicLong[] accounts; private final TransactionManager transactionManager; private final LockManager lockManager; private Transaction transaction; private final Random random; private Throwable termination; }