@@ -111,7 +111,7 @@ def wait_until_mysql_connection(self) -> None:
111
111
112
112
# Increment this PATCH version before using `charmcraft publish-lib` or reset
113
113
# to 0 if you are raising the major API version
114
- LIBPATCH = 54
114
+ LIBPATCH = 55
115
115
116
116
UNIT_TEARDOWN_LOCKNAME = "unit-teardown"
117
117
UNIT_ADD_LOCKNAME = "unit-add"
@@ -122,6 +122,7 @@ def wait_until_mysql_connection(self) -> None:
122
122
BYTES_1MiB = 1048576 # 1 mebibyte
123
123
RECOVERY_CHECK_TIME = 10 # seconds
124
124
GET_MEMBER_STATE_TIME = 10 # seconds
125
+ MIN_MAX_CONNECTIONS = 100
125
126
126
127
SECRET_INTERNAL_LABEL = "secret-id"
127
128
SECRET_DELETED_LABEL = "None"
@@ -710,7 +711,7 @@ def render_mysqld_configuration(
710
711
innodb_buffer_pool_size = 20 * BYTES_1MiB
711
712
innodb_buffer_pool_chunk_size = 1 * BYTES_1MiB
712
713
group_replication_message_cache_size = 128 * BYTES_1MiB
713
- max_connections = 20
714
+ max_connections = MIN_MAX_CONNECTIONS
714
715
performance_schema_instrument = "'memory/%=OFF'"
715
716
else :
716
717
available_memory = self .get_available_memory ()
@@ -723,7 +724,7 @@ def render_mysqld_configuration(
723
724
innodb_buffer_pool_chunk_size ,
724
725
group_replication_message_cache_size ,
725
726
) = 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 )
727
728
if available_memory < 2 * BYTES_1GiB :
728
729
# disable memory instruments if we have less than 2GiB of RAM
729
730
performance_schema_instrument = "'memory/%=OFF'"
@@ -1209,7 +1210,11 @@ def initialize_juju_units_operations_table(self) -> None:
1209
1210
raise MySQLInitializeJujuOperationsTableError (e .message )
1210
1211
1211
1212
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" ,
1213
1218
) -> None :
1214
1219
"""Add an instance to the InnoDB cluster.
1215
1220
@@ -1223,6 +1228,7 @@ def add_instance_to_cluster(
1223
1228
instance_address: address of the instance to add to the cluster
1224
1229
instance_unit_label: the label/name of the unit
1225
1230
from_instance: address of the adding instance, e.g. primary
1231
+ method: recovery method to use, either "auto" or "clone"
1226
1232
"""
1227
1233
options = {
1228
1234
"password" : self .cluster_admin_password ,
@@ -1243,39 +1249,37 @@ def add_instance_to_cluster(
1243
1249
"shell.options['dba.restartWaitTimeout'] = 3600" ,
1244
1250
)
1245
1251
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
+ )
1253
1258
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 ))
1258
1264
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 = } " ,
1275
1269
)
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
+ )
1279
1283
1280
1284
def is_instance_configured_for_innodb (
1281
1285
self , instance_address : str , instance_unit_label : str
@@ -1398,6 +1402,11 @@ def is_instance_in_cluster(self, unit_label: str) -> bool:
1398
1402
)
1399
1403
return False
1400
1404
1405
+ @retry (
1406
+ wait = wait_fixed (2 ),
1407
+ stop = stop_after_attempt (3 ),
1408
+ retry = retry_if_exception_type (TimeoutError ),
1409
+ )
1401
1410
def get_cluster_status (self , extended : Optional [bool ] = False ) -> Optional [dict ]:
1402
1411
"""Get the cluster status.
1403
1412
@@ -2505,13 +2514,19 @@ def get_pid_of_port_3306(self) -> Optional[str]:
2505
2514
except MySQLExecError :
2506
2515
return None
2507
2516
2508
- def flush_mysql_logs (self , logs_type : MySQLTextLogs ) -> None :
2517
+ def flush_mysql_logs (self , logs_type : Union [ MySQLTextLogs , list [ MySQLTextLogs ]] ) -> None :
2509
2518
"""Flushes the specified logs_type logs."""
2510
- flush_logs_commands = (
2519
+ flush_logs_commands = [
2511
2520
f"shell.connect('{ self .server_config_user } :{ self .server_config_password } @{ self .instance_address } ')" ,
2512
2521
'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
2515
2530
2516
2531
try :
2517
2532
self ._run_mysqlsh_script ("\n " .join (flush_logs_commands ))
0 commit comments