Konstantin Osipov wrote:
> * Davi Arnaut<Davi.Arnaut@stripped> [08/07/23 20:17]:
>
>> === modified file 'sql/backup/data_backup.cc'
>> --- a/sql/backup/data_backup.cc 2008-03-20 14:53:16 +0000
>> +++ b/sql/backup/data_backup.cc 2008-07-23 16:12:09 +0000
>> @@ -1585,7 +1585,7 @@ int restore_table_data(THD* thd, Restore
>> Close all tables if default or snapshot driver used.
>> */
>> if (table_list)
>> - close_thread_tables(::current_thd);
>> + close_thread_tables(::current_thd, CTT_RELEASE_TRANS_LOCKS);
>
> Is the transaction active? If not, why do you need to specify
> explicitly that the locks got to be released?
Because that how the code behaved before and since I'm ignorant of the
backup internals, I prefer to leave it as is.
> As far as I can tell, your patch has gone quite a bit off the low
> level design. Could you please describe what assumptions
> in the low level design were incorrect, and what solutions you
> suggest to deploy for the problems you've encountered?
Please be more specific, I tried to follow the assumptions in the low
level design. I only made new assumptions for problems that the low
level design wasn't specific, for example, the large amounts of code
that don't respect a transaction protocol.
>> + /*
>> + Allocate a new metadata lock request for the table object that
>> + doesn't have one already. This is done at this point because a
>> + implicit commit (with locks release and freeing) might have been
>> + issued after this object was assembled.
>> + */
>> + if (! table_list->mdl_lock_data)
>> + table_list->mdl_lock_data= mdl_alloc_lock(0, table_list->db,
>> + table_list->table_name,
>> + thd->lock_data_root());
>> +
>
> In that case we're better off never allocating a lock outside
> open_tables(). I will discuss with Dmitry.
OK.
>> @@ -3518,6 +3538,7 @@ int open_tables(THD *thd, TABLE_LIST **s
>> /* Also used for indicating that prelocking is need */
>> TABLE_LIST **query_tables_last_own;
>> bool safe_to_ignore_table;
>> + bool has_locks= mdl_has_locks(&thd->mdl_context);
>>
>> DBUG_ENTER("open_tables");
>> /*
>> @@ -3660,6 +3681,18 @@ int open_tables(THD *thd, TABLE_LIST **s
>> if (action)
>> {
>> /*
>> + We have met a exclusive metadata lock or a old version of table and
>> + we are inside a transaction that already hold locks. We can't follow
>> + the locking protocol in this scenario as it might lead to deadlocks.
>> + */
>> + if ((thd->options& (OPTION_NOT_AUTOCOMMIT |
> OPTION_BEGIN))&& has_locks)
>> + {
>> + my_error(ER_LOCK_DEADLOCK, MYF(0));
>> + result= -1;
>> + goto err;
>> + }
>
> I think you should merge close_thread_tables() into
> recover_from_* function, and move this code there.
I would have been much easier if you guys did move the the code before
it to recover_from_*. Since that piece is not there, it makes impossible
to move this piece.
>
>> + /**
>> + Returns a pointer to the memory root from which to allocate
>> + metadata locks. It returns the transactional mdl root if
>> + inside a transaction context, otherwise return the suitable
>> + memory root for the scope of this statement.
>> + */
>> + MEM_ROOT *lock_data_root()
>> + {
>> + MEM_ROOT *root= mem_root;
>> +
>> + if (locked_tables_root)
>> + root= locked_tables_root;
>> + else if (options& (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))
>> + root=&trans_mdl_root;
>> +
>> + return root;
>
> What's the point of ever returning thd->mem_root?
There are places (DDL) that commits and release the locks but expect to
be able to use the lock request again. If we changed this assumption, we
would need a good amount of code rework to cleanup dangling references.
> In autocommit mode, there is a transaction too, so we can always
> use trans_mdl_root, no?
Not quite, see above.
>> - if (trans_commit_implicit(thd))
>> + if (trans_commit_implicit(thd, TRANS_RELEASE_MDL))
>> goto error;
>
> Now the loop has closed. close-thread-tables commits the
> transaction, sometimes, and commit of transaction sometimes closes
> the thread tables. Why do you need this?
You removed the patch context...