interfaces.py 14.4 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439
##############################################################################
#
# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""Transaction Interfaces

$Id$
"""

import zope.interface

class IResourceManager(zope.interface.Interface):
    """Objects that manage resources transactionally.

    These objects may manage data for other objects, or they may manage
    non-object storages, such as relational databases.

    IDataManagerOriginal is the interface currently provided by ZODB
    database connections, but the intent is to move to the newer
    IDataManager.
    """

    # Two-phase commit protocol.  These methods are called by the
    # ITransaction object associated with the transaction being
    # committed.

    def tpc_begin(transaction):
        """Begin two-phase commit, to save data changes.

        An implementation should do as much work as possible without
        making changes permanent.  Changes should be made permanent
        when tpc_finish is called (or aborted if tpc_abort is called).
        The work can be divided between tpc_begin() and tpc_vote(), and
        the intent is that tpc_vote() be as fast as possible (to minimize
        the period of uncertainty).

        transaction is the ITransaction instance associated with the
        transaction being committed.
        """

    def tpc_vote(transaction):
        """Verify that a resource manager can commit the transaction.

        This is the last chance for a resource manager to vote 'no'.  A
        resource manager votes 'no' by raising an exception.

        transaction is the ITransaction instance associated with the
        transaction being committed.
        """

    def tpc_finish(transaction):
        """Indicate confirmation that the transaction is done.

        transaction is the ITransaction instance associated with the
        transaction being committed.

        This should never fail. If this raises an exception, the
        database is not expected to maintain consistency; it's a
        serious error.
        """

    def tpc_abort(transaction):
        """Abort a transaction.

        transaction is the ITransaction instance associated with the
        transaction being committed.

        All changes made by the current transaction are aborted.  Note
        that this includes all changes stored in any savepoints that may
        be associated with the current transaction.

        tpc_abort() can be called at any time, either in or out of the
        two-phase commit.

        This should never fail.
        """

    # The savepoint/rollback API.

    def savepoint(transaction):
        """Save partial transaction changes.

        There are two purposes:

        1) To allow discarding partial changes without discarding all
           dhanges.

        2) To checkpoint changes to disk that would otherwise live in
           memory for the duration of the transaction.

        Returns an object implementing ISavePoint2 that can be used
        to discard changes made since the savepoint was captured.

        An implementation that doesn't support savepoints should implement
        this method by returning a savepoint object that raises an
        exception when its rollback method is called.  The savepoint method
        shouldn't raise an error.  This way, transactions that create
        savepoints can proceed as long as an attempt is never made to roll
        back a savepoint.
        """

    def discard(transaction):
        """Discard changes within the transaction since the last savepoint.

        That means changes made since the last savepoint if one exists, or
        since the start of the transaction.
        """

class IDataManagerOriginal(zope.interface.Interface):
    """Objects that manage transactional storage.

    These objects may manage data for other objects, or they may manage
    non-object storages, such as relational databases.

    IDataManagerOriginal is the interface currently provided by ZODB
    database connections, but the intent is to move to the newer
    IDataManager.
    """

    def abort_sub(transaction):
        """Discard all subtransaction data.

        See subtransaction.txt

        This is called when top-level transactions are aborted.

        No further subtransactions can be started once abort_sub()
        has been called; this is only used when the transaction is
        being aborted.

        abort_sub also implies the abort of a 2-phase commit.

        This should never fail.
        """

    def commit_sub(transaction):
        """Commit all changes made in subtransactions and begin 2-phase commit

        Data are saved *as if* they are part of the current transaction.
        That is, they will not be persistent unless the current transaction
        is committed.

        This is called when the current top-level transaction is committed.

        No further subtransactions can be started once commit_sub()
        has been called; this is only used when the transaction is
        being committed.

        This call also implied the beginning of 2-phase commit.
        """

    # Two-phase commit protocol.  These methods are called by the
    # ITransaction object associated with the transaction being
    # committed.

    def tpc_begin(transaction, subtransaction=False):
        """Begin commit of a transaction, starting the two-phase commit.

        transaction is the ITransaction instance associated with the
        transaction being committed.

        subtransaction is a Boolean flag indicating whether the
        two-phase commit is being invoked for a subtransaction.

        Important note: Subtransactions are modelled in the sense that
        when you commit a subtransaction, subsequent commits should be
        for subtransactions as well.  That is, there must be a
        commit_sub() call between a tpc_begin() call with the
        subtransaction flag set to true and a tpc_begin() with the
        flag set to false.

        """


    def tpc_abort(transaction):
        """Abort a transaction.

        This is always called after a tpc_begin call.

        transaction is the ITransaction instance associated with the
        transaction being committed.

        This should never fail.
        """

    def tpc_finish(transaction):
        """Indicate confirmation that the transaction is done.

        transaction is the ITransaction instance associated with the
        transaction being committed.

        This should never fail. If this raises an exception, the
        database is not expected to maintain consistency; it's a
        serious error.

        """

    def tpc_vote(transaction):
        """Verify that a data manager can commit the transaction

        This is the last chance for a data manager to vote 'no'.  A
        data manager votes 'no' by raising an exception.

        transaction is the ITransaction instance associated with the
        transaction being committed.
        """

    def commit(object, transaction):
        """CCCommit changes to an object

        Save the object as part of the data to be made persistent if
        the transaction commits.
        """

    def abort(object, transaction):
        """Abort changes to an object

        Only changes made since the last transaction or
        sub-transaction boundary are discarded.

        This method may be called either:

        o Outside of two-phase commit, or

        o In the first phase of two-phase commit

        """

class IDataManager(zope.interface.Interface):
    """Data management interface for storing objects transactionally.

    ZODB database connections currently provides the older
    IDataManagerOriginal interface, but the intent is to move to this newer
    IDataManager interface.

    Our hope is that this interface will evolve and become the standard
    interface.  There are some issues to be resolved first, like:

    - Probably want separate abort methods for use in and out of
      two-phase commit.

    - The savepoint api may need some more thought.

    """

    def prepare(transaction):
        """Perform the first phase of a 2-phase commit

        The data manager prepares for commit any changes to be made
        persistent.  A normal return from this method indicated that
        the data manager is ready to commit the changes.

        The data manager must raise an exception if it is not prepared
        to commit the transaction after executing prepare().

        The transaction must match that used for preceeding
        savepoints, if any.
        """

        # This is equivalent to zodb3's tpc_begin, commit, and
        # tpc_vote combined.

    def abort(transaction):
        """Abort changes made by transaction

        This may be called before two-phase commit or in the second
        phase of two-phase commit.

        The transaction must match that used for preceeding
        savepoints, if any.

        """

        # This is equivalent to *both* zodb3's abort and tpc_abort
        # calls. This should probably be split into 2 methods.

    def commit(transaction):
        """Finish two-phase commit

        The prepare method must be called, with the same transaction,
        before calling commit.

        """

        # This is equivalent to zodb3's tpc_finish

    def savepoint(transaction):
        """Do tentative commit of changes to this point.

        Should return an object implementing IRollback that can be used
        to rollback to the savepoint.

        Note that (unlike zodb3) this doesn't use a 2-phase commit
        protocol.  If this call fails, or if a rollback call on the
        result fails, the (containing) transaction should be
        aborted.  Aborting the containing transaction is *not* the
        responsibility of the data manager, however.

        An implementation that doesn't support savepoints should
        implement this method by returning a rollback implementation
        that always raises an error when it's rollback method is
        called. The savepoing method shouldn't raise an error. This
        way, transactions that create savepoints can proceed as long
        as an attempt is never made to roll back a savepoint.

        """

class ITransaction(zope.interface.Interface):
    """Object representing a running transaction.

    Objects with this interface may represent different transactions
    during their lifetime (.begin() can be called to start a new
    transaction using the same instance).
    """

    user = zope.interface.Attribute(
        "user",
        "The name of the user on whose behalf the transaction is being\n"
        "performed.  The format of the user name is defined by the\n"
        "application.")
    # XXX required to be a string?

    description = zope.interface.Attribute(
        "description",
        "Textual description of the transaction.")

    def begin(info=None, subtransaction=None):
        """Begin a new transaction.

        If the transaction is in progress, it is aborted and a new
        transaction is started using the same transaction object.
        """

    def commit(subtransaction=None):
        """Finalize the transaction.

        This executes the two-phase commit algorithm for all
        IDataManager objects associated with the transaction.
        """

    def abort(subtransaction=0, freeme=1):
        """Abort the transaction.

        This is called from the application.  This can only be called
        before the two-phase commit protocol has been started.
        """

    def join(datamanager):
        """Add a datamanager to the transaction.

        The datamanager must implement the
        transactions.interfaces.IDataManager interface, and be
        adaptable to ZODB.interfaces.IDataManager.
        """

    def register(object):
        """Register the given object for transaction control."""

    def note(text):
        """Add text to the transaction description.

        If a description has already been set, text is added to the
        end of the description following two newline characters.
        Surrounding whitespace is stripped from text.
        """
        # XXX does impl do the right thing with ''?  Not clear what
        # the "right thing" is.

    def setUser(user_name, path="/"):
        """Set the user name.

        path should be provided if needed to further qualify the
        identified user.
        """

    def setExtendedInfo(name, value):
        """Add extension data to the transaction.

        name is the name of the extension property to set; value must
        be a picklable value.

        Storage implementations may limit the amount of extension data
        which can be stored.
        """
        # XXX is this this allowed to cause an exception here, during
        # the two-phase commit, or can it toss data silently?

class ISavePoint(zope.interface.Interface):
    """ISavePoint objects represent partial transaction changes.

    Sequences of savepoint objects are associated with transactions,
    and with IResourceManagers.
    """

    def rollback():
        """Discard changes made after this savepoint.

        This includes discarding (call the discard method on) all
        subsequent savepoints.
        """

    def discard():
        """Discard changes saved by this savepoint.

        That means changes made since the immediately preceding
        savepoint if one exists, or since the start of the transaction,
        until this savepoint.

        Once a savepoint has been discarded, it's an error to attempt
        to rollback or discard it again.
        """

    next_savepoint = zope.interface.Attribute(
        """The next savepoint (later in time), or None if self is the
           most recent savepoint.""")

class IRollback(zope.interface.Interface):

    def rollback():
        """Rollback changes since savepoint.

        IOW, rollback to the last savepoint.

        It is an error to rollback to a savepoint if:

        - An earlier savepoint within the same transaction has been
          rolled back to, or

        - The transaction has ended.
        """