sider.transaction — Transaction handling

Every Persist object provided by Sider can be used within transactions. You can atomically commit multiple operations.

Under the hood, transaction blocks are simply looped until objects the transaction deals with haven’t been faced any conflicts with other sessions/transactions. If there are no concurrent touches to names in the following transaction:

def block(trial, transaction):
    names.append(new_name)
session.transaction(block)

it will be successfully committed. Otherwise, it retries the whole transaction block. You can easily prove this by just printing trial (the first argument of the block function) inside the transaction block. It will print one or more retrial counting numbers.

This means you shouldn’t do I/O in the transaction block. Your I/O could be executed two or more times. Do I/O after or before transaction blocks instead.

There are two properties of every operation: query() or manipulative() or both. For example, Hash.get() method is a query operation. On the other hand, Set.add() method is manipulative. There is a rule of transaction: query operations can’t be used after manipulative operations. For example, the following transaction block has no problem:

# Atomically wraps an existing string value of the specific
# key of a hash.
hash_ = session.get('my_hash', Hash)
def block(trial, transaction):
    current_value = hash_['my_key']  # [query operation]
    updated_value = '(' + current_value + ')'
    hash_['my_key'] = updated_value  # [manipulative operation]
session.transaction(block)

while the following raises a CommitError:

hash_ = session.get('my_hash', Hash)
def block(trial, transaction):
    current_value = hash_['my_key']   # [query operation]
    updated_value = '(' + current_value + ')'
    hash_['my_key'] = updated_value   # [manipulative operation]
    # The following statement raises CommitError because
    # it contains a query operation.
    current_value2 = hash_['my_key2'] # [query operation]
    updated_value2 = '(' + current_value2 + ')'
    hash_['my_key'] = updated_value2  # [manipulative operation]
session.transaction(block)

See also

Redis Transactions
The Redis documentation that explains about its transactions.
class sider.transaction.Transaction(session, keys=frozenset([]))

Transaction block.

Parameters:
__call__(block, keys=frozenset([]), ignore_double=False)

Executes a block in the transaction:

def block(trial, transaction):
    list_[0] = list_[0].upper()
transaction(block)
Parameters:
  • block (collections.Callable) – a function to execute in a transaction. see the signature explained in the below: block()
  • keys (collections.Iterable) – a list of keys to watch
  • ignore_double (bool) – don’t raise any error even if any transaction has already being executed for a session. default is False
Raises sider.exceptions.DoubleTransactionError:
 

when any transaction has already being executed for a session and ignore_double is False

block(trial, transaction)
Parameters:
__iter__()

You can more explictly execute (and retry) a routine in the transaction than using __call__().

It returns a generator that yields an integer which represents its (re)trial count (from 0) until the transaction doesn’t face ConflictError.

For example:

for trial in transaction:
    list_[0] = list_[0].upper()
Raises sider.exceptions.DoubleTransactionError:
 when any transaction has already being executed for a session
__weakref__

list of weak references to the object (if defined)

begin_commit(_stacklevel=1)

Explicitly marks the transaction beginning to commit from this. From this to end of a transaction, any query operations will raise CommitError.

format_commit_stack(indent=4, title='Traceback of previous begin_commit() call:')

Makes commit_stack text readable. If its session.verbose_transaction_error is not True, it will simply return an empty string.

Parameters:
  • indent (numbers.Integral) – the number of space character for indentation. default is 4
  • title (basestring) – the title string of the formatted traceback. optional
Returns:

the formatted commit_stack text

Return type:

basestring

Note

It’s totally for internal use.

format_enter_stack(indent=4, title='Traceback where the transaction entered:')

Makes enter_stack text readable. If its session.verbose_transaction_error is not True, it will simply return an empty string.

Parameters:
  • indent (numbers.Integral) – the number of space character for indentation. default is 4
  • title (basestring) – the title string of the formatted traceback. optional
Returns:

the formatted enter_stack text

Return type:

basestring

Note

It’s totally for internal use.

watch(keys, initialize=False)

Watches more keys.

Parameters:
  • keys (collections.Iterable) – a set of keys to watch more
  • initialize (bool) – initializes the set of watched keys if it is True. default is False. option only for internal use
sider.transaction.manipulative(function)

The decorator that marks the method manipulative.

Parameters:function (collections.Callable) – the method to mark
Returns:the marked method
Return type:collections.Callable
sider.transaction.query(function)

The decorator that marks the method query.

Parameters:function (collections.Callable) – the method to mark
Returns:the marked method
Return type:collections.Callable