Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Range Locking support, MyRocks part #1185

Conversation

spetrunia
Copy link
Contributor

(Range Locking pull request,filed against fb-mysql-8.0.23)

This adds a my.cnf parameter, rocksdb_use_range_locking.

When it is ON, MyRocks will:

  • initialize RocksDB to use range-locking lock manager
  • for all DML operations (including SELECT .. FOR UPDATE) will lock
    the scanned range before reading/modifying rows.
  • In range locking mode, there is no snapshot checking (cannot do that
    for ranges). Instead, MyRocks will read and modify latest committed
    data, just like InnoDB does (in the code, grep for (start|end)ignore
    snapshot)
  • Queries that do not have a finite range to scan, like
    UPDATE t1 .... ORDER BY t1.key LIMIT n
    will use a "Locking iterator" which will read rows, lock the range,
    and re-read the rows. See class LockingIterator.

When it is ON, MyRocks will:
- initialize RocksDB to use range-locking lock manager
- for all DML operations (including SELECT .. FOR UPDATE) will lock
   the scanned range before reading/modifying rows.
- In range locking mode, there is no snapshot checking (cannot do that
  for ranges). Instead, MyRocks will read and modify latest committed
  data, just like InnoDB does (in the code, grep for (start|end)_ignore_
  snapshot)
- Queries that do not have a finite range to scan, like
    UPDATE t1 .... ORDER BY t1.key LIMIT n
  will use a  "Locking iterator" which will read rows, lock the range,
  and re-read the rows. See class LockingIterator.
@facebook-github-bot
Copy link

@hermanlee has imported this pull request. If you are a Meta employee, you can view this diff on Phabricator.

@hermanlee
Copy link
Contributor

Tracking some additional issues found so far:

  1. Range locks still interfere with each other in different tables:
create table t1 (pk int, val int, primary key (pk)) engine=rocksdb;
create table t2 (pk int, val int, primary key (pk)) engine=rocksdb;

txn 1: begin; select * from t1 for update;
txn 2: begin; select * from t2 for update; /* blocks on the range lock from txn1 */
  1. When waiting on a lock, aborting the query does not terminate the wait for the lock.
  2. There is a crash occurring during Rollback() where the transaction is releasing locks and looking at other waiters, but the waiting transaction object has been freed. Trying to lock wait_mutex_ seg faults because the memory contents are invalid.
#8  0x00007f995bbf4511 in std::terminate() () from /lib/libstdc++.so.6
#9  0x00007f995bbf47dc in __cxa_throw () from /lib/libstdc++.so.6
#10 0x00007f995bbf05c6 in std::__throw_system_error(int) () from /lib/libstdc++.so.6
#11 0x0000000005cd391d in std::mutex::lock (this=0x7f988762bed8) at /bits/std_mutex.h:104
#12 0x00000000060a9043 in std::lock_guard<std::mutex>::lock_guard (this=0x7f98c1291e40, __m=...)
    at /bits/std_mutex.h:159
#13 0x00000000086cb5e5 in my_rocksdb::PessimisticTransaction::SetWaitingTxn (this=0x7f988762bd00, ids=..., column_family_id=0, key=0x7f98bceaeed0)
    at /home/herman/rocks-mysql/8.0/_build-8.0-rpm/BUILD/fb-mysql-8.0.23/rocksdb/utilities/transactions/pessimistic_transaction.h:84
#14 0x000000000891c4b8 in my_rocksdb::wait_callback_for_locktree (infos=0x7f98c1292068)
    at /home/herman/rocks-mysql/8.0/_build-8.0-rpm/BUILD/fb-mysql-8.0.23/rocksdb/utilities/transactions/lock/range/range_tree/range_tree_lock_manager.cc:161
#15 0x000000000892f07d in toku::lock_request::report_waits (wait_conflicts=0x7f98c1292068, 
    lock_wait_callback=0x891c2a0 <my_rocksdb::wait_callback_for_locktree(void*, std::vector<toku::lock_wait_info, std::allocator<toku::lock_wait_info> >*)>, callback_arg=0x0)
    at /home/herman/rocks-mysql/8.0/_build-8.0-rpm/BUILD/fb-mysql-8.0.23/rocksdb/utilities/transactions/lock/range/range_tree/lib/locktree/lock_request.cc:437
#16 0x000000000892f3d4 in toku::lock_request::retry_all_lock_requests (lt=0x7f995b6db100, 
    lock_wait_callback=0x891c2a0 <my_rocksdb::wait_callback_for_locktree(void*, std::vector<toku::lock_wait_info, std::allocator<toku::lock_wait_info> >*)>, callback_arg=0x0, after_retry_all_test_callback=0x0)
    at /home/herman/rocks-mysql/8.0/_build-8.0-rpm/BUILD/fb-mysql-8.0.23/rocksdb/utilities/transactions/lock/range/range_tree/lib/locktree/lock_request.cc:397
#17 0x000000000892ac84 in my_rocksdb::RangeLockList::ReleaseLocks (this=0x7f98cce0ff50, mgr=0x7f9952eb6c00, txn=0x7f98e7c2ba80, all_trx_locks=true)
    at /home/herman/rocks-mysql/8.0/_build-8.0-rpm/BUILD/fb-mysql-8.0.23/rocksdb/utilities/transactions/lock/range/range_tree/range_tree_lock_tracker.cc:121
#18 0x000000000891fb5c in my_rocksdb::RangeTreeLockTracker::ReleaseLocks (this=0x7f98cce511c0, mgr=0x7f9952eb6c00, txn=0x7f98e7c2ba80, all_trx_locks=true)
    at /home/herman/rocks-mysql/8.0/_build-8.0-rpm/BUILD/fb-mysql-8.0.23/rocksdb/utilities/transactions/lock/range/range_tree/range_tree_lock_tracker.h:119
#19 0x000000000891c7c9 in my_rocksdb::RangeTreeLockManager::UnLock (this=0x7f9952eb6c00, txn=0x7f98e7c2ba80, tracker=...)
    at /home/herman/rocks-mysql/8.0/_build-8.0-rpm/BUILD/fb-mysql-8.0.23/rocksdb/utilities/transactions/lock/range/range_tree/range_tree_lock_manager.cc:200
#20 0x00000000086be7ba in my_rocksdb::PessimisticTransactionDB::UnLock (this=0x7f9952eabe00, txn=0x7f98e7c2ba80, keys=...)
    at /home/herman/rocks-mysql/8.0/_build-8.0-rpm/BUILD/fb-mysql-8.0.23/rocksdb/utilities/transactions/pessimistic_transaction_db.cc:391
#21 0x00000000086b5551 in my_rocksdb::PessimisticTransaction::Clear (this=0x7f98e7c2ba80)
    at /home/herman/rocks-mysql/8.0/_build-8.0-rpm/BUILD/fb-mysql-8.0.23/rocksdb/utilities/transactions/pessimistic_transaction.cc:108
#22 0x00000000086b7991 in my_rocksdb::PessimisticTransaction::Rollback (this=0x7f98e7c2ba80)
    at /home/herman/rocks-mysql/8.0/_build-8.0-rpm/BUILD/fb-mysql-8.0.23/rocksdb/utilities/transactions/pessimistic_transaction.cc:433
#23 0x00000000082010e7 in myrocks::Rdb_transaction_impl::rollback (this=0x7f994262ae00) at /home/herman/rocks-mysql/8.0/_build-8.0-rpm/BUILD/fb-mysql-8.0.23/storage/rocksdb/ha_rocksdb.cc:4326
#24 0x000000000820b833 in myrocks::Rdb_transaction::commit (this=0x7f994262ae00) at /home/herman/rocks-mysql/8.0/_build-8.0-rpm/BUILD/fb-mysql-8.0.23/storage/rocksdb/ha_rocksdb.cc:3270
#25 0x00000000081cbea0 in myrocks::rocksdb_commit (hton=0x7f995b6f2ba0, thd=0x7f98ccf7b000, all=false) at /home/herman/rocks-mysql/8.0/_build-8.0-rpm/BUILD/fb-mysql-8.0.23/storage/rocksdb/ha_rocksdb.cc:5406
#26 0x00000000057b8418 in ha_commit_low (thd=0x7f98ccf7b000, all=false, run_after_commit=true) at /home/herman/rocks-mysql/8.0/_build-8.0-rpm/BUILD/fb-mysql-8.0.23/sql/handler.cc:1922
#27 0x00000000070147e8 in MYSQL_BIN_LOG::commit (this=0x9519fb0 <mysql_bin_log>, thd=0x7f98ccf7b000, all=false) at /home/herman/rocks-mysql/8.0/_build-8.0-rpm/BUILD/fb-mysql-8.0.23/sql/binlog.cc:10583
#28 0x00000000057b7821 in ha_commit_trans (thd=0x7f98ccf7b000, all=false, ignore_global_read_lock=false) at /home/herman/rocks-mysql/8.0/_build-8.0-rpm/BUILD/fb-mysql-8.0.23/sql/handler.cc:1742
#29 0x00000000062d9f92 in trans_commit_stmt (thd=0x7f98ccf7b000, ignore_global_read_lock=false) at /home/herman/rocks-mysql/8.0/_build-8.0-rpm/BUILD/fb-mysql-8.0.23/sql/transaction.cc:554
#30 0x000000000609885f in mysql_execute_command (thd=0x7f98ccf7b000, first_level=true, last_timer=0x7f98c1298c80) at /home/herman/rocks-mysql/8.0/_build-8.0-rpm/BUILD/fb-mysql-8.0.23/sql/sql_parse.cc:5323
#31 0x000000000608caad in dispatch_sql_command (thd=0x7f98ccf7b000, parser_state=0x7f98c1299488, last_timer=0x7f98c1298c80) at /home/herman/rocks-mysql/8.0/_build-8.0-rpm/BUILD/fb-mysql-8.0.23/sql/sql_parse.cc:5862
#32 0x00000000060881a2 in dispatch_command (thd=0x7f98ccf7b000, com_data=0x7f98c1299c40, command=COM_QUERY) at /home/herman/rocks-mysql/8.0/_build-8.0-rpm/BUILD/fb-mysql-8.0.23/sql/sql_parse.cc:2310
#33 0x000000000608b4a5 in do_command (thd=0x7f98ccf7b000) at /home/herman/rocks-mysql/8.0/_build-8.0-rpm/BUILD/fb-mysql-8.0.23/sql/sql_parse.cc:1606
#34 0x000000000633b2cf in handle_connection (arg=0x7f9921899cb0) at /home/herman/rocks-mysql/8.0/_build-8.0-rpm/BUILD/fb-mysql-8.0.23/sql/conn_handler/connection_handler_per_thread.cc:330
#35 0x000000000807768b in pfs_spawn_thread (arg=0x7f991a8d8920) at /home/herman/rocks-mysql/8.0/_build-8.0-rpm/BUILD/fb-mysql-8.0.23/storage/perfschema/pfs.cc:2928

@hermanlee
Copy link
Contributor

There is a use-after-free which caused the problem. The transaction clean-up is not removing the transaction from the lock manager's wait list correctly.

Report from asan:

=================================================================
==3299794==ERROR: AddressSanitizer: heap-use-after-free on address 0x616003116328 at pc 0x00000a507b18 bp 0x7f54ff345d20 sp 0x7f54ff345d18
WRITE of size 8 at 0x616003116328 thread T440
    #0 0xa507b17 in my_rocksdb::autovector<unsigned long, 8ul>::assign(my_rocksdb::autovector<unsigned long, 8ul> const&) /home/herman/rocks-mysql/8.0/_build-8.0-rpm/BUILD/fb-mysql-8.0.23/rocksdb/util/autovector.h:356:11
    #1 0xa4fd484 in my_rocksdb::PessimisticTransaction::SetWaitingTxn(my_rocksdb::autovector<unsigned long, 8ul>, unsigned int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const*) /home/herman/rocks-mysql/8.0/_build-8.0-rpm/BUILD/fb-mysql-8.0.23/rocksdb/utilities/transactions/pessimistic_transaction.h:85:22
    #2 0xa837241 in my_rocksdb::wait_callback_for_locktree(void*, std::vector<toku::lock_wait_info, std::allocator<toku::lock_wait_info> >*) /home/herman/rocks-mysql/8.0/_build-8.0-rpm/BUILD/fb-mysql-8.0.23/rocksdb/utilities/transactions/lock/range/range_tree/range_tree_lock_manager.cc:161:10
    #3 0xa855421 in toku::lock_request::retry_all_lock_requests(toku::locktree*, void (*)(void*, std::vector<toku::lock_wait_info, std::allocator<toku::lock_wait_info> >*), void*, void (*)()) /home/herman/rocks-mysql/8.0/_build-8.0-rpm/BUILD/fb-mysql-8.0.23/rocksdb/utilities/transactions/lock/range/range_tree/lib/locktree/lock_request.cc:397:3
    #4 0xa84e4bb in my_rocksdb::RangeLockList::ReleaseLocks(my_rocksdb::RangeTreeLockManager*, my_rocksdb::PessimisticTransaction*, bool) /home/herman/rocks-mysql/8.0/_build-8.0-rpm/BUILD/fb-mysql-8.0.23/rocksdb/utilities/transactions/lock/range/range_tree/range_tree_lock_tracker.cc:121:7
    #5 0xa4e0531 in my_rocksdb::PessimisticTransaction::Clear() /home/herman/rocks-mysql/8.0/_build-8.0-rpm/BUILD/fb-mysql-8.0.23/rocksdb/utilities/transactions/pessimistic_transaction.cc:108:17
    #6 0xa4e2802 in my_rocksdb::PessimisticTransaction::Commit() /home/herman/rocks-mysql/8.0/_build-8.0-rpm/BUILD/fb-mysql-8.0.23/rocksdb/utilities/transactions/pessimistic_transaction.cc:338:5
    #7 0x9e0f466 in myrocks::Rdb_transaction_impl::commit_no_binlog() /home/herman/rocks-mysql/8.0/_build-8.0-rpm/BUILD/fb-mysql-8.0.23/storage/rocksdb/ha_rocksdb.cc:4284:23
    #8 0x9e4c68a in myrocks::rocksdb_commit(handlerton*, THD*, bool) /home/herman/rocks-mysql/8.0/_build-8.0-rpm/BUILD/fb-mysql-8.0.23/storage/rocksdb/ha_rocksdb.cc:5406:15
    #9 0x644bc7f in ha_commit_low(THD*, bool, bool) /home/herman/rocks-mysql/8.0/_build-8.0-rpm/BUILD/fb-mysql-8.0.23/sql/handler.cc:1922:18
    #10 0x87dff9d in MYSQL_BIN_LOG::process_commit_stage_queue(THD*, THD*) /home/herman/rocks-mysql/8.0/_build-8.0-rpm/BUILD/fb-mysql-8.0.23/sql/binlog.cc:10886:18
    #11 0x87b91a8 in MYSQL_BIN_LOG::ordered_commit(THD*, bool, bool) /home/herman/rocks-mysql/8.0/_build-8.0-rpm/BUILD/fb-mysql-8.0.23/sql/binlog.cc:11860:5
    #12 0x87ae3bd in MYSQL_BIN_LOG::commit(THD*, bool) /home/herman/rocks-mysql/8.0/_build-8.0-rpm/BUILD/fb-mysql-8.0.23/sql/binlog.cc:10551:9
    #13 0x644a758 in ha_commit_trans(THD*, bool, bool) /home/herman/rocks-mysql/8.0/_build-8.0-rpm/BUILD/fb-mysql-8.0.23/sql/handler.cc:1742:33
    #14 0x7358148 in trans_commit_stmt(THD*, bool) /home/herman/rocks-mysql/8.0/_build-8.0-rpm/BUILD/fb-mysql-8.0.23/sql/transaction.cc:554:11
    #15 0x70241d2 in mysql_execute_command(THD*, bool, unsigned long long*) /home/herman/rocks-mysql/8.0/_build-8.0-rpm/BUILD/fb-mysql-8.0.23/sql/sql_parse.cc:5323:7
    #16 0x701ee83 in dispatch_sql_command(THD*, Parser_state*, unsigned long long*) /home/herman/rocks-mysql/8.0/_build-8.0-rpm/BUILD/fb-mysql-8.0.23/sql/sql_parse.cc:5862:21
    #17 0x701b95e in dispatch_command(THD*, COM_DATA const*, enum_server_command) /home/herman/rocks-mysql/8.0/_build-8.0-rpm/BUILD/fb-mysql-8.0.23/sql/sql_parse.cc:2310:7
    #18 0x701d3e6 in do_command(THD*) /home/herman/rocks-mysql/8.0/_build-8.0-rpm/BUILD/fb-mysql-8.0.23/sql/sql_parse.cc:1606:18
    #19 0x73ccaf3 in handle_connection(void*) /home/herman/rocks-mysql/8.0/_build-8.0-rpm/BUILD/fb-mysql-8.0.23/sql/conn_handler/connection_handler_per_thread.cc:330:13
    #20 0x9c32e6d in pfs_spawn_thread(void*) /home/herman/rocks-mysql/8.0/_build-8.0-rpm/BUILD/fb-mysql-8.0.23/storage/perfschema/pfs.cc:2928:3
    #21 0x7f5580d4c20b in start_thread (/lib/libpthread.so.0+0x920b)
    #22 0x7f558123216e in clone (/lib/libc.so.6+0x11816e)

0x616003116328 is located 424 bytes inside of 544-byte region [0x616003116180,0x6160031163a0)
freed by thread T650 here:
    #0 0x641a587 in operator delete(void*) (/opt/mysql/8.0.23-202204081539.inst.asan.dbg.dev.herman/libexec/mysqld+0x641a587)
    #1 0x9e12a0f in myrocks::Rdb_transaction_impl::~Rdb_transaction_impl() /home/herman/rocks-mysql/8.0/_build-8.0-rpm/BUILD/fb-mysql-8.0.23/storage/rocksdb/ha_rocksdb.cc:4650:5
    #2 0x9e12a7d in myrocks::Rdb_transaction_impl::~Rdb_transaction_impl() /home/herman/rocks-mysql/8.0/_build-8.0-rpm/BUILD/fb-mysql-8.0.23/storage/rocksdb/ha_rocksdb.cc:4637:44
    #3 0x9e4b647 in myrocks::rocksdb_close_connection(handlerton*, THD*) /home/herman/rocks-mysql/8.0/_build-8.0-rpm/BUILD/fb-mysql-8.0.23/storage/rocksdb/ha_rocksdb.cc:5036:5
    #4 0x6448ae2 in closecon_handlerton(THD*, st_plugin_int*, void*) /home/herman/rocks-mysql/8.0/_build-8.0-rpm/BUILD/fb-mysql-8.0.23/sql/handler.cc:877:33
    #5 0x70806bf in plugin_foreach_with_mask(THD*, bool (**)(THD*, st_plugin_int*, void*), int, unsigned int, void*) /home/herman/rocks-mysql/8.0/_build-8.0-rpm/BUILD/fb-mysql-8.0.23/sql/sql_plugin.cc:2784:21
    #6 0x7080a0e in plugin_foreach_with_mask(THD*, bool (*)(THD*, st_plugin_int*, void*), int, unsigned int, void*) /home/herman/rocks-mysql/8.0/_build-8.0-rpm/BUILD/fb-mysql-8.0.23/sql/sql_plugin.cc:2797:10
    #7 0x6e0ab06 in THD::release_resources() /home/herman/rocks-mysql/8.0/_build-8.0-rpm/BUILD/fb-mysql-8.0.23/sql/sql_class.cc:1272:3
    #8 0x73ccb5e in handle_connection(void*) /home/herman/rocks-mysql/8.0/_build-8.0-rpm/BUILD/fb-mysql-8.0.23/sql/conn_handler/connection_handler_per_thread.cc:345:10
    #9 0x9c32e6d in pfs_spawn_thread(void*) /home/herman/rocks-mysql/8.0/_build-8.0-rpm/BUILD/fb-mysql-8.0.23/storage/perfschema/pfs.cc:2928:3
    #10 0x7f5580d4c20b in start_thread (/lib/libpthread.so.0+0x920b)

previously allocated by thread T650 here:
    #0 0x6419bb7 in operator new(unsigned long) (/opt/mysql/8.0.23-202204081539.inst.asan.dbg.dev.herman/libexec/mysqld+0x6419bb7)
    #1 0xa4ec338 in my_rocksdb::WriteCommittedTxnDB::BeginTransaction(my_rocksdb::WriteOptions const&, my_rocksdb::TransactionOptions const&, my_rocksdb::Transaction*) /home/herman/rocks-mysql/8.0/_build-8.0-rpm/BUILD/fb-mysql-8.0.23/rocksdb/utilities/transactions/pessimistic_transaction_db.cc:168:12
    #2 0x9e11c9f in myrocks::Rdb_transaction_impl::start_tx() /home/herman/rocks-mysql/8.0/_build-8.0-rpm/BUILD/fb-mysql-8.0.23/storage/rocksdb/ha_rocksdb.cc:4537:14
    #3 0x9dbc5b0 in myrocks::get_or_create_tx(THD*) /home/herman/rocks-mysql/8.0/_build-8.0-rpm/BUILD/fb-mysql-8.0.23/storage/rocksdb/ha_rocksdb.cc:5005:9
    #4 0x9ddaf7b in myrocks::ha_rocksdb::external_lock(THD*, int) /home/herman/rocks-mysql/8.0/_build-8.0-rpm/BUILD/fb-mysql-8.0.23/storage/rocksdb/ha_rocksdb.cc:12685:33
    #5 0x6464efa in handler::ha_external_lock(THD*, int) /home/herman/rocks-mysql/8.0/_build-8.0-rpm/BUILD/fb-mysql-8.0.23/sql/handler.cc:8113:3
    #6 0x6d1c731 in lock_external(THD*, TABLE**, unsigned int) /home/herman/rocks-mysql/8.0/_build-8.0-rpm/BUILD/fb-mysql-8.0.23/sql/lock.cc:399:35
    #7 0x6d1b6c0 in mysql_lock_tables(THD*, TABLE**, unsigned long, unsigned int) /home/herman/rocks-mysql/8.0/_build-8.0-rpm/BUILD/fb-mysql-8.0.23/sql/lock.cc:337:7
    #8 0x6ddb432 in lock_tables(THD*, TABLE_LIST*, unsigned int, unsigned int) /home/herman/rocks-mysql/8.0/_build-8.0-rpm/BUILD/fb-mysql-8.0.23/sql/sql_base.cc:7041:15
    #9 0x71269d3 in Sql_cmd_dml::execute(THD*) /home/herman/rocks-mysql/8.0/_build-8.0-rpm/BUILD/fb-mysql-8.0.23/sql/sql_select.cc:639:9
    #10 0x70246f0 in mysql_execute_command(THD*, bool, unsigned long long*) /home/herman/rocks-mysql/8.0/_build-8.0-rpm/BUILD/fb-mysql-8.0.23/sql/sql_parse.cc:4121:29
    #11 0x701ee83 in dispatch_sql_command(THD*, Parser_state*, unsigned long long*) /home/herman/rocks-mysql/8.0/_build-8.0-rpm/BUILD/fb-mysql-8.0.23/sql/sql_parse.cc:5862:21
    #12 0x701b95e in dispatch_command(THD*, COM_DATA const*, enum_server_command) /home/herman/rocks-mysql/8.0/_build-8.0-rpm/BUILD/fb-mysql-8.0.23/sql/sql_parse.cc:2310:7
    #13 0x701d3e6 in do_command(THD*) /home/herman/rocks-mysql/8.0/_build-8.0-rpm/BUILD/fb-mysql-8.0.23/sql/sql_parse.cc:1606:18
    #14 0x73ccaf3 in handle_connection(void*) /home/herman/rocks-mysql/8.0/_build-8.0-rpm/BUILD/fb-mysql-8.0.23/sql/conn_handler/connection_handler_per_thread.cc:330:13
    #15 0x9c32e6d in pfs_spawn_thread(void*) /home/herman/rocks-mysql/8.0/_build-8.0-rpm/BUILD/fb-mysql-8.0.23/storage/perfschema/pfs.cc:2928:3
    #16 0x7f5580d4c20b in start_thread (/lib/libpthread.so.0+0x920b)

Thread T440 created by T0 here:
    #0 0x62ace22 in pthread_create (/opt/mysql/8.0.23-202204081539.inst.asan.dbg.dev.herman/libexec/mysqld+0x62ace22)
    #1 0x9c32b72 in pfs_spawn_thread_vc(unsigned int, my_thread_handle*, pthread_attr_t const*, void* (*)(void*), void*) /home/herman/rocks-mysql/8.0/_build-8.0-rpm/BUILD/fb-mysql-8.0.23/storage/perfschema/pfs.cc:2978:16
    #2 0x73cc59e in Per_thread_connection_handler::add_connection(Channel_info*) /home/herman/rocks-mysql/8.0/_build-8.0-rpm/BUILD/fb-mysql-8.0.23/sql/conn_handler/connection_handler_per_thread.cc:450:7
    #3 0x6634831 in Connection_handler_manager::process_new_connection(Channel_info*) /home/herman/rocks-mysql/8.0/_build-8.0-rpm/BUILD/fb-mysql-8.0.23/sql/conn_handler/connection_handler_manager.cc:274:29
    #4 0x6b5f689 in Connection_acceptor<Mysqld_socket_listener>::connection_event_loop() /home/herman/rocks-mysql/8.0/_build-8.0-rpm/BUILD/fb-mysql-8.0.23/sql/conn_handler/connection_acceptor.h:65:41
    #5 0x6b51942 in mysqld_main(int, char**) /home/herman/rocks-mysql/8.0/_build-8.0-rpm/BUILD/fb-mysql-8.0.23/sql/mysqld.cc:8583:27
    #6 0x7f558113fdc4 in __libc_start_main (/lib/libc.so.6+0x25dc4)
    #7 0x629202d in _start (/opt/mysql/8.0.23-202204081539.inst.asan.dbg.dev.herman/libexec/mysqld+0x629202d)

Thread T650 created by T0 here:
    #0 0x62ace22 in pthread_create (/opt/mysql/8.0.23-202204081539.inst.asan.dbg.dev.herman/libexec/mysqld+0x62ace22)
    #1 0x9c32b72 in pfs_spawn_thread_vc(unsigned int, my_thread_handle*, pthread_attr_t const*, void* (*)(void*), void*) /home/herman/rocks-mysql/8.0/_build-8.0-rpm/BUILD/fb-mysql-8.0.23/storage/perfschema/pfs.cc:2978:16
    #2 0x73cc59e in Per_thread_connection_handler::add_connection(Channel_info*) /home/herman/rocks-mysql/8.0/_build-8.0-rpm/BUILD/fb-mysql-8.0.23/sql/conn_handler/connection_handler_per_thread.cc:450:7
    #3 0x6634831 in Connection_handler_manager::process_new_connection(Channel_info*) /home/herman/rocks-mysql/8.0/_build-8.0-rpm/BUILD/fb-mysql-8.0.23/sql/conn_handler/connection_handler_manager.cc:274:29
    #4 0x6b5f689 in Connection_acceptor<Mysqld_socket_listener>::connection_event_loop() /home/herman/rocks-mysql/8.0/_build-8.0-rpm/BUILD/fb-mysql-8.0.23/sql/conn_handler/connection_acceptor.h:65:41
    #5 0x6b51942 in mysqld_main(int, char**) /home/herman/rocks-mysql/8.0/_build-8.0-rpm/BUILD/fb-mysql-8.0.23/sql/mysqld.cc:8583:27
    #6 0x7f558113fdc4 in __libc_start_main (/lib/libc.so.6+0x25dc4)
    #7 0x629202d in _start (/opt/mysql/8.0.23-202204081539.inst.asan.dbg.dev.herman/libexec/mysqld+0x629202d)

SUMMARY: AddressSanitizer: heap-use-after-free /home/herman/rocks-mysql/8.0/_build-8.0-rpm/BUILD/fb-mysql-8.0.23/rocksdb/util/autovector.h:356:11 in my_rocksdb::autovector<unsigned long, 8ul>::assign(my_rocksdb::autovector<unsigned long, 8ul> const&)
Shadow bytes around the buggy address:
  0x0c2c8061ac10: fd fd fd fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c2c8061ac20: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c2c8061ac30: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x0c2c8061ac40: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x0c2c8061ac50: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
=>0x0c2c8061ac60: fd fd fd fd fd[fd]fd fd fd fd fd fd fd fd fd fd
  0x0c2c8061ac70: fd fd fd fd fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c2c8061ac80: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c2c8061ac90: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c2c8061aca0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c2c8061acb0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07 
  Heap left redzone:       fa
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
  Shadow gap:              cc
==3299794==ABORTING

@hermanlee
Copy link
Contributor

The range lock manager currently uses the address of the PessimisticTransaction object as the TXNID in the locktree. Various different callbacks cast this address back to PessimisticTransaction to get the rocksdb assigned transaction ID for reporting purposes.

However, other than the callbacks made when walking a locktree's request queue where a mutex is held to guarantee those pending lock requests (and consequently PessimisticTransactions) are still active, most of the other callbacks are invoked without holding any type of mutex or reference count to prevent the PessimisticTransaction from being freed.

It seems the following scenario is occurring:

  • Thread 1: TXN 1 acquires row lock a
  • Thread 2: TXN 2 tries to acquire row lock a and is waiting for TXN 1 to release it
  • Thread 3: TXN 3 commits, which calls ReleaseLocks and retry_all_lock_requests, which grabs a mutex. TXN 2 is retried, but still fails. The conflicting txnid are recorded (i.e. TXN 1), the mutexes are released, but the callback is not yet made.
  • Thread 1: TXN 1 commits and releases its locks. The thread terminates and TXN 1 is deallocated
  • Thread 3: Callback is now executed, it references TXN 1 which has been deallocated and crashes.

@hermanlee
Copy link
Contributor

Updated version: #1430

@hermanlee hermanlee closed this Feb 21, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants