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
Sergei Golubchik
s390x
PranavKTiwari
dds
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]>
Pekka Lampio
MDEV-40279 galera.tmp_space_usage test failure

The MTR test galera.tmp_space_usage printed the exact Tmp_space_used /
Max_tmp_space_used byte counts. These come from the binlog cache
temporary file, whose size depends on binary log event encoding and
thus varies across platforms and builds, making the test fail
(e.g. 101706 vs the recorded 102054).

Rewrite the test to check only the invariants the fix is about, as is
already done in main.tmp_space_usage: after the inserts Tmp_space_used
is non-zero and equals Max_tmp_space_used, and after change_user
Tmp_space_used is reset to 0 while Max_tmp_space_used is preserved.

Co-Authored-By: Claude Opus 4.8
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-37996 CMake: MariaDB:: targets for bundled-or-system libraries

Stop overwriting the standard find_package() result variables (ZLIB_FOUND,
ZLIB_LIBRARIES, ZLIB_INCLUDE_DIR(S), ...), this breaks vcpkg.

Provide namespaced INTERFACE targets that point at either the bundled or
the system library and carry their include directories (and, for SSL, the
compile definitions)

  MariaDB::zlib, MariaDB::OpenSSL, MariaDB::pcre2-8, MariaDB::pcre2-posix,
  MariaDB::fmt, MariaDB::readline

Link these consistently instead of the scattered ${*_LIBRARIES} and
${*_INCLUDE_DIR(S)} variables sprinkled across the tree.

Bundled pcre2-posix depends on pcre2-8 so the static link order is correct
for consumers that link only posix.

wolfssl carries its own usage requirements (HAVE_WOLFSSL,
WOLFSSL_USER_SETTINGS); MariaDB::OpenSSL keeps only HAVE_OPENSSL.

Update libmariadb to 3.3 (47a31a98): handles MariaDB::zlib as a submodule.
Vladislav Vaintroub
Merge branch '3.3' into 3.4
  • cc-x-codbc-windows: 'dojob pwd if '3.4' == '3.4' ls win32/test SET TEST_DSN=master SET TEST_DRIVER=master SET TEST_PORT=3306 SET TEST_SCHEMA=odbcmaster if '3.4' == '3.4' cd win32/test if '3.4' == '3.4' ctest --output-on-failure' failed -  stdio
PranavKTiwari
Incorporated CRC.
Sergei Golubchik
MDEV-40312 SHOW CREATE SERVER incorrect quoting

quote protocol name and option names
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]>
Dave Gosselin
MDEV-33524:  marked_for_read assertion with virtual column

A couple of things interact in this scenario.

1. A virtual column whose value depends on session state, such as a
VCOL calling DATE_FORMAT, has fix_fields (via fix_expr) run on it
again before each INSERT.  For a table reused from the cache this runs in
Vcol_expr_context before setup_tables sets the table map.  The test
first opens t1 with a SELECT that fails before setup_tables, leaving
it cached with map zero.

2. When the connection character set needs conversion, CONCAT (more
generally, any charset aggregation) wraps that column in a charset
converter.  The converter evaluates any argument reported as
constant, so it calls val_str() on the column as part of
fix_fields, before a row exists and without the column in the read
set.  On DEBUG builds this fails the marked_for_read assertion;
otherwise it reads an unread column.

Consequently:
When a table instance is opened, fix_fields runs with table->map
already nonzero, but the fix_fields (via fix_expr) call from vcol_fix_expr
did not have it nonzero; so set table->map=1 during Vcol_expr_context::init.
The original Vcol_expr_context::init() (MDEV-24176) called
init_lex_with_single_table, which set table->map= 1 as a side effect.
A later merge of 10.2 into 10.3 (6f6c74b0d18) replaced that call with
a backup of table->expr_arena, dropping the side effect.
The destructor of the Vcol_expr_context will reset the map back to its
original value.
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.
Dave Gosselin
MDEV-33524:  marked_for_read assertion with virtual column

vcol.vcol_misc deadlocks under --view-protocol at the
FLUSH TABLES WITH READ LOCK block.  The main connection holds
the global read lock.  The SELECT COUNT(*) FROM t1 query becomes
CREATE OR REPLACE VIEW on a separate connection, and that DDL
blocks on the read lock and never returns.  So the same mysqltest
client never reaches unlock tables.  The fix is to wrap only that
one SELECT in the view_protocol guards.
Sergei Golubchik
MDEV-30041 don't set utf8_is_utf8mb3 by default in the old-mode
Pekka Lampio
MDEV-40279  Further improvements

Removed unnecessary --enable/disable_query_log statements.
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.
Vladislav Vaintroub
Fix bundled pcre2 static link order (buildbot fulltest regression)

pcre2-posix calls into pcre2-8, and as bundled static libs the linker
resolves pcre2_pattern_info_8 only if pcre2-8 comes after pcre2-posix.
mariadb-test-embedded links mysqlserver, which also pulls pcre2-8, so
CMake de-duplicated the explicit trailing pcre2-8 and left it before
pcre2-posix -> undefined reference. Declare pcre2-posix -> pcre2-8 as an
interface dependency so the order is always correct (also fixes the
mariadb-backup case that links only pcre2-posix).
Dave Gosselin
MDEV-33524:  marked_for_read assertion with virtual column

A couple of things interact in this scenario.

1. A virtual column whose value depends on session state, such as a
VCOL calling DATE_FORMAT, has fix_fields (via fix_expr) run on it
again before each INSERT.  For a table reused from the cache this runs in
Vcol_expr_context before setup_tables sets the table map.  The test
first opens t1 with a SELECT that fails before setup_tables, leaving
it cached with map zero.

2. When the connection character set needs conversion, CONCAT (more
generally, any charset aggregation) wraps that column in a charset
converter.  The converter evaluates any argument reported as
constant, so it calls val_str() on the column as part of
fix_fields, before a row exists and without the column in the read
set.  On DEBUG builds this fails the marked_for_read assertion;
otherwise it reads an unread column.

Consequently:
When a table instance is opened, fix_fields runs with table->map
already nonzero, but the fix_fields (via fix_expr) call from vcol_fix_expr
did not have it nonzero; so set table->map=1 during Vcol_expr_context::init.
The original Vcol_expr_context::init() (MDEV-24176) called
init_lex_with_single_table, which set table->map= 1 as a side effect.
A later merge of 10.2 into 10.3 (6f6c74b0d18) replaced that call with
a backup of table->expr_arena, dropping the side effect.
The destructor of the Vcol_expr_context will reset the map back to its
original value.
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
Vladislav Vaintroub
Update libmariadb to 3.3 (47a31a98)

Pulls the connector fix that removes the bogus stmt_fetch_to_bind length
checks. Without it, connect.bson_udf/json_udf and wide decimal fetches
fail with error 102 (CR_MALFORMED_PACKET) under --ps-protocol.
Vladislav Vaintroub
Remove length checks in mthd_stmt_fetch_to_bind, keep only the sentinel

Commit dcd0a343 added checks that reject a row as CR_MALFORMED_PACKET
based on server-declared lengths -- the field display width
(field->length) and a hardcoded maximum decimal string length. Both
reject valid data under --ps-protocol:

- field->length is result-set metadata, unrelated to the bytes on the
  wire and routinely large for computed expressions and UDFs; it broke
  connect.bson_udf / connect.json_udf with error 102.
- the decimal cap is a copy of a server-internal limit (already bumped
  67 -> 83 -> 121) that goes stale whenever the server raises precision,
  and it guards nothing: a DECIMAL is fetched as a string and converted
  with bounded parsing/copies, so any in-packet length is handled safely.

The sentinel (data_len > remaining packet space) is the real and only
malformed-packet guard the row data needs. Remove both checks, the now
unused MAX_ZEROFILL_LEN / MAX_DECIMAL_LEN, and the test case that
asserted the removed display-length behaviour.
  • cc-x-codbc-windows: 'dojob pwd if '3.4' == '3.4' ls win32/test SET TEST_DSN=master SET TEST_DRIVER=master SET TEST_PORT=3306 SET TEST_SCHEMA=odbcmaster if '3.4' == '3.4' cd win32/test if '3.4' == '3.4' ctest --output-on-failure' failed -  stdio
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.
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.
Sergei Golubchik
CREATE SERVER: fix option parsing to support backticks properly

CREATE SERVER used to:
* support arbitrary options in backticks and not in backticks
* hard-coded historical options worked *only* without backticks
* PORT range was different when given as a number or a string

all that is fixed, unused keywords are removed
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.
Dave Gosselin
MDEV-33524:  marked_for_read assertion with virtual column

vcol.vcol_misc deadlocks under --view-protocol at the
FLUSH TABLES WITH READ LOCK block.  The main connection holds
the global read lock.  The SELECT COUNT(*) FROM t1 query becomes
CREATE OR REPLACE VIEW on a separate connection, and that DDL
blocks on the read lock and never returns.  So the same mysqltest
client never reaches unlock tables.  The fix is to wrap only that
one SELECT in the view_protocol guards.
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.
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.