简介

TokuDB使用LockTree(ft-index/locktree)来维护事务的锁状态(row-lock和range-lock),LockTree的数据结构是一个Binary Tree。
本篇将通过几个“栗子”来谈谈TokuDB的row-lock和range-lock。
表t:

  1. mysql> show create table t\G
  2. *************************** 1. row ***************************
  3. Table: t
  4. Create Table: CREATE TABLE `t` (
  5. `id` int(11) NOT NULL,
  6. PRIMARY KEY (`id`)
  7. ) ENGINE=TokuDB DEFAULT CHARSET=latin1

row-lock

  1. mysql> set autocommit=off;
  2. Query OK, 0 rows affected (0.00 sec)
  3. mysql> insert into t values (1),(10),(100);
  4. Query OK, 3 rows affected (0.00 sec)
  5. Records: 3 Duplicates: 0 Warnings: 0
  6. mysql> select * from information_schema.tokudb_locks\G
  7. *************************** 1. row ***************************
  8. locks_trx_id: 238
  9. locks_mysql_thread_id: 3
  10. locks_dname: ./test/t-main
  11. locks_key_left: 0001000000
  12. locks_key_right: 0001000000
  13. locks_table_schema: test
  14. locks_table_name: t
  15. locks_table_dictionary_name: main
  16. *************************** 2. row ***************************
  17. locks_trx_id: 238
  18. locks_mysql_thread_id: 3
  19. locks_dname: ./test/t-main
  20. locks_key_left: 000a000000
  21. locks_key_right: 000a000000
  22. locks_table_schema: test
  23. locks_table_name: t
  24. locks_table_dictionary_name: main
  25. *************************** 3. row ***************************
  26. locks_trx_id: 238
  27. locks_mysql_thread_id: 3
  28. locks_dname: ./test/t-main
  29. locks_key_left: 0064000000
  30. locks_key_right: 0064000000
  31. locks_table_schema: test
  32. locks_table_name: t
  33. locks_table_dictionary_name: main
  34. 3 rows in set (0.00 sec)

从tokudb_locks表可以查询到,生成了3条row-lock(locks_key_left和locks_key_right相等)。
为了存储和显示方便,locks_key_left/locks_key_right取key的hash值。

range-lock

  1. mysql> set autocommit=off;
  2. Query OK, 0 rows affected (0.00 sec)
  3. mysql> delete from t where id<100;
  4. Query OK, 0 rows affected (0.00 sec)
  5. mysql> select * from information_schema.tokudb_locks\G
  6. *************************** 1. row ***************************
  7. locks_trx_id: 280
  8. locks_mysql_thread_id: 12
  9. locks_dname: ./test/t-main
  10. locks_key_left: -infinity
  11. locks_key_right: ff64000000
  12. locks_table_schema: test
  13. locks_table_name: t
  14. locks_table_dictionary_name: main
  15. 1 row in set (0.00 sec)

从tokudb_locks表可以查询到,where条件的rang-lock区间为[-infinity, ff64000000],只要其他事务的锁区间跟这个有任何重叠,则需要等待。

锁冲突

client1执行如下操作:

  1. mysql1> set autocommit=off;
  2. Query OK, 0 rows affected (0.00 sec)
  3. mysql1> insert into t values (1),(10),(100);
  4. Query OK, 3 rows affected (0.00 sec)
  5. Records: 3 Duplicates: 0 Warnings: 0
  6. mysql1> select * from information_schema.tokudb_locks\G
  7. *************************** 1. row ***************************
  8. locks_trx_id: 283
  9. locks_mysql_thread_id: 14
  10. locks_dname: ./test/t-main
  11. locks_key_left: 0001000000
  12. locks_key_right: 0001000000
  13. locks_table_schema: test
  14. locks_table_name: t
  15. locks_table_dictionary_name: main
  16. *************************** 2. row ***************************
  17. locks_trx_id: 283
  18. locks_mysql_thread_id: 14
  19. locks_dname: ./test/t-main
  20. locks_key_left: 000a000000
  21. locks_key_right: 000a000000
  22. locks_table_schema: test
  23. locks_table_name: t
  24. locks_table_dictionary_name: main
  25. *************************** 3. row ***************************
  26. locks_trx_id: 283
  27. locks_mysql_thread_id: 14
  28. locks_dname: ./test/t-main
  29. locks_key_left: 0064000000
  30. locks_key_right: 0064000000
  31. locks_table_schema: test
  32. locks_table_name: t
  33. locks_table_dictionary_name: main
  34. 3 rows in set (0.00 sec)

client2执行如下操作:

  1. mysql2> set autocommit=off;
  2. Query OK, 0 rows affected (0.00 sec)
  3. mysql2> insert into t values (2),(100);
  4. ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
  5. mysql2> select * from information_schema.tokudb_locks\G
  6. *************************** 1. row ***************************
  7. locks_trx_id: 283
  8. locks_mysql_thread_id: 14
  9. locks_dname: ./test/t-main
  10. locks_key_left: 0001000000
  11. locks_key_right: 0001000000
  12. locks_table_schema: test
  13. locks_table_name: t
  14. locks_table_dictionary_name: main
  15. *************************** 2. row ***************************
  16. locks_trx_id: 283
  17. locks_mysql_thread_id: 14
  18. locks_dname: ./test/t-main
  19. locks_key_left: 000a000000
  20. locks_key_right: 000a000000
  21. locks_table_schema: test
  22. locks_table_name: t
  23. locks_table_dictionary_name: main
  24. *************************** 3. row ***************************
  25. locks_trx_id: 283
  26. locks_mysql_thread_id: 14
  27. locks_dname: ./test/t-main
  28. locks_key_left: 0064000000
  29. locks_key_right: 0064000000
  30. locks_table_schema: test
  31. locks_table_name: t
  32. locks_table_dictionary_name: main
  33. *************************** 4. row ***************************
  34. locks_trx_id: 289
  35. locks_mysql_thread_id: 16
  36. locks_dname: ./test/t-main
  37. locks_key_left: 0002000000
  38. locks_key_right: 0002000000
  39. locks_table_schema: test
  40. locks_table_name: t
  41. locks_table_dictionary_name: main
  42. 4 rows in set (0.00 sec)
  43. mysql2> select @@tokudb_last_lock_timeout;
  44. +--------------------------------------------------------------------------------------------------------------------+
  45. | @@tokudb_last_lock_timeout |
  46. +--------------------------------------------------------------------------------------------------------------------+
  47. | {"mysql_thread_id":16, "dbname":"./test/t-main", "requesting_txnid":289, "blocking_txnid":283, "key":"0064000000"} |
  48. +--------------------------------------------------------------------------------------------------------------------+
  49. 1 row in set (0.00 sec)

锁等待超时了,通过参数tokudb_last_lock_timeout得知,hash为0064000000的row-lock已经被txnid为283(client1)抢占。

总结

在使用TokuDB过程中,如果show processlist里有锁等待语句,可以通过tokudb_locks表获取到当前所有事务的锁信息,以快速定位到问题。
TokuDB提供tokudb_lock_timeout_debug参数,可以设置不同值(默认值为1)来记录锁冲突信息,说明如下:

  1. tokudb_lock_timeout_debug = 0: No lock timeouts or lock deadlocks are reported.
  2. tokudb_lock_timeout_debug = 1: A JSON document that describes the lock conflict is stored in the tokudb_last_lock_timeout session variable
  3. tokudb_lock_timeout_debug = 2: A JSON document that describes the lock conflict is printed to the MySQL error log.
  4. tokudb_lock_timeout_debug = 3: A JSON document that describes the lock conflict is stored in the tokudb_last_lock_timeout session variable and is printed to the MySQL error log.