cinder dbapi中的 sqlalchemy 事务锁 管理

对需要经常并发操作的表,sqlalchemy可以加锁保证数据一致性,with_lockmode('update')

with_lockmode(mode) 可选mode参数说明:

mode 参数 说明
None translates to no lockmode
'update' translates to FOR UPDATE (standard SQL, supported by most dialects)
'update_nowait' translates to FOR UPDATE NOWAIT (supported by Oracle, PostgreSQL 8.1 upwards)
'read' translates to LOCK IN SHARE MODE (for MySQL), and FOR SHARE (for PostgreSQL)
def _get_quota_usages(context, session, project_id):
    # Broken out for testability
    rows = model_query(context, models.QuotaUsage,
                       read_deleted="no",
                       session=session). \
        filter_by(project_id=project_id). \
        order_by(models.QuotaUsage.id.asc()). \
        with_lockmode('update'). \
        all()
    return {row.resource: row for row in rows}

cinder dbapi里处理死锁的方法,_retry_on_deadlock(f)

def _retry_on_deadlock(f):
    """Decorator to retry a DB API call if Deadlock was received."""

    @functools.wraps(f)
    def wrapped(*args, **kwargs):
        while True:
            try:
                return f(*args, **kwargs)
            except db_exc.DBDeadlock:
                LOG.warning(_LW("Deadlock detected when running "
                                "'%(func_name)s': Retrying..."),
                            dict(func_name=f.__name__))
                # Retry!
                time.sleep(0.5)
                continue

    functools.update_wrapper(wrapped, f)
    return wrapped
    
    
@require_context
@_retry_on_deadlock
def reservation_commit(context, reservations, project_id=None):
    

_retry_on_deadlock(f)逻辑简单,即抓到死锁异常db_exc.DBDeadlock,则过0.5秒后重新执行。调用方法是作为db函数的注释标签。
@functools.wraps(f)和functools.update_wrapper(wrapped, f)是为了让被注释的方法保持 __name__ 和 __doc__ 等属性,相关介绍参考 《Python-进阶-functools模块小结》

你可能感兴趣的:(cinder dbapi中的 sqlalchemy 事务锁 管理)