Merge lp://staging/~free.ekanayaka/storm/tpc-support into lp://staging/storm
Status: | Merged | ||||
---|---|---|---|---|---|
Approved by: | Thomas Herve | ||||
Approved revision: | 443 | ||||
Merged at revision: | 449 | ||||
Proposed branch: | lp://staging/~free.ekanayaka/storm/tpc-support | ||||
Merge into: | lp://staging/storm | ||||
Diff against target: | 0 lines | ||||
To merge this branch: | bzr merge lp://staging/~free.ekanayaka/storm/tpc-support | ||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Thomas Herve (community) | Approve | ||
Stuart Bishop (community) | Approve | ||
Review via email: mp+95357@code.staging.launchpad.net |
Description of the change
This branch adds support for two-phase commits, using the DB API version 2.0 (only implemented by psycopg2 at the moment). An example usage is:
xid = Xid(0, "my-txn", "my-branch") # This models a XA-compliant transaction ID
store.begin(xid)
store.execute(...)
store.prepare()
store.commit()
Or using ZStorm, just call zstorm.
In order to transparently use store.commit() and store.rollback(), without introducing two new ad-hoc APIs (e.g. Store.tpc_
=== modified file 'NEWS'
+- Add support for two-phase commits, using the DB API version 2.0, which
+ for now is only supported by psycopg2.
'for now is only supported by psycopg2' is better written as 'is only supported by PostgreSQL'. It isn't so much a driver issue, but that PostgreSQL is the only backend that provides the TPC feature... and not our fault :-)
=== modified file 'storm/store.py'
+ def begin(self, xid):
+ """Start a new two-phase transaction.
Should xid be an optional parameter, and we generate one using a UUID if it isn't provided? If we do make xid optional, the xid needs to be returned from this method. Optional parameter means people can be lazy, but this may not be a good thing as ideally your global transaction id should be shared between all the TPC participants, making it easier to resolve a failed TPC dance.
=== added file 'storm/xid.py' transaction_ id, branch_qualifier): transaction_ id = global_ transaction_ id qualifier = branch_qualifier
+class Xid(object):
+ """
+ Represent a transaction identifier compliant with the XA specification.
+ """
+
+ def __init__(self, format_id, global_
+ self.format_id = format_id
+ self.global_
+ self.branch_
Should any or all of the constructor's parameters be optional?
=== modified file 'storm/ zope/zstorm. py'
+from random import randint
+ if global_ transaction_ id is None: transaction_ id = "_storm_%032x" % randint(0, 2 ** 128) transaction_ id__ = global_ transaction_ id
+ # The the global transaction doesn't have an ID yet, let's create
+ # one in a way that it will be unique
+ global_
+ txn.__storm_
You should be using a UUID here rather than randint. Random methods try to provide a random distribution. UUIDs guarantee (as much as possible) to provide unique value. We are after the UUID behavior here.
+ xid = Xid(0, global_ transaction_ id, zstorm. get_name( store))
+ store.begin(xid)
This seems good. We get a unique global transaction id each transaction that is shared between stores, helping us result transactions lost during TPC failure. I think store names will always be valid XID components, but we might want to check this. In any case, psycopg2 should raise an exception if it is given invalid input and it is nice we have a meaningful name.
The commit/tpc_* method changes look correct for PostgreSQL. However, for backends that don't support TPC we are moving the actual commit from happening in the commit() method to the tpc_finish() method. This is not ideal, but maybe it is good enough.
The use case here is if your application is mixing PostgreSQL and SQLLite. Provided you have only a single SQLLite Store, you can actually get TPC reliability. You first need to prepare() all TPC capable backends, then commit() the single TPC incapable backend, then tpc_commit() the TPC capable backends.
I think we can do this easily enough if we added an attribute to the Store that lets us check if that Store is TPC capable. We then change the sortKey in zstorm.py to list TPC capable Stores first in the commit order, and then adjust the logic in the commit/tpc_* methods to only c...