polardbxengine/sql/log_table.cc

288 lines
8.4 KiB
C++

/* Copyright (c) 2000, 2019, Alibaba 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 */
#include "sql/dd/cache/dictionary_client.h"
#include "sql/dd/dd_schema.h"
#include "sql/dd/dd_table.h"
#include "sql/dd/types/abstract_table.h" // dd::enum_table_type
#include "sql/dd/types/table.h" // dd::Table
#include "sql/dd_table_share.h" // open_table_def
#include "sql/handler.h"
#include "sql/sql_base.h"
#include "sql/sql_class.h"
#include "sql/sql_table.h"
#include "sql/table.h"
#include "sql/log_table.h"
namespace im {
/**
Last rotated file name.
It will display './DATABASE/FILE.EXT' format name
when show global variables, and it is not protected
by any lock, we think it is safe even though there
will may be concurrent update.
*/
char rotate_log_table_last_name[FN_REFLEN] = {0};
char *rotate_log_table_last_name_ptr = rotate_log_table_last_name;
void update_rotate_log_table_last_name_ptr() {
rotate_log_table_last_name_ptr = rotate_log_table_last_name;
}
/**
Validate and backup current context.
@retval true Failure
@retval false Success
*/
bool Log_table::validate_and_backup_context() {
/**
Report error if THD is in:
- Locked tables
- Active transaction
- Stored function or trigger
*/
/**
Never reached active transaction, because FLUSH command
will trigger implicit commit earlier than here.
*/
if (m_thd->locked_tables_mode || m_thd->in_active_multi_stmt_transaction()) {
my_error(ER_LOCK_OR_ACTIVE_TRANSACTION, MYF(0));
return true;
}
/* Never reached here, it will report error early if FLUSH command */
if (m_thd->in_sub_stmt) {
my_error(ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG, MYF(0), "FLUSH");
return true;
}
/**
Now only support Log tables:
- Slow_log
- General_log
*/
if (m_log_table_type == QUERY_LOG_NONE) {
my_error(ER_ROTATE_REQUIRE_LOG_TABLE, MYF(0));
return true;
}
DBUG_ASSERT(!(m_thd->server_status & SERVER_STATUS_IN_TRANS));
/* Backup and override current context. */
m_ctx_state.m_thd_option_bits = m_thd->variables.option_bits;
m_thd->reset_n_backup_open_tables_state(&m_ctx_state.m_open_tables_state,
Open_tables_state::SYSTEM_TABLES);
m_thd->variables.option_bits &= ~OPTION_BIN_LOG;
m_backup = true;
return false;
}
/* Destructor */
Log_table::~Log_table() {
/* Restore current context. */
if (m_backup) {
m_thd->variables.option_bits = m_ctx_state.m_thd_option_bits;
m_thd->restore_backup_open_tables_state(&m_ctx_state.m_open_tables_state);
}
}
/**
Lock the target log table, report error if failed.
@retval true Failure
@retval false Success
*/
bool Log_table::lock_log_table() {
const char *table_name = nullptr;
const char *schema_name = nullptr;
uint table_length = 0;
uint schema_length = 0;
DBUG_ENTER("Log_table::lock_log_table");
DBUG_ASSERT(m_log_table_type != QUERY_LOG_NONE);
m_table_list = new (m_thd->mem_root) TABLE_LIST();
schema_name = MYSQL_SCHEMA_NAME.str;
schema_length = MYSQL_SCHEMA_NAME.length;
if (m_log_table_type == QUERY_LOG_SLOW) {
table_name = SLOW_LOG_NAME.str;
table_length = SLOW_LOG_NAME.length;
} else if (m_log_table_type == QUERY_LOG_GENERAL) {
table_name = GENERAL_LOG_NAME.str;
table_length = GENERAL_LOG_NAME.length;
} else {
DBUG_ASSERT(0);
}
m_table_list = new (m_thd->mem_root) TABLE_LIST(
schema_name, schema_length, table_name, table_length, table_name,
TL_WRITE, MDL_EXCLUSIVE);
m_table_list->open_strategy = TABLE_LIST::OPEN_IF_EXISTS;
m_table_list->open_type = OT_BASE_ONLY;
DBUG_ASSERT(m_table_list->next_global == NULL);
/**
Lock the table include:
- Global read lock
- Schema lock
- Table lock
*/
if (lock_table_names(m_thd, m_table_list, NULL,
m_thd->variables.lock_wait_timeout, 0))
DBUG_RETURN(true);
dd::cache::Dictionary_client::Auto_releaser releaser(m_thd->dd_client());
const dd::Table *table_def = nullptr;
if (m_thd->dd_client()->acquire(schema_name, table_name, &table_def)) {
// Report error in DD subsystem.
DBUG_RETURN(true);
}
// Report no such table error.
if (table_def == nullptr ||
table_def->hidden() == dd::Abstract_table::HT_HIDDEN_SE) {
my_error(ER_NO_SUCH_TABLE, MYF(0), schema_name, table_name);
DBUG_RETURN(true);
}
/* Table is already locked exclusively. */
tdc_remove_table(m_thd, TDC_RT_REMOVE_ALL, m_table_list->db,
m_table_list->table_name, false);
DBUG_RETURN(false);
}
/**
Rotate the target log table data file.
@retval true Failure
@retval false Success
*/
bool Log_table::rotate_table() {
int error = 1;
DBUG_ENTER("Log_table::rotate_table");
/* Lock the table exclusively */
if (lock_log_table()) DBUG_RETURN(true);
dd::cache::Dictionary_client::Auto_releaser releaser(m_thd->dd_client());
const dd::Table *table_def = NULL;
if (m_thd->dd_client()->acquire(m_table_list->db, m_table_list->table_name,
&table_def)) {
// Error is reported by the dictionary subsystem.
DBUG_RETURN(true);
}
DBUG_ASSERT(table_def);
TABLE table_arg;
TABLE_SHARE share;
HA_CREATE_INFO create_info;
char path[FN_REFLEN + 1];
char name_buff[FN_REFLEN + 1];
const char *name;
build_table_filename(path, sizeof(path) - 1, m_table_list->db,
m_table_list->table_name, "", 0);
init_tmp_table_share(m_thd, &share, m_table_list->db, 0,
m_table_list->table_name, path, nullptr);
if (open_table_def(m_thd, &share, *table_def)) goto err;
destroy(&table_arg);
if (open_table_from_share(m_thd, &share, "", 0, (uint)READ_ALL, 0, &table_arg,
false, nullptr))
goto err;
name = get_canonical_filename(table_arg.file, share.path.str, name_buff);
error = table_arg.file->ha_rotate_table(name, table_def);
if (error) {
table_arg.file->print_error(error, MYF(0));
}
(void)closefrm(&table_arg, 0);
err:
free_table_share(&share);
DBUG_RETURN(error != 0);
}
/**
Rotate log table.
@param[in] thd current thread
@param[in] log_table_type Slow_log or general_log
@retval true Failure
@retval false Success
*/
bool rotate_log_table(THD *thd, enum_log_table_type log_table_type) {
DBUG_ENTER("rotate_log_table");
Log_table log_table(thd, log_table_type);
if (log_table.validate_and_backup_context()) DBUG_RETURN(true);
DBUG_RETURN(log_table.rotate_table());
}
} /* namespace im */
/**
Handler interface implementation
Putting here is in order to decrease possibility of conflict.
*/
int handler::ha_rotate_table(const char *name, const dd::Table *table_def) {
DBUG_ASSERT(table_share->tmp_table != NO_TMP_TABLE || m_lock_type == F_WRLCK);
mark_trx_read_write();
return (rotate_table(name, table_def));
}
/**
Rotate the log table.
@param[in] thd current thread
@param[in] log_type log table type
@retval true failure
@retval false success
*/
bool Query_logger::rotate_log_table(THD *thd, enum_log_table_type log_type) {
bool res = false;
/* Now only support slow log rotate */
DBUG_ASSERT(log_type == QUERY_LOG_SLOW);
if (thd->variables.rotate_log_table && is_log_table_enabled(log_type)) {
res = im::rotate_log_table(thd, log_type);
}
return res;
}