mirror of
				https://github.com/MariaDB/server.git
				synced 2025-11-04 04:46:15 +01:00 
			
		
		
		
	TDC_RT_REMOVE_ALL -> tdc_remove_table(). Some occurrences replaced with TDC_element::flush() (whenver TABLE_SHARE is available). TDC_RT_REMOVE_NOT_OWN[_KEEP_SHARE] -> TDC_element::flush(). These modes assume that current thread owns TABLE_SHARE reference, which means we can avoid hash lookup and flush unused TABLE instances directly. TDC_RT_REMOVE_UNUSED -> TDC_element::flush_unused(). Only [ab]used by mysql_admin_table() currently. Should be removed eventually. Part of MDEV-17882 - Cleanup refresh version
		
			
				
	
	
		
			331 lines
		
	
	
	
		
			9 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			331 lines
		
	
	
	
		
			9 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
/* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
 | 
						|
// vim: ft=cpp:expandtab:ts=8:sw=4:softtabstop=4:
 | 
						|
/* -*- mode: C; c-basic-offset: 4 -*- */
 | 
						|
#ident "$Id$"
 | 
						|
/*======
 | 
						|
This file is part of TokuDB
 | 
						|
 | 
						|
 | 
						|
Copyright (c) 2006, 2015, Percona and/or its affiliates. All rights reserved.
 | 
						|
 | 
						|
    TokuDBis is free software: you can redistribute it and/or modify
 | 
						|
    it under the terms of the GNU General Public License, version 2,
 | 
						|
    as published by the Free Software Foundation.
 | 
						|
 | 
						|
    TokuDB 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 for more details.
 | 
						|
 | 
						|
    You should have received a copy of the GNU General Public License
 | 
						|
    along with TokuDB.  If not, see <http://www.gnu.org/licenses/>.
 | 
						|
 | 
						|
======= */
 | 
						|
 | 
						|
#ident "Copyright (c) 2006, 2015, Percona and/or its affiliates. All rights reserved."
 | 
						|
 | 
						|
#include "hatoku_hton.h"
 | 
						|
#include "tokudb_dir_cmd.h"
 | 
						|
#include "my_dbug.h"
 | 
						|
#include "sql_base.h"
 | 
						|
 | 
						|
#include <vector>
 | 
						|
#include <string>
 | 
						|
 | 
						|
namespace tokudb {
 | 
						|
 | 
						|
const char tokens_delimiter = ' ';
 | 
						|
const char tokens_escape_delimiter_char = '\\';
 | 
						|
 | 
						|
static int MDL_and_TDC(THD *thd,
 | 
						|
                       const char *db,
 | 
						|
                       const char *table,
 | 
						|
                       const dir_cmd_callbacks &cb) {
 | 
						|
    int error;
 | 
						|
    LEX_CSTRING db_arg;
 | 
						|
    LEX_CSTRING table_arg;
 | 
						|
 | 
						|
    db_arg.str = const_cast<char *>(db);
 | 
						|
    db_arg.length = strlen(db);;
 | 
						|
    table_arg.str = const_cast<char *>(table);
 | 
						|
    table_arg.length = strlen(table);
 | 
						|
    Table_ident table_ident(thd, &db_arg, &table_arg, true);;
 | 
						|
    thd->lex->first_select_lex()->add_table_to_list(
 | 
						|
        thd, &table_ident, NULL, 1, TL_UNLOCK, MDL_EXCLUSIVE, 0, 0, 0);
 | 
						|
    /* The lock will be released at the end of mysq_execute_command() */
 | 
						|
    error = lock_table_names(thd,
 | 
						|
                             thd->lex->first_select_lex()->table_list.first,
 | 
						|
                             NULL,
 | 
						|
                             thd->variables.lock_wait_timeout,
 | 
						|
                             0);
 | 
						|
    if (error) {
 | 
						|
        if (cb.set_error)
 | 
						|
            cb.set_error(thd,
 | 
						|
                         error,
 | 
						|
                         "Can't lock table '%s.%s'",
 | 
						|
                         db,
 | 
						|
                         table);
 | 
						|
        return error;
 | 
						|
    }
 | 
						|
    tdc_remove_table(thd, db, table);
 | 
						|
    return error;
 | 
						|
}
 | 
						|
 | 
						|
static bool parse_db_and_table(const char *dname,
 | 
						|
                              std::string /*out*/ &db_name,
 | 
						|
                              std::string /*out*/ &table_name) {
 | 
						|
    const char *begin;
 | 
						|
    const char *end;
 | 
						|
    const char *db_name_begin;
 | 
						|
    const char *db_name_end;
 | 
						|
 | 
						|
    begin = strchr(dname, '/');
 | 
						|
    if (!begin)
 | 
						|
        return false;
 | 
						|
    ++begin;
 | 
						|
    end = strchr(begin, '/');
 | 
						|
    if (!end)
 | 
						|
        return false;
 | 
						|
 | 
						|
    db_name_begin = begin;
 | 
						|
    db_name_end = end;
 | 
						|
 | 
						|
    begin = end + 1;
 | 
						|
 | 
						|
    end = strchr(begin, '-');
 | 
						|
    if (!end)
 | 
						|
        return false;
 | 
						|
 | 
						|
    if (strncmp(end, "-main", strlen("-main")) &&
 | 
						|
        strncmp(end, "-status", strlen("-status")) &&
 | 
						|
        strncmp(end, "-key", strlen("-key")))
 | 
						|
        return false;
 | 
						|
 | 
						|
    db_name.assign(db_name_begin, db_name_end);
 | 
						|
    table_name.assign(begin, end);
 | 
						|
 | 
						|
    return true;
 | 
						|
}
 | 
						|
 | 
						|
static int attach(THD *thd,
 | 
						|
                   const std::string &dname,
 | 
						|
                   const std::string &iname,
 | 
						|
                   const dir_cmd_callbacks &cb) {
 | 
						|
    int error;
 | 
						|
    DB_TXN* txn = NULL;
 | 
						|
    DB_TXN *parent_txn = NULL;
 | 
						|
    tokudb_trx_data *trx = NULL;
 | 
						|
 | 
						|
    std::string db_name;
 | 
						|
    std::string table_name;
 | 
						|
 | 
						|
    if (parse_db_and_table(dname.c_str(), db_name, table_name)) {
 | 
						|
        error = MDL_and_TDC(thd, db_name.c_str(), table_name.c_str(), cb);
 | 
						|
        if (error)
 | 
						|
            goto cleanup;
 | 
						|
    }
 | 
						|
 | 
						|
    trx = (tokudb_trx_data *) thd_get_ha_data(thd, tokudb_hton);
 | 
						|
    if (trx && trx->sub_sp_level)
 | 
						|
        parent_txn = trx->sub_sp_level;
 | 
						|
    error = txn_begin(db_env, parent_txn, &txn, 0, thd);
 | 
						|
    if (error)
 | 
						|
        goto cleanup;
 | 
						|
 | 
						|
    error = db_env->dirtool_attach(db_env,
 | 
						|
                                   txn,
 | 
						|
                                   dname.c_str(),
 | 
						|
                                   iname.c_str());
 | 
						|
cleanup:
 | 
						|
    if (txn) {
 | 
						|
        if (error) {
 | 
						|
            abort_txn(txn);
 | 
						|
        }
 | 
						|
        else {
 | 
						|
            commit_txn(txn, 0);
 | 
						|
        }
 | 
						|
    }
 | 
						|
    return error;
 | 
						|
}
 | 
						|
 | 
						|
static int detach(THD *thd,
 | 
						|
                  const std::string &dname,
 | 
						|
                  const dir_cmd_callbacks &cb) {
 | 
						|
    int error;
 | 
						|
    DB_TXN* txn = NULL;
 | 
						|
    DB_TXN *parent_txn = NULL;
 | 
						|
    tokudb_trx_data *trx = NULL;
 | 
						|
 | 
						|
    std::string db_name;
 | 
						|
    std::string table_name;
 | 
						|
 | 
						|
    if (parse_db_and_table(dname.c_str(), db_name, table_name)) {
 | 
						|
        error = MDL_and_TDC(thd, db_name.c_str(), table_name.c_str(), cb);
 | 
						|
        if (error)
 | 
						|
            goto cleanup;
 | 
						|
    }
 | 
						|
 | 
						|
    trx = (tokudb_trx_data *) thd_get_ha_data(thd, tokudb_hton);
 | 
						|
    if (trx && trx->sub_sp_level)
 | 
						|
        parent_txn = trx->sub_sp_level;
 | 
						|
    error = txn_begin(db_env, parent_txn, &txn, 0, thd);
 | 
						|
    if (error)
 | 
						|
        goto cleanup;
 | 
						|
 | 
						|
    error = db_env->dirtool_detach(db_env,
 | 
						|
                                   txn,
 | 
						|
                                   dname.c_str());
 | 
						|
cleanup:
 | 
						|
    if (txn) {
 | 
						|
        if (error) {
 | 
						|
            abort_txn(txn);
 | 
						|
        }
 | 
						|
        else {
 | 
						|
            commit_txn(txn, 0);
 | 
						|
        }
 | 
						|
    }
 | 
						|
    return error;
 | 
						|
}
 | 
						|
 | 
						|
static int move(THD *thd,
 | 
						|
                const std::string &old_dname,
 | 
						|
                const std::string &new_dname,
 | 
						|
                const dir_cmd_callbacks &cb) {
 | 
						|
    int error;
 | 
						|
    DB_TXN* txn = NULL;
 | 
						|
    DB_TXN *parent_txn = NULL;
 | 
						|
    tokudb_trx_data *trx = NULL;
 | 
						|
 | 
						|
    std::string db_name;
 | 
						|
    std::string table_name;
 | 
						|
 | 
						|
    if (parse_db_and_table(old_dname.c_str(), db_name, table_name)) {
 | 
						|
        error = MDL_and_TDC(thd, db_name.c_str(), table_name.c_str(), cb);
 | 
						|
        if (error)
 | 
						|
            goto cleanup;
 | 
						|
    }
 | 
						|
 | 
						|
    trx = (tokudb_trx_data *) thd_get_ha_data(thd, tokudb_hton);
 | 
						|
    if (trx && trx->sub_sp_level)
 | 
						|
        parent_txn = trx->sub_sp_level;
 | 
						|
    error = txn_begin(db_env, parent_txn, &txn, 0, thd);
 | 
						|
    if (error)
 | 
						|
        goto cleanup;
 | 
						|
 | 
						|
    error = db_env->dirtool_move(db_env,
 | 
						|
                                 txn,
 | 
						|
                                 old_dname.c_str(),
 | 
						|
                                 new_dname.c_str());
 | 
						|
cleanup:
 | 
						|
    if (txn) {
 | 
						|
        if (error) {
 | 
						|
            abort_txn(txn);
 | 
						|
        }
 | 
						|
        else {
 | 
						|
            commit_txn(txn, 0);
 | 
						|
        }
 | 
						|
    }
 | 
						|
    return error;
 | 
						|
}
 | 
						|
 | 
						|
static void tokenize(const char *cmd_str,
 | 
						|
                     std::vector<std::string> /*out*/ &tokens) {
 | 
						|
    DBUG_ASSERT(cmd_str);
 | 
						|
 | 
						|
    bool was_escape = false;
 | 
						|
    const char *token_begin = cmd_str;
 | 
						|
    const char *token_end = token_begin;
 | 
						|
 | 
						|
    while (*token_end) {
 | 
						|
      if (*token_end == tokens_escape_delimiter_char) {
 | 
						|
        was_escape = true;
 | 
						|
      }
 | 
						|
      else if (*token_end == tokens_delimiter) {
 | 
						|
        if (was_escape)
 | 
						|
          was_escape = false;
 | 
						|
        else {
 | 
						|
          if (token_begin == token_end)
 | 
						|
            ++token_begin;
 | 
						|
          else {
 | 
						|
            tokens.push_back(std::string(token_begin, token_end));
 | 
						|
            token_begin = token_end + 1;
 | 
						|
          }
 | 
						|
        }
 | 
						|
      }
 | 
						|
      else {
 | 
						|
        was_escape = false;
 | 
						|
      }
 | 
						|
      ++token_end;
 | 
						|
    }
 | 
						|
 | 
						|
    if (token_begin != token_end)
 | 
						|
      tokens.push_back(std::string(token_begin, token_end));
 | 
						|
}
 | 
						|
 | 
						|
void process_dir_cmd(THD *thd,
 | 
						|
                     const char *cmd_str,
 | 
						|
                     const dir_cmd_callbacks &cb) {
 | 
						|
 | 
						|
    DBUG_ASSERT(thd);
 | 
						|
    DBUG_ASSERT(cmd_str);
 | 
						|
 | 
						|
    std::vector<std::string> tokens;
 | 
						|
    tokenize(cmd_str, tokens);
 | 
						|
 | 
						|
    if (tokens.empty())
 | 
						|
        return;
 | 
						|
 | 
						|
    const std::string &cmd = tokens[0];
 | 
						|
 | 
						|
    if (!cmd.compare("attach")) {
 | 
						|
        if (tokens.size() != 3) {
 | 
						|
            if (cb.set_error)
 | 
						|
                cb.set_error(thd,
 | 
						|
                             EINVAL,
 | 
						|
                             "attach command requires two arguments");
 | 
						|
        }
 | 
						|
        else {
 | 
						|
            int r = attach(thd, tokens[1], tokens[2], cb);
 | 
						|
            if (r && cb.set_error)
 | 
						|
                cb.set_error(thd, r, "Attach command error");
 | 
						|
        }
 | 
						|
    }
 | 
						|
    else if (!cmd.compare("detach")) {
 | 
						|
        if (tokens.size() != 2) {
 | 
						|
            if (cb.set_error)
 | 
						|
                cb.set_error(thd,
 | 
						|
                             EINVAL,
 | 
						|
                             "detach command requires one argument");
 | 
						|
        }
 | 
						|
        else {
 | 
						|
            int r = detach(thd, tokens[1], cb);
 | 
						|
            if (r && cb.set_error)
 | 
						|
                cb.set_error(thd, r, "detach command error");
 | 
						|
        }
 | 
						|
    }
 | 
						|
    else if (!cmd.compare("move")) {
 | 
						|
        if (tokens.size() != 3) {
 | 
						|
            if (cb.set_error)
 | 
						|
                cb.set_error(thd,
 | 
						|
                             EINVAL,
 | 
						|
                             "move command requires two arguments");
 | 
						|
        }
 | 
						|
        else {
 | 
						|
            int r = move(thd, tokens[1], tokens[2], cb);
 | 
						|
            if (r && cb.set_error)
 | 
						|
                cb.set_error(thd, r, "move command error");
 | 
						|
        }
 | 
						|
    }
 | 
						|
    else {
 | 
						|
        if (cb.set_error)
 | 
						|
            cb.set_error(thd,
 | 
						|
                         ENOENT,
 | 
						|
                         "Unknown command '%s'",
 | 
						|
                         cmd.c_str());
 | 
						|
    }
 | 
						|
 | 
						|
    return;
 | 
						|
};
 | 
						|
 | 
						|
 | 
						|
} // namespace tokudb
 |