polardbxengine/storage/ndb/plugin/ndb_schema_dist.h

330 lines
12 KiB
C++

/*
Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License, version 2.0,
as published by the Free Software Foundation.
This program is also distributed with certain software (including
but not limited to OpenSSL) that is licensed under separate terms,
as designated in a particular file or component or in included license
documentation. The authors of MySQL hereby grant you an additional
permission to link the program and your derivative works with the
separately licensed software that they have included with MySQL.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License, version 2.0, for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef NDB_SCHEMA_DIST_H
#define NDB_SCHEMA_DIST_H
#include <string>
#include <vector>
#include "my_inttypes.h"
/**
The numbers below must not change as they are passed
between MySQL servers as part of the schema distribution
protocol. Changes would break compatibility between versions.
Add new numbers to the end.
*/
enum SCHEMA_OP_TYPE {
SOT_DROP_TABLE = 0,
SOT_CREATE_TABLE = 1,
SOT_RENAME_TABLE_NEW = 2, // Unused, but still reserved
SOT_ALTER_TABLE_COMMIT = 3,
SOT_DROP_DB = 4,
SOT_CREATE_DB = 5,
SOT_ALTER_DB = 6,
SOT_CLEAR_SLOCK = 7,
SOT_TABLESPACE = 8,
SOT_LOGFILE_GROUP = 9,
SOT_RENAME_TABLE = 10,
SOT_TRUNCATE_TABLE = 11,
SOT_RENAME_TABLE_PREPARE = 12,
SOT_ONLINE_ALTER_TABLE_PREPARE = 13,
SOT_ONLINE_ALTER_TABLE_COMMIT = 14,
SOT_CREATE_USER = 15,
SOT_DROP_USER = 16,
SOT_RENAME_USER = 17,
SOT_GRANT = 18,
SOT_REVOKE = 19,
SOT_CREATE_TABLESPACE = 20,
SOT_ALTER_TABLESPACE = 21,
SOT_DROP_TABLESPACE = 22,
SOT_CREATE_LOGFILE_GROUP = 23,
SOT_ALTER_LOGFILE_GROUP = 24,
SOT_DROP_LOGFILE_GROUP = 25,
SOT_ACL_SNAPSHOT = 26,
SOT_ACL_STATEMENT = 27,
SOT_ACL_STATEMENT_REFRESH = 28,
};
namespace Ndb_schema_dist {
// Schema operation result codes
enum Schema_op_result_code {
NODE_UNSUBSCRIBE = 9001, // Node unsubscribe during
NODE_FAILURE = 9002, // Node failed during
NODE_TIMEOUT = 9003, // Node timeout during
COORD_ABORT = 9004, // Coordinator aborted
CLIENT_ABORT = 9005, // Client aborted
CLIENT_KILLED = 9007, // Client killed
SCHEMA_OP_FAILURE = 9008 // Failure not related to protocol but the actual
// schema operation to be distributed
};
/**
Check if schema distribution has been initialized and is
ready to communicate with the other MySQL Server(s) in the cluster.
@param requestor Pointer value identifying caller
@return true schema distribution is ready
*/
bool is_ready(void *requestor);
} // namespace Ndb_schema_dist
class Ndb;
/**
@brief Ndb_schema_dist_client, class represents a Client
in the schema distribution.
Contains functionality for distributing a schema operation
to the other MySQL Server(s) which need to update their
data structures when a metadata change occurs.
The Client primarily communicates with the Coordinator(which is
in the same MySQL Server) while the Coordinator handles communication
with the Participant nodes(in other MySQL Server). When Coordinator
have got replies from all Participants, by acknowledging the schema
operation, the Client will be woken up again.
Should also have functionality for:
- checking that "schema dist is ready", i.e checking that
the mysql.ndb_schema table has been created and schema
distribution has been initialized properly(by the ndb
binlog thread)
- checking that schema distribution of the table and db name
is supported by the current mysql.ndb_schema, for example
that length of the table or db name fits in the columns of that
table
- checking which functionality the other MySQL Server(s) support,
for example if they are on an older version they would probably
still not support longer table names or new schema dist operation types.
*/
class Ndb_schema_dist_client {
class THD *const m_thd;
class Thd_ndb *const m_thd_ndb;
struct NDB_SHARE *m_share{nullptr};
class Prepared_keys {
using Key = std::pair<std::string, std::string>;
std::vector<Key> m_keys;
public:
const std::vector<Key> &keys() { return m_keys; }
void add_key(const char *db, const char *tabname);
bool check_key(const char *db, const char *tabname) const;
} m_prepared_keys;
bool m_holding_acl_mutex;
// List of schema operation results, populated when schema operation has
// completed sucessfully.
struct Schema_op_result {
uint32 nodeid;
uint32 result;
std::string message;
};
std::vector<Schema_op_result> m_schema_op_results;
void push_and_clear_schema_op_results();
bool log_schema_op_impl(Ndb *ndb, const char *query, int query_length,
const char *db, const char *table_name,
uint32 ndb_table_id, uint32 ndb_table_version,
SCHEMA_OP_TYPE type, uint32 anyvalue);
/**
@brief Write row to ndb_schema to initiate the schema operation
@return true on sucess and false on failure
*/
bool write_schema_op_to_NDB(Ndb *ndb, const char *query, int query_length,
const char *db, const char *name, uint32 id,
uint32 version, uint32 nodeid, uint32 type,
uint32 schema_op_id, uint32 anyvalue);
/**
@brief Distribute the schema operation to the other MySQL Server(s)
@note For now, just call the old log_schema_op_impl(), over time
the functionality of that function will gradually be moved over
to this new Ndb_schema_dist_client class
@return false if schema distribution fails
*/
bool log_schema_op(const char *query, size_t query_length, const char *db,
const char *table_name, uint32 id, uint32 version,
SCHEMA_OP_TYPE type, bool log_query_on_participant = true);
/**
@brief Calculate the anyvalue to use for this schema change. The anyvalue
is used to transport additional settings from client to the participants.
@param force_nologging Force setting anyvalue to not log schema change on
participant
@return The anyvalue to use for schema change
*/
uint32 calculate_anyvalue(bool force_nologging) const;
/**
@brief Acquire the ACL change mutex
*/
void acquire_acl_lock();
public:
Ndb_schema_dist_client() = delete;
Ndb_schema_dist_client(const Ndb_schema_dist_client &) = delete;
Ndb_schema_dist_client(class THD *thd);
~Ndb_schema_dist_client();
/*
@brief Generate unique id for distribution of objects which doesn't have
global id in NDB.
@return unique id
*/
uint32 unique_id() const;
/*
@brief Generate unique version for distribution of objects which doesn't
have global id in NDB.
@return unique version
*/
uint32 unique_version() const;
/**
@brief Prepare client for schema operation, check that
schema distribution is ready and other conditions are fulfilled.
@param db database name
@param tabname table name
@note Always done early to avoid changing metadata which is
hard to rollback at a later stage.
@return true if prepare succeed
*/
bool prepare(const char *db, const char *tabname);
/**
@brief Prepare client for rename schema operation, check that
schema distribution is ready and other conditions are fulfilled.
The rename case is different as two different "keys" may be used
and need to be prepared.
@param db database name
@param table_name table name
@param new_db new database name
@param new_tabname new table name
@note Always done early to avoid changing metadata which is
hard to rollback at a later stage.
@return true if prepare succeed
*/
bool prepare_rename(const char *db, const char *tabname, const char *new_db,
const char *new_tabname);
/**
@brief Prepare client for an ACL change notification
(e.g. CREATE USER, GRANT, REVOKE, etc.).
@param node_id Unique number identifying this mysql server
@return true if prepare succeed
*/
bool prepare_acl_change(uint node_id);
/**
@brief Check that the prepared identifiers is supported by the schema
distribution. For example long identifiers can't be communicated
between the MySQL Servers unless the table used for communication
have large enough columns.
@note This is done separately from @prepare since different error
code(or none at all) should be returned for this error.
@note Always done early to avoid changing metadata which is
hard to rollback at a later stage.
@param invalid_identifer The name of the identifier that failed the check
@return true if check succeed
*/
bool check_identifier_limits(std::string &invalid_identifier);
/**
* @brief Check if given name is the schema distribution table, special
handling for that table is required in a few places.
@param db database name
@param table_name table name
@return true if table is the schema distribution table
*/
static bool is_schema_dist_table(const char *db, const char *table_name);
/**
* @brief Check if given name is the schema distribution result table, special
handling for that table is required in a few places.
@param db database name
@param table_name table name
@return true if table is the schema distribution result table
*/
static bool is_schema_dist_result_table(const char *db,
const char *table_name);
/**
* @brief Convert SCHEMA_OP_TYPE to string
* @param type
* @return string describing the type
*/
static const char *type_name(SCHEMA_OP_TYPE type);
bool create_table(const char *db, const char *table_name, int id,
int version);
bool truncate_table(const char *db, const char *table_name, int id,
int version);
bool alter_table(const char *db, const char *table_name, int id, int version,
bool log_on_participant = true);
bool alter_table_inplace_prepare(const char *db, const char *table_name,
int id, int version);
bool alter_table_inplace_commit(const char *db, const char *table_name,
int id, int version);
bool rename_table_prepare(const char *db, const char *table_name, int id,
int version, const char *new_key_for_table);
bool rename_table(const char *db, const char *table_name, int id, int version,
const char *new_dbname, const char *new_tabname,
bool log_on_participant);
bool drop_table(const char *db, const char *table_name, int id, int version,
bool log_on_participant = true);
bool create_db(const char *query, uint query_length, const char *db,
unsigned int id, unsigned int version);
bool alter_db(const char *query, uint query_length, const char *db,
unsigned int id, unsigned int version);
bool drop_db(const char *db);
bool acl_notify(const char *db, const char *query, uint query_length,
bool participants_must_refresh);
bool acl_notify(std::string user_list);
bool tablespace_changed(const char *tablespace_name, int id, int version);
bool logfilegroup_changed(const char *logfilegroup_name, int id, int version);
bool create_tablespace(const char *tablespace_name, int id, int version);
bool alter_tablespace(const char *tablespace_name, int id, int version);
bool drop_tablespace(const char *tablespace_name, int id, int version);
bool create_logfile_group(const char *logfile_group_name, int id,
int version);
bool alter_logfile_group(const char *logfile_group_name, int id, int version);
bool drop_logfile_group(const char *logfile_group_name, int id, int version);
};
#endif