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