Merge "Add retry for DBDeadlock in credential delete" into stable/stein
This commit is contained in:
commit
918aa07eed
|
@ -12,6 +12,8 @@
|
||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
|
from oslo_db import api as oslo_db_api
|
||||||
|
|
||||||
from keystone.common import driver_hints
|
from keystone.common import driver_hints
|
||||||
from keystone.common import sql
|
from keystone.common import sql
|
||||||
from keystone.credential.backends import base
|
from keystone.credential.backends import base
|
||||||
|
@ -96,6 +98,7 @@ class Credential(base.CredentialDriverBase):
|
||||||
query = query.filter_by(project_id=project_id)
|
query = query.filter_by(project_id=project_id)
|
||||||
query.delete()
|
query.delete()
|
||||||
|
|
||||||
|
@oslo_db_api.wrap_db_retry(retry_on_deadlock=True)
|
||||||
def delete_credentials_for_user(self, user_id):
|
def delete_credentials_for_user(self, user_id):
|
||||||
with sql.session_for_write() as session:
|
with sql.session_for_write() as session:
|
||||||
query = session.query(CredentialModel)
|
query = session.query(CredentialModel)
|
||||||
|
|
|
@ -17,6 +17,8 @@ import json
|
||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
from keystoneclient.contrib.ec2 import utils as ec2_utils
|
from keystoneclient.contrib.ec2 import utils as ec2_utils
|
||||||
|
import mock
|
||||||
|
from oslo_db import exception as oslo_db_exception
|
||||||
from six.moves import http_client
|
from six.moves import http_client
|
||||||
from testtools import matchers
|
from testtools import matchers
|
||||||
|
|
||||||
|
@ -262,6 +264,38 @@ class CredentialTestCase(CredentialBaseTestCase):
|
||||||
'/credentials/%(credential_id)s' % {
|
'/credentials/%(credential_id)s' % {
|
||||||
'credential_id': self.credential['id']})
|
'credential_id': self.credential['id']})
|
||||||
|
|
||||||
|
def test_delete_credential_retries_on_deadlock(self):
|
||||||
|
patcher = mock.patch('sqlalchemy.orm.query.Query.delete',
|
||||||
|
autospec=True)
|
||||||
|
|
||||||
|
class FakeDeadlock(object):
|
||||||
|
def __init__(self, mock_patcher):
|
||||||
|
self.deadlock_count = 2
|
||||||
|
self.mock_patcher = mock_patcher
|
||||||
|
self.patched = True
|
||||||
|
|
||||||
|
def __call__(self, *args, **kwargs):
|
||||||
|
if self.deadlock_count > 1:
|
||||||
|
self.deadlock_count -= 1
|
||||||
|
else:
|
||||||
|
self.mock_patcher.stop()
|
||||||
|
self.patched = False
|
||||||
|
raise oslo_db_exception.DBDeadlock
|
||||||
|
|
||||||
|
sql_delete_mock = patcher.start()
|
||||||
|
side_effect = FakeDeadlock(patcher)
|
||||||
|
sql_delete_mock.side_effect = side_effect
|
||||||
|
|
||||||
|
try:
|
||||||
|
PROVIDERS.credential_api.delete_credentials_for_user(
|
||||||
|
user_id=self.user['id'])
|
||||||
|
finally:
|
||||||
|
if side_effect.patched:
|
||||||
|
patcher.stop()
|
||||||
|
|
||||||
|
# initial attempt + 1 retry
|
||||||
|
self.assertEqual(sql_delete_mock.call_count, 2)
|
||||||
|
|
||||||
def test_create_ec2_credential(self):
|
def test_create_ec2_credential(self):
|
||||||
"""Call ``POST /credentials`` for creating ec2 credential."""
|
"""Call ``POST /credentials`` for creating ec2 credential."""
|
||||||
blob, ref = unit.new_ec2_credential(user_id=self.user['id'],
|
blob, ref = unit.new_ec2_credential(user_id=self.user['id'],
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
---
|
||||||
|
fixes:
|
||||||
|
- |
|
||||||
|
[`bug 1840291 <https://bugs.launchpad.net/keystone/+bug/1840291>`_]
|
||||||
|
Adds retries for ``delete_credential_for_user`` method to avoid
|
||||||
|
DBDeadlocks when deleting large number of credentials concurrently.
|
Loading…
Reference in New Issue