transaction
read_view_open_now
read_view_t(現在実行中のトランザクションIDのリスト: PostgreSQLのsnapshotに相当する)を作成する。
(1)read_view_create_lowでメモリを確保。
実行中のトランザクション数は、trx_sys->trx_listに登録されている。
(2)view->low_limit_noとview->low_limit_idに、trx_sys->max_trx_idを設定。
low_limit_noは後続の処理で変更される場合がある。
(3)view->trx_ids配列に、アクティブなトランザクションIDを追加する。
(4)view->up_limit_idに、trx_ids内の最小トランザクションIDを追加する。
read_view_tはトランザクションの分離レベルがREPEATABLE READの場合、トランザクションが終了するまで保持される。
分離レベルをREAD COMMITTED以下にすると、毎回削除される。
if (trx->isolation_level <= TRX_ISO_READ_COMMITTED && trx->global_read_view) { /* At low transaction isolation levels we let each consistent read set its own snapshot */ read_view_close_for_mysql(trx); }
read_view_sees_trx_id
取り出したタプルが現在のトランザクションから参照可能か評価する。
ha_innobase::index_first -> ha_innobase::index_read -> row_search_for_mysql -> lock_clust_rec_cons_read_sees -> read_view_sees_trx_id
trx_id: タプルのトランザクションID
view: 現在のトランザクションの情報 (snapshot)
(1)trx_idがview->up_limit_idより小さかったら見える
(2)trx_idがview->low_limit_id以上だったら見えない
(3)view->trx_idsに登録されているトランザクションID(=実行中のトランザクション)と一致したら見えない
/* We go through the trx ids in the array smallest first: this order may save CPU time, because if there was a very long running transaction in the trx id array, its trx id is looked at first, and the first two comparisons may well decide the visibility of trx_id. */ n_ids = view->n_trx_ids; for (i = 0; i < n_ids; i++) { cmp = ut_dulint_cmp(trx_id, read_view_get_nth_trx_id(view, n_ids - i - 1)); if (cmp <= 0) { return(cmp < 0); } }
read_view_get_nth_trx_idで、view->trx_idx配列からトランザクションIDを取得する。trx_id == view->trx_idx[X]になったら、実行中のトランザクションが更新したタプルなので、参照できない。(FALSEを返す)
view->trx_ids配列には、降順でトランザクションIDが入っていて、小さいトランザクションから比較している。trx_id < view->trx_idx[X]が成立した時点で、それ以降にtrx_idと一致することはないので、TRUEを返すことができる。
長時間実行中のトランザクションが1つある場合、最初の2回の比較で結果が分かる可能性が高いので、小さい方からチェックしている。
トランザクションの分離レベルがREAD UNCOMMITTEDの場合、commit前であっても常に最新のタプルを参照するためread_view_sees_trx_idは実行されない。
また、分離レベルがSERIALIZABLEのときは、テーブルを共有ロックしてから検索するため、read_view_sees_trx_idは実行されない。(共有ロックが取得できたということは、更新中(未commit)のタプルが存在しないから。)