cinder dbapiのsqlalchemyトランザクションロック管理

2162 ワード

頻繁に同時操作が必要なテーブルに対して、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関数としてのコメントラベルです[email protected](f)とfunctools.update_wrapper(wrapped,f)は、注釈される方法を__保持するためであるname__ および_doc__ などのプロパティについては、「Python-ステップアップ-functoolsモジュールのまとめ」を参照してください.