1 /*****************************************************************************
2 
3 Copyright (c) 2020, 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 #ifndef lock0guards_h
28 #define lock0guards_h
29 
30 #include "lock0lock.h"
31 #include "ut0class_life_cycle.h"
32 
33 namespace locksys {
34 /**
35 A RAII helper which latches global_latch in exclusive mode during constructor,
36 and unlatches it during destruction, preventing any other threads from activity
37 within lock_sys for it's entire scope.
38 */
39 class Global_exclusive_latch_guard : private ut::Non_copyable {
40  public:
41   Global_exclusive_latch_guard();
42   ~Global_exclusive_latch_guard();
43 };
44 
45 /**
46 A RAII helper which tries to exclusively latch the global_lach in constructor
47 and unlatches it, if needed, during destruction, preventing any other threads
48 from activity within lock_sys for it's entire scope, if owns_lock().
49 */
50 class Global_exclusive_try_latch : private ut::Non_copyable {
51  public:
52   Global_exclusive_try_latch();
53   ~Global_exclusive_try_latch();
54   /** Checks if succeeded to latch the global_latch during construction.
55   @return true iff the current thread owns (through this instance) the exclusive
56           global lock_sys latch */
owns_lock()57   bool owns_lock() const noexcept { return m_owns_exclusive_global_latch; }
58 
59  private:
60   /** Did the constructor succeed to acquire exclusive global lock_sys latch? */
61   bool m_owns_exclusive_global_latch;
62 };
63 
64 /**
65 A RAII helper which latches global_latch in shared mode during constructor,
66 and unlatches it during destruction, preventing any other thread from acquiring
67 exclusive latch. This should be used in combination Shard_naked_latch_guard,
68 preferably by simply using Shard_latch_guard which combines the two for you.
69 */
70 class Global_shared_latch_guard : private ut::Non_copyable {
71  public:
72   Global_shared_latch_guard();
73   ~Global_shared_latch_guard();
74 };
75 
76 /**
77 A RAII helper which latches the mutex protecting given shard during constructor,
78 and unlatches it during destruction.
79 You quite probably don't want to use this class, which only takes a shard's
80 latch, without acquiring global_latch - which gives no protection from threads
81 which latch only the global_latch exclusively to prevent any activity.
82 You should use it in combination with Global_shared_latch_guard, so that you
83 first obtain an s-latch on the global_latch, or simply use the Shard_latch_guard
84 class which already combines the two for you.
85 */
86 class Shard_naked_latch_guard : private ut::Non_copyable {
87   explicit Shard_naked_latch_guard(Lock_mutex &shard_mutex);
88 
89  public:
90   explicit Shard_naked_latch_guard(const dict_table_t &table);
91 
92   explicit Shard_naked_latch_guard(const page_id_t &page_id);
93 
94   ~Shard_naked_latch_guard();
95 
96  private:
97   /** The mutex protecting the shard requested in constructor */
98   Lock_mutex &m_shard_mutex;
99 };
100 
101 /**
102 A RAII wrapper class which combines Global_shared_latch_guard and
103 Shard_naked_latch_guard to s-latch the global lock_sys latch and latch the mutex
104 protecting the specified shard for the duration of its scope.
105 The order of initialization is important: we have to take shared global latch
106 BEFORE we attempt to use hash function to compute correct shard and latch it. */
107 class Shard_latch_guard {
108   Global_shared_latch_guard m_global_shared_latch_guard;
109   Shard_naked_latch_guard m_shard_naked_latch_guard;
110 
111  public:
Shard_latch_guard(const dict_table_t & table)112   explicit Shard_latch_guard(const dict_table_t &table)
113       : m_global_shared_latch_guard{}, m_shard_naked_latch_guard{table} {}
114 
Shard_latch_guard(const page_id_t & page_id)115   explicit Shard_latch_guard(const page_id_t &page_id)
116       : m_global_shared_latch_guard{}, m_shard_naked_latch_guard{page_id} {}
117 };
118 
119 /**
120 A RAII helper which latches the mutexes protecting specified shards for the
121 duration of its scope.
122 It makes sure to take the latches in correct order and handles the case where
123 both pages are in the same shard correctly.
124 You quite probably don't want to use this class, which only takes a shard's
125 latch, without acquiring global_latch - which gives no protection from threads
126 which latch only the global_latch exclusively to prevent any activity.
127 You should use it in combination with Global_shared_latch_guard, so that you
128 first obtain an s-latch on the global_latch, or simply use the
129 Shard_latches_guard class which already combines the two for you.
130 */
131 class Shard_naked_latches_guard {
132   explicit Shard_naked_latches_guard(Lock_mutex &shard_mutex_a,
133                                      Lock_mutex &shard_mutex_b);
134 
135  public:
136   explicit Shard_naked_latches_guard(const buf_block_t &block_a,
137                                      const buf_block_t &block_b);
138 
139   ~Shard_naked_latches_guard();
140 
141  private:
142   /** The "smallest" of the two shards' mutexes in the latching order */
143   Lock_mutex &m_shard_mutex_1;
144   /** The "largest" of the two shards' mutexes in the latching order */
145   Lock_mutex &m_shard_mutex_2;
146   /** The ordering on shard mutexes used to avoid deadlocks */
147   static constexpr std::less<Lock_mutex *> MUTEX_ORDER{};
148 };
149 
150 /**
151 A RAII wrapper class which s-latches the global lock_sys shard, and mutexes
152 protecting specified shards for the duration of its scope.
153 It makes sure to take the latches in correct order and handles the case where
154 both pages are in the same shard correctly.
155 The order of initialization is important: we have to take shared global latch
156 BEFORE we attempt to use hash function to compute correct shard and latch it.
157 */
158 class Shard_latches_guard {
159  public:
Shard_latches_guard(const buf_block_t & block_a,const buf_block_t & block_b)160   explicit Shard_latches_guard(const buf_block_t &block_a,
161                                const buf_block_t &block_b)
162       : m_global_shared_latch_guard{},
163         m_shard_naked_latches_guard{block_a, block_b} {}
164 
165  private:
166   Global_shared_latch_guard m_global_shared_latch_guard;
167   Shard_naked_latches_guard m_shard_naked_latches_guard;
168 };
169 
170 }  // namespace locksys
171 
172 #endif /* lock0guards_h */
173