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