From 6fe482a4c8bd71cc63f0104b76a690e73c54f4c1 Mon Sep 17 00:00:00 2001 From: Alexander Kukushkin Date: Fri, 25 Oct 2019 14:52:13 +0200 Subject: [PATCH] Avoid calling expensive os.listdir() (#1254) When the system is under IO stress, `os.listdir()` could take a few seconds (or even minutes) to execute what is badly affecting the HA loop of Patroni and could even cause the leader key to disappear from DCS due to the lack of updates. There is a better and less expensive way to check that the PGDATA is not empty. Instead of doing the `os.listdir` we simply check the presence of the `global/pg_control` file in it. --- patroni/postgresql/__init__.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/patroni/postgresql/__init__.py b/patroni/postgresql/__init__.py index 932b6b6d..fc1941f8 100644 --- a/patroni/postgresql/__init__.py +++ b/patroni/postgresql/__init__.py @@ -51,6 +51,7 @@ class Postgresql(object): self._data_dir = config['data_dir'] self._database = config.get('database', 'postgres') self._version_file = os.path.join(self._data_dir, 'PG_VERSION') + self._pg_control = os.path.join(self._data_dir, 'global', 'pg_control') self._major_version = self.get_major_version() self._state_lock = Lock() @@ -256,9 +257,15 @@ class Postgresql(object): except RetryFailedError as e: raise PostgresConnectionException(str(e)) + def pg_control_exists(self): + return os.path.isfile(self._pg_control) + def data_directory_empty(self): - return not os.path.exists(self._data_dir) or \ - all(os.name != 'nt' and (n.startswith('.') or n == 'lost+found') for n in os.listdir(self._data_dir)) + if self.pg_control_exists(): + return False + if not os.path.exists(self._data_dir): + return True + return all(os.name != 'nt' and (n.startswith('.') or n == 'lost+found') for n in os.listdir(self._data_dir)) def replica_method_options(self, method): return deepcopy(self.config.get(method, {}))