Commit 198385b
Venkatesh Prasad
PS-9719: changing binlog_transaction_dependency_tracking hit segmentation fault
https://perconadev.atlassian.net/browse/PS-9719
Problem
-------
When changing binlog_transaction_dependency_tracking in high load
workload, MySQL can get a segmentation fault.
Analysis
--------
Address sanitizer runs exposed the heap-use-after-free.
READ of size 8 at 0x6030002c3298 thread T52
#0 _M_hash_code()
#1 _M_bucket_index()
..
#7 std::unordered_map::insert()
#8 Writeset_trx_dependency_tracker::get_dependency()
#9 Transaction_dependency_tracker::get_dependency()
#10 MYSQL_BIN_LOG::write_transaction()
#11 binlog_cache_data::flush()
#12 binlog_cache_mngr::flush()
#13 MYSQL_BIN_LOG::flush_thread_caches()
#14 MYSQL_BIN_LOG::process_flush_stage_queue()
#15 MYSQL_BIN_LOG::ordered_commit()
#16 MYSQL_BIN_LOG::commit()
freed by thread T49 here:
#0 operator delete()
...
#7 std::unordered_map::clear()
#8 Writeset_trx_dependency_tracker::rotate(long)
#9 Transaction_dependency_tracker::tracking_mode_changed()
#10 update_binlog_transaction_dependency_tracking
#11 sys_var::update()
- The Writeset_trx_dependency_tracker uses std::unordered_map for
storing depdendency information.
- When a transaction is committing, the committing thread inserts the
dependency information to this map in through get_dependency().
- When the tracking mode is changed, then the map is cleared by
Writeset_trx_dependency_tracker::rotate(). Note that no lock/mutex is
taken during the rotation.
- As the rotate() and get_dependency() operations can be concurrently
called from different threads and there is no mutex protection to
handle it, it can result in segmentation fault when the get_dependency()
tries to insert to the already deleted map.
Solution
--------
Use std::shared_ptr with atomic load/store for safer dependency tracker map rotation.
- Replaced direct usage of of map with std::shared_ptr in the
Writeset_trx_dependency_tracker class.
- Modified the implementation of rotate() to used std::atomic_load and
std::atomic_store to enable thread-safe reads and rotations.
With the new solution the rotation happens in an atomic manner. So that
transactions calling get_dependency() always use the object returned by
shared_ptr. So, even if rotate() happens in parallel, the memory won't
be freed until all readers are done.1 parent 2df90d5 commit 198385b
2 files changed
+15
-8
lines changed| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
245 | 245 | | |
246 | 246 | | |
247 | 247 | | |
| 248 | + | |
248 | 249 | | |
249 | 250 | | |
250 | 251 | | |
| |||
253 | 254 | | |
254 | 255 | | |
255 | 256 | | |
256 | | - | |
| 257 | + | |
257 | 258 | | |
258 | 259 | | |
259 | 260 | | |
| |||
262 | 263 | | |
263 | 264 | | |
264 | 265 | | |
265 | | - | |
266 | | - | |
| 266 | + | |
| 267 | + | |
267 | 268 | | |
268 | 269 | | |
269 | 270 | | |
270 | 271 | | |
271 | 272 | | |
272 | 273 | | |
273 | | - | |
| 274 | + | |
274 | 275 | | |
275 | 276 | | |
276 | 277 | | |
| |||
292 | 293 | | |
293 | 294 | | |
294 | 295 | | |
295 | | - | |
| 296 | + | |
| 297 | + | |
| 298 | + | |
296 | 299 | | |
297 | 300 | | |
298 | 301 | | |
299 | 302 | | |
300 | 303 | | |
301 | | - | |
| 304 | + | |
| 305 | + | |
302 | 306 | | |
303 | 307 | | |
304 | 308 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
127 | 127 | | |
128 | 128 | | |
129 | 129 | | |
130 | | - | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
131 | 134 | | |
132 | 135 | | |
133 | 136 | | |
| |||
161 | 164 | | |
162 | 165 | | |
163 | 166 | | |
164 | | - | |
| 167 | + | |
165 | 168 | | |
166 | 169 | | |
167 | 170 | | |
| |||
0 commit comments