Skip to content

MDEV-39548 Further cleanup of MDL_request boilerplate#5160

Open
longjinvan wants to merge 1 commit into
MariaDB:mainfrom
longjinvan:MDEV-39548
Open

MDEV-39548 Further cleanup of MDL_request boilerplate#5160
longjinvan wants to merge 1 commit into
MariaDB:mainfrom
longjinvan:MDEV-39548

Conversation

@longjinvan
Copy link
Copy Markdown
Contributor

Description

This is a follow-up work to PR 5075 ("Cleanup MDL_request boilerplate with ACQUIRE_LOCK macro").

Change thd->backup_commit_lock from MDL_request* to MDL_ticket*

Previously, thd->backup_commit_lock stored a pointer to a stack-allocated MDL_request, creating dangling pointer risks if the function returned early or the code was refactored without clearing the pointer. This patch changes the type to MDL_ticket*, which is managed by the MDL subsystem and does not depend on the caller's stack frame. All related call sites (handler.cc, log.cc, sql_class.cc, xa.cc, sql_reload.cc, sql_repl.cc) are converted to use MDL_ACQUIRE_LOCK directly.

Convert partition_info.cc to MDL_ACQUIRE_LOCK

Investigation confirmed that tl->mdl_request is not accessed by downstream code after lock acquisition -- only table->mdl_ticket is used. The conversion is safe.

Add MDL_REQUEST_LIST_ADD() helper

For batch lock acquisition via acquire_locks(), callers previously needed 3 steps: allocate an MDL_request on MEM_ROOT, initialize it, and push it into the list. The new MDL_REQUEST_LIST_ADD() macro combines these into a single call with built-in OOM checking. Call sites in sql_base.cc and sp.cc are converted.

sql_show.cc investigation

Investigation determined that table_list.mdl_request.key is used by tdc_acquire_share() for hash lookup after lock acquisition, so this call site cannot be converted to MDL_ACQUIRE_LOCK without a larger refactor of the TDC interface.

Release Notes

N/A

How can this PR be tested?

  • All MTR tests pass, confirming no regressions introduced by this refactoring.

Basing the PR against the correct MariaDB version

  • This is a refactoring change, and the PR is based against the latest MariaDB development branch.

Copyright

All new code of the whole pull request, including one or several files that are either new files or modified ones, are contributed under the BSD-new license. I am contributing on behalf of my employer Amazon Web Services, Inc.

- Change thd->backup_commit_lock from MDL_request* to MDL_ticket*,
  and convert all related call sites.

- Convert acquire_lock() in partition_info.cc to MDL_ACQUIRE_LOCK.

- Convert try_acquire_lock()/acquire_lock() in sql_show.cc to
  MDL_TRY_ACQUIRE_LOCK/MDL_ACQUIRE_LOCK.

- Add MDL_REQUEST_LIST_ADD() helper for enqueuing lock requests into
  MDL_request_list, and convert call sites in sql_base.cc and sp.cc.

All new code of the whole pull request, including one or several files
that are either new files or modified ones, are contributed under the
BSD-new license. I am contributing on behalf of my employer Amazon Web
Services, Inc.
Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request refactors metadata locking (MDL) by replacing local MDL_request stack allocations and manual lock acquisitions with helper macros like MDL_ACQUIRE_LOCK and MDL_REQUEST_LIST_ADD, and changing backup_commit_lock to store an MDL_ticket pointer. The review feedback highlights a code smell in sql_show.cc where a sentinel pointer (MDL_ticket *) 1 is returned to indicate errors; the reviewer suggests returning a boolean instead, populating the ticket directly, and encapsulating key initialization within the helper function.

Comment thread sql/sql_show.cc
Comment on lines +5165 to +5169
static MDL_ticket *
try_acquire_high_prio_shared_mdl_lock(THD *thd, TABLE_LIST *table,
bool can_deadlock)
{
bool error;
MDL_REQUEST_INIT(&table->mdl_request, MDL_key::TABLE, table->db.str,
table->table_name.str, MDL_SHARED_HIGH_PRIO,
MDL_TRANSACTION);
MDL_ticket *ticket;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

Returning (MDL_ticket *) 1 as a sentinel value to indicate an error is a code smell and can lead to undefined behavior or hard-to-debug issues if the caller ever attempts to dereference it.\n\nInstead of using a sentinel pointer, we should keep the return type as bool (returning true on error, false on success) and populate table->mdl_request.ticket directly. This preserves the original clean semantics, avoids sentinel pointer hacks, and ensures table->mdl_request.ticket is correctly populated for any downstream code.\n\nWe should also initialize table->mdl_request.key inside this function using mdl_key_init to keep the implementation details encapsulated.

static bool\ntry_acquire_high_prio_shared_mdl_lock(THD *thd, TABLE_LIST *table,\n                                      bool can_deadlock)\n{\n  MDL_ticket *ticket;\n  table->mdl_request.key.mdl_key_init(MDL_key::TABLE, table->db.str,\n                                      table->table_name.str);

Comment thread sql/sql_show.cc
Comment on lines +5185 to 5203
bool error;
ticket= thd->mdl_context.MDL_TRY_ACQUIRE_LOCK(
MDL_key::TABLE, table->db.str, table->table_name.str,
MDL_SHARED_HIGH_PRIO, MDL_TRANSACTION, error);
if (error)
return (MDL_ticket *) 1; /* error indicator */
}
else
error= thd->mdl_context.acquire_lock(&table->mdl_request,
thd->variables.lock_wait_timeout);
{
ticket= thd->mdl_context.MDL_ACQUIRE_LOCK(
MDL_key::TABLE, table->db.str, table->table_name.str,
MDL_SHARED_HIGH_PRIO, MDL_TRANSACTION,
thd->variables.lock_wait_timeout);
if (!ticket)
return (MDL_ticket *) 1; /* error indicator */
}

return error;
return ticket;
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

Update the return statements and populate table->mdl_request.ticket directly to avoid using the (MDL_ticket *) 1 sentinel pointer.

    bool error;\n    ticket= thd->mdl_context.MDL_TRY_ACQUIRE_LOCK(\n        MDL_key::TABLE, table->db.str, table->table_name.str,\n        MDL_SHARED_HIGH_PRIO, MDL_TRANSACTION, error);\n    if (error)\n      return true;\n  }\n  else\n  {\n    ticket= thd->mdl_context.MDL_ACQUIRE_LOCK(\n        MDL_key::TABLE, table->db.str, table->table_name.str,\n        MDL_SHARED_HIGH_PRIO, MDL_TRANSACTION,\n        thd->variables.lock_wait_timeout);\n    if (!ticket)\n      return true;\n  }\n\n  table->mdl_request.ticket= ticket;\n  return false;

Comment thread sql/sql_show.cc
Comment on lines +5305 to 5309
table_list.mdl_request.key.mdl_key_init(MDL_key::TABLE,
table_list.db.str,
table_list.table_name.str);

if (schema_table->i_s_requested_object & OPEN_TRIGGER_ONLY)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

Since table_list.mdl_request.key is now fully initialized inside try_acquire_high_prio_shared_mdl_lock, we can remove this manual initialization from the caller.

  if (schema_table->i_s_requested_object & OPEN_TRIGGER_ONLY)

Comment thread sql/sql_repl.cc

MDL_request mdl_request;
MDL_REQUEST_INIT(&mdl_request, MDL_key::BACKUP, "", "", MDL_BACKUP_START,
MDL_EXPLICIT);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@knielsen, what was the intention behind taking MDL_BACKUP_START here? It is normally issued by BACKUP STAGE.

Also, does it really have to register itself as a commit lock in thd->backup_commit_lock?

@knielsen
Copy link
Copy Markdown
Member

knielsen commented Jun 1, 2026 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

3 participants