# thread buffer がいつ解放されるか? ## thread buffer の種類 - join_buffer - sort_buffer - tmp_table_size - select_into_buffer_size ref: https://gihyo.jp/article/2022/10/mysql-rcn0183 ## sort_buffer ここで止めてみる (Filesort_info class) - https://github.com/mysql/mysql-server/blob/mysql-cluster-8.0.32/sql/sql_sort.h#L260 ### backtrace ``` (gdb) bt #0 Filesort_info::free_sort_buffer (this=0x7fdfe5092ae0) at /mysql-8.0.32/sql/sql_sort.h:260 #1 0x000055a0caf53a17 in SortingIterator::CleanupAfterQuery (this=0x7fdfe5092ab8) at /mysql-8.0.32/sql/iterators/sorting_iterator.cc:418 #2 0x000055a0caf53954 in SortingIterator::~SortingIterator (this=0x7fdfe5092ab8, __in_chrg=<optimized out>) at /mysql-8.0.32/sql/iterators/sorting_iterator.cc:414 #3 0x000055a0ca790fb2 in destroy<RowIterator> (ptr=0x7fdfe5092ab8) at /mysql-8.0.32/include/my_alloc.h:459 #4 0x000055a0ca790ef2 in Destroy_only<RowIterator>::operator() (this=0x7fdfe5092c18, ptr=0x7fdfe5092ab8) at /mysql-8.0.32/include/my_alloc.h:481 #5 0x000055a0ca790e14 in std::unique_ptr<RowIterator, Destroy_only<RowIterator> >::~unique_ptr (this=0x7fdfe5092c18, __in_chrg=<optimized out>) at /usr/include/c++/11/bits/unique_ptr.h:361 #6 0x000055a0caf7ac92 in LimitOffsetIterator::~LimitOffsetIterator (this=0x7fdfe5092c08, __in_chrg=<optimized out>) at /mysql-8.0.32/sql/iterators/composite_iterators.h:106 #7 0x000055a0ca790fb2 in destroy<RowIterator> (ptr=0x7fdfe5092c08) at /mysql-8.0.32/include/my_alloc.h:459 #8 0x000055a0ca790ef2 in Destroy_only<RowIterator>::operator() (this=0x7fdfe507fc48, ptr=0x7fdfe5092c08) at /mysql-8.0.32/include/my_alloc.h:481 #9 0x000055a0ca8f1d86 in std::__uniq_ptr_impl<RowIterator, Destroy_only<RowIterator> >::reset (this=0x7fdfe507fc48, __p=0x0) at /usr/include/c++/11/bits/unique_ptr.h:182 #10 0x000055a0ca995cdb in std::unique_ptr<RowIterator, Destroy_only<RowIterator> >::reset (this=0x7fdfe507fc48, __p=0x0) at /usr/include/c++/11/bits/unique_ptr.h:456 #11 0x000055a0caaaad8f in Query_expression::cleanup (this=0x7fdfe507fc10, full=true) at /mysql-8.0.32/sql/sql_union.cc:1841 #12 0x000055a0ca812c25 in LEX::cleanup (this=0x7fdff01379d0, full=true) at /mysql-8.0.32/sql/sql_lex.h:4072 #13 0x000055a0ca95d750 in mysql_execute_command (thd=0x7fdff0acb960, first_level=true) at /mysql-8.0.32/sql/sql_parse.cc:4907 #14 0x000055a0ca95ecaa in dispatch_sql_command (thd=0x7fdff0acb960, parser_state=0x7fe0647f79f0) at /mysql-8.0.32/sql/sql_parse.cc:5322 #15 0x000055a0ca95433d in dispatch_command (thd=0x7fdff0acb960, com_data=0x7fe0647f8340, command=COM_QUERY) at /mysql-8.0.32/sql/sql_parse.cc:2036 #16 0x000055a0ca9522eb in do_command (thd=0x7fdff0acb960) at /mysql-8.0.32/sql/sql_parse.cc:1439 #17 0x000055a0cab9eaa9 in handle_connection (arg=0x55a0d362bf20) at /mysql-8.0.32/sql/conn_handler/connection_handler_per_thread.cc:302 #18 0x000055a0ccb7aeae in pfs_spawn_thread (arg=0x55a0d3636760) at /mysql-8.0.32/storage/perfschema/pfs.cc:2986 #19 0x00007fe0b1c09ac3 in start_thread (arg=<optimized out>) at ./nptl/pthread_create.c:442 #20 0x00007fe0b1c9b850 in clone3 () at ../sysdeps/unix/sysv/linux/x86_64/clone3.S:81 ``` 次の step ``` (gdb) s Filesort_buffer::free_sort_buffer (this=0x7fdfe5092ae0) at /mysql-8.0.32/sql/filesort_utils.cc:414 414 void Filesort_buffer::free_sort_buffer() { ``` filesort_buffer class https://github.com/mysql/mysql-server/blob/mysql-8.0.32/sql/filesort_utils.h#L80 の、free_sort_buffer 関数に飛ぶ https://github.com/mysql/mysql-server/blob/mysql-8.0.32/sql/filesort_utils.cc#L414 backtrace を辿っていくと、[my_alloc.h:459](https://github.com/mysql/mysql-server/blob/mysql-8.0.32/include/my_alloc.h#L459) がわからない sql/sql_lex.h:4072 の cleanup() 関数で呼ばれてるのでクエリ実行後? cleanup 関数のコメントは以下 ```cpp /** Cleanup this subtree (this Query_block and all nested Query_blockes and Query_expressions). @param full if false only partial cleanup is done, JOINs and JOIN_TABs are kept to provide info for EXPLAIN CONNECTION; if true, complete cleanup is done, all JOINs are freed. */ void cleanup(bool full) override; ``` mysql の query 実行関数は mysql_execute_command()? https://github.com/mysql/mysql-server/blob/mysql-8.0.32/sql/sql_parse.cc#L2915 →実際に実行されるのはここっぽい? (mysql_sql_stmt_execute()?) https://github.com/mysql/mysql-server/blob/mysql-8.0.32/sql/sql_prepare.cc#L1942 mysql_execute_command() から cleanup() が呼ばれてる https://github.com/mysql/mysql-server/blob/mysql-8.0.32/sql/sql_parse.cc#L4907 ## 2/6 実行したクエリ ``` SELECT * FROM employeess ORDER BY birth_date LIMIT 3 ``` .h のファイルにはブレークポイントを置けないっぽい?ので [/mysql-8.0.32/sql/sql_union.cc:1841](https://github.com/mysql/mysql-server/blob/mysql-8.0.32/sql/sql_union.cc#L1841) にブレークポイントを置いてステップ実行していく ← .h はヘッダファイル(クラスの型定義とか)、.cpp はソースファイル(ヘッダファイルで定義された型に対する実際の実装) ここでの this は [Query_expression](https://dev.mysql.com/doc/dev/mysql-server/latest/classQuery__expression.html). gdb 上で `print this.query_term` とかやってみたらクエリの中身見れるのかと思ったら、そんなことはなかった 次に step 実行したら `std::unique_ptr::reset()` に辿り着く https://cpprefjp.github.io/reference/memory/unique_ptr/reset.html ← 引数を与えない場合、ポインタから値を開放して、該当ポインタが何も指していない状態になる 20回ぐらい step 実行したら [/mysql-8.0.32/include/my_alloc.h:481](https://github.com/mysql/mysql-server/blob/mysql-8.0.32/include/my_alloc.h#L481) に辿り着く ``` (gdb) print ptr $1 = (RowIterator *) 0xfffebcad91b8 ``` ptr は [RowIterator](https://dev.mysql.com/doc/dev/mysql-server/latest/classRowIterator.html) というクラスのものらしい Detailed description によれば、選択された取得方法を使用して、テーブルから1行ずつレコードを読み取る単純なイテレータらしい。 なんだか THD が取れる。 ``` (gdb) print ptr.thd $2 = {THD *(const RowIterator * const)} 0xaaaac01a56cc <RowIterator::thd() const> ``` 次に step 実行したら、[my_alloc.h:459](https://github.com/mysql/mysql-server/blob/mysql-8.0.32/include/my_alloc.h#L459) に辿り着く ptr は先ほどの RowIterator なので、RowIterator の destructor が呼ばれている。 → https://github.com/mysql/mysql-server/blob/mysql-8.0.32/sql/iterators/row_iterator.h#L86 ```c++ class RowIterator { public: // NOTE: Iterators should typically be instantiated using NewIterator, // in sql/iterators/timing_iterator.h. explicit RowIterator(THD *thd) : m_thd(thd) {} virtual ~RowIterator() = default; ``` virtual って何!? default って何!? https://cpprefjp.github.io/lang/cpp11/defaulted_and_deleted_functions.html デフォルトの動作が定義されていて、特殊なメンバ関数に対してのみ代入できる感じっぽい https://yohe.gitbooks.io/cpp-14/content/chapter_1/core/explicit_default_func.html destructor は default を指定すると空の関数になると書いてある... 次の step 実行→ [/mysql-8.0.32/sql/iterators/composite_iterators.h:106](https://github.com/mysql/mysql-server/blob/mysql-8.0.32/sql/iterators/composite_iterators.h#L106) ```c++ LimitOffsetIterator::~LimitOffsetIterator (this=0xfffebcad91b8, __in_chrg=<optimized out>) at /mysql-8.0.32/sql/iterators/composite_iterators.h:106 class LimitOffsetIterator final : public RowIterator { ``` RowIterator を継承した LimitOffsetIterator の方に処理が移った 次の step 実行 ```c++ (gdb) s std::unique_ptr<RowIterator, Destroy_only<RowIterator> >::~unique_ptr (this=0xfffebcad91c8, __in_chrg=<optimized out>) at /usr/include/c++/11/bits/unique_ptr.h:359 359 auto& __ptr = _M_t._M_ptr(); ``` c++ の標準ライブラリを抜けると、次の step 実行 ```c++ (gdb) s Destroy_only<RowIterator>::operator() (this=0xfffebcad91c8, ptr=0xfffebcad9068) at /mysql-8.0.32/include/my_alloc.h:481 481 destroy(ptr); (gdb) s destroy<RowIterator> (ptr=0xfffebcad9068) at /mysql-8.0.32/include/my_alloc.h:459 459 if (ptr != nullptr) ptr->~T(); (gdb) print ptr $5 = (RowIterator *) 0xfffebcad9068 (gdb) s SortingIterator::~SortingIterator (this=0xfffebcad9068, __in_chrg=<optimized out>) at /mysql-8.0.32/sql/iterators/sorting_iterator.cc:412 412 SortingIterator::~SortingIterator() { (gdb) ``` [SortingIterator](https://dev.mysql.com/doc/dev/mysql-server/latest/classSortingIterator.html) の destructor に辿り着いた https://github.com/mysql/mysql-server/blob/mysql-8.0.32/sql/iterators/sorting_iterator.cc#L412 ```c++ SortingIterator::~SortingIterator() { ReleaseBuffers(); CleanupAfterQuery(); } ``` step 実行、当然 ReleaseBuffers() の中に入る ```c++ (gdb) s 413 ReleaseBuffers(); (gdb) s SortingIterator::ReleaseBuffers (this=0xfffebcad9068) at /mysql-8.0.32/sql/iterators/sorting_iterator.cc:425 425 m_result_iterator.reset(); (gdb) ``` https://github.com/mysql/mysql-server/blob/mysql-8.0.32/sql/iterators/sorting_iterator.cc#L424 かなりここっぽい... my_free() してるし... - m_result_iterator - m_sort_result.io_cache の二つがどういう意味なのか調べるところから