1 /***************************************************************************** 2 3 Copyright (c) 2013, 2015, Oracle and/or its affiliates. All Rights Reserved. 4 5 This program is free software; you can redistribute it and/or modify 6 it under the terms of the GNU General Public License, version 2.0, 7 as published by the Free Software Foundation. 8 9 This program is also distributed with certain software (including 10 but not limited to OpenSSL) that is licensed under separate terms, 11 as designated in a particular file or component or in included license 12 documentation. The authors of MySQL hereby grant you an additional 13 permission to link the program and your derivative works with the 14 separately licensed software that they have included with MySQL. 15 16 This program is distributed in the hope that it will be useful, 17 but WITHOUT ANY WARRANTY; without even the implied warranty of 18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 GNU General Public License, version 2.0, for more details. 20 21 You should have received a copy of the GNU General Public License along with 22 this program; if not, write to the Free Software Foundation, Inc., 23 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA 24 25 *****************************************************************************/ 26 27 /******************************************************************//** 28 @file include/sync0policy.h 29 Policies for mutexes. 30 31 Created 2012-08-21 Sunny Bains. 32 ***********************************************************************/ 33 34 #ifndef sync0policy_h 35 #define sync0policy_h 36 37 #include "univ.i" 38 #include "ut0rnd.h" 39 #include "os0thread.h" 40 #include "sync0types.h" 41 #include "srv0mon.h" 42 43 #ifdef UNIV_DEBUG 44 45 # define MUTEX_MAGIC_N 979585UL 46 47 template <typename Mutex> 48 class MutexDebug { 49 public: 50 51 /** For passing context to SyncDebug */ 52 struct Context : public latch_t { 53 54 /** Constructor */ ContextContext55 Context() 56 : 57 m_mutex(), 58 m_filename(), 59 m_line(), 60 m_thread_id(os_thread_id_t(ULINT_UNDEFINED)) 61 { 62 /* No op */ 63 } 64 65 /** Create the context for SyncDebug 66 @param[in] id ID of the latch to track */ ContextContext67 Context(latch_id_t id) 68 : 69 latch_t(id) 70 { 71 /* No op */ 72 } 73 74 /** Set to locked state 75 @param[in] mutex The mutex to acquire 76 @param[in] filename File name from where to acquire 77 @param[in] line Line number in filename */ lockedContext78 void locked( 79 const Mutex* mutex, 80 const char* filename, 81 ulint line) 82 UNIV_NOTHROW 83 { 84 m_mutex = mutex; 85 86 m_thread_id = os_thread_get_curr_id(); 87 88 m_filename = filename; 89 90 m_line = line; 91 } 92 93 /** Reset to unlock state */ releaseContext94 void release() 95 UNIV_NOTHROW 96 { 97 m_mutex = NULL; 98 99 m_thread_id = os_thread_id_t(ULINT_UNDEFINED); 100 101 m_filename = NULL; 102 103 m_line = ULINT_UNDEFINED; 104 } 105 106 /** Print information about the latch 107 @return the string representation */ to_stringContext108 virtual std::string to_string() const 109 UNIV_NOTHROW 110 { 111 std::ostringstream msg; 112 113 msg << m_mutex->policy().to_string(); 114 115 if (os_thread_pf(m_thread_id) != ULINT_UNDEFINED) { 116 117 msg << " addr: " << m_mutex 118 << " acquired: " << locked_from().c_str(); 119 120 } else { 121 msg << "Not locked"; 122 } 123 124 return(msg.str()); 125 } 126 127 /** @return the name of the file and line number in the file 128 from where the mutex was acquired "filename:line" */ locked_fromContext129 virtual std::string locked_from() const 130 { 131 std::ostringstream msg; 132 133 msg << sync_basename(m_filename) << ":" << m_line; 134 135 return(std::string(msg.str())); 136 } 137 138 /** Mutex to check for lock order violation */ 139 const Mutex* m_mutex; 140 141 /** Filename from where enter was called */ 142 const char* m_filename; 143 144 /** Line mumber in filename */ 145 ulint m_line; 146 147 /** Thread ID of the thread that own(ed) the mutex */ 148 os_thread_id_t m_thread_id; 149 }; 150 151 /** Constructor. */ MutexDebug()152 MutexDebug() 153 : 154 m_magic_n(), 155 m_context() 156 UNIV_NOTHROW 157 { 158 /* No op */ 159 } 160 161 /* Destructor */ ~MutexDebug()162 virtual ~MutexDebug() { } 163 164 /** Mutex is being destroyed. */ destroy()165 void destroy() UNIV_NOTHROW 166 { 167 ut_ad(m_context.m_thread_id == os_thread_id_t(ULINT_UNDEFINED)); 168 169 m_magic_n = 0; 170 171 m_context.m_thread_id = 0; 172 } 173 174 /** Called when the mutex is "created". Note: Not from the constructor 175 but when the mutex is initialised. 176 @param[in] id Mutex ID */ 177 void init(latch_id_t id) 178 UNIV_NOTHROW; 179 180 /** Called when an attempt is made to lock the mutex 181 @param[in] mutex Mutex instance to be locked 182 @param[in] filename Filename from where it was called 183 @param[in] line Line number from where it was called */ 184 void enter( 185 const Mutex* mutex, 186 const char* filename, 187 ulint line) 188 UNIV_NOTHROW; 189 190 /** Called when the mutex is locked 191 @param[in] mutex Mutex instance that was locked 192 @param[in] filename Filename from where it was called 193 @param[in] line Line number from where it was called */ 194 void locked( 195 const Mutex* mutex, 196 const char* filename, 197 ulint line) 198 UNIV_NOTHROW; 199 200 /** Called when the mutex is released 201 @param[in] mutx Mutex that was released */ 202 void release(const Mutex* mutex) 203 UNIV_NOTHROW; 204 205 /** @return true if thread owns the mutex */ is_owned()206 bool is_owned() const UNIV_NOTHROW 207 { 208 return(os_thread_eq( 209 m_context.m_thread_id, 210 os_thread_get_curr_id())); 211 } 212 213 /** @return the name of the file from the mutex was acquired */ get_enter_filename()214 const char* get_enter_filename() const 215 UNIV_NOTHROW 216 { 217 return(m_context.m_filename); 218 } 219 220 /** @return the name of the file from the mutex was acquired */ get_enter_line()221 ulint get_enter_line() const 222 UNIV_NOTHROW 223 { 224 return(m_context.m_line); 225 } 226 227 /** @return id of the thread that was trying to acquire the mutex */ get_thread_id()228 os_thread_id_t get_thread_id() const 229 UNIV_NOTHROW 230 { 231 return(m_context.m_thread_id); 232 } 233 234 /** Magic number to check for memory corruption. */ 235 ulint m_magic_n; 236 237 /** Latch state of the mutex owner */ 238 Context m_context; 239 }; 240 #endif /* UNIV_DEBUG */ 241 242 /* Do nothing */ 243 template <typename Mutex> 244 struct NoPolicy { 245 /** Default constructor. */ NoPolicyNoPolicy246 NoPolicy() { } 247 initNoPolicy248 void init(const Mutex&, latch_id_t, const char*, uint32_t) 249 UNIV_NOTHROW { } destroyNoPolicy250 void destroy() UNIV_NOTHROW { } enterNoPolicy251 void enter(const Mutex&, const char*, ulint line) UNIV_NOTHROW { } addNoPolicy252 void add(uint32_t, uint32_t) UNIV_NOTHROW { } lockedNoPolicy253 void locked(const Mutex&, const char*, ulint) UNIV_NOTHROW { } releaseNoPolicy254 void release(const Mutex&) UNIV_NOTHROW { } to_stringNoPolicy255 std::string to_string() const { return(""); }; 256 latch_id_t get_id() const; 257 }; 258 259 /** Collect the metrics per mutex instance, no aggregation. */ 260 template <typename Mutex> 261 struct GenericPolicy 262 #ifdef UNIV_DEBUG 263 : public MutexDebug<Mutex> 264 #endif /* UNIV_DEBUG */ 265 { 266 public: 267 typedef Mutex MutexType; 268 269 /** Constructor. */ GenericPolicyGenericPolicy270 GenericPolicy() 271 UNIV_NOTHROW 272 : 273 #ifdef UNIV_DEBUG 274 MutexDebug<MutexType>(), 275 #endif /* UNIV_DEBUG */ 276 m_count(), 277 m_id() 278 { } 279 280 /** Destructor */ ~GenericPolicyGenericPolicy281 ~GenericPolicy() { } 282 283 /** Called when the mutex is "created". Note: Not from the constructor 284 but when the mutex is initialised. 285 @param[in] mutex Mutex instance to track 286 @param[in] id Mutex ID 287 @param[in] filename File where mutex was created 288 @param[in] line Line in filename */ initGenericPolicy289 void init( 290 const MutexType& mutex, 291 latch_id_t id, 292 const char* filename, 293 uint32_t line) 294 UNIV_NOTHROW 295 { 296 m_id = id; 297 298 latch_meta_t& meta = sync_latch_get_meta(id); 299 300 ut_ad(meta.get_id() == id); 301 302 meta.get_counter()->single_register(&m_count); 303 304 sync_file_created_register(this, filename, line); 305 306 ut_d(MutexDebug<MutexType>::init(m_id)); 307 } 308 309 /** Called when the mutex is destroyed. */ destroyGenericPolicy310 void destroy() 311 UNIV_NOTHROW 312 { 313 latch_meta_t& meta = sync_latch_get_meta(m_id); 314 315 meta.get_counter()->single_deregister(&m_count); 316 317 sync_file_created_deregister(this); 318 319 ut_d(MutexDebug<MutexType>::destroy()); 320 } 321 322 /** Called after a successful mutex acquire. 323 @param[in] n_spins Number of times the thread did 324 spins while trying to acquire the mutex 325 @param[in] n_waits Number of times the thread waited 326 in some type of OS queue */ addGenericPolicy327 void add( 328 uint32_t n_spins, 329 uint32_t n_waits) 330 UNIV_NOTHROW 331 { 332 /* Currently global on/off. Keeps things simple and fast */ 333 334 if (!m_count.m_enabled) { 335 336 return; 337 } 338 339 m_count.m_spins += n_spins; 340 m_count.m_waits += n_waits; 341 342 ++m_count.m_calls; 343 } 344 345 /** Called when an attempt is made to lock the mutex 346 @param[in] mutex Mutex instance to be locked 347 @param[in] filename Filename from where it was called 348 @param[in] line Line number from where it was called */ enterGenericPolicy349 void enter( 350 const MutexType& mutex, 351 const char* filename, 352 ulint line) 353 UNIV_NOTHROW 354 { 355 ut_d(MutexDebug<MutexType>::enter(&mutex, filename, line)); 356 } 357 358 /** Called when the mutex is locked 359 @param[in] mutex Mutex instance that is locked 360 @param[in] filename Filename from where it was called 361 @param[in] line Line number from where it was called */ lockedGenericPolicy362 void locked( 363 const MutexType& mutex, 364 const char* filename, 365 ulint line) 366 UNIV_NOTHROW 367 { 368 ut_d(MutexDebug<MutexType>::locked(&mutex, filename, line)); 369 } 370 371 /** Called when the mutex is released 372 @param[in] mutex Mutex instance that is released */ releaseGenericPolicy373 void release(const MutexType& mutex) 374 UNIV_NOTHROW 375 { 376 ut_d(MutexDebug<MutexType>::release(&mutex)); 377 } 378 379 /** Print the information about the latch 380 @return the string representation */ 381 std::string print() const 382 UNIV_NOTHROW; 383 384 /** @return the latch ID */ get_idGenericPolicy385 latch_id_t get_id() const 386 UNIV_NOTHROW 387 { 388 return(m_id); 389 } 390 391 /** @return the string representation */ 392 std::string to_string() const; 393 394 private: 395 typedef latch_meta_t::CounterType Counter; 396 397 /** The user visible counters, registered with the meta-data. */ 398 Counter::Count m_count; 399 400 /** Latch meta data ID */ 401 latch_id_t m_id; 402 }; 403 404 /** Track agregate metrics policy, used by the page mutex. There are just 405 too many of them to count individually. */ 406 template <typename Mutex> 407 class BlockMutexPolicy 408 #ifdef UNIV_DEBUG 409 : public MutexDebug<Mutex> 410 #endif /* UNIV_DEBUG */ 411 { 412 public: 413 typedef Mutex MutexType; 414 typedef typename latch_meta_t::CounterType::Count Count; 415 416 /** Default constructor. */ BlockMutexPolicy()417 BlockMutexPolicy() 418 : 419 #ifdef UNIV_DEBUG 420 MutexDebug<MutexType>(), 421 #endif /* UNIV_DEBUG */ 422 m_count(), 423 m_id() 424 { 425 /* Do nothing */ 426 } 427 428 /** Destructor */ ~BlockMutexPolicy()429 ~BlockMutexPolicy() { } 430 431 /** Called when the mutex is "created". Note: Not from the constructor 432 but when the mutex is initialised. 433 @param[in] mutex Mutex instance to track 434 @param[in] id Mutex ID 435 @param[in] filename File where mutex was created 436 @param[in] line Line in filename */ init(const MutexType & mutex,latch_id_t id,const char * filename,uint32_t line)437 void init( 438 const MutexType& mutex, 439 latch_id_t id, 440 const char* filename, 441 uint32_t line) 442 UNIV_NOTHROW 443 { 444 /* It can be LATCH_ID_BUF_BLOCK_MUTEX or 445 LATCH_ID_BUF_POOL_ZIP. Unfortunately, they 446 are mapped to the same mutex type in the 447 buffer pool code. */ 448 449 m_id = id; 450 451 latch_meta_t& meta = sync_latch_get_meta(m_id); 452 453 ut_ad(meta.get_id() == id); 454 455 m_count = meta.get_counter()->sum_register(); 456 457 ut_d(MutexDebug<MutexType>::init(m_id)); 458 } 459 460 /** Called when the mutex is destroyed. */ destroy()461 void destroy() 462 UNIV_NOTHROW 463 { 464 latch_meta_t& meta = sync_latch_get_meta(m_id); 465 466 ut_ad(meta.get_id() == m_id); 467 468 meta.get_counter()->sum_deregister(m_count); 469 470 m_count = NULL; 471 472 ut_d(MutexDebug<MutexType>::destroy()); 473 } 474 475 /** Called after a successful mutex acquire. 476 @param[in] n_spins Number of times the thread did 477 spins while trying to acquire the mutex 478 @param[in] n_waits Number of times the thread waited 479 in some type of OS queue */ add(uint32_t n_spins,uint32_t n_waits)480 void add( 481 uint32_t n_spins, 482 uint32_t n_waits) 483 UNIV_NOTHROW 484 { 485 if (!m_count->m_enabled) { 486 487 return; 488 } 489 490 m_count->m_spins += n_spins; 491 m_count->m_waits += n_waits; 492 493 ++m_count->m_calls; 494 } 495 496 /** Called when the mutex is locked 497 @param[in] mutex Mutex instance that is locked 498 @param[in] filename Filename from where it was called 499 @param[in] line Line number from where it was called */ locked(const MutexType & mutex,const char * filename,ulint line)500 void locked( 501 const MutexType& mutex, 502 const char* filename, 503 ulint line) 504 UNIV_NOTHROW 505 { 506 ut_d(MutexDebug<MutexType>::locked(&mutex, filename, line)); 507 } 508 509 /** Called when the mutex is released 510 @param[in] mutex Mutex instance that is released */ release(const MutexType & mutex)511 void release(const MutexType& mutex) 512 UNIV_NOTHROW 513 { 514 ut_d(MutexDebug<MutexType>::release(&mutex)); 515 } 516 517 /** Called when an attempt is made to lock the mutex 518 @param[in] mutex Mutex instance to be locked 519 @param[in] filename Filename from where it was called 520 @param[in] line Line number from where it was called */ enter(const MutexType & mutex,const char * filename,ulint line)521 void enter( 522 const MutexType& mutex, 523 const char* filename, 524 ulint line) 525 UNIV_NOTHROW 526 { 527 ut_d(MutexDebug<MutexType>::enter(&mutex, filename, line)); 528 } 529 530 /** Print the information about the latch 531 @return the string representation */ 532 std::string print() const 533 UNIV_NOTHROW; 534 535 /** @return the latch ID */ get_id()536 latch_id_t get_id() const 537 { 538 return(m_id); 539 } 540 541 /** @return the string representation */ 542 std::string to_string() const; 543 544 private: 545 typedef latch_meta_t::CounterType Counter; 546 547 /** The user visible counters, registered with the meta-data. */ 548 Counter::Count* m_count; 549 550 /** Latch meta data ID */ 551 latch_id_t m_id; 552 }; 553 554 #ifndef UNIV_NONINL 555 #include "sync0policy.ic" 556 #endif /* UNIV_NOINL */ 557 558 #endif /* sync0policy_h */ 559