Merge "Quota: Fix multiple race conditions"

This commit is contained in:
Zuul 2021-04-02 08:10:08 +00:00 committed by Gerrit Code Review
commit 393c2e4ad9
1 changed files with 24 additions and 18 deletions

View File

@ -1338,6 +1338,13 @@ def _dict_with_usage_id(usages):
def reservation_commit(context, reservations, project_id=None): def reservation_commit(context, reservations, project_id=None):
session = get_session() session = get_session()
with session.begin(): with session.begin():
# NOTE: There's a potential race condition window with
# reservation_expire, since _get_reservation_resources does not lock
# the rows, but we won't fix it because:
# - Minuscule chance of happening, since quota expiration is usually
# very high
# - Solution could create a DB lock on rolling upgrades since we need
# to reverse the order of locking the rows.
usages = _get_quota_usages( usages = _get_quota_usages(
context, session, project_id, context, session, project_id,
resources=_get_reservation_resources(session, context, resources=_get_reservation_resources(session, context,
@ -1363,6 +1370,13 @@ def reservation_commit(context, reservations, project_id=None):
def reservation_rollback(context, reservations, project_id=None): def reservation_rollback(context, reservations, project_id=None):
session = get_session() session = get_session()
with session.begin(): with session.begin():
# NOTE: There's a potential race condition window with
# reservation_expire, since _get_reservation_resources does not lock
# the rows, but we won't fix it because:
# - Minuscule chance of happening, since quota expiration is usually
# very high
# - Solution could create a DB lock on rolling upgrades since we need
# to reverse the order of locking the rows.
usages = _get_quota_usages( usages = _get_quota_usages(
context, session, project_id, context, session, project_id,
resources=_get_reservation_resources(session, context, resources=_get_reservation_resources(session, context,
@ -1398,32 +1412,23 @@ def quota_destroy_all_by_project(context, project_id, only_quotas=False):
""" """
session = get_session() session = get_session()
with session.begin(): with session.begin():
quotas = model_query(context, models.Quota, session=session, model_query(context, models.Quota, session=session,
read_deleted="no").\ read_deleted="no").\
filter_by(project_id=project_id).\ filter_by(project_id=project_id).\
all() update(models.Quota.delete_values())
for quota_ref in quotas:
quota_ref.delete(session=session)
if only_quotas: if only_quotas:
return return
quota_usages = model_query(context, models.QuotaUsage, model_query(context, models.QuotaUsage, session=session,
session=session, read_deleted="no").\ read_deleted="no").\
filter_by(project_id=project_id).\ filter_by(project_id=project_id).\
all() update(models.QuotaUsage.delete_values())
for quota_usage_ref in quota_usages: model_query(context, models.Reservation, session=session,
quota_usage_ref.delete(session=session) read_deleted="no").\
reservations = model_query(context, models.Reservation,
session=session, read_deleted="no").\
filter_by(project_id=project_id).\ filter_by(project_id=project_id).\
all() update(models.Reservation.delete_values())
for reservation_ref in reservations:
reservation_ref.delete(session=session)
@require_admin_context @require_admin_context
@ -1435,6 +1440,7 @@ def reservation_expire(context):
results = model_query(context, models.Reservation, session=session, results = model_query(context, models.Reservation, session=session,
read_deleted="no").\ read_deleted="no").\
filter(models.Reservation.expire < current_time).\ filter(models.Reservation.expire < current_time).\
with_for_update().\
all() all()
if results: if results: