Use one query instead of two for quota_usages

The second query was unnecessary and not using a proper index. It
seemed to be contributing to a deadlock issue as well.

Change-Id: I1031451b25140d71380c8149d3c83827eec0d4a9
Closes-Bug: #1308715
Co-Authored-by: Chris Behrens <cbehrens@codestud.com>
This commit is contained in:
Vishvananda Ishaya 2014-04-16 13:41:17 -07:00
parent 0e080bdcdb
commit da1fa5dc93
2 changed files with 25 additions and 41 deletions

View File

@ -3030,38 +3030,26 @@ def _reservation_create(context, uuid, usage, project_id, user_id, resource,
# code always acquires the lock on quota_usages before acquiring the lock # code always acquires the lock on quota_usages before acquiring the lock
# on reservations. # on reservations.
def _get_user_quota_usages(context, session, project_id, user_id): def _get_project_user_quota_usages(context, session, project_id,
# Broken out for testability user_id):
rows = model_query(context, models.QuotaUsage,
read_deleted="no",
session=session).\
filter_by(project_id=project_id).\
filter(or_(models.QuotaUsage.user_id == user_id,
models.QuotaUsage.user_id == None)).\
with_lockmode('update').\
all()
return dict((row.resource, row) for row in rows)
def _get_project_quota_usages(context, session, project_id):
rows = model_query(context, models.QuotaUsage, rows = model_query(context, models.QuotaUsage,
read_deleted="no", read_deleted="no",
session=session).\ session=session).\
filter_by(project_id=project_id).\ filter_by(project_id=project_id).\
with_lockmode('update').\ with_lockmode('update').\
all() all()
result = dict() proj_result = dict()
user_result = dict()
# Get the total count of in_use,reserved # Get the total count of in_use,reserved
for row in rows: for row in rows:
if row.resource in result: proj_result.setdefault(row.resource,
result[row.resource]['in_use'] += row.in_use dict(in_use=0, reserved=0, total=0))
result[row.resource]['reserved'] += row.reserved proj_result[row.resource]['in_use'] += row.in_use
result[row.resource]['total'] += (row.in_use + row.reserved) proj_result[row.resource]['reserved'] += row.reserved
else: proj_result[row.resource]['total'] += (row.in_use + row.reserved)
result[row.resource] = dict(in_use=row.in_use, if row.user_id is None or row.user_id == user_id:
reserved=row.reserved, user_result[row.resource] = row
total=row.in_use + row.reserved) return proj_result, user_result
return result
@require_context @require_context
@ -3079,10 +3067,8 @@ def quota_reserve(context, resources, project_quotas, user_quotas, deltas,
user_id = context.user_id user_id = context.user_id
# Get the current usages # Get the current usages
user_usages = _get_user_quota_usages(context, session, project_usages, user_usages = _get_project_user_quota_usages(
project_id, user_id) context, session, project_id, user_id)
project_usages = _get_project_quota_usages(context, session,
project_id)
# Handle usage refresh # Handle usage refresh
work = set(deltas.keys()) work = set(deltas.keys())
@ -3291,11 +3277,12 @@ def _quota_reservations_query(session, context, reservations):
def reservation_commit(context, reservations, project_id=None, user_id=None): def reservation_commit(context, reservations, project_id=None, user_id=None):
session = get_session() session = get_session()
with session.begin(): with session.begin():
usages = _get_user_quota_usages(context, session, project_id, user_id) _project_usages, user_usages = _get_project_user_quota_usages(
context, session, project_id, user_id)
reservation_query = _quota_reservations_query(session, context, reservation_query = _quota_reservations_query(session, context,
reservations) reservations)
for reservation in reservation_query.all(): for reservation in reservation_query.all():
usage = usages[reservation.resource] usage = user_usages[reservation.resource]
if reservation.delta >= 0: if reservation.delta >= 0:
usage.reserved -= reservation.delta usage.reserved -= reservation.delta
usage.in_use += reservation.delta usage.in_use += reservation.delta
@ -3307,11 +3294,12 @@ def reservation_commit(context, reservations, project_id=None, user_id=None):
def reservation_rollback(context, reservations, project_id=None, user_id=None): def reservation_rollback(context, reservations, project_id=None, user_id=None):
session = get_session() session = get_session()
with session.begin(): with session.begin():
usages = _get_user_quota_usages(context, session, project_id, user_id) _project_usages, user_usages = _get_project_user_quota_usages(
context, session, project_id, user_id)
reservation_query = _quota_reservations_query(session, context, reservation_query = _quota_reservations_query(session, context,
reservations) reservations)
for reservation in reservation_query.all(): for reservation in reservation_query.all():
usage = usages[reservation.resource] usage = user_usages[reservation.resource]
if reservation.delta >= 0: if reservation.delta >= 0:
usage.reserved -= reservation.delta usage.reserved -= reservation.delta
reservation_query.soft_delete(synchronize_session=False) reservation_query.soft_delete(synchronize_session=False)

View File

@ -2161,11 +2161,9 @@ class QuotaReserveSqlAlchemyTestCase(test.TestCase):
def fake_get_session(): def fake_get_session():
return FakeSession() return FakeSession()
def fake_get_project_quota_usages(context, session, project_id): def fake_get_project_user_quota_usages(context, session, project_id,
return self.usages.copy() user_id):
return self.usages.copy(), self.usages.copy()
def fake_get_user_quota_usages(context, session, project_id, user_id):
return self.usages.copy()
def fake_quota_usage_create(context, project_id, user_id, resource, def fake_quota_usage_create(context, project_id, user_id, resource,
in_use, reserved, until_refresh, in_use, reserved, until_refresh,
@ -2190,10 +2188,8 @@ class QuotaReserveSqlAlchemyTestCase(test.TestCase):
return reservation_ref return reservation_ref
self.stubs.Set(sqa_api, 'get_session', fake_get_session) self.stubs.Set(sqa_api, 'get_session', fake_get_session)
self.stubs.Set(sqa_api, '_get_project_quota_usages', self.stubs.Set(sqa_api, '_get_project_user_quota_usages',
fake_get_project_quota_usages) fake_get_project_user_quota_usages)
self.stubs.Set(sqa_api, '_get_user_quota_usages',
fake_get_user_quota_usages)
self.stubs.Set(sqa_api, '_quota_usage_create', fake_quota_usage_create) self.stubs.Set(sqa_api, '_quota_usage_create', fake_quota_usage_create)
self.stubs.Set(sqa_api, '_reservation_create', fake_reservation_create) self.stubs.Set(sqa_api, '_reservation_create', fake_reservation_create)