Transaction Intro slide XXX New builtin gettransaction Returns
Transaction Intro slide XXX • New builtin get_transaction() • Returns transaction for current thread • ZEO manages transactions across processes, machines • Transactions & Connections – Independent, consistent views of DB
ACID properties • Atomic – All updates performed, or none • Consistent – Responsibility of application – Changes should preserve object invariants • Isolated – Each transaction sees consistent state – Transactions occur in serializable order • Durable – After a commit, change will survive crash
-Concurrency control • Optimistic concurrency vs. locking – ZODB assumes many more reads than writes – No locking of objects; most writes succeed so don’t need to pay overhead of locking – However, conflicts can occur on writes (and in a ZEO environment, on reads too) – Conflict resolution is the application’s responsibility
Transaction boundaries • Under application control • Transaction begin is implicit • get_transaction(). commit() • get_transaction(). abort()
Write conflicts • Transactions must be serializable • Two transactions change object concurrently – Only one change can succeed – Other raises Conflict. Error on commit() • Handling Conflict. Error – Abort transaction, and retry – Application-level conflict resolution
Conflicts and Consistency • New method on Calendar object def make_appointment(self, apt, attendees): self. add_appointment(apt) for person in attendees: if person. is_available(apt. date, apt. duration): person. add_appointment(apt) apt. add_person(person) – Guarantees appointments don’t conflict • Consider two calls at same time – Data race on is_available()? – Conflict raised when object commits
Conflict Example def update 1(cal, attendees): apt = Appointment(“refrigerator policy”, Time(“ 2/5/2002 10: 00”), Time(“ 0: 30”)) cal. make_appointment(apt, attendees) def update 2(cal, attendees): apt = Appointment(“curly braces”, Time(“ 2/5/2002 10: 00”), Time(“ 1: 00”)) cal. make_appointment(apt, attendees) Two calls at once results in one error Traceback (most recent call last): File “<stdin>”, line 1, in ? File “ZODB/Transaction. py”, line 233, in commit File “ZODB/Connection. py”, line 347, in commit File “ZODB/File. Storage. py”, line 634, in store Conflict. Error: database conflict error (serial was 034144749675 e 55 d, now 03414442940 c 1 bdd)
Object serial numbers • Every object has a serial number – monotonically increasing – might be a timestamp <wink> – a. k. a. revision number, transaction id • Upon commit, current serial number is compared to stored serial number. If they differ, object has been modified externally in the interim: Conflict. Error is raised • Upon successful write, object gets a new serial number
Dealing w/write conflicts • Depends on the application! from ZODB. POSException import Confict. Error while 1: try: obj. counter += 1 get_transaction(). commit() except Conflict. Error: pass else: break
Dealing w/write conflicts con’t • What’s (possibly) wrong with this picture? obj. counter += 1 while 1: try: get_transaction(). commit() except Conflict. Error: pass else: break
Read conflicts with ZEO • When using ZEO, it is possible to get Conflict. Errors on reading an object – Storage servers send invalidation messages to clients when an object changes – Invalidation messages are only visible at transaction boundaries – Clients read only most current object revision • Future: Multi-version concurrency control • Now: get_transaction(). abort() and try again
Application level conflict resolution • Objects can implement their own (write) conflict resolution logic • Implement _p_resolve. Conflict() method – args: oid, old serial #, new serial #, current pickle data – returns: new pickle data or None – None signals a Conflict. Error
Subtransactions • You can create subtransactions within a main transaction – individually commit and abort subtransactions – not “truly committed” until containing transaction is committed • Primarily for reducing in-memory footprint >>> get_transaction(). commit(1)
- Slides: 13