Skip to content

Commit 53e5474

Browse files
authored
DPE-3547 bump floor value for max_connections (#398)
* couple optimizations (mainly for k8s) * fix floor value * fix typo
1 parent 6c8bd7b commit 53e5474

File tree

5 files changed

+67
-47
lines changed

5 files changed

+67
-47
lines changed

lib/charms/mysql/v0/mysql.py

+53-38
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ def wait_until_mysql_connection(self) -> None:
111111

112112
# Increment this PATCH version before using `charmcraft publish-lib` or reset
113113
# to 0 if you are raising the major API version
114-
LIBPATCH = 54
114+
LIBPATCH = 55
115115

116116
UNIT_TEARDOWN_LOCKNAME = "unit-teardown"
117117
UNIT_ADD_LOCKNAME = "unit-add"
@@ -122,6 +122,7 @@ def wait_until_mysql_connection(self) -> None:
122122
BYTES_1MiB = 1048576 # 1 mebibyte
123123
RECOVERY_CHECK_TIME = 10 # seconds
124124
GET_MEMBER_STATE_TIME = 10 # seconds
125+
MIN_MAX_CONNECTIONS = 100
125126

126127
SECRET_INTERNAL_LABEL = "secret-id"
127128
SECRET_DELETED_LABEL = "None"
@@ -710,7 +711,7 @@ def render_mysqld_configuration(
710711
innodb_buffer_pool_size = 20 * BYTES_1MiB
711712
innodb_buffer_pool_chunk_size = 1 * BYTES_1MiB
712713
group_replication_message_cache_size = 128 * BYTES_1MiB
713-
max_connections = 20
714+
max_connections = MIN_MAX_CONNECTIONS
714715
performance_schema_instrument = "'memory/%=OFF'"
715716
else:
716717
available_memory = self.get_available_memory()
@@ -723,7 +724,7 @@ def render_mysqld_configuration(
723724
innodb_buffer_pool_chunk_size,
724725
group_replication_message_cache_size,
725726
) = self.get_innodb_buffer_pool_parameters(available_memory)
726-
max_connections = self.get_max_connections(available_memory)
727+
max_connections = max(self.get_max_connections(available_memory), MIN_MAX_CONNECTIONS)
727728
if available_memory < 2 * BYTES_1GiB:
728729
# disable memory instruments if we have less than 2GiB of RAM
729730
performance_schema_instrument = "'memory/%=OFF'"
@@ -1209,7 +1210,11 @@ def initialize_juju_units_operations_table(self) -> None:
12091210
raise MySQLInitializeJujuOperationsTableError(e.message)
12101211

12111212
def add_instance_to_cluster(
1212-
self, instance_address: str, instance_unit_label: str, from_instance: Optional[str] = None
1213+
self,
1214+
instance_address: str,
1215+
instance_unit_label: str,
1216+
from_instance: Optional[str] = None,
1217+
method: str = "auto",
12131218
) -> None:
12141219
"""Add an instance to the InnoDB cluster.
12151220
@@ -1223,6 +1228,7 @@ def add_instance_to_cluster(
12231228
instance_address: address of the instance to add to the cluster
12241229
instance_unit_label: the label/name of the unit
12251230
from_instance: address of the adding instance, e.g. primary
1231+
method: recovery method to use, either "auto" or "clone"
12261232
"""
12271233
options = {
12281234
"password": self.cluster_admin_password,
@@ -1243,39 +1249,37 @@ def add_instance_to_cluster(
12431249
"shell.options['dba.restartWaitTimeout'] = 3600",
12441250
)
12451251

1246-
for recovery_method in ["auto", "clone"]:
1247-
# Prefer "auto" recovery method, but if it fails, try "clone"
1248-
try:
1249-
options["recoveryMethod"] = recovery_method
1250-
add_instance_command = (
1251-
f"cluster.add_instance('{self.cluster_admin_user}@{instance_address}', {json.dumps(options)})",
1252-
)
1252+
# Prefer "auto" recovery method, but if it fails, try "clone"
1253+
try:
1254+
options["recoveryMethod"] = method
1255+
add_instance_command = (
1256+
f"cluster.add_instance('{self.cluster_admin_user}@{instance_address}', {options})",
1257+
)
12531258

1254-
logger.debug(
1255-
f"Adding instance {instance_address}/{instance_unit_label} to cluster {self.cluster_name} with recovery method {recovery_method}"
1256-
)
1257-
self._run_mysqlsh_script("\n".join(connect_commands + add_instance_command))
1259+
logger.info(
1260+
f"Adding instance {instance_address}/{instance_unit_label} to {self.cluster_name=}"
1261+
f"with recovery {method=}"
1262+
)
1263+
self._run_mysqlsh_script("\n".join(connect_commands + add_instance_command))
12581264

1259-
break
1260-
except MySQLClientError as e:
1261-
if recovery_method == "clone":
1262-
logger.exception(
1263-
f"Failed to add instance {instance_address} to cluster {self.cluster_name} on {self.instance_address}",
1264-
exc_info=e,
1265-
)
1266-
self._release_lock(
1267-
from_instance or self.instance_address,
1268-
instance_unit_label,
1269-
UNIT_ADD_LOCKNAME,
1270-
)
1271-
raise MySQLAddInstanceToClusterError(e.message)
1272-
1273-
logger.debug(
1274-
f"Failed to add instance {instance_address} to cluster {self.cluster_name} with recovery method 'auto'. Trying method 'clone'"
1265+
except MySQLClientError:
1266+
if method == "clone":
1267+
logger.exception(
1268+
f"Failed to add {instance_address=} to {self.cluster_name=} on {self.instance_address=}",
12751269
)
1276-
self._release_lock(
1277-
from_instance or self.instance_address, instance_unit_label, UNIT_ADD_LOCKNAME
1278-
)
1270+
raise MySQLAddInstanceToClusterError
1271+
1272+
logger.debug(
1273+
f"Cannot add {instance_address=} to {self.cluster_name=} with recovery {method=}. Trying method 'clone'"
1274+
)
1275+
self.add_instance_to_cluster(
1276+
instance_address, instance_unit_label, from_instance, method="clone"
1277+
)
1278+
finally:
1279+
# always release the lock
1280+
self._release_lock(
1281+
from_instance or self.instance_address, instance_unit_label, UNIT_ADD_LOCKNAME
1282+
)
12791283

12801284
def is_instance_configured_for_innodb(
12811285
self, instance_address: str, instance_unit_label: str
@@ -1398,6 +1402,11 @@ def is_instance_in_cluster(self, unit_label: str) -> bool:
13981402
)
13991403
return False
14001404

1405+
@retry(
1406+
wait=wait_fixed(2),
1407+
stop=stop_after_attempt(3),
1408+
retry=retry_if_exception_type(TimeoutError),
1409+
)
14011410
def get_cluster_status(self, extended: Optional[bool] = False) -> Optional[dict]:
14021411
"""Get the cluster status.
14031412
@@ -2505,13 +2514,19 @@ def get_pid_of_port_3306(self) -> Optional[str]:
25052514
except MySQLExecError:
25062515
return None
25072516

2508-
def flush_mysql_logs(self, logs_type: MySQLTextLogs) -> None:
2517+
def flush_mysql_logs(self, logs_type: Union[MySQLTextLogs, list[MySQLTextLogs]]) -> None:
25092518
"""Flushes the specified logs_type logs."""
2510-
flush_logs_commands = (
2519+
flush_logs_commands = [
25112520
f"shell.connect('{self.server_config_user}:{self.server_config_password}@{self.instance_address}')",
25122521
'session.run_sql("SET sql_log_bin = 0")',
2513-
f'session.run_sql("FLUSH {logs_type.value}")',
2514-
)
2522+
]
2523+
2524+
if type(logs_type) is list:
2525+
flush_logs_commands.extend(
2526+
[f"session.run_sql('FLUSH {log.value}')" for log in logs_type]
2527+
)
2528+
else:
2529+
flush_logs_commands.append(f'session.run_sql("FLUSH {logs_type.value}")') # type: ignore
25152530

25162531
try:
25172532
self._run_mysqlsh_script("\n".join(flush_logs_commands))

src/flush_mysql_logs.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ def __init__(self, charm: "MySQLOperatorCharm"):
4242

4343
def _flush_mysql_logs(self, _) -> None:
4444
"""Flush the specified (via LOGS_TYPE env var) mysql logs."""
45-
logs_type = os.environ.get("LOGS_TYPE")
45+
logs_type = os.environ.get("LOGS_TYPE", "")
4646

4747
try:
4848
text_logs = MySQLTextLogs[logs_type]

tests/integration/high_availability/test_replication.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ async def test_custom_variables(ops_test: OpsTest, mysql_charm_series) -> None:
123123

124124
for unit in application.units:
125125
custom_vars = {}
126-
custom_vars["max_connections"] = 20
126+
custom_vars["max_connections"] = 100
127127
for k, v in custom_vars.items():
128128
logger.info(f"Checking that {k} is set to {v} on {unit.name}")
129129
value = await retrieve_database_variable_value(ops_test, unit, k)

tests/unit/test_mysql.py

+11-6
Original file line numberDiff line numberDiff line change
@@ -370,16 +370,18 @@ def test_create_cluster_set_exceptions(self, _run_mysqlsh_script):
370370
def test_add_instance_to_cluster(self, _run_mysqlsh_script, _acquire_lock, _release_lock):
371371
"""Test a successful execution of create_cluster."""
372372
add_instance_to_cluster_commands = (
373-
"shell.connect('clusteradmin:clusteradminpassword@127.0.0.1')",
374-
"cluster = dba.get_cluster('test_cluster')",
375-
"shell.options['dba.restartWaitTimeout'] = 3600",
376-
"cluster.add_instance('clusteradmin@127.0.0.2', {\"password\": "
377-
'"clusteradminpassword", "label": "mysql-1", "recoveryMethod": "auto"})',
373+
"shell.connect('clusteradmin:clusteradminpassword@127.0.0.1')\n"
374+
"cluster = dba.get_cluster('test_cluster')\n"
375+
"shell.options['dba.restartWaitTimeout'] = 3600\n"
376+
"cluster.add_instance('clusteradmin@127.0.0.2', {'password': 'clusteradminpassword',"
377+
" 'label': 'mysql-1', 'recoveryMethod': 'auto'})"
378378
)
379379

380380
self.mysql.add_instance_to_cluster("127.0.0.2", "mysql-1")
381381

382-
_run_mysqlsh_script.assert_called_once_with("\n".join(add_instance_to_cluster_commands))
382+
_run_mysqlsh_script.assert_called_once_with(add_instance_to_cluster_commands)
383+
_acquire_lock.assert_called_once()
384+
_release_lock.assert_called_once()
383385

384386
@patch("charms.mysql.v0.mysql.MySQLBase._release_lock")
385387
@patch("charms.mysql.v0.mysql.MySQLBase._acquire_lock", return_value=True)
@@ -392,6 +394,9 @@ def test_add_instance_to_cluster_exception(
392394

393395
with self.assertRaises(MySQLAddInstanceToClusterError):
394396
self.mysql.add_instance_to_cluster("127.0.0.2", "mysql-1")
397+
_acquire_lock.assert_called_once()
398+
_release_lock.assert_called_once()
399+
_run_mysqlsh_script.assert_called()
395400

396401
@patch(
397402
"charms.mysql.v0.mysql.MySQLBase._run_mysqlsh_script", return_value="INSTANCE_CONFIGURED"

tests/unit/test_mysqlsh_helpers.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -305,7 +305,7 @@ def test_write_mysqld_config(
305305
"bind-address = 0.0.0.0",
306306
"mysqlx-bind-address = 0.0.0.0",
307307
"report_host = 127.0.0.1",
308-
"max_connections = 20",
308+
"max_connections = 100",
309309
"innodb_buffer_pool_size = 20971520",
310310
"log_error_services = log_filter_internal;log_sink_internal",
311311
"log_error = /var/snap/charmed-mysql/common/var/log/mysql/error.log",

0 commit comments

Comments
 (0)