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.
This commit is contained in:
Alexander Kukushkin
2019-10-25 14:52:13 +02:00
committed by GitHub
parent 828585079f
commit 6fe482a4c8
+9 -2
View File
@@ -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, {}))