Add caching of get_auth call in Swift

Should make calls significantly faster for our Swift customers

Fixes https://jira.prod.coreos.systems/browse/QS-39
This commit is contained in:
Joseph Schorr 2017-10-17 13:09:37 -04:00
parent dcec90649e
commit ffaff5a27e
2 changed files with 38 additions and 9 deletions

View file

@ -8,6 +8,8 @@ import hmac
import string import string
import logging import logging
import json import json
from cachetools import lru_cache
from _pyio import BufferedReader from _pyio import BufferedReader
from uuid import uuid4 from uuid import uuid4
@ -147,6 +149,14 @@ class SwiftStorage(BaseStorage):
logger.exception('Could not head object at path %s: %s', path, ex) logger.exception('Could not head object at path %s: %s', path, ex)
return None return None
@lru_cache(maxsize=1)
def _get_root_storage_url(self):
""" Returns the root storage URL for this Swift storage. Note that since this requires a call
to Swift, we cache the result of this function call.
"""
storage_url, _ = self._get_connection().get_auth()
return storage_url
def get_direct_download_url(self, object_path, request_ip=None, expires_in=60, requires_cors=False, head=False): def get_direct_download_url(self, object_path, request_ip=None, expires_in=60, requires_cors=False, head=False):
if requires_cors: if requires_cors:
return None return None
@ -155,17 +165,17 @@ class SwiftStorage(BaseStorage):
if not self._temp_url_key: if not self._temp_url_key:
return None return None
# Retrieve the auth details for the connection. # Retrieve the root storage URL for the connection.
try: try:
object_url_value, _ = self._get_connection().get_auth() root_storage_url = self._get_root_storage_url()
except ClientException: except ClientException:
logger.exception('Got client exception when trying to load Swift auth') logger.exception('Got client exception when trying to load Swift auth')
return None return None
object_url = urlparse(object_url_value) parsed_storage_url = urlparse(root_storage_url)
scheme = object_url.scheme scheme = parsed_storage_url.scheme
path = object_url.path.rstrip('/') path = parsed_storage_url.path.rstrip('/')
hostname = object_url.netloc hostname = parsed_storage_url.netloc
object_path = self._normalize_path(object_path) object_path = self._normalize_path(object_path)

View file

@ -8,6 +8,7 @@ from mock import MagicMock
from storage import StorageContext from storage import StorageContext
from storage.swift import SwiftStorage from storage.swift import SwiftStorage
from swiftclient.client import ClientException
base_args = { base_args = {
'context': StorageContext('nyc', None, None, None, None), 'context': StorageContext('nyc', None, None, None, None),
@ -27,18 +28,26 @@ class MockSwiftStorage(SwiftStorage):
return self._connection return self._connection
class FakeSwiftStorage(SwiftStorage): class FakeSwiftStorage(SwiftStorage):
def __init__(self, fail_checksum=False, connection=None, *args, **kwargs): def __init__(self, fail_checksum=False,connection=None, *args, **kwargs):
super(FakeSwiftStorage, self).__init__(*args, **kwargs) super(FakeSwiftStorage, self).__init__(*args, **kwargs)
self._connection = connection or FakeSwift(fail_checksum=fail_checksum) self._connection = connection or FakeSwift(fail_checksum=fail_checksum,
temp_url_key=kwargs.get('temp_url_key'))
def _get_connection(self): def _get_connection(self):
return self._connection return self._connection
class FakeSwift(object): class FakeSwift(object):
def __init__(self, fail_checksum=False): def __init__(self, fail_checksum=False, temp_url_key=None):
self.containers = defaultdict(dict) self.containers = defaultdict(dict)
self.fail_checksum = fail_checksum self.fail_checksum = fail_checksum
self.temp_url_key = temp_url_key
def get_auth(self):
if self.temp_url_key == 'exception':
raise ClientException('I failed!')
return 'http://fake/swift', None
def head_object(self, container, path): def head_object(self, container, path):
return self.containers[container].get(path) return self.containers[container].get(path)
@ -258,3 +267,13 @@ def test_empty_chunks_queued_for_deletion():
found2 = chunk_cleanup_queue.get() found2 = chunk_cleanup_queue.get()
assert found2 is None assert found2 is None
@pytest.mark.parametrize('temp_url_key, expects_url', [
(None, False),
('foobarbaz', True),
('exception', False),
])
def test_get_direct_download_url(temp_url_key, expects_url):
swift = FakeSwiftStorage(temp_url_key=temp_url_key, **base_args)
swift.put_content('somepath', 'hello world!')
assert (swift.get_direct_download_url('somepath') is not None) == expects_url