/* * Process a request of a lock for the variable with @variableIndex * @transactionNumber is the transaction number of the trasaction requesting the lock * @isLockRequestReadOnly refers to the type of lock to request * @return the lock or null if not successful * */ public Lock requestLock( int currentTimestamp, int transactionNumber, int variableIndex, boolean isLockRequestReadOnly) { Lock candidateLock = new Lock(transactionNumber, this.siteIndex, variableIndex, isLockRequestReadOnly); for (Lock lock : this.activeLocks) { // Loop through all the active locks. // If there is a write lock already on @variableIndex, no other transaction may access it, so // return null // If a different transaction has a read lock and the requesting lock is a write lock, do not // give the lock i.e. return null if ((lock.getTransactionNumber() != transactionNumber && lock.getLockedVariableIndex() == variableIndex && !lock.isReadOnly()) || (lock.getTransactionNumber() != transactionNumber && lock.getLockedVariableIndex() == variableIndex && lock.isReadOnly() && !isLockRequestReadOnly)) { System.out.println( "Site: T" + transactionNumber + " found conflicting lock held by T" + lock.getTransactionNumber()); System.out.println( "Site: " + (isLockRequestReadOnly ? "Read" : "Exclusive") + " Lock denied for T" + transactionNumber + " on x" + variableIndex + "." + siteIndex); return null; } } // At this point, the check is successful and add the lock to the active locks this.activeLocks.add(candidateLock); System.out.println( "Site: " + (isLockRequestReadOnly ? "Read" : "Exclusive") + " Lock give to T" + transactionNumber + " on x" + variableIndex + "." + siteIndex); // Give lock and record in the site String[] details = new String[] { "give lock", "" + transactionNumber, "" + variableIndex, "" + isLockRequestReadOnly }; siteLog.addEvent(currentTimestamp, details); // Return the lock to the requesting transaction return candidateLock; }
/* * Process an upgrade request of a lock from read to exclusive for the variable with @variableIndex * @transactionNumber is the transaction number of the transaction requesting the lock * @return the lock or null if not successful * */ public Lock upgradeRequest(int currentTimestamp, int transactionNumber, int variableIndex) { Lock candidateLock = new Lock(transactionNumber, this.siteIndex, variableIndex, false); for (Lock lock : this.activeLocks) { // Loop through all the active locks. // If there is a write lock already on @variableIndex, no other transaction may access it, so // return null // If a different transaction has a read lock and the requesting lock is a write lock, do not // give the lock i.e. return null if ((lock.getTransactionNumber() != transactionNumber && lock.getLockedVariableIndex() == variableIndex && !lock.isReadOnly()) || (lock.getTransactionNumber() != transactionNumber && lock.getLockedVariableIndex() == variableIndex && lock.isReadOnly())) { System.out.println( "Site: T" + transactionNumber + " found conflicting lock held by T" + lock.getTransactionNumber()); System.out.println( "Site: Upgrade to exclusive lock denied for T" + transactionNumber + " on x" + variableIndex + "." + siteIndex); return null; } } // If successful, remove the lock from the activeLocks and add the candidate to the activeLocks int index = 0; while (index < this.activeLocks.size()) { if (this.activeLocks.get(index).getLockedVariableIndex() == variableIndex && this.activeLocks.get(index).getTransactionNumber() == transactionNumber) { this.activeLocks.remove(index); break; } index++; } this.activeLocks.add(candidateLock); System.out.println( "Site: Upgrade to exclusive lock give to T" + transactionNumber + " on x" + variableIndex + "." + siteIndex); // Give lock and record in the site String[] details = new String[] {"give lock", "" + transactionNumber, "" + variableIndex, "" + false}; siteLog.addEvent(currentTimestamp, details); return candidateLock; }
/* * For recovery purposes, if Variable.isAllowRead = false, then set it to true, * now that there is a current new update to it Set lastCommittedVersion to the currentVersion * Add a before image and timestamp to the list of versions * @variableIndex is the variable index, also given from Transaction. * @committingTransaction indicates which transaction is committing * @currentTimestamp is the current timestamp * @transactionNumber is the current transaction doing this operation */ public void commit( int variableIndex, int committingTransaction, int currentTimestamp, int transactionNumber) { System.out.println( "Site: Committing T" + committingTransaction + " x" + variableIndex + "." + this.siteIndex); int valueCommitted = this.getVariable(variableIndex).commit(committingTransaction); String[] details = new String[] {"commit", "" + transactionNumber, "" + variableIndex, "" + valueCommitted}; siteLog.addEvent(currentTimestamp, details); }
/* * Set all variable's Site.isAllowRead = false * All sites must release locks from living transactions that were also live at that site. */ public void fail(int currentTimestamp) { setSiteDown(true); // Set all variable's Site.isAllowRead = false for (Integer key : siteVariables.keySet()) { Variable variable = siteVariables.get(key); variable.setAllowRead(false); } this.activeLocks = new ArrayList<Lock>(); System.out.println("Site: Site " + this.siteIndex + " erased locks."); String[] details = new String[] {"fail"}; siteLog.addEvent(currentTimestamp, details); System.out.println("Site: fail site " + this.getSiteIndex()); }
/* * Release all locks for a particular transaction from @activeLocks * @transactionNumber refers to the transaction in which his locks should be released */ public void releaseLocks(int transactionNumber, int currentTimestamp) { int i = 0; while (i < this.activeLocks.size()) { Lock lock = this.activeLocks.get(i); if (lock.getTransactionNumber() == transactionNumber) { System.out.println( "Site: Release lock from T" + transactionNumber + " on x" + lock.getLockedVariableIndex() + "." + siteIndex); // Give lock and record in the site String[] details = new String[] { "release lock", "" + transactionNumber, "" + lock.getLockedVariableIndex(), "" + lock.isReadOnly() }; siteLog.addEvent(currentTimestamp, details); this.activeLocks.remove(lock); } else { if (debug) System.out.println( "Site: Lock not released on x" + lock.getLockedVariableIndex() + "." + siteIndex + " held by T" + lock.getTransactionNumber()); i++; } } }
/* * Recover this site. * For all Variables at x, if the variable is not replicated at any other sites, then Variable.isAllowRead = true. * This allows reads to a variable not replicated anywhere else. * If the variable is replicated: * - Variable.lastCommittedVersion = -1, which sets the data to unusable, until a write happens. * - Variable.currentVersion = -1, which sets the data to unusable until a write happens. * * Site.isSiteDown = false, which allows writes to the site, but not reads to replicated ones. * Record the recovery in the site's log. */ public void recover(int currentTimestamp) { System.out.println("Site: recover site " + this.getSiteIndex()); // For all Variables at x, if the variable is not replicated at any other sites, then // Variable.isAllowRead = true. // This allows reads to a variable not replicated anywhere else. for (Variable variable : this.siteVariables.values()) { if (!isVariableReplicated(variable.getIndexVariable())) { variable.setAllowRead(true); } else { // Version.lastCommittedVersion = -1, which sets the data to unreadable, until a write // happens // Version.currentVersion = -1, which sets the data to unreadable until a write happens variable.resetVersionIndexes(); } } // Site.isSiteDown = false, which allows writes to the site, but not reads to replicated ones this.isSiteDown = false; String[] details = new String[] {"recover"}; siteLog.addEvent(currentTimestamp, details); }