From fc13fa3727eecce0162e52852d2ac0f724da6aa2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C5=82awomir=20Nizio?= Date: Thu, 14 Nov 2019 01:16:17 +0100 Subject: [PATCH] [entropy.server] correct close_repositories() with Python 3 Function callers, in order (during eit commit): 1. filename='lib/entropy/server/interfaces/main.py', function='switch_default_repository', code_context=[' self.close_repositories()\n'], index=0) 2. filename='server/eit/commands/command.py', function='_call_exclusive', code_context=[' server.close_repositories()\n'], index=0) 3. filename='lib/entropy/client/interfaces/client.py', function='destroy', code_context=[' self.close_repositories(mask_clear = False)\n'], index=0) 4. filename='lib/entropy/server/interfaces/main.py', function='destroy', code_context=[' self.close_repositories()\n'], index=0) Third one triggers packages set synchronization (which would cause "dictionary changed size during iteration"), and marks sets as being synchronized. Fourth does not trigger sets synchronization, so closes all repositories without new ones being opened in the meantime. Side note: It's similar to this in "client," lib/entropy/client/interfaces/methods.py: def close_repositories(self, mask_clear = True): ... # list() -> python3 support for item, val in list(repo_cache.items()): ... repo_cache.pop(item).close(_token = repository_id) ... but (based on shallow look), it doesn't do as much magic; just calls .pop() (not sure if there are similar side effects in close() there, though), so the explanation may possibly apply to the lib/entropy/server function only. --- lib/entropy/server/interfaces/main.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/lib/entropy/server/interfaces/main.py b/lib/entropy/server/interfaces/main.py index b633681fd..4a7103ff6 100644 --- a/lib/entropy/server/interfaces/main.py +++ b/lib/entropy/server/interfaces/main.py @@ -5384,7 +5384,15 @@ class Server(Client): srv_dbcache = self._server_dbcache if srv_dbcache is not None: - for item in srv_dbcache.keys(): + # list() is for Python3. Because _sync_package_sets may open a + # repository (and add it to the cache), Python would complain: + # "RuntimeError: dictionary changed size during iteration." With + # list() (which creates copy of keys at a given point of time), + # there is a risk that newly added connection(s) would not be + # closed, but the last close_repositories() runs with sets being + # marked as already synchronized, so the repository is not opened + # (added) again to the cache, and each of srv_dbcache is handled. + for item in list(srv_dbcache.keys()): try: srv_dbcache[item].close() except ProgrammingError: # already closed?