1 /* Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved. 2 3 This program is free software; you can redistribute it and/or modify 4 it under the terms of the GNU General Public License, version 2.0, 5 as published by the Free Software Foundation. 6 7 This program is also distributed with certain software (including 8 but not limited to OpenSSL) that is licensed under separate terms, 9 as designated in a particular file or component or in included license 10 documentation. The authors of MySQL hereby grant you an additional 11 permission to link the program and your derivative works with the 12 separately licensed software that they have included with MySQL. 13 14 This program is distributed in the hope that it will be useful, 15 but WITHOUT ANY WARRANTY; without even the implied warranty of 16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 GNU General Public License, version 2.0, for more details. 18 19 You should have received a copy of the GNU General Public License 20 along with this program; if not, write to the Free Software 21 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ 22 23 #ifndef RESOURCEGROUPS_RESOURCE_GROUP_MGR_H_ 24 #define RESOURCEGROUPS_RESOURCE_GROUP_MGR_H_ 25 26 #include <stdint.h> 27 #include <memory> 28 #include <string> 29 #include <vector> 30 31 #include "m_string.h" 32 #include "my_dbug.h" 33 #include "my_inttypes.h" 34 #include "mysql/components/service.h" 35 #include "mysql/components/services/log_builtins.h" 36 #include "mysql/components/services/log_shared.h" 37 #include "mysql/components/services/mysql_rwlock_bits.h" 38 #include "mysql/components/services/pfs_notification.h" 39 #include "mysql/components/services/pfs_resource_group.h" 40 #include "mysql/components/services/psi_thread_bits.h" 41 #include "mysql/components/services/registry.h" 42 #include "mysql/psi/mysql_mutex.h" 43 #include "sql/debug_sync.h" 44 #include "sql/log.h" 45 #include "sql/mdl.h" 46 #include "sql/resourcegroups/resource_group_basic_types.h" 47 #include "sql/sql_class.h" 48 49 namespace dd { 50 class Resource_group; 51 } // namespace dd 52 namespace resourcegroups { 53 class Resource_group; 54 } // namespace resourcegroups 55 template <class Key, class Value> 56 class collation_unordered_map; 57 58 namespace resourcegroups { 59 60 /** 61 This is a singleton class that provides various functionalities related to 62 Resource group management, more importantly the managing and the mapping of 63 resource group names to the corresponding in-memory resource group object. 64 */ 65 66 class Resource_group_mgr { 67 public: 68 /** 69 Singleton method to return an instance of this class. 70 */ 71 72 static Resource_group_mgr *instance(); 73 74 /** 75 Destroy the singleton instance. 76 */ 77 78 static void destroy_instance(); 79 80 /** 81 Check if support for Resource group exists at runtime. 82 83 @return true if resource group feature is supported else false. 84 */ 85 resource_group_support()86 bool resource_group_support() { return m_resource_group_support; } 87 88 /** 89 Reason for resource group not being supported. 90 91 @return pointer to string which indicate reason for resource group unsupport 92 */ 93 unsupport_reason()94 const char *unsupport_reason() { return m_unsupport_reason.c_str(); } 95 96 /** 97 Set reason for resource group not being supported. 98 99 @param reason string representing reason for resource group unsupport. 100 */ 101 set_unsupport_reason(const std::string & reason)102 void set_unsupport_reason(const std::string &reason) { 103 m_unsupport_reason = reason; 104 } 105 106 /** 107 Initialize the Resource group manager. 108 Must be called before instance() can be used. 109 110 @return true if initialization failed, false otherwise. 111 */ 112 113 bool init(); 114 115 /** 116 Post initialization sequence during mysqld startup. 117 118 @return true if post initialization failed, else false. 119 */ 120 121 bool post_init(); 122 123 /** 124 Disable and deinitialize the resource group if it was initialized before. 125 */ 126 disable_resource_group()127 void disable_resource_group() { 128 if (m_resource_group_support) { 129 LogErr(INFORMATION_LEVEL, ER_RES_GRP_FEATURE_NOT_AVAILABLE); 130 deinit(); 131 m_resource_group_support = false; 132 } 133 } 134 135 /** 136 Get the in-memory Resource group object corresponding 137 to a resource group name. 138 139 @param resource_group_name Name of the resource group. 140 @return Pointer to the Resource group if it exists else nullptr. 141 */ 142 143 Resource_group *get_resource_group(const std::string &resource_group_name); 144 145 /** 146 Get the thread attributes identified by PSI thread ID. 147 148 @param [out] pfs_thread_attr Pointer to thread attribute object which 149 shall be populated if the call is successful. 150 @param thread_id PFS thread identifier representing a thread of mysqld. 151 152 @return true if call failed else false. 153 */ 154 get_thread_attributes(PSI_thread_attrs * pfs_thread_attr,ulonglong thread_id)155 bool get_thread_attributes(PSI_thread_attrs *pfs_thread_attr, 156 ulonglong thread_id) { 157 DBUG_ASSERT(m_resource_group_support); 158 return m_resource_group_svc->get_thread_system_attrs_by_id( 159 nullptr, thread_id, pfs_thread_attr) != 0; 160 } 161 162 /** 163 Add the resource group to the Resource group map. 164 165 @param resource_group_ptr pointer to in-memory Resource_group. 166 @return true if the call failed else false. 167 */ 168 169 bool add_resource_group(std::unique_ptr<Resource_group> resource_group_ptr); 170 171 /** 172 Remove the resource group from the map identified by it's name. 173 174 @param name of the resource group. 175 */ 176 177 void remove_resource_group(const std::string &name); 178 179 /** 180 Create an in-memory resource group identified by its attributes 181 and add it to the resource group map. 182 183 @param name Name of resource group. 184 @param type Type of resource group. 185 @param enabled Is resource group enabled? 186 @param cpus Pointer to list of Range objects representing CPU IDS. 187 @param thr_priority Thread priority. 188 189 @returns Pointer to Resource Group object if call is successful else null. 190 */ 191 192 Resource_group *create_and_add_in_resource_group_hash( 193 const LEX_CSTRING &name, Type type, bool enabled, 194 std::unique_ptr<std::vector<Range>> cpus, int thr_priority); 195 196 /** 197 Move the Resource group of the current thread identified by from_res_group 198 to the Resource group to_res_grp. 199 200 @param from_res_grp Pointer to current Resource_group of the thread. 201 @param to_res_grp Pointer to the destination Resource group which the 202 thread will be switched to. 203 @return true if move_resource_group failed else false. 204 */ 205 206 bool move_resource_group(Resource_group *from_res_grp, 207 Resource_group *to_res_grp); 208 209 /** 210 Deserialize a DD resource group object into an 211 in-memory Resource group object. 212 213 @param res_grp Pointer to DD Resource_group object. 214 @return Pointer to in-memory Resource_group subject if 215 Successful else null. 216 */ 217 218 Resource_group *deserialize_resource_group(const dd::Resource_group *res_grp); 219 220 /** 221 Set Resource group name in the PFS table performance_schema.threads for 222 the PFS thread id. 223 224 @param name Pointer to name of resource group. 225 @param length length of the resource group name. 226 @param thread_id PFS thread id of the thread, 227 */ 228 set_res_grp_in_pfs(const char * name,int length,ulonglong thread_id)229 void set_res_grp_in_pfs(const char *name, int length, ulonglong thread_id) { 230 DBUG_ASSERT(m_resource_group_support); 231 m_resource_group_svc->set_thread_resource_group_by_id( 232 nullptr, thread_id, name, length, nullptr); 233 } 234 235 /** 236 Return the SYS_default resource group instance. 237 238 @return pointer to the SYS_default resource group. 239 */ 240 sys_default_resource_group()241 Resource_group *sys_default_resource_group() { 242 return m_sys_default_resource_group; 243 } 244 245 /** 246 Return the USR_default resource group instance. 247 248 @return pointer to the USR_default resource group. 249 */ 250 usr_default_resource_group()251 Resource_group *usr_default_resource_group() { 252 return m_usr_default_resource_group; 253 } 254 255 /** 256 Check if a given Resource group is either SYS_default or USR_default. 257 258 @return true if resource is USR_default or SYS_default else false. 259 */ 260 is_resource_group_default(const Resource_group * res_grp)261 bool is_resource_group_default(const Resource_group *res_grp) { 262 return (res_grp == m_usr_default_resource_group || 263 res_grp == m_sys_default_resource_group); 264 } 265 266 /** 267 Check if a thread priority setting can be done. 268 269 @return true if thread priority setting could be done else false. 270 */ 271 thread_priority_available()272 bool thread_priority_available() { 273 DBUG_ASSERT(m_resource_group_support); 274 return m_thread_priority_available; 275 } 276 277 /** 278 Acquire an shared MDL lock on resource group name. 279 280 @param thd Pointer to THD context. 281 @param res_grp_name Resource group name. 282 @param lock_duration Duration of lock. 283 @param[out] ticket reference to ticket object. 284 @param acquire_lock true if one needs to wait on lock 285 else false. 286 287 @return true if lock acquisition failed else false. 288 */ 289 290 bool acquire_shared_mdl_for_resource_group(THD *thd, const char *res_grp_name, 291 enum_mdl_duration lock_duration, 292 MDL_ticket **ticket, 293 bool acquire_lock); 294 295 /** 296 Release the shared MDL lock held on a resource group. 297 298 @param thd THD context. 299 @param ticket Pointer to lock ticket object. 300 */ 301 release_shared_mdl_for_resource_group(THD * thd,MDL_ticket * ticket)302 void release_shared_mdl_for_resource_group(THD *thd, MDL_ticket *ticket) { 303 DBUG_ASSERT(ticket != nullptr); 304 thd->mdl_context.release_lock(ticket); 305 } 306 307 /** 308 String corressponding to the type of resource group. 309 310 @param type Type of resource group. 311 312 @return string corressponding to resource group type. 313 */ 314 resource_group_type_str(const Type & type)315 const char *resource_group_type_str(const Type &type) { 316 return type == Type::USER_RESOURCE_GROUP ? "User" : "System"; 317 } 318 319 /** 320 Number of VCPUs present in the system. 321 322 @returns Number of VCPUs in the system. 323 */ 324 num_vcpus()325 uint32_t num_vcpus() { return m_num_vcpus; } 326 327 void deinit(); 328 329 #ifndef DBUG_OFF // The belows methods are required in debug build for testing. 330 bool disable_pfs_notification(); 331 #endif 332 333 /** 334 Switch Resource Group if it is requested by environment. 335 336 @param thd THD context. 337 @param[out] src_res_grp Original resource group from that 338 switching is performed 339 @param[out] dest_res_grp Destination resource group to that 340 switching is performed 341 @param[out] ticket Pointer to MDL ticket object. 342 @param[out] cur_ticket Pointer to current resource group MDL ticket 343 object. 344 345 @return true if switching was performed, else false 346 */ 347 348 bool switch_resource_group_if_needed( 349 THD *thd, resourcegroups::Resource_group **src_res_grp, 350 resourcegroups::Resource_group **dest_res_grp, MDL_ticket **ticket, 351 MDL_ticket **cur_ticket); 352 353 /** 354 Restore original resource group if 355 resource group switching was performed before. 356 357 @param thd Thread context. 358 @param[out] src_res_grp resource group to that 359 switching was performed 360 @param[out] dest_res_grp original resource group to that 361 switching is performed 362 */ 363 restore_original_resource_group(THD * thd,resourcegroups::Resource_group * src_res_grp,resourcegroups::Resource_group * dest_res_grp)364 void restore_original_resource_group( 365 THD *thd, resourcegroups::Resource_group *src_res_grp, 366 resourcegroups::Resource_group *dest_res_grp) { 367 mysql_mutex_lock(&thd->LOCK_thd_data); 368 if (thd->resource_group_ctx()->m_cur_resource_group == nullptr || 369 thd->resource_group_ctx()->m_cur_resource_group == src_res_grp) { 370 resourcegroups::Resource_group_mgr::instance()->move_resource_group( 371 dest_res_grp, thd->resource_group_ctx()->m_cur_resource_group); 372 } 373 mysql_mutex_unlock(&thd->LOCK_thd_data); 374 DBUG_EXECUTE_IF("pause_after_rg_switch", { 375 const char act[] = 376 "now " 377 "SIGNAL restore_finished"; 378 DBUG_ASSERT(!debug_sync_set_action(thd, STRING_WITH_LEN(act))); 379 };); 380 } 381 382 private: 383 /** 384 Pointer to singleton instance of the Resource_group_mgr class. 385 */ 386 static Resource_group_mgr *m_instance; 387 388 /** 389 Handles to the PFS registry, Resource Group and 390 Notification services. 391 */ 392 393 SERVICE_TYPE(registry) * m_registry_svc; 394 SERVICE_TYPE(pfs_resource_group_v3) * m_resource_group_svc; 395 SERVICE_TYPE(pfs_notification_v3) * m_notify_svc; 396 my_h_service m_h_res_grp_svc; 397 my_h_service m_h_notification_svc; 398 int m_notify_handle; 399 400 /** 401 Pointer to USR_default and SYS_default resource groups. 402 Owernship of these pointers is resource group hash. 403 */ 404 Resource_group *m_usr_default_resource_group; 405 Resource_group *m_sys_default_resource_group; 406 407 /** 408 Map mapping resource group name with it's corresponding in-memory 409 Resource_group object 410 */ 411 collation_unordered_map<std::string, std::unique_ptr<Resource_group>> 412 *m_resource_group_hash; 413 414 /** 415 Lock protecting the resource group map. 416 */ 417 mysql_rwlock_t m_map_rwlock; 418 419 /** 420 Boolean value indicating whether setting of thread priority is allowed. 421 */ 422 bool m_thread_priority_available; 423 424 /** 425 Bool value indicating support for resource group. 426 */ 427 bool m_resource_group_support; 428 429 /** 430 String indicating reason for resource group not being supported. 431 */ 432 std::string m_unsupport_reason; 433 434 /** 435 Value indicating the number of vcpus in the system. This is initialized 436 during startup so that we do not call the platform API everytime 437 which is expensive. 438 */ 439 uint32_t m_num_vcpus; 440 Resource_group_mgr()441 Resource_group_mgr() 442 : m_registry_svc(nullptr), 443 m_resource_group_svc(nullptr), 444 m_notify_svc(nullptr), 445 m_h_res_grp_svc(nullptr), 446 m_h_notification_svc(nullptr), 447 m_notify_handle(0), 448 m_usr_default_resource_group(nullptr), 449 m_sys_default_resource_group(nullptr), 450 m_resource_group_hash(nullptr), 451 m_thread_priority_available(false), 452 m_resource_group_support(false), 453 m_num_vcpus(0) {} 454 ~Resource_group_mgr()455 ~Resource_group_mgr() {} 456 457 // Disable copy construction and assignment for Resource_group_mgr class. 458 Resource_group_mgr(const Resource_group_mgr &) = delete; 459 void operator=(const Resource_group_mgr &) = delete; 460 }; 461 } // namespace resourcegroups 462 #endif // RESOURCEGROUPS_RESOURCE_GROUP_MGR_H_ 463