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