Concurrency and Transactions
Concurrency
- When multiple threads access the same resources, care must be taken to
ensure that data is accessed in a consistent manner.
- Example: Bank account transfer, academic record
- Atomic operations execute without interference from other operations.
- Is
a += 1
an atomic operation?
- See java.util.concurrent.atomic package.
- Should a transfer or a GPA update be atomic?
- The Java keyword synchronized ensures that only 1 thread may
access an object at any time.
- Bank account: getBalance, setBalance, deposit, withdraw
- Is this too restrictive?
Conflicts
- Operations are read or write.
- Conflicts occur if the order in which operations are executed impacts
the result.
- Write/write and read/write are conflicting operations.
- Read/read is OK.
Locking
- Retrieve a lock on a resource before accessing it.
- Rules:
- if requested lock is read and (no lock held or read lock held):
grant read lock
- if requested lock is read and write lock held: wait
- if requested lock is write and no lock held: grant write lock
- if requested lock is write and (read lock held or write lock held):
wait
- Java's wait/notify enable threads to communicate. wait blocks
waiting for a lock. notify releases a lock and notifies all those waiting
for the lock.
Models for XML DB Thread Safety
- Synchronize all - the most restrictive model that does not allow
concurrent reads.
- Copy update - make changes to a copy of the DB and replace old with an
(atomic) assignment. Keeps two copies of DB in memory during update.
- Locking - no one attempted.
Transactions
- A transaction is a series of operations between a client and
server.
- Goals:
- Objects remain in consistent state
- System is tolerant to crash failures
- Transactions are independent
- Transactions are completed or not started
- Example: bank account transfer
Commit/Abort
- A transaction is committed or aborted.
- Commit - all operations completed, results are written to permanent
storage, operation cannot be undone.
- Abort - transaction cannot be completed, all operations are undone.
ACID
- Acronym used to refer to the properties of transactions.
- Atomicity, Consistency, Isolation, Durability
Atomicity
- "all-or-nothing"
- Either a transaction completes successfully, and all effects are
applied to all objects, or it has no effect all all.
Consistency
- A transaction must move the system from one consistent state to another
consistent state.
- Example: sum of all account balances equal to branch's total
accounts
Isolation
- The intermediate effects of a transaction must not be visible to other
transactions.
- Example: for an account transfer, cannot see accounts after withdrawal
but before deposit
Durability
- After a transaction has been processed, its effects are saved to
permanent storage.
Problems in Transaction Processing: Lost Updates
- One transaction may overwrite the result of another.
- Example: Transaction T wants to increase b's balance by 10%,
transferring from a.
- bal = b.getBalance()
- b.setBalance(bal*1.1)
- a.withdraw(bal/10)
- Transaction U wants to increase b's balance by 10%, transferring from
c.
- bal = b.getBalance()
- b.setBalance(bal*1.1)
- c.withdraw(bal/10)
- Problem: suppose order is T1, U1, U2, T2, T3, U3. Balance of b is $220
(not $242 as it should be).
Problems in Transaction Processing: Inconsistent Retrievals
- An inconsistent value may be reported if a transaction is in
progress.
- Example: Transaction V transfers $100 from a to b.
- a.withdraw(100)
- b.deposit(100)
- Transaction W gets the total of all accounts at the bank branch.
- getBranchTotal()
- If W executes between V1 and V2, the total will be short $100.
Serial Equivalence
- Interleaving of operations should produce the same effect as a
non-interleaved execution.
- From lost update example: T1, T2, U1, U2, T3, U3 is OK.
- Recall, write/write and read/write are conflicting. Read/read
operations are not conflicting.
- For two transactions to be serially equivalent, all pairs of
conflicting operations must execute in the same order on all objects they
both access.
- Example: T: x=read(i); write(i, 10); write(j, 20) U: read(j); write(j,
30); z=read(i)
- write(i, 10) and read(i) conflict -- write(j, 20) and read(j)
conflict
- To be serially equivalent, (T must access i before U does AND T must
access j before U does) OR (U must access i before T does and U must
access j before T does).
Locking
- The most common way to achieve serial equivalence is through the use of
locks.
- Before a client accesses an object, it must acquire a lock on that
object.
- A process may not acquire new locks within a transaction once a lock
has been released.
- This is two-phase locking. There is a lock-growing phase
and a lock-shrinking phase.
Locking Example
- T1 - bal = b.getBalance() - Transaction T locks b
- T2 - b.setBalance(bal*1.1)
- U begins
- T3 - a.withdraw(bal/10) - Transaction T locks a
- U1 - bal = b.getBalance() - b locked, U must wait
- T completes - a and b unlocked
- U locks b - gets balance
- U2 - b.setBalance(bal*1.1)
- U3 - c.withdraw(bal/10) - Transaction U locks c
- U completes - b and c unlocked
Strict Two-Phase Locking
- All locks are held until transaction is committed.
- Prevents dirty reads and premature writes.
- Dirty read - a transaction sees a value that is part of another
transaction that is later aborted
- T1: bal1 = a.getBalance() ($100)
- T2: a.setBalance(bal1+10) ($110)
- U1: bal2 = a.getBalance() ($110)
- U2: a..setBalance(bal2+20) ($130)
- U commits
- T aborts
- U cannot be undone
- Premature write - an aborted operation is reset to the wrong value
- Some systems store the before image with a write and roll back to
that value in the event of an abort. This is a problem if another
process overwrites the value before the abort.
- a - balance is $100
- T: a.setBalance($105) - (before image: 100)
- U: a.setBalance($110) - (before image: 105)
- U commits, T aborts and resets to 100 -- should be 110
- If T aborts then U aborts, result will be 105, but should be
100.
Deadlocks
- Two or more processes wait for lock held by other processes.
- Neither can proceed until it gives up the lock, and neither can give up
the lock until it proceeds.
- Example:
- T: a.deposit(100); b.withdraw(100)
- U: b.deposit(50); a.withdraw(50)
- T1: a.deposit(100) - locks a
- U1: b.deposit(50) - locks b
- T2: b.withdraw(100) - wait for lock on b
- U2: a.withdraw(50) - wait for lock on a
Preventing Deadlock
- Atomically acquire all locks at beginning of transaction - very
restrictive
- Specify order in which locks must be acquired - also restrictive
Detecting Deadlock
- Have the process that grants locks force transactions to abort.
- Use a wait-for-graph where vertices are processes and edges
are lock dependencies
- When a lock is requested an edge is added; when a lock is freed and
edge is removed.
- If the graph has a cycle, there is a deadlock.
- The transaction of one of the processes must be aborted.
Distributed Transactions
- A transaction that accesses objects at multiple servers.
- If a transaction commits at one server, it must commit at all
servers.
- If a transaction aborts at one server, it must abort at all
servers.
- A coordinator process manages the transaction. The coordinator is a
process on one of the servers.
- Each server that manages an object used in the transaction is a
participant.
- When a participant joins, it informs the coordinator.

Two-phase Commit
- The coordinator uses two-phase commit to ensure that all participants
either commit or abort.
- Phase 1: The coordinator asks each participant whether it can commit. A
participant may not change its vote to abort once it has voted to
commit.
- Phase 2: Once all participants have voted, if any participant voted to
abort then an abort is sent to all participants. If all participants
voted to commit then a commit is sent to all participants.
- The participants inform the coordinator that they have committed.
Failure in Two-phase Commit
- Server crash: To address the failure of a participant server, servers
store the state of the transaction to permanent storage so that the
process may be restarted and recover.
- Communication failure: To address communication failure, timeouts are
used. If the coordinator times out waiting for participants to vote, it
will eventually decide to abort. If a participant times out waiting for
the final vote from the coordinator, it will ping the coordinator. if the
coordinator has failed, the participant will wait for it to be restarted.
Distributed Deadlock
- Deadlock can occur in distributed transactions.
- Example: T locks object X on server A; U locks object Y on server B; T
blocks waiting to lock object Y on server B; U blocks waiting to lock
object X on server A.
- A simple approach to deadlock detection: all lock managers send
information to a central authority. This approach comes with all of the
usual problems of a centralized solution.
Edge Chasing
- Edge chasing is a distributed approach to detecting
deadlock.
- Each lock manager keeps a graph of the edges it knows about and sends
probes that follow the edges and attempt to detect cycles.
- When a transaction begins waiting for a lock, the coordinator is
informed.
- When a process receives a request for a lock, and another transaction
is holding that lock, it checks with the coordinator to see if the other
process is waiting.
- If it is, it sends a probe to the server administering that lock, which
includes the wait-for-graph.
- As probes are forwarded, edges are added and cycles are detected.

Breaking Deadlock
- To break deadlock, transactions are aborted.
- Transactions are given globally unique priority IDs and the lowest
priority is aborted.
Sami Rollins
Date: 2008-03-27