1 /* 2 Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved. 3 4 This program is free software; you can redistribute it and/or modify 5 it under the terms of the GNU General Public License, version 2.0, 6 as published by the Free Software Foundation. 7 8 This program is also distributed with certain software (including 9 but not limited to OpenSSL) that is licensed under separate terms, 10 as designated in a particular file or component or in included license 11 documentation. The authors of MySQL hereby grant you an additional 12 permission to link the program and your derivative works with the 13 separately licensed software that they have included with MySQL. 14 15 This program is distributed in the hope that it will be useful, 16 but WITHOUT ANY WARRANTY; without even the implied warranty of 17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 GNU General Public License, version 2.0, for more details. 19 20 You should have received a copy of the GNU General Public License 21 along with this program; if not, write to the Free Software 22 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 23 */ 24 25 #ifndef NDB_SCHEMA_DIST_H 26 #define NDB_SCHEMA_DIST_H 27 28 #include <string> 29 #include <vector> 30 31 #include "my_inttypes.h" 32 33 /** 34 The numbers below must not change as they are passed 35 between MySQL servers as part of the schema distribution 36 protocol. Changes would break compatibility between versions. 37 Add new numbers to the end. 38 */ 39 enum SCHEMA_OP_TYPE { 40 SOT_DROP_TABLE = 0, 41 SOT_CREATE_TABLE = 1, 42 SOT_RENAME_TABLE_NEW = 2, // Unused, but still reserved 43 SOT_ALTER_TABLE_COMMIT = 3, 44 SOT_DROP_DB = 4, 45 SOT_CREATE_DB = 5, 46 SOT_ALTER_DB = 6, 47 SOT_CLEAR_SLOCK = 7, 48 SOT_TABLESPACE = 8, 49 SOT_LOGFILE_GROUP = 9, 50 SOT_RENAME_TABLE = 10, 51 SOT_TRUNCATE_TABLE = 11, 52 SOT_RENAME_TABLE_PREPARE = 12, 53 SOT_ONLINE_ALTER_TABLE_PREPARE = 13, 54 SOT_ONLINE_ALTER_TABLE_COMMIT = 14, 55 SOT_CREATE_USER = 15, 56 SOT_DROP_USER = 16, 57 SOT_RENAME_USER = 17, 58 SOT_GRANT = 18, 59 SOT_REVOKE = 19, 60 SOT_CREATE_TABLESPACE = 20, 61 SOT_ALTER_TABLESPACE = 21, 62 SOT_DROP_TABLESPACE = 22, 63 SOT_CREATE_LOGFILE_GROUP = 23, 64 SOT_ALTER_LOGFILE_GROUP = 24, 65 SOT_DROP_LOGFILE_GROUP = 25, 66 SOT_ACL_SNAPSHOT = 26, 67 SOT_ACL_STATEMENT = 27, 68 SOT_ACL_STATEMENT_REFRESH = 28, 69 }; 70 71 namespace Ndb_schema_dist { 72 73 // Schema operation result codes 74 enum Schema_op_result_code { 75 NODE_UNSUBSCRIBE = 9001, // Node unsubscribe during 76 NODE_FAILURE = 9002, // Node failed during 77 NODE_TIMEOUT = 9003, // Node timeout during 78 COORD_ABORT = 9004, // Coordinator aborted 79 CLIENT_ABORT = 9005, // Client aborted 80 CLIENT_KILLED = 9007, // Client killed 81 SCHEMA_OP_FAILURE = 9008, // Failure not related to protocol but the actual 82 // schema operation to be distributed 83 NDB_TRANS_FAILURE = 9009 // An NDB read/write transaction failed 84 }; 85 86 /** 87 Check if schema distribution has been initialized and is 88 ready to communicate with the other MySQL Server(s) in the cluster. 89 90 @param requestor Pointer value identifying caller 91 92 @return true schema distribution is ready 93 */ 94 bool is_ready(void *requestor); 95 96 } // namespace Ndb_schema_dist 97 98 class Ndb; 99 100 /** 101 @brief Ndb_schema_dist_client, class represents a Client 102 in the schema distribution. 103 104 Contains functionality for distributing a schema operation 105 to the other MySQL Server(s) which need to update their 106 data structures when a metadata change occurs. 107 108 The Client primarily communicates with the Coordinator(which is 109 in the same MySQL Server) while the Coordinator handles communication 110 with the Participant nodes(in other MySQL Server). When Coordinator 111 have got replies from all Participants, by acknowledging the schema 112 operation, the Client will be woken up again. 113 114 Should also have functionality for: 115 - checking that "schema dist is ready", i.e checking that 116 the mysql.ndb_schema table has been created and schema 117 distribution has been initialized properly(by the ndb 118 binlog thread) 119 - checking that schema distribution of the table and db name 120 is supported by the current mysql.ndb_schema, for example 121 that length of the table or db name fits in the columns of that 122 table 123 - checking which functionality the other MySQL Server(s) support, 124 for example if they are on an older version they would probably 125 still not support longer table names or new schema dist operation types. 126 */ 127 class Ndb_schema_dist_client { 128 class THD *const m_thd; 129 class Thd_ndb *const m_thd_ndb; 130 struct NDB_SHARE *m_share{nullptr}; 131 const std::string m_share_reference; 132 class Prepared_keys { 133 using Key = std::pair<std::string, std::string>; 134 std::vector<Key> m_keys; 135 136 public: keys()137 const std::vector<Key> &keys() { return m_keys; } 138 void add_key(const char *db, const char *tabname); 139 bool check_key(const char *db, const char *tabname) const; 140 } m_prepared_keys; 141 bool m_holding_acl_mutex; 142 143 // List of schema operation results, populated when schema operation has 144 // completed sucessfully. 145 struct Schema_op_result { 146 uint32 nodeid; 147 uint32 result; 148 std::string message; 149 }; 150 std::vector<Schema_op_result> m_schema_op_results; 151 152 static bool m_ddl_blocked; 153 154 void push_and_clear_schema_op_results(); 155 156 bool log_schema_op_impl(Ndb *ndb, const char *query, int query_length, 157 const char *db, const char *table_name, 158 uint32 ndb_table_id, uint32 ndb_table_version, 159 SCHEMA_OP_TYPE type, uint32 anyvalue); 160 161 /** 162 @brief Write row to ndb_schema to initiate the schema operation 163 @return true on sucess and false on failure 164 */ 165 bool write_schema_op_to_NDB(Ndb *ndb, const char *query, int query_length, 166 const char *db, const char *name, uint32 id, 167 uint32 version, uint32 nodeid, uint32 type, 168 uint32 schema_op_id, uint32 anyvalue); 169 /** 170 @brief Distribute the schema operation to the other MySQL Server(s) 171 @note For now, just call the old log_schema_op_impl(), over time 172 the functionality of that function will gradually be moved over 173 to this new Ndb_schema_dist_client class 174 @return false if schema distribution fails 175 */ 176 bool log_schema_op(const char *query, size_t query_length, const char *db, 177 const char *table_name, uint32 id, uint32 version, 178 SCHEMA_OP_TYPE type, bool log_query_on_participant = true); 179 180 /** 181 @brief Calculate the anyvalue to use for this schema change. The anyvalue 182 is used to transport additional settings from client to the participants. 183 184 @param force_nologging Force setting anyvalue to not log schema change on 185 participant 186 187 @return The anyvalue to use for schema change 188 */ 189 uint32 calculate_anyvalue(bool force_nologging) const; 190 191 /** 192 @brief Acquire the ACL change mutex 193 */ 194 void acquire_acl_lock(); 195 196 public: 197 Ndb_schema_dist_client() = delete; 198 Ndb_schema_dist_client(const Ndb_schema_dist_client &) = delete; 199 Ndb_schema_dist_client(class THD *thd); 200 201 ~Ndb_schema_dist_client(); 202 block_ddl(bool ddl_blocked)203 static void block_ddl(bool ddl_blocked) { m_ddl_blocked = ddl_blocked; } is_ddl_blocked()204 static bool is_ddl_blocked() { return m_ddl_blocked; } 205 206 /* 207 @brief Generate unique id for distribution of objects which doesn't have 208 global id in NDB. 209 @return unique id 210 */ 211 uint32 unique_id() const; 212 213 /* 214 @brief Generate unique version for distribution of objects which doesn't 215 have global id in NDB. 216 @return unique version 217 */ 218 uint32 unique_version() const; 219 220 /** 221 @brief Prepare client for schema operation, check that 222 schema distribution is ready and other conditions are fulfilled. 223 @param db database name 224 @param tabname table name 225 @note Always done early to avoid changing metadata which is 226 hard to rollback at a later stage. 227 @return true if prepare succeed 228 */ 229 bool prepare(const char *db, const char *tabname); 230 231 /** 232 @brief Prepare client for rename schema operation, check that 233 schema distribution is ready and other conditions are fulfilled. 234 The rename case is different as two different "keys" may be used 235 and need to be prepared. 236 @param db database name 237 @param tabname table name 238 @param new_db new database name 239 @param new_tabname new table name 240 @note Always done early to avoid changing metadata which is 241 hard to rollback at a later stage. 242 @return true if prepare succeed 243 */ 244 bool prepare_rename(const char *db, const char *tabname, const char *new_db, 245 const char *new_tabname); 246 247 /** 248 @brief Prepare client for an ACL change notification 249 (e.g. CREATE USER, GRANT, REVOKE, etc.). 250 @param node_id Unique number identifying this mysql server 251 @return true if prepare succeed 252 */ 253 bool prepare_acl_change(uint node_id); 254 255 /** 256 @brief Check that the prepared identifiers is supported by the schema 257 distribution. For example long identifiers can't be communicated 258 between the MySQL Servers unless the table used for communication 259 have large enough columns. 260 @note This is done separately from @prepare since different error 261 code(or none at all) should be returned for this error. 262 @note Always done early to avoid changing metadata which is 263 hard to rollback at a later stage. 264 @param invalid_identifier The name of the identifier that failed the check 265 @return true if check succeed 266 */ 267 bool check_identifier_limits(std::string &invalid_identifier); 268 269 /** 270 * @brief Check if given name is the schema distribution table, special 271 handling for that table is required in a few places. 272 @param db database name 273 @param table_name table name 274 @return true if table is the schema distribution table 275 */ 276 static bool is_schema_dist_table(const char *db, const char *table_name); 277 278 /** 279 * @brief Check if given name is the schema distribution result table, special 280 handling for that table is required in a few places. 281 @param db database name 282 @param table_name table name 283 @return true if table is the schema distribution result table 284 */ 285 static bool is_schema_dist_result_table(const char *db, 286 const char *table_name); 287 288 /** 289 * @brief Convert SCHEMA_OP_TYPE to string 290 * @return string describing the type 291 */ 292 static const char *type_name(SCHEMA_OP_TYPE type); 293 294 bool create_table(const char *db, const char *table_name, int id, 295 int version); 296 bool truncate_table(const char *db, const char *table_name, int id, 297 int version); 298 bool alter_table(const char *db, const char *table_name, int id, int version, 299 bool log_on_participant = true); 300 bool alter_table_inplace_prepare(const char *db, const char *table_name, 301 int id, int version); 302 bool alter_table_inplace_commit(const char *db, const char *table_name, 303 int id, int version); 304 bool rename_table_prepare(const char *db, const char *table_name, int id, 305 int version, const char *new_key_for_table); 306 bool rename_table(const char *db, const char *table_name, int id, int version, 307 const char *new_dbname, const char *new_tabname, 308 bool log_on_participant); 309 bool drop_table(const char *db, const char *table_name, int id, int version, 310 bool log_on_participant = true); 311 312 bool create_db(const char *query, uint query_length, const char *db, 313 unsigned int id, unsigned int version); 314 bool alter_db(const char *query, uint query_length, const char *db, 315 unsigned int id, unsigned int version); 316 bool drop_db(const char *db); 317 318 bool acl_notify(const char *db, const char *query, uint query_length, 319 bool participants_must_refresh); 320 bool acl_notify(std::string user_list); 321 322 bool tablespace_changed(const char *tablespace_name, int id, int version); 323 bool logfilegroup_changed(const char *logfilegroup_name, int id, int version); 324 325 bool create_tablespace(const char *tablespace_name, int id, int version); 326 bool alter_tablespace(const char *tablespace_name, int id, int version); 327 bool drop_tablespace(const char *tablespace_name, int id, int version); 328 329 bool create_logfile_group(const char *logfile_group_name, int id, 330 int version); 331 bool alter_logfile_group(const char *logfile_group_name, int id, int version); 332 bool drop_logfile_group(const char *logfile_group_name, int id, int version); 333 }; 334 335 #endif 336