1 /***************************************************************************** 2 3 Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved. 4 5 This program is free software; you can redistribute it and/or modify it under 6 the terms of the GNU General Public License, version 2.0, as published by the 7 Free Software Foundation. 8 9 This program is also distributed with certain software (including but not 10 limited to OpenSSL) that is licensed under separate terms, as designated in a 11 particular file or component or in included license documentation. The authors 12 of MySQL hereby grant you an additional permission to link the program and 13 your derivative works with the separately licensed software that they have 14 included with MySQL. 15 16 This program is distributed in the hope that it will be useful, but WITHOUT 17 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 18 FOR A PARTICULAR PURPOSE. See the GNU General Public License, version 2.0, 19 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 St, Fifth Floor, Boston, MA 02110-1301 USA 24 25 *****************************************************************************/ 26 27 /** @file include/sync0policy.h 28 Policies for mutexes. 29 30 Created 2012-08-21 Sunny Bains. 31 ***********************************************************************/ 32 33 #ifndef sync0policy_h 34 #define sync0policy_h 35 36 #include "os0thread.h" 37 #include "srv0mon.h" 38 #include "sync0types.h" 39 #include "univ.i" 40 #include "ut0rnd.h" 41 42 #ifndef UNIV_LIBRARY 43 #ifdef UNIV_DEBUG 44 45 #define MUTEX_MAGIC_N 979585UL 46 47 template <typename Mutex> 48 class MutexDebug { 49 public: 50 /** For passing context to SyncDebug */ 51 struct Context : public latch_t { 52 /** Constructor */ ContextContext53 Context() 54 : m_mutex(), 55 m_filename(), 56 m_line(), 57 m_thread_id(os_thread_id_t(ULINT_UNDEFINED)) { 58 /* No op */ 59 } 60 61 /** Create the context for SyncDebug 62 @param[in] id ID of the latch to track */ ContextContext63 Context(latch_id_t id) : latch_t(id) { /* No op */ 64 } 65 66 /** Set to locked state 67 @param[in] mutex The mutex to acquire 68 @param[in] filename File name from where to acquire 69 @param[in] line Line number in filename */ lockedContext70 void locked(const Mutex *mutex, const char *filename, 71 ulint line) UNIV_NOTHROW { 72 m_mutex = mutex; 73 74 m_thread_id = os_thread_get_curr_id(); 75 76 m_filename = filename; 77 78 m_line = line; 79 } 80 81 /** Reset to unlock state */ releaseContext82 void release() UNIV_NOTHROW { 83 m_mutex = nullptr; 84 85 m_thread_id = os_thread_id_t(ULINT_UNDEFINED); 86 87 m_filename = nullptr; 88 89 m_line = ULINT_UNDEFINED; 90 } 91 92 /** Print information about the latch 93 @return the string representation */ to_stringContext94 virtual std::string to_string() const UNIV_NOTHROW { 95 std::ostringstream msg; 96 97 msg << m_mutex->policy().to_string(); 98 99 if (m_thread_id != os_thread_id_t(ULINT_UNDEFINED)) { 100 msg << " addr: " << m_mutex << " acquired: " << locked_from().c_str(); 101 102 } else { 103 msg << "Not locked"; 104 } 105 106 return (msg.str()); 107 } 108 109 /** @return the name of the file and line number in the file 110 from where the mutex was acquired "filename:line" */ locked_fromContext111 virtual std::string locked_from() const { 112 std::ostringstream msg; 113 114 msg << sync_basename(m_filename) << ":" << m_line; 115 116 return (std::string(msg.str())); 117 } 118 119 /** Mutex to check for lock order violation */ 120 const Mutex *m_mutex; 121 122 /** Filename from where enter was called */ 123 const char *m_filename; 124 125 /** Line mumber in filename */ 126 ulint m_line; 127 128 /** Thread ID of the thread that own(ed) the mutex */ 129 os_thread_id_t m_thread_id; 130 }; 131 132 /** Constructor. */ MutexDebug()133 MutexDebug() : m_magic_n(), m_context() UNIV_NOTHROW { /* No op */ 134 } 135 136 /* Destructor */ ~MutexDebug()137 virtual ~MutexDebug() {} 138 139 /** Mutex is being destroyed. */ destroy()140 void destroy() UNIV_NOTHROW { 141 ut_ad(m_context.m_thread_id == os_thread_id_t(ULINT_UNDEFINED)); 142 143 m_magic_n = 0; 144 145 m_context.m_thread_id = 0; 146 } 147 148 /** Called when the mutex is "created". Note: Not from the constructor 149 but when the mutex is initialised. 150 @param[in] id Mutex ID */ 151 void init(latch_id_t id) UNIV_NOTHROW; 152 153 /** Called when an attempt is made to lock the mutex 154 @param[in] mutex Mutex instance to be locked 155 @param[in] filename Filename from where it was called 156 @param[in] line Line number from where it was called */ 157 void enter(const Mutex *mutex, const char *filename, ulint line) UNIV_NOTHROW; 158 159 /** Called when the mutex is locked 160 @param[in] mutex Mutex instance that was locked 161 @param[in] filename Filename from where it was called 162 @param[in] line Line number from where it was called */ 163 void locked(const Mutex *mutex, const char *filename, 164 ulint line) UNIV_NOTHROW; 165 166 /** Called when the mutex is released 167 @param[in] mutex Mutex that was released */ 168 void release(const Mutex *mutex) UNIV_NOTHROW; 169 170 /** @return true if thread owns the mutex */ is_owned()171 bool is_owned() const UNIV_NOTHROW { 172 return (os_thread_eq(m_context.m_thread_id, os_thread_get_curr_id())); 173 } 174 175 /** @return the name of the file from the mutex was acquired */ get_enter_filename()176 const char *get_enter_filename() const UNIV_NOTHROW { 177 return (m_context.m_filename); 178 } 179 180 /** @return the name of the file from the mutex was acquired */ get_enter_line()181 ulint get_enter_line() const UNIV_NOTHROW { return (m_context.m_line); } 182 183 /** @return id of the thread that was trying to acquire the mutex */ get_thread_id()184 os_thread_id_t get_thread_id() const UNIV_NOTHROW { 185 return (m_context.m_thread_id); 186 } 187 188 /** Magic number to check for memory corruption. */ 189 ulint m_magic_n; 190 191 /** Latch state of the mutex owner */ 192 Context m_context; 193 }; 194 #endif /* UNIV_DEBUG */ 195 196 /* Do nothing */ 197 template <typename Mutex> 198 struct NoPolicy { 199 /** Default constructor. */ NoPolicyNoPolicy200 NoPolicy() {} 201 initNoPolicy202 void init(const Mutex &, latch_id_t, const char *, uint32_t) UNIV_NOTHROW {} destroyNoPolicy203 void destroy() UNIV_NOTHROW {} enterNoPolicy204 void enter(const Mutex &, const char *, ulint line) UNIV_NOTHROW {} addNoPolicy205 void add(uint32_t, uint32_t) UNIV_NOTHROW {} lockedNoPolicy206 void locked(const Mutex &, const char *, ulint) UNIV_NOTHROW {} releaseNoPolicy207 void release(const Mutex &) UNIV_NOTHROW {} to_stringNoPolicy208 std::string to_string() const { return (""); } 209 latch_id_t get_id() const; 210 }; 211 212 /** Collect the metrics per mutex instance, no aggregation. */ 213 template <typename Mutex> 214 struct GenericPolicy 215 #ifdef UNIV_DEBUG 216 : public MutexDebug<Mutex> 217 #endif /* UNIV_DEBUG */ 218 { 219 public: 220 typedef Mutex MutexType; 221 222 /** Constructor. */ GenericPolicyGenericPolicy223 GenericPolicy() UNIV_NOTHROW : 224 #ifdef UNIV_DEBUG 225 MutexDebug<MutexType>(), 226 #endif /* UNIV_DEBUG */ 227 m_count(), 228 m_id() { 229 } 230 231 /** Destructor */ ~GenericPolicyGenericPolicy232 ~GenericPolicy() {} 233 234 /** Called when the mutex is "created". Note: Not from the constructor 235 but when the mutex is initialised. 236 @param[in] mutex Mutex instance to track 237 @param[in] id Mutex ID 238 @param[in] filename File where mutex was created 239 @param[in] line Line in filename */ initGenericPolicy240 void init(const MutexType &mutex, latch_id_t id, const char *filename, 241 uint32_t line) UNIV_NOTHROW { 242 m_id = id; 243 244 latch_meta_t &meta = sync_latch_get_meta(id); 245 246 ut_ad(meta.get_id() == id); 247 248 meta.get_counter()->single_register(&m_count); 249 250 sync_file_created_register(this, filename, line); 251 252 ut_d(MutexDebug<MutexType>::init(m_id)); 253 } 254 255 /** Called when the mutex is destroyed. */ destroyGenericPolicy256 void destroy() UNIV_NOTHROW { 257 latch_meta_t &meta = sync_latch_get_meta(m_id); 258 259 meta.get_counter()->single_deregister(&m_count); 260 261 sync_file_created_deregister(this); 262 263 ut_d(MutexDebug<MutexType>::destroy()); 264 } 265 266 /** Called after a successful mutex acquire. 267 @param[in] n_spins Number of times the thread did 268 spins while trying to acquire the mutex 269 @param[in] n_waits Number of times the thread waited 270 in some type of OS queue */ addGenericPolicy271 void add(uint32_t n_spins, uint32_t n_waits) UNIV_NOTHROW { 272 /* Currently global on/off. Keeps things simple and fast */ 273 274 if (!m_count.m_enabled) { 275 return; 276 } 277 278 m_count.m_spins += n_spins; 279 m_count.m_waits += n_waits; 280 281 ++m_count.m_calls; 282 } 283 284 /** Called when an attempt is made to lock the mutex 285 @param[in] mutex Mutex instance to be locked 286 @param[in] filename Filename from where it was called 287 @param[in] line Line number from where it was called */ enterGenericPolicy288 void enter(const MutexType &mutex, const char *filename, 289 ulint line) UNIV_NOTHROW { 290 ut_d(MutexDebug<MutexType>::enter(&mutex, filename, line)); 291 } 292 293 /** Called when the mutex is locked 294 @param[in] mutex Mutex instance that is locked 295 @param[in] filename Filename from where it was called 296 @param[in] line Line number from where it was called */ lockedGenericPolicy297 void locked(const MutexType &mutex, const char *filename, 298 ulint line) UNIV_NOTHROW { 299 ut_d(MutexDebug<MutexType>::locked(&mutex, filename, line)); 300 } 301 302 /** Called when the mutex is released 303 @param[in] mutex Mutex instance that is released */ releaseGenericPolicy304 void release(const MutexType &mutex) UNIV_NOTHROW { 305 ut_d(MutexDebug<MutexType>::release(&mutex)); 306 } 307 308 /** Print the information about the latch 309 @return the string representation */ 310 std::string print() const UNIV_NOTHROW; 311 312 /** @return the latch ID */ get_idGenericPolicy313 latch_id_t get_id() const UNIV_NOTHROW { return (m_id); } 314 315 /** @return the string representation */ 316 std::string to_string() const; 317 318 private: 319 typedef latch_meta_t::CounterType Counter; 320 321 /** The user visible counters, registered with the meta-data. */ 322 Counter::Count m_count; 323 324 /** Latch meta data ID */ 325 latch_id_t m_id; 326 }; 327 328 /** Track agregate metrics policy, used by the page mutex. There are just 329 too many of them to count individually. */ 330 template <typename Mutex> 331 class BlockMutexPolicy 332 #ifdef UNIV_DEBUG 333 : public MutexDebug<Mutex> 334 #endif /* UNIV_DEBUG */ 335 { 336 public: 337 typedef Mutex MutexType; 338 typedef typename latch_meta_t::CounterType::Count Count; 339 340 /** Default constructor. */ BlockMutexPolicy()341 BlockMutexPolicy() 342 : 343 #ifdef UNIV_DEBUG 344 MutexDebug<MutexType>(), 345 #endif /* UNIV_DEBUG */ 346 m_count(), 347 m_id() { 348 /* Do nothing */ 349 } 350 351 /** Destructor */ ~BlockMutexPolicy()352 ~BlockMutexPolicy() {} 353 354 /** Called when the mutex is "created". Note: Not from the constructor 355 but when the mutex is initialised. 356 @param[in] mutex Mutex instance to track 357 @param[in] id Mutex ID 358 @param[in] filename File where mutex was created 359 @param[in] line Line in filename */ init(const MutexType & mutex,latch_id_t id,const char * filename,uint32_t line)360 void init(const MutexType &mutex, latch_id_t id, const char *filename, 361 uint32_t line) UNIV_NOTHROW { 362 /* It can be LATCH_ID_BUF_BLOCK_MUTEX or 363 LATCH_ID_BUF_POOL_ZIP. Unfortunately, they 364 are mapped to the same mutex type in the 365 buffer pool code. */ 366 367 m_id = id; 368 369 latch_meta_t &meta = sync_latch_get_meta(m_id); 370 371 ut_ad(meta.get_id() == id); 372 373 m_count = meta.get_counter()->sum_register(); 374 375 ut_d(MutexDebug<MutexType>::init(m_id)); 376 } 377 378 /** Called when the mutex is destroyed. */ destroy()379 void destroy() UNIV_NOTHROW { 380 latch_meta_t &meta = sync_latch_get_meta(m_id); 381 382 ut_ad(meta.get_id() == m_id); 383 384 meta.get_counter()->sum_deregister(m_count); 385 386 m_count = nullptr; 387 388 ut_d(MutexDebug<MutexType>::destroy()); 389 } 390 391 /** Called after a successful mutex acquire. 392 @param[in] n_spins Number of times the thread did 393 spins while trying to acquire the mutex 394 @param[in] n_waits Number of times the thread waited 395 in some type of OS queue */ add(uint32_t n_spins,uint32_t n_waits)396 void add(uint32_t n_spins, uint32_t n_waits) UNIV_NOTHROW { 397 if (!m_count->m_enabled) { 398 return; 399 } 400 401 m_count->m_spins += n_spins; 402 m_count->m_waits += n_waits; 403 404 ++m_count->m_calls; 405 } 406 407 /** Called when the mutex is locked 408 @param[in] mutex Mutex instance that is locked 409 @param[in] filename Filename from where it was called 410 @param[in] line Line number from where it was called */ locked(const MutexType & mutex,const char * filename,ulint line)411 void locked(const MutexType &mutex, const char *filename, 412 ulint line) UNIV_NOTHROW { 413 ut_d(MutexDebug<MutexType>::locked(&mutex, filename, line)); 414 } 415 416 /** Called when the mutex is released 417 @param[in] mutex Mutex instance that is released */ release(const MutexType & mutex)418 void release(const MutexType &mutex) UNIV_NOTHROW { 419 ut_d(MutexDebug<MutexType>::release(&mutex)); 420 } 421 422 /** Called when an attempt is made to lock the mutex 423 @param[in] mutex Mutex instance to be locked 424 @param[in] filename Filename from where it was called 425 @param[in] line Line number from where it was called */ enter(const MutexType & mutex,const char * filename,ulint line)426 void enter(const MutexType &mutex, const char *filename, 427 ulint line) UNIV_NOTHROW { 428 ut_d(MutexDebug<MutexType>::enter(&mutex, filename, line)); 429 } 430 431 /** Print the information about the latch 432 @return the string representation */ 433 std::string print() const UNIV_NOTHROW; 434 435 /** @return the latch ID */ get_id()436 latch_id_t get_id() const { return (m_id); } 437 438 /** @return the string representation */ 439 std::string to_string() const; 440 441 private: 442 typedef latch_meta_t::CounterType Counter; 443 444 /** The user visible counters, registered with the meta-data. */ 445 Counter::Count *m_count; 446 447 /** Latch meta data ID */ 448 latch_id_t m_id; 449 }; 450 451 #include "sync0policy.ic" 452 453 #endif /* !UNIV_LIBRARY */ 454 #endif /* sync0policy_h */ 455