diff --git a/lib/charms/postgresql_k8s/v0/postgresql.py b/lib/charms/postgresql_k8s/v0/postgresql.py index 03aaded346..a8b5931030 100644 --- a/lib/charms/postgresql_k8s/v0/postgresql.py +++ b/lib/charms/postgresql_k8s/v0/postgresql.py @@ -32,7 +32,7 @@ # Increment this PATCH version before using `charmcraft publish-lib` or reset # to 0 if you are raising the major API version -LIBPATCH = 13 +LIBPATCH = 14 INVALID_EXTRA_USER_ROLE_BLOCKING_MESSAGE = "invalid role(s) for extra user roles" @@ -428,11 +428,21 @@ def build_postgresql_parameters( Args: profile: the profile to use. - available_memory: available memory to use in calculation + available_memory: available memory to use in calculation in bytes. Returns: Dictionary with the PostgreSQL parameters. """ logger.debug(f"Building PostgreSQL parameters for {profile=} and {available_memory=}") if profile == "production": - return {"shared_buffers": "987MB", "effective_cache_size": "2958MB"} + # Use 25% of the available memory for shared_buffers. + # and the remaind as cache memory. + shared_buffers = int(available_memory * 0.25) + effective_cache_size = int(available_memory - shared_buffers) + + parameters = { + "shared_buffers": f"{int(shared_buffers/10**6)}MB", + "effective_cache_size": f"{int(effective_cache_size/10**6)}MB", + } + + return parameters diff --git a/src/charm.py b/src/charm.py index 9e44ac1780..af41352a14 100755 --- a/src/charm.py +++ b/src/charm.py @@ -1362,6 +1362,11 @@ def update_config(self, is_creating_backup: bool = False) -> bool: """Updates Patroni config file based on the existence of the TLS files.""" enable_tls = all(self.tls.get_tls_files()) + # Build PostgreSQL parameters. + pg_parameters = self.postgresql.build_postgresql_parameters( + self.config["profile"], self.get_available_memory() + ) + # Update and reload configuration based on TLS files availability. self._patroni.render_patroni_yml_file( connectivity=self.unit_peer_data.get("connectivity", "on") == "on", @@ -1370,7 +1375,7 @@ def update_config(self, is_creating_backup: bool = False) -> bool: backup_id=self.app_peer_data.get("restoring-backup"), stanza=self.app_peer_data.get("stanza"), restore_stanza=self.app_peer_data.get("restore-stanza"), - parameters=self.postgresql.build_postgresql_parameters(self.config["profile"], 0), + parameters=pg_parameters, ) if not self._is_workload_running: # If Patroni/PostgreSQL has not started yet and TLS relations was initialised, @@ -1417,6 +1422,15 @@ def _update_relation_endpoints(self) -> None: self.legacy_db_relation.update_endpoints() self.legacy_db_admin_relation.update_endpoints() + def get_available_memory(self) -> int: + """Returns the system available memory in bytes.""" + with open("/proc/meminfo") as meminfo: + for line in meminfo: + if "MemTotal" in line: + return int(line.split()[1]) * 1024 + + return 0 + if __name__ == "__main__": main(PostgresqlOperatorCharm) diff --git a/tests/unit/test_charm.py b/tests/unit/test_charm.py index f5b64d6d83..2c1ebfdfab 100644 --- a/tests/unit/test_charm.py +++ b/tests/unit/test_charm.py @@ -2,7 +2,7 @@ # See LICENSE file for licensing details. import subprocess import unittest -from unittest.mock import MagicMock, Mock, PropertyMock, patch +from unittest.mock import MagicMock, Mock, PropertyMock, mock_open, patch from charms.operator_libs_linux.v2 import snap from charms.postgresql_k8s.v0.postgresql import ( @@ -1391,3 +1391,20 @@ def test_is_workload_running(self, _snap_cache): pg_snap.present = True self.assertTrue(self.charm._is_workload_running) + + def test_get_available_memory(self): + meminfo = ( + "MemTotal: 16089488 kB" + "MemFree: 799284 kB" + "MemAvailable: 3926924 kB" + "Buffers: 187232 kB" + "Cached: 4445936 kB" + "SwapCached: 156012 kB" + "Active: 11890336 kB" + ) + + with patch("builtins.open", mock_open(read_data=meminfo)): + self.assertEqual(self.charm.get_available_memory(), 16475635712) + + with patch("builtins.open", mock_open(read_data="")): + self.assertEqual(self.charm.get_available_memory(), 0)