Skip to content

k3txutil

Action-CI Documentation Status Package

Compare-and-swap (CAS) loop utilities for implementing transactional operations with optimistic concurrency control.

k3txutil is a component of pykit3 project: a python3 toolkit set.

Installation

pip install k3txutil

Quick Start

import k3txutil

# Simple counter with CAS
data = {'value': 0, 'version': 0}

def getter():
    return data['value'], data['version']

def setter(new_val, old_version):
    if data['version'] != old_version:
        raise k3txutil.CASConflict()
    data['value'] = new_val
    data['version'] += 1

# Increment with retry on conflict
for rec in k3txutil.cas_loop(getter, setter):
    rec.v += 1

API Reference

k3txutil

Name

txutil

Status

This library is considered production ready.

Description

A collection of helper functions to implement transactional operations.

Exceptions

CASConflict

syntax: CASConflict()

User should raise this exception when a CAS conflict detect in a user defined set function.

CASConflict

Bases: CASError

User should raise this exception when a CAS conflict detect in a user defined set function.

Source code in k3txutil/txutil.py
15
16
17
18
19
20
21
class CASConflict(CASError):
    """
    User should raise this exception when a CAS conflict detect in a user defined
    `set` function.
    """

    pass

cas_loop(getter, setter, args=(), kwargs=None, conflicterror=CASConflict)

The loop body runs several times until a successful update is made(setter returns True). :param getter: is a callable receiving one argument and returns a tuple of (value, stat) stat is any object that will be send back to setter for it to check whether stat changed after getter called. :param setter: is a callable to check and set the changed value. :param args and kwargs: optional positioned arguments and key-value arguments that will be passed to getter and setter By default it is an empty tuple () and None. :param conflicterror: specifies what raised error indicating a CAS conflict, instead of using the default CASConflict. :return: a generator that yields a CASRecord for user to update its attribute v. If a user modifies v, an attempt to update by calling setter will be made.

If the update succeeds, the generator quits.

If the update detects a conflict, it yields a new CASRecord and repeat the update.

Source code in k3txutil/txutil.py
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
def cas_loop(getter, setter, args=(), kwargs=None, conflicterror=CASConflict):
    """
    The loop body runs several times until a successful update is made(`setter` returns `True`).
    :param getter: is a `callable` receiving one argument and returns a tuple of `(value, stat)`
    `stat` is any object that will be send back to `setter` for it to check
    whether stat changed after `getter` called.
    :param setter: is a `callable` to check and set the changed value.
    :param args and kwargs: optional positioned arguments and key-value arguments that will be
    passed to `getter` and `setter`
    By default it is an empty tuple `()` and `None`.
    :param conflicterror: specifies what raised error indicating a CAS conflict, instead of
    using the default `CASConflict`.
    :return:
    a `generator` that yields a `CASRecord` for user to update its attribute `v`.
    If a user modifies `v`, an attempt to update by calling `setter`  will be made.

    If the update succeeds, the `generator` quits.

    If the update detects a conflict, it yields a new `CASRecord` and repeat the
    update.
    """
    if kwargs is None:
        kwargs = {}

    i = -1
    while True:
        i += 1

        val, stat = getter(*args, **kwargs)
        rec = CASRecord(copy.deepcopy(val), stat, i)

        yield rec

        if rec.v == val:
            # nothing to update
            return

        try:
            setter(*(args + (rec.v, rec.stat)), **kwargs)
            return
        except conflicterror as e:
            logger.info(repr(e) + " while cas set")
            continue

License

The MIT License (MIT) - Copyright (c) 2015 Zhang Yanpo (张炎泼)