InnoDB---the underlying implementation principle of the repeatable read isolation level

Implementation of repeatable read

    Repeatable Read (repeatable read): a transaction can see the newly inserted records that other transactions have committed during the execution process (reading has been committed, in fact, reading is earlier than the transaction started and has been committed), but cannot see Updates to existing records by other transactions (that is, started later than this transaction), and this transaction is not required to be "serializable" with other transactions.

    The core of this sentence is "but you cannot see the updates of existing records by other transactions", so how does the RR isolation level guarantee this?

    Use MVCC (Multi-Version Concurrency Control). InnoDB adds a version number (system version number) to each row of records, and the version number increases by one whenever data is modified.
At the beginning of the read transaction, the system will give the transaction a current version number, and the transaction will read the data with version number <= current version number. At this time, even if another transaction inserts a data, and commits it immediately, the newly inserted data The version number will be higher than the version number of the read transaction, so the data read by the read transaction will not change.

    If the database concurrency control engine is a simple blocking protocol mechanism, it should judge whether the data item has been updated by other transactions when reading data. However , InnoDB did not do this, but set up a "consistent read view (ie snapshot)" for the transaction under the RR isolation level in the following way, and then read the data based on this snapshot, so that you can't read the data. To the update of the existing record by the transaction later than this transaction (the update generates a new version, which must not be within the scope of the old snapshot).

static my_bool snapshot_handlerton(THD *thd, plugin_ref plugin, void *arg)

{

    handlerton *hton= plugin_data<handlerton*>(plugin);

    if (hton->state == SHOW_OPTION_YES && hton-> start_consistent_snapshot ) // start_consistent_snapshot is only assigned when the isolation level is RR

    {

        hton-> start_consistent_snapshot (hton, thd); // For InnoDB , actually execute the innobase_start_trx_and_assign_read_view() function

        *((bool *)arg)= false;

    }

    return FALSE;

}

    As shown in Figure 11-4 and the following code analysis, when the transaction starts, trans_begin() will call the snapshot_handlerton () function pointer, that is, use the innobase_start_trx_and_assign_read_view () function to create a snapshot under the repeatable read isolation level, and other isolation levels will not create snapshots .


Figure 11-4  snapshot_handlerton () function context call diagram

innobase_start_trx_and_assign_read_view (   // Create a snapshot under the repeatable read isolation level, other isolation levels do not create snapshots

    handlerton*    hton,    /*!< in: InnoDB handlerton */

    THD*thd)/*!< in: MySQL thread handle of the user for whom the transaction should be committed */                

{...

    if (trx->isolation_level ==  TRX_ISO_REPEATABLE_READ ) { // If it is the RR isolation level, assign a value to the read view , that is, build a consistent view

        trx_assign_read_view (trx);  // Assign a value to the read consistency view (snapshot), note that in store_lock() , the isolation level should be less than RR before closing the snapshot

    } else {

        push_warning_printf(thd, Sql_condition::SL_WARNING,

                    HA_ERR_UNSUPPORTED,

                    "InnoDB: WITH CONSISTENT SNAPSHOT"

                    " was ignored because this phrase"

                    " can only be used with"

                    " REPEATABLE READ isolation level.");

    }

...

}

    之后,在每条SQL语句执行的时候,根据隔离级别判断是不是要使用一个新的快照,如果是可重复读,则不使用新快照,沿用老的快照,这样就能保证所有的读操作看到的是同一个数据状态;同时也确保了读已提交隔离级别下一个事务块内的不同语句的读操作看到的不是同一个数据状态。

ha_innobase::store_lock(...)

{...

    if (lock_type != TL_IGNORE && trx->n_mysql_tables_in_use == 0) {

        trx->isolation_level = innobase_map_isolation_level((enum_tx_isolation) thd_tx_isolation(thd));

        if (trx->isolation_level <= TRX_ISO_READ_COMMITTED  //隔离级别小于等于读已提交,关闭老的快照。可重复读不关闭老快照所以可以沿用

            && MVCC::is_view_active(trx->read_view)) {

            /* At low transaction isolation levels we let each consistent read set its own snapshot */

            mutex_enter(&trx_sys->mutex);

            trx_sys->mvcc->view_close(trx->read_view, true);  //隔离级别小,关闭快照,这样下一条SQL执行时,将获取新快照

            mutex_exit(&trx_sys->mutex);

        }

    }

...

}

     从上面的分析可以看出, InnoDB 的可重复读的实现,利用了实现 MVCC 技术的快照技术。这是 MVCC 和基于封锁技术这两个并非控制技术的结合之处。

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326039853&siteId=291194637