def _begin(self, transaction): # This function is called when PJDataManager joins transaction. When # two phase commit is requested, we will assign transaction id to # underlying connection. if not PJ_TWO_PHASE_COMMIT_ENABLED: # We don't need to do anything special when two phase commit is # disabled. Transaction starts automatically. return assert self._pristine, ("Error attempting to add data manager " "from old transaction. Create a new " "PJDataManager for new transaction, do not " "modify objects from previously committed " "transactions") self._pristine = False # Create a global id for the transaction. If it wasn't yet created, # create now. try: txnid = transaction.data(PREPARED_TRANSACTION_ID) except KeyError: txnid = str(uuid.uuid4()) transaction.set_data(PREPARED_TRANSACTION_ID, txnid) try: xid = self._conn.xid(0, txnid, self.database) self._conn.tpc_begin(xid) except psycopg2.Error as e: check_for_disconnect(e, 'PJDataManager._begin') raise self._tpc_activated = True
def commit(self, transaction): """Commit changes to an object""" transaction = transaction.data(self) if self._savepoint_storage is not None: # We first checkpoint the current changes to the savepoint self.savepoint() # then commit all of the savepoint changes at once self._commit_savepoint(transaction) # No need to call _commit since savepoint did. else: self._commit(transaction) for oid, serial in six.iteritems(self._readCurrent): try: self._storage.checkCurrentSerialInTransaction( oid, serial, transaction) except ConflictError: self._cache.invalidate(oid) raise
def tpc_finish(self, transaction): """Indicate confirmation that the transaction is done. """ transaction = transaction.data(self) serial = self._storage.tpc_finish(transaction) assert type(serial) is bytes, repr(serial) for oid_iterator in self._modified, self._creating: for oid in oid_iterator: obj = self._cache.get(oid) # Ignore missing objects and don't update ghosts. if obj is not None and obj._p_changed is not None: obj._p_changed = 0 obj._p_serial = serial self._tpc_cleanup()
def tpc_vote(self, transaction): """Verify that a data manager can commit the transaction.""" try: vote = self._storage.tpc_vote except AttributeError: return transaction = transaction.data(self) try: s = vote(transaction) except ReadConflictError as v: if v.oid: self._cache.invalidate(v.oid) raise if s: # Resolved conflicts. for oid in s: obj = self._cache.get(oid) if obj is not None: del obj._p_changed # transition from changed to ghost
def tpc_abort(self, transaction): transaction = transaction.data(self) if self._import: self._import = None if self._savepoint_storage is not None: self._abort_savepoint() self._storage.tpc_abort(transaction) # Note: If we invalidate a non-ghostifiable object (i.e. a # persistent class), the object will immediately reread its # state. That means that the following call could result in a # call to self.setstate, which, of course, must succeed. In # general, it would be better if the read could be delayed # until the start of the next transaction. If we read at the # end of a transaction and if the object was invalidated # during this transaction, then we'll read non-current data, # which we'll discard later in transaction finalization. We # could, theoretically queue this invalidation by calling # self.invalidate. Unfortunately, attempts to make that # change resulted in mysterious test failures. It's pretty # unlikely that the object we are invalidating was invalidated # by another thread, so the risk of a reread is pretty low. # It's really not worth the effort to pursue this. self._cache.invalidate(self._modified) self._invalidate_creating() while self._added: oid, obj = self._added.popitem() if obj._p_changed: obj._p_changed = False del obj._p_oid del obj._p_jar self._tpc_cleanup()
def tpc_abort(self, transaction): try: transaction = transaction.data(self) self._storage.tpc_abort(transaction) finally: self.close()
def tpc_vote(self, transaction): transaction = transaction.data(self) self._storage.tpc_vote(transaction)
def tpc_finish(self, transaction): transaction = transaction.data(self) self._storage.tpc_finish(transaction)
def commit(self, transaction): transaction = transaction.data(self) for tid in self._tids: self._storage.undo(tid, transaction)
def tpc_abort(self, transaction): transaction = transaction.data(self) self._storage.tpc_abort(transaction)