Browse Source

Merge "Quota: Fix multiple race conditions"

changes/03/784603/1
Zuul 7 months ago
committed by Gerrit Code Review
parent
commit
393c2e4ad9
  1. 42
      cinder/db/sqlalchemy/api.py

42
cinder/db/sqlalchemy/api.py

@ -1338,6 +1338,13 @@ def _dict_with_usage_id(usages):
def reservation_commit(context, reservations, project_id=None):
session = get_session()
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(
context, session, project_id,
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):
session = get_session()
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(
context, session, project_id,
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()
with session.begin():
quotas = model_query(context, models.Quota, session=session,
read_deleted="no").\
model_query(context, models.Quota, session=session,
read_deleted="no").\
filter_by(project_id=project_id).\
all()
for quota_ref in quotas:
quota_ref.delete(session=session)
update(models.Quota.delete_values())
if only_quotas:
return
quota_usages = model_query(context, models.QuotaUsage,
session=session, read_deleted="no").\
model_query(context, models.QuotaUsage, session=session,
read_deleted="no").\
filter_by(project_id=project_id).\
all()
update(models.QuotaUsage.delete_values())
for quota_usage_ref in quota_usages:
quota_usage_ref.delete(session=session)
reservations = model_query(context, models.Reservation,
session=session, read_deleted="no").\
model_query(context, models.Reservation, session=session,
read_deleted="no").\
filter_by(project_id=project_id).\
all()
for reservation_ref in reservations:
reservation_ref.delete(session=session)
update(models.Reservation.delete_values())
@require_admin_context
@ -1435,6 +1440,7 @@ def reservation_expire(context):
results = model_query(context, models.Reservation, session=session,
read_deleted="no").\
filter(models.Reservation.expire < current_time).\
with_for_update().\
all()
if results:

Loading…
Cancel
Save