diff --git a/swift/account/backend.py b/swift/account/backend.py index a4d7137ee6..3ff016689e 100644 --- a/swift/account/backend.py +++ b/swift/account/backend.py @@ -224,6 +224,18 @@ class AccountBroker(DatabaseBroker): record['bytes_used'], record['deleted'], record['storage_policy_index']) + @property + def path(self): + """ + Logical namespace path used for logging. + + For ContainerBroker this is "/"; + for AccountBroker we return just "". + """ + if self.account is None: + self._populate_instance_cache() + return self.account or '' + def put_container(self, name, put_timestamp, delete_timestamp, object_count, bytes_used, storage_policy_index): """ @@ -336,7 +348,7 @@ class AccountBroker(DatabaseBroker): 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, delete_timestamp, status_changed_at, container_count, @@ -344,12 +356,14 @@ class AccountBroker(DatabaseBroker): """ self._commit_puts_stale_ok() with self.get() as conn: - return dict(conn.execute(''' + data = dict(conn.execute(''' SELECT account, created_at, put_timestamp, delete_timestamp, status_changed_at, container_count, object_count, bytes_used, hash, id FROM account_stat ''').fetchone()) + self.account = data.get('account') + return data def list_containers_iter(self, limit, marker, end_marker, prefix, delimiter, reverse=False, allow_reserved=False): @@ -639,3 +653,15 @@ class AccountBroker(DatabaseBroker): ALTER TABLE container ADD COLUMN storage_policy_index INTEGER DEFAULT 0; ''' + 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() diff --git a/test/unit/account/test_backend.py b/test/unit/account/test_backend.py index 48daa8114e..3ab4bab5c2 100644 --- a/test/unit/account/test_backend.py +++ b/test/unit/account/test_backend.py @@ -14,7 +14,6 @@ # limitations under the License. """ Tests for swift.account.backend """ - from collections import defaultdict import json import pickle @@ -1216,6 +1215,25 @@ class TestAccountBrokerBeforeMetadata(TestAccountBroker): exc = err 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): AccountBroker.create_account_stat_table = \ self._imported_create_account_stat_table