Repository navigation
Manifest merge local public - #826
surendarchandra wants to merge 2 commits into
Conversation
mysql-test-run.pl treats <basedir>/bin/mysqld.my as scratch space it
owns. create_manifest_file truncates whatever is there (using a
two-arg open in write mode) and writes an MTR redirect manifest
{"read_local_manifest": true}; remove_manifest_file then unlinks
the file. There is no backup and no restore, so a component manifest
that was present before the run is silently destroyed.
The global manifest is the only mechanism that loads components before
InnoDB starts (mysql.component is InnoDB-resident). A distribution
or administrator who installs a manifest — for example to load a
keyring component for tablespace encryption at rest — loses it the
first time MTR runs against that basedir.
Design
------
Move the manifest aside (<path>.mtr_saved) before the first server
start; a same-directory rename preserves mode and ownership and needs
only directory write permission, so a read-only manifest is handled
without changing its permissions. Restore it from the single END hook
inside its parent-only guard, which is armed before the manifest is
touched. The restore is three-state idempotent:
* pending — backup exists, rename it back; clear state only on success.
* done — no-op (double-restore safe).
* (unset) — nothing was saved, nothing to do.
Additional safeguards:
* A run holds an exclusive flock on <path>.mtr_lock from the backup
until the restore, so a second run sharing the basedir dies before
touching anything instead of renaming its stub over the backup.
The lock file is created shared-mode (0666), as mtr_unique.pm does
for build-thread ids, so sequential runs by different users of a
group-writable directory can reuse it.
* The restore is skipped only when --start-and-exit hands off after
the worker reports that the servers are running (and every worker
exited 0): the detached server keeps running and needs MTR's
manifest in place, and the backup stays adjacent for the next MTR
run to adopt and restore. A --start-and-exit run whose setup or
server start fails, or whose tests are all skipped, is restored like
any other run.
* An existing backup from a crashed prior run is adopted only when the
file at the manifest path is MTR's own stub; if both hold different
content, MTR dies before truncating anything rather than guessing
which is current.
* When MTR creates the stub itself it also drops a marker
(<path>.mtr_stub). At the next start, a file beside a marker is
MTR-owned: a leftover stub is unlinked, and anything else (e.g. a
manifest written by an interrupted test) is moved to <path>.mtr_leftover
with a warning rather than being restored into the installation.
* die() is called before truncating if the rename fails.
* Every move is a same-directory rename(), never File::Copy::move: it
is atomic and has no copy fallback, so a failed restore leaves the
stub and the backup untouched for the END-block retry or for
adoption by the next run.
* Restore state is cleared only after the files are actually gone, so
the END-block safety net can retry after a failed unlink or rename.
* On exit the stub is unlinked only if it still holds MTR's own text; a
stub that changed during the run (e.g. a keyring test that failed
before its teardown) is quarantined to <path>.mtr_leftover with a
warning, so the next run never adopts it as a user manifest. If
that rename fails the marker is kept and the next run quarantines it.
* Restore never dies: an unreadable stub is reported and kept for a
later retry.
* A manifest that cannot be read is reported as such, never as a
content conflict.
Abort handling: when MTR is interrupted or dies, its workers may still
be running a test that rewrites the manifest (keyring tests rename their
own backup over it at teardown). The END hook therefore stops and reaps
the workers (stop_workers(), shared with the normal exit path) before it
restores the manifest. On Windows mtr_error() leaves via POSIX::_exit,
which skips END blocks, so the parent installs a pre-exit hook in
mtr_report that stops the workers and restores the manifest first.
The lifecycle logic is extracted into My::Manifest so it can be tested
independently of the MTR harness.
Test coverage
-------------
mysql-test/lib/t/manifest.t exercises the module with Test::More,
following the existing lib/t convention; manifest.t runs under
main.mtr_unit_tests, with test descriptions and skip reasons normalized
so the recorded result does not depend on the platform or user. Cases:
* crashed-prior-run backup adoption
* conflicting backup and newly installed manifest → refuse loudly
* double-restore no-op
* rename failure at create (die before truncate)
* whitespace-path open
* failed restore leaves stub and backup intact; retry restores, and a
next run adopts the backup without a conflict
* failed unlink keeps state for retry
* leftover-stub (marker) detection
* stub-text manifest without marker is preserved
* content written after the stub was created is quarantined, not restored
* interrupted keyring-style test leaves no permanent manifest
* mode/inode preservation across backup and restore
* manifest replaced during the run is quarantined at cleanup and not
adopted by the next run
* stub-write failure after the backup is restored by the END path
* unreadable manifest yields an accurate error
* unreadable stub at restore is kept and retried
* a concurrent run is refused while the first holds the lock; a lock
left by a dead run does not block the next one; the lock file is
mode 0666 regardless of umask and an existing one is reused
* --start-and-exit: a failed setup is restored; a hand-off leaves the
stub and backup for the next run, which restores the original
* root-unreliable chmod injection (SKIPped when running as root)
There was a problem hiding this comment.
Found one correctness issue: the saved-manifest regex can select the wrong JSON field or miss an escaped key, silently changing the components loaded during MTR. See the inline comment for examples and a suggested fix.
Reviewed all 10 changed files statically. PR-provided code and tests were not executed, as required by this workflow; CI check data was unavailable.
Warning
Firewall blocked 1 domain
The following domain was blocked by the firewall during workflow execution:
ab.chatgpt.com
To allow these domains, add them to the network.allowed list in your workflow frontmatter:
network:
allowed:
- defaults
- "ab.chatgpt.com"See Network Configuration for more information.
Generated by Codex PR Review for #826 · codex · gpt60 · 187 AIC · ⌖ 23.8 AIC · ⊞ 13.9K
Comment /codex to run again
0fd6bbb to
3f8046c
Compare
There was a problem hiding this comment.
Found two correctness issues: unreadable local manifests are silently omitted during merging, and MTR's generated stub overrides existing read_local_manifest precedence. Both are detailed inline with suggested regression coverage.
Static review of the PR diff and affected callers only; PR code and tests were not executed. Existing review threads were unavailable under the access policy.
Warning
Firewall blocked 1 domain
The following domain was blocked by the firewall during workflow execution:
ab.chatgpt.com
To allow these domains, add them to the network.allowed list in your workflow frontmatter:
network:
allowed:
- defaults
- "ab.chatgpt.com"See Network Configuration for more information.
Generated by Codex PR Review for #826 · codex · gpt60 · 196.5 AIC · ⌖ 24 AIC · ⊞ 13.9K
Comment /codex to run again
Blueprint https://blueprints.launchpad.net/percona-server/+spec/audit-log-default-db Add field `DB' for `MYSQL_AUDIT_GENERAL_STATUS' records. ========================================== [mysql#786] Bug 1610242: Reading past the end of heap buffer on saving the default DB in audit p Original title: [mysql#786] Bug 1610242: Reading past the end of heap buffer on saving the default DB in audit plugin memcpy in the call memcpy(local->db, event_general->general_query, sizeof(local->db)); always copies `NAME_LEN' bytes, but the real length of the `general_query' can be less than `NAME_LEN' Fix is to copy `general_query_length' bytes. ========================================== [#930] Bug 1613647: Sporadic audit_log_filter_users failures Insert silent statements (which aren't are grepped away) before connects to make sure the previous statement we which want to see in the audit log actually gets there before the connect. ========================================== [#941] Bug 1617833: audit_log_default_db failures 1. Insert silent statement after UNINSTALL PLUGIN to make sure that SHOW WARNINGS is logged before the statement from the next connection. 2. Insert silent statement before establishing the connection which does 'INSTALL PLUGIN', make sure 'SELECT * FROM t' gets to the log. 3. Make reconnect in case of error optional for 'change_user' mysqltest command ========================================== [#1682] Bug 1650294: Test main.audit_log_filter_users is unstable The source of instability is the fact that event of creating new connection and closing previous one are not synchronized. It makes "Quit" record to appear after "Connect" one. Fix is to replace `include/wait_until_disconnected.inc' which waits for client connection to be closed with `include/wait_until_count_sessions.inc' which waits for specific `Threads_connected' value which is updated after `MYSQL_AUDIT_NOTIFY_CONNECTION_DISCONNECT'. ========================================== [#1762] Bug 1626559: Test `main.audit_log_default_db' is unstable Sometimes "SHOW WARNINGS" appears in the audit log around UNINSTALL PLUGIN / INSTALL PLUGIN. This is the warning which MySQL issue about plugin being in use. Normally warning should not make it to audit log because test case truncates log after UNINSTALL PLUGIN. But sometimes mysql-test picks this warning up after plugin has been reinstalled and it gets logged into audit log. This patch makes sure that test execution continues only when plugin disappeared from the `mysql.plgins', which happens after `deinit' is called and all plugin is fully shut down. ========================================== [mysql#736] Allow to log only queries for specific DBs in audit log plugin Blueprint: [https://blueprints.launchpad.net/percona-server/+spec/audit-filer-db] Add two global variables: - `audit_log_include_databases' comma separated list of databases to include in audit logging - `audit_log_exclude_databases' comma separated list of databases to exclude from audit logging Allow escaped backticks in the `next_word' function. This change needs to be backported to the 5.6. Patch changes behaviour of user and database filters. User filter becomes case sensitive for user name and case insensitive for host name. Database filter becomes case insensitive. [#931] Bug 1617828: audit_log_filter_db failures The fix increases timeout for event shot wait to 10 minutes and adds silent query at the end of the event. ============================================================ [mysql#826] Add filtering by `sql_command' Blueprint: https://blueprints.launchpad.net/percona-server/+spec/audit-filer-command - add option `audit_log_include_command' to specify commands to log - add option `audit_log_exclude_command' to specify commands to exclude from logging - backport changes for `next_word' fixing the capture of default database with quoted backticks. - backport case-sensitivity fix for account filters ========================================== [#1381] Bug 1650321: Valgrind error on main.audit_log_filter_commands Valgrind complained about `cmd' being used uninitialized. However, I don't a path when it could happen, since the first command was to initialize it unconditionally. Still this error message pointed me to the fact that we don't need `cmd' at all, we can simply use `name' and `length' provided as arguments. ========================================== [#1444] Bug 1663251: ASan errors on main.audit_log_filter_commands `my_hash_search' takes two arguments - key to search for and it's length. When length is 0, `my_hash_search' considers that key has the same length as hash length. Since this behaviour may be relied on somewhere, the fix is to avoid calling `my_hash_search' for empty strings. ========================================== [#846] Bug 1614444: Assertion `local->stack.frames[local->stack.top].query == event_general->general_query.str' failed It is a bug which can affects filtering by DB for triggers. There is a trigger CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW SET @Aux=1; and query INSERT INTO t1(c5,c6)VALUES (1,0); Lets see which events are sent to the audit_log: 1. TABLE ACCESS event for "INSERT INTO t1(c5,c6)VALUES (1,0)" 2. STATUS event for "SET @Aux=1" 3. STATUS event for "INSERT INTO t1(c5,c6)VALUES (1,0)" When (1) comes, plugin pushes "INSERT INTO t1(c5,c6)VALUES (1,0)" to the top of the stack, so it can match it later with STATUS event. When (2) comes, plugin is trying to match "SET @Aux=1" against the stack top. But "SET @Aux=1" isn't on the stack since it doesn't access any database. In debug mode we see the assertion failure. In the release mode, "SET @Aux=1" will be attributed as accessing table "t1", which is wrong. The fix is to replace assert with if statement. Now the query the within trigger which doesn't access any database will always be logged just like any similar query executed outside of the trigger. ============================================================ [#1176] Bug 1641910: Trying to set audit_log_exclude_accounts crashes server The root cause of this bug is that logic around filtering variables rely heavily on the fact that CHECK and UPDATE functions are always called. This is not true when variables passed via defaults file or set as command line options. The fix is add special handling for filtering variables on startup. ========================================== [#1451] Bug 1666496: Server crashes on startup if plugin is unable to create file pointed by --audit_log_file In order to expose this bug we need to set both --audit-log-exclude-commands and --audit-log-file at start up. Second one has to be incorrect, so that plugin would refuse to start with error: mysqld: File './data-dir/mysql-audit.json' not found (Errcode: 2 - No such file or directory) 2017-02-21T11:58:42.392280Z 0 [ERROR] Plugin audit_log reported: 'Cannot open file ./data-dir/mysql-audit.json.' 2017-02-21T11:58:42.392350Z 0 [ERROR] Plugin audit_log reported: 'Error: No such file or directory' 2017-02-21T11:58:42.392355Z 0 [ERROR] Plugin 'audit_log' init function returned error. 2017-02-21T11:58:42.392360Z 0 [ERROR] Plugin 'audit_log' registration as a AUDIT failed. The cause for the crash is common with bug 1641910. MEMALLOC'ed variables are not properly initialized by server (UPDATE and CHECK functions aren't invoked). The fix is to make sure that initialization of MEMALLOC'ed variables is the very first thing we do. ========================================== [#2032] lp1716844: Escaping control characters in the audit log Implemented escaping for the JSON output format, and updated the test suite. The other output formats are left unchanged, as they do not have a well defined method for escaping these characters. XML does support control characters in version 1.1, but most tools only understand 1.0, and our output is 1.0. ========================================== [g5]PS-5363 (Merge MySQL 8.0.17): fixed audit_log.audit_log_default_db MTR test case Similarly to what Oracle did in treir fix for Bug #29248047 "5.7 AUDIT PLUGIN DOES NOT LOG WHO UNINSTALLS THE AUDIT PLUGIN UNLIKE 5.6" (commit mysql/mysql-server@6a893b8) added '--source include/disconnect_connections.inc' to 'audit_log.audit_log_default_db' MTR test case after plugin uninstallation.
Blueprint https://blueprints.launchpad.net/percona-server/+spec/audit-log-default-db Add field `DB' for `MYSQL_AUDIT_GENERAL_STATUS' records. ========================================== [mysql#786] Bug 1610242: Reading past the end of heap buffer on saving the default DB in audit p Original title: [mysql#786] Bug 1610242: Reading past the end of heap buffer on saving the default DB in audit plugin memcpy in the call memcpy(local->db, event_general->general_query, sizeof(local->db)); always copies `NAME_LEN' bytes, but the real length of the `general_query' can be less than `NAME_LEN' Fix is to copy `general_query_length' bytes. ========================================== [#930] Bug 1613647: Sporadic audit_log_filter_users failures Insert silent statements (which aren't are grepped away) before connects to make sure the previous statement we which want to see in the audit log actually gets there before the connect. ========================================== [#941] Bug 1617833: audit_log_default_db failures 1. Insert silent statement after UNINSTALL PLUGIN to make sure that SHOW WARNINGS is logged before the statement from the next connection. 2. Insert silent statement before establishing the connection which does 'INSTALL PLUGIN', make sure 'SELECT * FROM t' gets to the log. 3. Make reconnect in case of error optional for 'change_user' mysqltest command ========================================== [#1682] Bug 1650294: Test main.audit_log_filter_users is unstable The source of instability is the fact that event of creating new connection and closing previous one are not synchronized. It makes "Quit" record to appear after "Connect" one. Fix is to replace `include/wait_until_disconnected.inc' which waits for client connection to be closed with `include/wait_until_count_sessions.inc' which waits for specific `Threads_connected' value which is updated after `MYSQL_AUDIT_NOTIFY_CONNECTION_DISCONNECT'. ========================================== [#1762] Bug 1626559: Test `main.audit_log_default_db' is unstable Sometimes "SHOW WARNINGS" appears in the audit log around UNINSTALL PLUGIN / INSTALL PLUGIN. This is the warning which MySQL issue about plugin being in use. Normally warning should not make it to audit log because test case truncates log after UNINSTALL PLUGIN. But sometimes mysql-test picks this warning up after plugin has been reinstalled and it gets logged into audit log. This patch makes sure that test execution continues only when plugin disappeared from the `mysql.plgins', which happens after `deinit' is called and all plugin is fully shut down. ========================================== [mysql#736] Allow to log only queries for specific DBs in audit log plugin Blueprint: [https://blueprints.launchpad.net/percona-server/+spec/audit-filer-db] Add two global variables: - `audit_log_include_databases' comma separated list of databases to include in audit logging - `audit_log_exclude_databases' comma separated list of databases to exclude from audit logging Allow escaped backticks in the `next_word' function. This change needs to be backported to the 5.6. Patch changes behaviour of user and database filters. User filter becomes case sensitive for user name and case insensitive for host name. Database filter becomes case insensitive. [#931] Bug 1617828: audit_log_filter_db failures The fix increases timeout for event shot wait to 10 minutes and adds silent query at the end of the event. ============================================================ [mysql#826] Add filtering by `sql_command' Blueprint: https://blueprints.launchpad.net/percona-server/+spec/audit-filer-command - add option `audit_log_include_command' to specify commands to log - add option `audit_log_exclude_command' to specify commands to exclude from logging - backport changes for `next_word' fixing the capture of default database with quoted backticks. - backport case-sensitivity fix for account filters ========================================== [#1381] Bug 1650321: Valgrind error on main.audit_log_filter_commands Valgrind complained about `cmd' being used uninitialized. However, I don't a path when it could happen, since the first command was to initialize it unconditionally. Still this error message pointed me to the fact that we don't need `cmd' at all, we can simply use `name' and `length' provided as arguments. ========================================== [#1444] Bug 1663251: ASan errors on main.audit_log_filter_commands `my_hash_search' takes two arguments - key to search for and it's length. When length is 0, `my_hash_search' considers that key has the same length as hash length. Since this behaviour may be relied on somewhere, the fix is to avoid calling `my_hash_search' for empty strings. ========================================== [#846] Bug 1614444: Assertion `local->stack.frames[local->stack.top].query == event_general->general_query.str' failed It is a bug which can affects filtering by DB for triggers. There is a trigger CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW SET @Aux=1; and query INSERT INTO t1(c5,c6)VALUES (1,0); Lets see which events are sent to the audit_log: 1. TABLE ACCESS event for "INSERT INTO t1(c5,c6)VALUES (1,0)" 2. STATUS event for "SET @Aux=1" 3. STATUS event for "INSERT INTO t1(c5,c6)VALUES (1,0)" When (1) comes, plugin pushes "INSERT INTO t1(c5,c6)VALUES (1,0)" to the top of the stack, so it can match it later with STATUS event. When (2) comes, plugin is trying to match "SET @Aux=1" against the stack top. But "SET @Aux=1" isn't on the stack since it doesn't access any database. In debug mode we see the assertion failure. In the release mode, "SET @Aux=1" will be attributed as accessing table "t1", which is wrong. The fix is to replace assert with if statement. Now the query the within trigger which doesn't access any database will always be logged just like any similar query executed outside of the trigger. ============================================================ [#1176] Bug 1641910: Trying to set audit_log_exclude_accounts crashes server The root cause of this bug is that logic around filtering variables rely heavily on the fact that CHECK and UPDATE functions are always called. This is not true when variables passed via defaults file or set as command line options. The fix is add special handling for filtering variables on startup. ========================================== [#1451] Bug 1666496: Server crashes on startup if plugin is unable to create file pointed by --audit_log_file In order to expose this bug we need to set both --audit-log-exclude-commands and --audit-log-file at start up. Second one has to be incorrect, so that plugin would refuse to start with error: mysqld: File './data-dir/mysql-audit.json' not found (Errcode: 2 - No such file or directory) 2017-02-21T11:58:42.392280Z 0 [ERROR] Plugin audit_log reported: 'Cannot open file ./data-dir/mysql-audit.json.' 2017-02-21T11:58:42.392350Z 0 [ERROR] Plugin audit_log reported: 'Error: No such file or directory' 2017-02-21T11:58:42.392355Z 0 [ERROR] Plugin 'audit_log' init function returned error. 2017-02-21T11:58:42.392360Z 0 [ERROR] Plugin 'audit_log' registration as a AUDIT failed. The cause for the crash is common with bug 1641910. MEMALLOC'ed variables are not properly initialized by server (UPDATE and CHECK functions aren't invoked). The fix is to make sure that initialization of MEMALLOC'ed variables is the very first thing we do. ========================================== [#2032] lp1716844: Escaping control characters in the audit log Implemented escaping for the JSON output format, and updated the test suite. The other output formats are left unchanged, as they do not have a well defined method for escaping these characters. XML does support control characters in version 1.1, but most tools only understand 1.0, and our output is 1.0. ========================================== [g5]PS-5363 (Merge MySQL 8.0.17): fixed audit_log.audit_log_default_db MTR test case Similarly to what Oracle did in treir fix for Bug #29248047 "5.7 AUDIT PLUGIN DOES NOT LOG WHO UNINSTALLS THE AUDIT PLUGIN UNLIKE 5.6" (commit mysql/mysql-server@6a893b8) added '--source include/disconnect_connections.inc' to 'audit_log.audit_log_default_db' MTR test case after plugin uninstallation.
3f8046c to
76d61e5
Compare
There was a problem hiding this comment.
Found two correctness issues: merge-enabled startup skips deduplication when the local manifest is absent or zero bytes, and MTR's JSON conversion can silently change the selected components when keys repeat. Both findings include inline examples and suggested regression coverage.
Reviewed the changes and relevant callers without executing PR code or tests. Existing review threads were unavailable under the GitHub integrity policy, so duplicate-comment checking was limited.
Warning
Firewall blocked 1 domain
The following domain was blocked by the firewall during workflow execution:
ab.chatgpt.com
To allow these domains, add them to the network.allowed list in your workflow frontmatter:
network:
allowed:
- defaults
- "ab.chatgpt.com"See Network Configuration for more information.
Generated by Codex PR Review for #826 · codex · gpt60 · 239.5 AIC · ⌖ 24.2 AIC · ⊞ 13.9K
Comment /codex to run again
76d61e5 to
2198f6d
Compare
There was a problem hiding this comment.
Reviewed the changes at 2198f6d3f7d59cfbe7057766fd2e9989de350cea. Found one correctness issue: merge mode silently drops a local manifest that cannot be opened, allowing startup with an incomplete component set. See the inline finding for the suggested fix and regression coverage.
Static review only; PR code and tests were not executed. Existing review threads were unavailable because the read tool's integrity policy blocked access.
Warning
Firewall blocked 1 domain
The following domain was blocked by the firewall during workflow execution:
ab.chatgpt.com
To allow these domains, add them to the network.allowed list in your workflow frontmatter:
network:
allowed:
- defaults
- "ab.chatgpt.com"See Network Configuration for more information.
Generated by Codex PR Review for #826 · codex · gpt60 · 170.2 AIC · ⌖ 24 AIC · ⊞ 13.9K
Comment /codex to run again
read_local_manifest discards the global manifest reader before the
"components" key is parsed, so code that needs both the global and
local component lists has no way to obtain them from a single
reader — they are mutually exclusive.
A new boolean key, merge_local_manifest, makes the global reader
append the local manifest's components after the global ones.
Existing single-key manifests are unaffected: the key defaults to
false and the reader's behaviour is unchanged when it is absent.
The component separator is single-sourced as a constexpr consumed by
both the splitter (get_next_component) and an inline merge helper
(merge_component_lists), so there is exactly one representation of
the delimiter in the codebase.
Merged lists are de-duplicated and a local manifest resolving to
the global file is not merged into itself. A local manifest that
cannot be opened is treated as absent, as Manifest_reader does
elsewhere; one that opens but has no readable "components" is a
startup error.
The merge step (merge_local_components) always passes the global list
through the de-duplicating merge, so a repeated global URN is loaded
once even when no local manifest exists or it is zero bytes.
The MTR consumer (My::Manifest) preserves the deployment's
components for the duration of the run, ensuring restarts see the
same list that was present at boot. It decodes the saved manifest
with JSON::PP and takes only the top-level "components" string, as
the server's reader does. A saved manifest whose read_local_manifest is
true keeps the plain redirect stub, because the server applies that
key before reading "components". A saved manifest that repeats
"components" or read_local_manifest at the top level is refused:
JSON::PP keeps the last occurrence while the server's RapidJSON lookup
selects the first.
GUnit coverage (manifest-t.cc):
* composition of global + local component lists
* empty inputs (global-only, local-only, both empty)
* no trailing separator in merged output
* duplicate URN across global and local is kept once (global position)
* local entirely contained in global yields global unchanged
* duplicates within one side are also collapsed
* empty tokens (',,') do not produce empty URNs
* new-key default-false (merge_local_manifest absent)
* read_local_manifest behaviour unchanged
* merge step with an absent, zero-byte, populated or self-referencing
local manifest de-duplicates the global list; a local manifest
without "components" fails
* POSIX fixture (tempfile cleanup) guarded for non-Windows
Tests (manifest.t):
* crash recovery when the merge stub is on disk
* nested "components" ignored; escaped key recognised; value
re-encoded; non-string value and malformed JSON rejected
* repeated top-level "components" / read_local_manifest rejected;
nested or unrelated repeated keys accepted
2198f6d to
f194c20
Compare
There was a problem hiding this comment.
No high-confidence defects found in the reviewed changes. Reviewed global/local component merging, MTR manifest preservation and cleanup, and the added test coverage.
Validation was static only; PR code and tests were not executed. Existing review threads were unavailable under the GitHub read integrity policy.
Warning
Firewall blocked 1 domain
The following domain was blocked by the firewall during workflow execution:
ab.chatgpt.com
To allow these domains, add them to the network.allowed list in your workflow frontmatter:
network:
allowed:
- defaults
- "ab.chatgpt.com"See Network Configuration for more information.
Generated by Codex PR Review for #826 · codex · gpt60 · 210 AIC · ⌖ 23.6 AIC · ⊞ 13.9K
Comment /codex to run again
What does this change do?
Fixes #827
Stacked PR: this branch is built on #823 ("MTR: preserve a pre-existing component manifest"), and its first commit is that fix. Please review #823 first and this PR after it; only the second commit, "Components: support merge_local_manifest in the global manifest", is new here. Once #823 merges, this branch will be rebased so that only that commit remains.
This change adds a boolean manifest key,
merge_local_manifest. When it istruein the global manifest, the global components are loaded first and the local manifest's components are appended after them.Behaviour:
merge_local_manifestdefaults tofalse; manifests that do not use it, including those usingread_local_manifest, behave exactly as before.,,are ignored. A local manifest that resolves to the global file is not merged into itself.componentscannot be read is a startup error, as for the global manifest; it is never silently dropped.constexprshared by the splitter and the merge helper, andmanifest_version_1_0is madeinlineto remove a header-defined-variable ODR violation.components, MTR writes a merge stub so those components stay loaded during the run and across restarts; otherwise it writes the plain redirect as before. The saved manifest is decoded as JSON (coreJSON::PP) and only its top-levelcomponentsstring is used, as the server's reader does; a non-string value, or malformed JSON that mentionscomponents, stops the run with the original kept.Why is it needed?
read_local_manifestdiscards the global manifest reader before itscomponentskey is parsed, so the global and local component lists are mutually exclusive. A deployment cannot say "always load these components and let each instance add its own"; the global list must be duplicated in every local manifest, which is error-prone and prevents central management of components such as a keyring or audit log.How was it tested?
mysql-test/(Perl unit testmysql-test/lib/t/manifest.t)scripts/ci/mtr.shpasses locallymysql-testsuite, this branch vs the unpatched base;component_keyring_fileDetails:
manifest-t(merged intomerge_small_tests-t): 12 cases, 12/12 pass. Global + local composition, empty inputs, no trailing separator, cross-side and same-side duplicates, local contained in global, empty tokens,merge_local_manifestabsent/present, andread_local_manifestunchanged.mysql-test/lib/t/manifest.t: 213 Test::More assertions (185 from MTR: preserve a pre-existing component manifest #823), all pass. Adds merge-stub creation, fallback to the plain stub when there is nocomponentskey, an unparseablecomponentsvalue failing loudly with the original intact, crash recovery with the merge stub on disk, and JSON handling: a nestedcomponentskey is ignored, an escaped key (\u0063omponents) is recognised, the value is re-encoded, and non-string values and malformed JSON are rejected.component_keyring_filesuite: all 38 tests successful (37 tests + shutdown report; 22 skipped: 21 need--big-test, 1 is Windows-only).bin/mysqld.my={"components":"file://component_keyring_file"},main.1standcomponent_keyring_file.encrypt_explicit --big-testpass withcomponent_keyring_fileloaded through the merge stub, and the manifest is unchanged afterwards (same inode, mode, size, mtime and checksum; no.mtr_saved/.mtr_stubleft, only the persistent.mtr_lock). (--nowarningswas used because the globally loaded keyring has no keyring configuration in this setup and logs an initialisation error.)mysql-testsuite (Debug,--parallel=16 --retry=0, NDB skipped) on this branch vs the unpatched base: 6/7124 tests failing vs 8/7123 on the base. Five failures are common to both runs; the only failure seen just with the patch,perfschema.system_events_component(it loads its component withINSTALL COMPONENT, not through a manifest), passes 3/3 in isolation on both builds, and the three base-only failures passed with the patch. Zero patch-attributable regressions.Contributor checklist
scripts/ci/format.sh)AI assistance
If AI assistance was used, describe the tool(s) and extent of use:
An AI coding assistant was used to draft parts of the implementation, tests and this description. All changes were reviewed, built and tested by the author, who takes responsibility for them.
Areas touched
components / manifest (
include/manifest.h,sql/sql_component.cc), mysql-test harness (mysql-test/lib/My/Manifest.pm), tests (unittest/gunit/manifest-t.cc,unittest/gunit/CMakeLists.txt,mysql-test/lib/t/manifest.t).This contribution is submitted under the corporate Oracle Contributor Agreement that covers the author's submissions to the MySQL project.