account-broker: add resilient path property with lazy cache
Add a path property for AccountBroker and use lazy, resilient _populate_instance_cache(). Use None attrs as flags, avoid broad try/except in path, and retry if cache population fails. Change-Id: Ic7c2aa878caf039b29abb900b4f491130be3d8a8 Signed-off-by: ashnair <ashnair@nvidia.com>
This commit is contained in:
@@ -224,6 +224,18 @@ class AccountBroker(DatabaseBroker):
|
|||||||
record['bytes_used'], record['deleted'],
|
record['bytes_used'], record['deleted'],
|
||||||
record['storage_policy_index'])
|
record['storage_policy_index'])
|
||||||
|
|
||||||
|
@property
|
||||||
|
def path(self):
|
||||||
|
"""
|
||||||
|
Logical namespace path used for logging.
|
||||||
|
|
||||||
|
For ContainerBroker this is "<account>/<container>";
|
||||||
|
for AccountBroker we return just "<account>".
|
||||||
|
"""
|
||||||
|
if self.account is None:
|
||||||
|
self._populate_instance_cache()
|
||||||
|
return self.account or ''
|
||||||
|
|
||||||
def put_container(self, name, put_timestamp, delete_timestamp,
|
def put_container(self, name, put_timestamp, delete_timestamp,
|
||||||
object_count, bytes_used, storage_policy_index):
|
object_count, bytes_used, storage_policy_index):
|
||||||
"""
|
"""
|
||||||
@@ -336,7 +348,7 @@ class AccountBroker(DatabaseBroker):
|
|||||||
|
|
||||||
def get_info(self):
|
def get_info(self):
|
||||||
"""
|
"""
|
||||||
Get global data for the account.
|
Return a dict with account name for this broker.
|
||||||
|
|
||||||
:returns: dict with keys: account, created_at, put_timestamp,
|
:returns: dict with keys: account, created_at, put_timestamp,
|
||||||
delete_timestamp, status_changed_at, container_count,
|
delete_timestamp, status_changed_at, container_count,
|
||||||
@@ -344,12 +356,14 @@ class AccountBroker(DatabaseBroker):
|
|||||||
"""
|
"""
|
||||||
self._commit_puts_stale_ok()
|
self._commit_puts_stale_ok()
|
||||||
with self.get() as conn:
|
with self.get() as conn:
|
||||||
return dict(conn.execute('''
|
data = dict(conn.execute('''
|
||||||
SELECT account, created_at, put_timestamp, delete_timestamp,
|
SELECT account, created_at, put_timestamp, delete_timestamp,
|
||||||
status_changed_at, container_count, object_count,
|
status_changed_at, container_count, object_count,
|
||||||
bytes_used, hash, id
|
bytes_used, hash, id
|
||||||
FROM account_stat
|
FROM account_stat
|
||||||
''').fetchone())
|
''').fetchone())
|
||||||
|
self.account = data.get('account')
|
||||||
|
return data
|
||||||
|
|
||||||
def list_containers_iter(self, limit, marker, end_marker, prefix,
|
def list_containers_iter(self, limit, marker, end_marker, prefix,
|
||||||
delimiter, reverse=False, allow_reserved=False):
|
delimiter, reverse=False, allow_reserved=False):
|
||||||
@@ -639,3 +653,15 @@ class AccountBroker(DatabaseBroker):
|
|||||||
ALTER TABLE container
|
ALTER TABLE container
|
||||||
ADD COLUMN storage_policy_index INTEGER DEFAULT 0;
|
ADD COLUMN storage_policy_index INTEGER DEFAULT 0;
|
||||||
''' + POLICY_STAT_TRIGGER_SCRIPT)
|
''' + POLICY_STAT_TRIGGER_SCRIPT)
|
||||||
|
|
||||||
|
def _populate_instance_cache(self):
|
||||||
|
"""
|
||||||
|
Lazily hydrate instance attributes used for logging and other
|
||||||
|
read-mostly flows. Use `self.account is None` as the only
|
||||||
|
indicator that we haven't populated yet.
|
||||||
|
|
||||||
|
On failure, we leave `self.account` as-is (likely None) so that
|
||||||
|
a future caller can try again.
|
||||||
|
"""
|
||||||
|
if self.account is None:
|
||||||
|
self.get_info()
|
||||||
|
@@ -14,7 +14,6 @@
|
|||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
""" Tests for swift.account.backend """
|
""" Tests for swift.account.backend """
|
||||||
|
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
import json
|
import json
|
||||||
import pickle
|
import pickle
|
||||||
@@ -1216,6 +1215,25 @@ class TestAccountBrokerBeforeMetadata(TestAccountBroker):
|
|||||||
exc = err
|
exc = err
|
||||||
self.assertIn('no such column: metadata', str(exc))
|
self.assertIn('no such column: metadata', str(exc))
|
||||||
|
|
||||||
|
def test_path_lazy_populates_from_db(self):
|
||||||
|
b = AccountBroker(self.get_db_path(), account=None)
|
||||||
|
self.assertIsNone(getattr(b, 'account', None))
|
||||||
|
called = {'n': 0}
|
||||||
|
|
||||||
|
def stub_populate(self, conn=None):
|
||||||
|
called['n'] += 1
|
||||||
|
self.account = 'a'
|
||||||
|
|
||||||
|
with mock.patch.object(AccountBroker, '_populate_instance_cache',
|
||||||
|
stub_populate):
|
||||||
|
self.assertEqual('a', b.path)
|
||||||
|
self.assertEqual('a', b.account)
|
||||||
|
self.assertEqual(1, called['n'])
|
||||||
|
|
||||||
|
def test_path_best_effort_when_partial_attrs(self):
|
||||||
|
b = AccountBroker(self.get_db_path(), account='a')
|
||||||
|
self.assertEqual('a', b.path)
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
AccountBroker.create_account_stat_table = \
|
AccountBroker.create_account_stat_table = \
|
||||||
self._imported_create_account_stat_table
|
self._imported_create_account_stat_table
|
||||||
|
Reference in New Issue
Block a user