Home - Waterfall Grid T-Grid Console Builders Recent Builds Buildslaves Changesources - JSON API - About

Console View


Categories: connectors experimental galera main
Legend:   Passed Failed Warnings Failed Again Running Exception Offline No data

connectors experimental galera main
Sergei Golubchik
s390x
forkfun
MDEV-40308-followup mariadb-dump --system emits invalid SQL

Escape single quotes in SONAME (plugins, UDFs) and in
CREATE SERVER option values via unescape(). Also emit the
DATABASE/USER option keywords instead of the Db/Username
column names, and dump aggregate UDFs as CREATE AGGREGATE
FUNCTION (type column was tested wrong). Add check_io().
Rucha Deodhar
MDEV-40125: OLD_VALUE crashes on a view with an expression

Analysis:

When OLD_VALUE() is used on a view, field resolution creates an
Item_direct_view_ref instead of an Item_ref where real_item() points to the
expression. But Item_old_field::fix_fields() continues assuming that a Field
object was available, but view references do not have a field pointer,
which resulted in a crash.

Fix:
Store the real referenced item in Item_old_field::expr and use it when
the OLD_VALUE() reference does not have a Field object. This allows
OLD_VALUE() to work with view fields and avoids dereferencing a NULL
field pointer. Fix relevant methods accordingly.
Sergei Golubchik
s390x
PranavKTiwari
dds
Kristian Nielsen
MDEV-34135: Parallel replication hangs on corrupt binlog with partial event group

If relay log corruption caused an incomplete event group to appear (ie. a
new GTID before the prior event group is complete), this could cause
parallel replication to hang hard. The problem was that the worker thread
handling the incomplete event group would never get a COMMIT event, and thus
never signal the following GCO to start.

Fix by detecting in the SQL driver thread an incomplete event group, and
stopping the slave with an error in this case. The user can then investigate
the problem and recover the corruption as appropriate (eg.
--relay-log-recovery for example).

Giving an error here, rather than rolling back the incomplete transaction,
seems appropriate and safest here, to avoid silent data loss. If the relay
log is corrupted somehow (eg. lost events due to crash for example), we
cannot know that merely rolling back will be a correct fix, it might easily
cause lost transactions for example.

Fix a few bugs/inconsistencies in the rli->is_in_group() so that it can be
used to detect an incomplete event group: Make sure a standalone GTID is
also recognised as an event group, and terminate an incomplete event group
due to master crash or INCIDENT event.

Remove an incorrect assertion in write_ignored_events_info_to_relay_log().
This assertion in the slave IO thread was checking the is_in_group() state,
but that is completely invalid as is_in_group() is the state of the SQL
thread, not the IO thread.

Fix a few incorrect my_error(..., MYF(MY_WME), ...) calls.

Add a test case that simulates the original bug report where this occurred
in a production environment.

Adjust the test case rpl.rpl_parallel_deadlock_corrupt_binlog since
incomplete event group in the relay log now causes an error, not silent
rollback.

Signed-off-by: Kristian Nielsen <[email protected]>
Alexander Barkov
MDEV-39518 Allow prepared statements in stored functions in assignment right hand

Allowing prepared statements in stored functions when
a stored function is used in an assignment right hand.

Both DEFALT clause of a variable initialization and
the right side of the SET statement are supported:

  CREATE PROCEDURE p1()
  BEGIN
    -- case 1: DEFAULT clause
    DECLARE spvar1 INT DEFAULT f1_with_ps(); -- OK

    -- case 2: SP variable assignment statement
    DECLARE spvar2 INT;
    SET spvar= f1_with_ps(); -- OK
  END;

- The parser now does not reject PS statements in stored functions.
  PS applicability in stored functions is now detected as run time.
  Note, PS statements in triggers are still prohibited by the parser.

- Functions with PS do not acquire MDL locks on tables.
  They work like procedures in terms of table opening.

- Functions with PS are not replicated as a single `SELECT f1()` call.
  They are replicated per-statement, like procedures.
Alexander Barkov
MDEV-39518 Allow prepared statements in stored functions in assignment right hand

Allowing prepared statements in stored functions when
a stored function is used in an assignment right hand.

Both DEFALT clause of a variable initialization and
the right side of the SET statement are supported:

  CREATE PROCEDURE p1()
  BEGIN
    -- case 1: DEFAULT clause
    DECLARE spvar1 INT DEFAULT f1_with_ps(); -- OK

    -- case 2: SP variable assignment statement
    DECLARE spvar2 INT;
    SET spvar= f1_with_ps(); -- OK
  END;

- The parser now does not reject PS statements in stored functions.
  PS applicability in stored functions is now detected as run time.
  Note, PS statements in triggers are still prohibited by the parser.

- Functions with PS do not acquire MDL locks on tables.
  They work like procedures in terms of table opening.

- Functions with PS are not replicated as a single `SELECT f1()` call.
  They are replicated per-statement, like procedures.
Vladislav Vaintroub
Unify synchronous and asynchronous I/O; enable Schannel async

The non-blocking (async) API kept a complete parallel I/O stack next to
the synchronous one: async_read/async_write pvio methods,
ma_pvio_read_async/ma_pvio_write_async, and per-backend
ma_tls_read_async/ma_tls_write_async, each re-implementing the
"non-blocking attempt + my_context_yield() on would-block" loop.

But ma_pvio_wait_io_or_timeout() already yields the fiber in async mode.
Now that the socket is always non-blocking and the synchronous read/write
loops wait through it, the two paths are structurally identical - the only
difference is whether the wait blocks the thread (poll/select) or suspends
the fiber (yield), which is exactly what wait_io_or_timeout already decides.

So route the synchronous pvio_socket_read/write waits through
ma_pvio_wait_io_or_timeout() and drop the entire parallel async stack:

- remove async_read/async_write from the pvio method table (and the
  socket/shmem/npipe implementations)
- remove ma_pvio_read_async/ma_pvio_write_async and the async branches
  in ma_pvio_read/ma_pvio_write
- remove ma_tls_read_async/ma_tls_write_async (openssl, gnutls),
  ma_tls_async_check_result, and the IS_PVIO_ASYNC_ACTIVE branches in the
  OpenSSL BIO and GnuTLS push/pull callbacks - they now just call the
  blocking pvio read/write, which yields under the hood
- remove the now-unused IS_BLOCKING_ERROR macro

This also enables async for Schannel: ma_pvio_read/write no longer special
-case !HAVE_SCHANNEL, and Schannel already funnels all socket I/O through
pvio->methods->read/write, so it now suspends/resumes like the others.

Named pipe and shared memory cannot suspend/resume (no pollable socket).
Previously async over them errored on the first read (the async_read
method was NULL -> CR_ASYNC_NOT_SUPPORTED in ma_pvio_read_async). That
guard is gone with the parallel stack, so reject MYSQL_OPT_NONBLOCK over
these transports up front in mysql_real_connect() with the same
CR_ASYNC_NOT_SUPPORTED, instead of silently running synchronously and
blocking the caller's event loop. The ordinary blocking API is unaffected.

Tested:
- main.mysql_client_test_nonblock (the full mysql_client_test suite run
  through the non-blocking start/cont API) passes
- mtr unit suite: all 21 unit.conc_* pass (incl. unit.conc_async)
- the async unit test run directly over forced TLS with both OpenSSL and
  GnuTLS clients (test_async = 100 async connect+handshake+query+close
  iterations) passes, confirming the fiber yields correctly through the
  TLS stack

Co-Authored-By: Claude Opus 4.8 <[email protected]>
bsrikanth-mariadb
MDEV-39916: Crash with having filter when being pushed down

When Item_func_not::fix_fields() is invoked, there are several instances where
ref argument being passed is NULL. One such instance is from the method
st_select_lex::pushdown_from_having_into_where().

Since a null ref is being accessed, a crash occurs.

This PR fixes the problem by not passing null to
Item_func_not::fix_fields() when caling it from
st_select_lex::pushdown_from_having_into_where()
PranavKTiwari
Incorporated CRC.
Vladislav Vaintroub
MDEV-40323 CONNECT engine - add file access checks for JSON UDFs

Check FILE_ACL and secure_file_priv for the current user inside CONNECT
file UDFs (json_file, jfile_make, jbin_file, bson_file, bfile_make,
bbin_file).

Fix NULL filename: guard GetFileLength in jbin_file_init and check for
NULL fn in UDF bodies before the access check, so NULL arguments report
"Missing file name" instead of "Access denied".
Rucha Deodhar
MDEV-40125: OLD_VALUE crashes on a view with an expression

Analysis:

When OLD_VALUE() is used on a view, field resolution creates an
Item_direct_view_ref instead of an Item_field. Item_old_field::fix_fields()
continued assuming that a Field object was available, but view references
do not have a field pointer, which resulted in a crash.

Fix:
Store the real referenced item in Item_old_field::expr and use it when
the OLD_VALUE() reference does not have a Field object. This allows
OLD_VALUE() to work with view fields and avoids dereferencing a NULL
field pointer. Fix relevant methods accordingly.
Vladislav Vaintroub
Unify synchronous and asynchronous I/O; enable Schannel async

The non-blocking (async) API kept a complete parallel I/O stack next to
the synchronous one: async_read/async_write pvio methods,
ma_pvio_read_async/ma_pvio_write_async, and per-backend
ma_tls_read_async/ma_tls_write_async, each re-implementing the
"non-blocking attempt + my_context_yield() on would-block" loop.

But ma_pvio_wait_io_or_timeout() already yields the fiber in async mode.
Now that the socket is always non-blocking and the synchronous read/write
loops wait through it, the two paths are structurally identical - the only
difference is whether the wait blocks the thread (poll/select) or suspends
the fiber (yield), which is exactly what wait_io_or_timeout already decides.

So route the synchronous pvio_socket_read/write waits through
ma_pvio_wait_io_or_timeout() and drop the entire parallel async stack:

- remove async_read/async_write from the pvio method table (and the
  socket/shmem/npipe implementations)
- remove ma_pvio_read_async/ma_pvio_write_async and the async branches
  in ma_pvio_read/ma_pvio_write
- remove ma_tls_read_async/ma_tls_write_async (openssl, gnutls),
  ma_tls_async_check_result, and the IS_PVIO_ASYNC_ACTIVE branches in the
  OpenSSL BIO and GnuTLS push/pull callbacks - they now just call the
  blocking pvio read/write, which yields under the hood
- remove the now-unused IS_BLOCKING_ERROR macro

This also enables async for Schannel: ma_pvio_read/write no longer special
-case !HAVE_SCHANNEL, and Schannel already funnels all socket I/O through
pvio->methods->read/write, so it now suspends/resumes like the others.

Named pipe and shared memory cannot suspend/resume (no pollable socket).
Previously async over them errored on the first read (the async_read
method was NULL -> CR_ASYNC_NOT_SUPPORTED in ma_pvio_read_async). That
guard is gone with the parallel stack, so reject MYSQL_OPT_NONBLOCK over
these transports up front in mysql_real_connect() with the same
CR_ASYNC_NOT_SUPPORTED, instead of silently running synchronously and
blocking the caller's event loop. The ordinary blocking API is unaffected.

Tested:
- main.mysql_client_test_nonblock (the full mysql_client_test suite run
  through the non-blocking start/cont API) passes
- mtr unit suite: all 21 unit.conc_* pass (incl. unit.conc_async)
- the async unit test run directly over forced TLS with both OpenSSL and
  GnuTLS clients (test_async = 100 async connect+handshake+query+close
  iterations) passes, confirming the fiber yields correctly through the
  TLS stack

Co-Authored-By: Claude Opus 4.8 <[email protected]>
PranavKTiwari
MDEV-38839: Assertion `(thd->state_flags & Open_tables_state::BACKUPS_AVAIL) || !thd->has_pending_row_events()' failed in close_thread_tables on CREATE TABLE

Problem:
CREATE TABLE ... SELECT ... FOR UPDATE involving a MyISAM temporary table can trigger an assertion in close_thread_tables() when binary logging is enabled in MIXED mode.

Cause:
MyISAM temporary tables do not support row-level locking, so FOR UPDATE acquires a write lock even for read-only access. This causes the table to be incorrectly classified as a write operation, preventing binlog_truncate_trx_cache() from running and ultimately triggering an assertion.

Fix:
Update decide_logging_format() to check tbl->updating and distinguish actual writes from read-only access. For read-only access to temporary non-transactional tables, mark the statement as STMT_READS_TEMP_NON_TRANS_TABLE instead of treating it as a write. This prevents incorrect write classification and avoids the assertion failure.
Dmitry Shulga
MDEV-37086 Service crashed on procedure call

Extra tests were added
Rucha Deodhar
MDEV-40125: OLD_VALUE crashes on a view with an expression

Analysis:

When OLD_VALUE() is used on a view, field resolution creates an
Item_direct_view_ref instead of an Item_ref where real_item() points to the
expression. But Item_old_field::fix_fields() continues assuming that a Field
object was available, but view references do not have a field pointer,
which resulted in a crash.

Fix:
Store the real referenced item in Item_old_field::expr and use it when
the OLD_VALUE() reference does not have a Field object. This allows
OLD_VALUE() to work with view fields and avoids dereferencing a NULL
field pointer. Fix relevant methods accordingly.
Vladislav Vaintroub
CONC-828 Always use non-blocking sockets

Drop setsockopt, it creates non-portable problems.
We already can do timeouts portably via non-blocking and poll/select.

Also, make sure SSL libraries use underlying pvio methods,
like they do for Schannel already. it is important, also for timeout handling,
and simplifies architecture quite a bit.

So, no more set_fd, but BIO and gnutls push/pull callbacks.
Vladislav Vaintroub
MDEV-40323 CONNECT engine - add file access checks for JSON UDFs

Check FILE_ACL and secure_file_priv for the current user inside json UDFs
Sergei Golubchik
MDEV-40329 Binary_string::qs_append(char): Assertion `str_length + (uint32) (1) <= Alloced_length' failed in AsText

Geometry::as_wkt() didn't take into account bytes written into the
result string in the recusrive call of get_data_as_wkt().
Gis_geometry_collection::get_data_as_wkt() didn't reserve space at all.
Thus nested geometry collections could overflow the buffer.
Vladislav Vaintroub
MDEV-40323 CONNECT engine - add file access checks for JSON UDFs

Check FILE_ACL and secure_file_priv for the current user inside CONNECT
file UDFs (json_file, jfile_make, jbin_file, bson_file, bfile_make,
bbin_file).

Fix NULL filename: guard GetFileLength in jbin_file_init and check for
NULL fn in UDF bodies before the access check, so NULL arguments report
"Missing file name" instead of "Access denied".
Sergei Golubchik
MDEV-40328 ASAN error on malformed WKB multipolygon

before `data+= WKB_HEADER_SIZE` verify that there's enough data.

rewrite this line in Gis_multi_line_string::get_mbr to make clear
that it does not need this check.
bsrikanth-mariadb
MDEV-39916: Crash with having filter when being pushed down

When Item_func_not::fix_fields() is invoked, there are several instances where
ref argument being passed is NULL. One such instance is from the method
st_select_lex::pushdown_from_having_into_where().

Since a null ref is being accessed, a crash occurs.

This PR fixes the problem by not passing null to
Item_func_not::fix_fields() when caling it from
st_select_lex::pushdown_from_having_into_where()
Vladislav Vaintroub
MDEV-40323 CONNECT engine - add file access checks for JSON UDFs

Check FILE_ACL and secure_file_priv for the current user inside json UDFs
bsrikanth-mariadb
MDEV-16462: explain format=json produces illegal json text

The attached_condition field of the produced json text had
"String with illegal unicode symbol" instead of the proper unicode
value.

The reason is that, the item field when being written to the json
writer in write_item(), used a String with charset my_charset_bin,
and that prevented the string from being escaped.

Solution is to change the charset to utf8mb4, and also use
writer->add_escaped_str(...), instead of writer->add_str(...);
Vladislav Vaintroub
CONC-828 Remove pvio blocking/is_blocking methods

Follow-up cleanup to "always use non-blocking sockets": now that the
socket is non-blocking for its whole lifetime, the mode-switching
machinery is dead weight, so remove it.

- Drop the blocking() and is_blocking() pvio methods, the
  ma_pvio_blocking()/ma_pvio_is_blocking() wrappers and the per-plugin
  implementations (socket, shmem, npipe).
- Create the socket non-blocking from the start: a new_nonblocking_socket()
  wrapper around socket() sets O_NONBLOCK/FIONBIO immediately, so the fd
  is never blocking at any point in its lifetime. Replaces the old
  per-operation mode toggling; the connect helpers no longer touch it.
- Remove the Windows-only WIN_SET_NONBLOCKING macro and all its call
  sites in mariadb_async.c - it only existed to work around MSG_DONTWAIT
  not being available on Windows.
- Remove MSG_DONTWAIT usage entirely (the socket is already
  non-blocking). The synchronous pvio_socket_read/write loop over the
  ma_recv()/ma_send() primitives with poll()/select(); the async_read/
  async_write methods stay single non-blocking attempts (the fiber yield
  on would-block remains in ma_pvio_read_async()/ma_pvio_write_async()).
- Fold the three identical EAGAIN/EWOULDBLOCK checks (pvio_socket,
  openssl, gnutls) into a single ma_socket_wouldblock() helper in
  ma_global.h, next to the SOCKET_E* definitions.
- Drop the now-unconditional GNUTLS_EXTERNAL_TRANSPORT define and its
  #ifdef guards in gnutls.c; routing TLS through the pvio methods is the
  only mode, so the dead gnutls_transport_set_int() branch goes away.
PranavKTiwari
dds
forkfun
MDEV-40303 SIGSEGV in Item_field::type_handler() on PS re-execution

Re-executing a prepared statement that reads a derived-table column
holding a scalar UNION subquery crashed the server: between executions
st_select_lex_unit::cleanup() frees union_result and sets 'cleaned' but
leaves 'prepared' set, so on re-fix set_row() walks a stale item_list
whose Item_field::field are NULL.

Fix: prepare() re-prepares a cleaned unit instead of treating it as
still prepared.
Vladislav Vaintroub
MDEV-40323 CONNECT engine - add file access checks for JSON UDFs

Check FILE_ACL and secure_file_priv for the current user inside CONNECT
file UDFs (json_file, jfile_make, jbin_file, bson_file, bfile_make,
bbin_file).

Fix NULL filename: guard GetFileLength in jbin_file_init and check for
NULL fn in UDF bodies before the access check, so NULL arguments report
"Missing file name" instead of "Access denied".
Thirunarayanan Balathandayuthapani
MDEV-39648 Mariabackup: redo log copier stalls and fails with misleading error message

Problem:
========
During backup process, log copier thread stalls at lsn and fails with
the misleading "Was only able to copy log from X to Y, not Z; try increasing
innodb_log_file_size", even when the redo was intact and the log far
from full.

Problem is that copier advances recv_sys.lsn only on CRC-validated mtr,
but it parses the redo at the server is concurrently writing. InnoDB
rewrites the current partial write block repeatedly as mini-transaction
fills it, so an mmap read (or) pread of a page being written can observe
a torn/intermediate image of the tail block. If that tail block happens
to parse as a longer, still valid crc valid mtr then recv_sys.lsn,
recv_sys.offset gets advanced wrongly and points to middle of the
mini-transaction. In that case, later parse return GOT_EOF always
and copier thread never reaches target and fails

Solution:
=========
Poll the server's durably-flushed LSN (status var Innodb_lsn_flushed) and
limit the redo log copier based on it.

backup_log_parse(): parses one mtr and if it exceeds the limit
rolls back recv_sys.lsn/offset and reports GOT_EOF; the copier
re-parses those bytes on a later pass once the fence has
advanced past them. Used on both the mmap and buffered paths.

parse_limit_from_flushed(): Rounds the flushed LSN down to a write-block
boundary, excluding the tail block InnoDB may still be rewriting

log_copying_thread(): opens its own connection (it runs
concurrently with the main thread, which owns mysql_connection) and refreshes
the max_limit for parsing of redo log in each pass.

In the final backup phase (BACKUP STAGE BLOCK_COMMIT) it gates
on the exact target max(metadata_last_lsn, metadata_to_lsn) with no
block-align, so the last partial block is copied in full up to the target.

The stall diagnostic / retry spin is suppressed on a reached_parse_limit wait
so a normal "caught up, wait" is not misreported as drift.

get_log_flushed_lsn(): Added to get log_flushed_lsn from SHOW STATUS outout;
bsrikanth-mariadb
MDEV-16462: explain format=json produces illegal json text

The attached_condition field of the produced json text had
"String with illegal unicode symbol" instead of the proper unicode
value.

The reason is that, the item field when being written to the json
writer in write_item(), used a String with charset my_charset_bin,
and that prevented the string from being escaped.

Solution is to change the charset to utf8mb4, and also use
writer->add_escaped_str(...), instead of writer->add_str(...);
Alexander Barkov
MDEV-37086 Service crashed on procedure call

sp_pcontext::retrieve_field_definitions() did not work correctly
in all combinations of mixed declarations of variables and cursors
with parameters.

Rewriting it in a 2-way merge style algorithm.
- The first tape is the array of variables in m_vars.
- The second tape is the children contexts in m_children,
  also containing variables and cursor parameters.
Daniel Black
MDEV-29542: enable --view-protocol on set_password test

By using the case correct User,Host,Password from the
mysql.user view.
Vladislav Vaintroub
CONC-828 Remove pvio blocking/is_blocking methods

Follow-up cleanup to "always use non-blocking sockets": now that the
socket is non-blocking for its whole lifetime, the mode-switching
machinery is dead weight, so remove it.

- Drop the blocking() and is_blocking() pvio methods, the
  ma_pvio_blocking()/ma_pvio_is_blocking() wrappers and the per-plugin
  implementations (socket, shmem, npipe).
- Create the socket non-blocking from the start: a new_nonblocking_socket()
  wrapper around socket() sets O_NONBLOCK/FIONBIO immediately, so the fd
  is never blocking at any point in its lifetime. Replaces the old
  per-operation mode toggling; the connect helpers no longer touch it.
- Remove the Windows-only WIN_SET_NONBLOCKING macro and all its call
  sites in mariadb_async.c - it only existed to work around MSG_DONTWAIT
  not being available on Windows.
- Remove MSG_DONTWAIT usage entirely (the socket is already
  non-blocking). The synchronous pvio_socket_read/write loop over the
  ma_recv()/ma_send() primitives with poll()/select(); the async_read/
  async_write methods stay single non-blocking attempts (the fiber yield
  on would-block remains in ma_pvio_read_async()/ma_pvio_write_async()).
- Fold the three identical EAGAIN/EWOULDBLOCK checks (pvio_socket,
  openssl, gnutls) into a single ma_socket_wouldblock() helper in
  ma_global.h, next to the SOCKET_E* definitions.
- Drop the now-unconditional GNUTLS_EXTERNAL_TRANSPORT define and its
  #ifdef guards in gnutls.c; routing TLS through the pvio methods is the
  only mode, so the dead gnutls_transport_set_int() branch goes away.
Daniel Black
MDEV-40313 mariadb client creates `.mariadb_histor` instead of `.mariadb_history`

`histfile_size` in `client/mysql.cc` is calculated using the string
"/.mysql_history" (15 chars) rather than "/.mariadb_history" (17 chars).

Because the buffer is only allocated to that shorter length, the resulting
filename is truncated by 2 characters.

Thanks David Lu for the bug report and diagnosis.
Raghunandan Bhat
MDEV-40316: Infer: PULSE_RESOURCE_LEAK in connect

Problem:
  Infer found file descriptors left open on some error code paths in
  connect storage engine.

Fix:
  Close file descriptors on error before returning.
Dmitry Shulga
MDEV-37086 Service crashed on procedure call

Extra tests were added
Vladislav Vaintroub
CONC-828 Always use non-blocking sockets

Drop setsockopt, it creates non-portable problems.
We already can do timeouts portably via non-blocking and poll/select.

Also, make sure SSL libraries use underlying pvio methods,
like they do for Schannel already. it is important, also for timeout handling,
and simplifies architecture quite a bit.

So, no more set_fd, but BIO and gnutls push/pull callbacks.
bsrikanth-mariadb
MDEV-16462: explain format=json produces illegal json text

The attached_condition field of the produced json text had
"String with illegal unicode symbol" instead of the proper unicode
value.

The reason is that, the item field when being written to the json
writer in write_item(), used a String with charset my_charset_bin,
and that prevented the string from being escaped.

Solution is to change the charset to utf8mb4, and also use
writer->add_escaped_str(...), instead of writer->add_str(...);
Teemu Ollakka
MDEV-40222 Prevent MTR hang when waiting for wsrep_ready

A query against a server that is up but wedged can connect yet never
return, so the loop-count bound in wait_wsrep_ready() did not actually
limit the wait and MTR could hang until the suite timeout fired.

Add an optional $timeout to run_query_output(): the mysql client is
now spawned via My::SafeProcess->new and waited for with
wait_one($timeout), killing the client and returning non-zero if it
does not finish in time.

Bound wait_wsrep_ready() by a wall-clock deadline (start_timer)
instead of a loop count, and pass the remaining time to each query so
no single hung client can exceed the overall server startup budget.