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