以下僅用于本人調試mysql所用,不具備可讀性。
———————————————————–
create table t1 (a int primary key, b int not null) engine=innodb;
insert into t1 values (4,2);
ha_innobase::write_row
|–>row_insert_for_mysql
|–>轉換記錄格式row_mysql_convert_row_to_innobase
|–>儲存檢查點savept = trx_savept_take(trx);
|–>row_ins_step
|–>加ix鎖lock_table(0, node->table, lock_ix, thr)
|–> row_ins //輪詢索引,向表中插入記錄,這裡隻有聚集索引
. |–>row_ins_index_entry_step
. |–>建構索引記錄(node->entry)row_ins_index_entry_set_vals
. |–>row_ins_index_entry(node->index, node->entry, 0, true, thr)
. . |–>檢查外鍵限制row_ins_check_foreign_constraints
. . |->使用如下兩步嘗試插入記錄
>>step1.row_ins_index_entry_low(btr_modify_leaf, index, entry,n_ext, thr)/* try first optimistic descent to the b-tree */
>>step2,若step1失敗,row_ins_index_entry_low(btr_modify_tree, index, entry,n_ext, thr);/* try then pessimistic descent to the b-tree */
|–> row_ins_index_entry_low
|–>确定search_mode
1)如果是聚集索引,search_mode為傳參btr_modify_leaf或btr_modify_tree
2)目前事務的check_unique_secondary為false時(由變量unique_checks控制,預設為true,表示檢查唯一索引限制),search_mode = mode | btr_insert | btr_ignore_sec_unique
3)否則,search_mode = mode | btr_insert
|–>btr_cur_search_to_nth_level 查詢索引樹,将cursor移動到記錄相應的位置(待分析)
|–>檢測是否有dup key,主鍵索引調用row_ins_duplicate_error_in_clust,二級索引調用row_ins_scan_sec_index_for_duplicate
|–>modify = row_ins_must_modify (待分析)
>>當modify!=0時,表明已經有一個足夠長的common prefix,直接覆寫插入記錄(待分析)
>>當modify=0時:
1)當mode=btr_modify_leaf時,調用btr_cur_optimistic_insert,嘗試向一個索引page中插入記錄,如果頁面空閑空間太小,則傳回失敗
|–>btr_cur_ins_lock_and_undo //檢查是否有鎖沖突,并插入undolog
|–>lock_rec_insert_check_and_lock //檢查鎖沖突
|–>沒有下一個記錄的鎖沖突,即lock_rec_get_first傳回null,更新二級索引trx id,傳回
|–>調用lock_rec_other_has_conflicting,檢查是否有其他事務鎖有下一個記錄的lock_x, lock_gap和lock_insert_intention鎖
|–>檢測到有沖突lock_rec_enqueue_waiting
|–> 建立鎖記錄lock_rec_create,type_code為lock_x | lock_gap|lock_insert_intention
|–>檢測死鎖
|–>如果是聚集索引且不是insert buffer
|–>寫入undo資訊 trx_undo_report_row_operation(待分析)
|–>設定聚集索引記錄的trx id和復原段指針,row_upd_index_entry_sys_field
|–>插入記錄page_cur_tuple_insert
|–>更新該page的哈希索引btr_search_update_hash_on_insert(待分析)
|–>繼承下一條記錄的gap鎖?(inherit為true),調lock_update_insert,這裡不調用 (待分析)
2)否則
a)調用buf_lru_buf_pool_running_out,傳回true,表示少于25%的buffer pool可用。根據注釋,對于大事務,會将鎖存儲在buffer pool中(待證明)
b)調用btr_cur_pessimistic_insert(待分析)
drop table t1;
insert into t1 values (1,2);
insert into t1 values (1,5) on duplicate key update b = b+1;
————————————————-
函數調用邏輯:
write_record->handler::ha_write_row->ha_innobase::write_row->
row_insert_for_mysql
—->row_ins_step->row_ins->row_ins_index_entry
|–>row_ins_index_entry_low
|–>調用row_ins_duplicate_error_in_clust檢測是否有dup key錯誤。
|–>對記錄加鎖
>>對于replace, load datafile replace以及insert on duplicate key update操作,對記錄加一個排他鎖(lock_x)row_ins_set_exclusive_rec_lock
a)聚集索引lock_clust_rec_read_check_and_lock
b)二級索引lock_sec_rec_read_check_and_lock
>>否則,加一個共享鎖(lock_s)row_ins_set_shared_rec_lock
|–>調用row_ins_dupl_error_with_rec檢查實體記錄和将要插入的記錄是否相同
從innodb層傳回到server層後,write_record函數根據傳回的錯誤值,繼續下面的邏輯
|–>判斷是否是dup key錯誤
|–>if (table->file->extra(ha_extra_flush_cache)) // bug#52020相關點,稍後再議
|–>一堆亂七八糟的檢查,建構記錄等….
|–>row_update_for_mysql傳遞record到innodb更新資料
|–>row_upd_step->row_upd
|–>row_upd_clust_step
|–>如果沒有x鎖,則嘗試加鎖lock_clust_rec_modify_check_and_lock
|–>row_upd_clust_rec(待分析)
|–>btr_cur_optimistic_update