280 lines
8.7 KiB
C++
280 lines
8.7 KiB
C++
/*
|
|
Copyright (c) 2015, 2018, 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 as published by
|
|
the Free Software Foundation; version 2 of the License.
|
|
|
|
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 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 "program.h"
|
|
#include "i_connection_provider.h"
|
|
#include "thread_specific_connection_provider.h"
|
|
#include "single_transaction_connection_provider.h"
|
|
#include "simple_id_generator.h"
|
|
#include "i_progress_watcher.h"
|
|
#include "standard_progress_watcher.h"
|
|
#include "i_crawler.h"
|
|
#include "mysql_crawler.h"
|
|
#include "i_chain_maker.h"
|
|
#include "mysqldump_tool_chain_maker.h"
|
|
#include <boost/chrono.hpp>
|
|
|
|
using namespace Mysql::Tools::Dump;
|
|
|
|
void Program::close_redirected_stderr()
|
|
{
|
|
if (m_stderr != NULL)
|
|
fclose(m_stderr);
|
|
}
|
|
|
|
void Program::error_log_file_callback(char*)
|
|
{
|
|
if (!m_error_log_file.has_value())
|
|
return;
|
|
this->close_redirected_stderr();
|
|
m_stderr= freopen(m_error_log_file.value().c_str(), "a", stderr);
|
|
if (m_stderr == NULL)
|
|
{
|
|
this->error(Mysql::Tools::Base::Message_data(errno,
|
|
"Cannot append error log to specified file: \""
|
|
+ m_error_log_file.value() + "\"",
|
|
Mysql::Tools::Base::Message_type_error));
|
|
}
|
|
}
|
|
|
|
bool Program::message_handler(const Mysql::Tools::Base::Message_data& message)
|
|
{
|
|
this->error(message);
|
|
return false;
|
|
}
|
|
|
|
void Program::error(const Mysql::Tools::Base::Message_data& message)
|
|
{
|
|
std::cerr << this->get_name() << ": [" << message.get_message_type_string()
|
|
<< "] (" << message.get_code() << ") " << message.get_message()
|
|
<< std::endl;
|
|
|
|
if (message.get_message_type() == Mysql::Tools::Base::Message_type_error)
|
|
{
|
|
std::cerr << "Dump process encountered error and will not continue."
|
|
<< std::endl;
|
|
m_error_code.store((int)message.get_code());
|
|
}
|
|
}
|
|
|
|
void Program::create_options()
|
|
{
|
|
this->create_new_option(&m_error_log_file, "log-error-file",
|
|
"Append warnings and errors to specified file.")
|
|
->add_callback(new Mysql::Instance_callback<void, char*, Program>(
|
|
this, &Program::error_log_file_callback));
|
|
this->create_new_option(&m_watch_progress, "watch-progress",
|
|
"Shows periodically dump process progress information on error output. "
|
|
"Progress information include both completed and total number of "
|
|
"tables, rows and other objects collected.")
|
|
->set_value(true);
|
|
this->create_new_option(&m_single_transaction, "single-transaction",
|
|
"Creates a consistent snapshot by dumping all tables in a single "
|
|
"transaction. Works ONLY for tables stored in storage engines which "
|
|
"support multiversioning (currently only InnoDB does); the dump is NOT "
|
|
"guaranteed to be consistent for other storage engines. "
|
|
"While a --single-transaction dump is in process, to ensure a valid "
|
|
"dump file (correct table contents and binary log position), no other "
|
|
"connection should use the following statements: ALTER TABLE, DROP "
|
|
"TABLE, RENAME TABLE, TRUNCATE TABLE, as consistent snapshot is not "
|
|
"isolated from them. This option is mutually exclusive with "
|
|
"--add-locks option.");
|
|
}
|
|
|
|
void Program::check_mutually_exclusive_options()
|
|
{
|
|
/*
|
|
In case of --add-locks we dont allow parallelism
|
|
*/
|
|
if (m_mysqldump_tool_chain_maker_options->m_default_parallelism ||
|
|
m_mysqldump_tool_chain_maker_options->get_parallel_schemas_thread_count())
|
|
{
|
|
if (m_mysqldump_tool_chain_maker_options->m_formatter_options->m_add_locks)
|
|
m_mysql_chain_element_options->get_program()->error(
|
|
Mysql::Tools::Base::Message_data(1, "Usage of --add-locks "
|
|
"is mutually exclusive with parallelism.",
|
|
Mysql::Tools::Base::Message_type_error));
|
|
}
|
|
}
|
|
|
|
int Program::get_total_connections()
|
|
{
|
|
/*
|
|
total thread count for mysqlpump would be as below:
|
|
1 main thread +
|
|
default queues thread (specified by default parallelism) +
|
|
total parallel-schemas without threads specified * dp +
|
|
total threads mentioned in parallel-schemas
|
|
*/
|
|
|
|
int dp= m_mysqldump_tool_chain_maker_options->m_default_parallelism;
|
|
return (1 + dp +
|
|
m_mysqldump_tool_chain_maker_options->get_parallel_schemas_thread_count() +
|
|
(m_mysqldump_tool_chain_maker_options->
|
|
get_parallel_schemas_with_default_thread_count() * dp));
|
|
}
|
|
|
|
int Program::get_error_code()
|
|
{
|
|
return m_error_code.load();
|
|
}
|
|
|
|
int Program::execute(std::vector<std::string> positional_options)
|
|
{
|
|
I_connection_provider* connection_provider= NULL;
|
|
int num_connections= get_total_connections();
|
|
|
|
Mysql::I_callable<bool, const Mysql::Tools::Base::Message_data&>*
|
|
message_handler= new Mysql::Instance_callback
|
|
<bool, const Mysql::Tools::Base::Message_data&, Program>(
|
|
this, &Program::message_handler);
|
|
|
|
try
|
|
{
|
|
connection_provider=
|
|
m_single_transaction ?
|
|
new Single_transaction_connection_provider(this, num_connections, message_handler)
|
|
: new Thread_specific_connection_provider(this);
|
|
}
|
|
catch (const std::exception &e)
|
|
{
|
|
this->error(Mysql::Tools::Base::Message_data(
|
|
0, "Error during creating connection.",
|
|
Mysql::Tools::Base::Message_type_error));
|
|
}
|
|
|
|
Mysql::Tools::Base::Mysql_query_runner* runner= connection_provider
|
|
->get_runner(message_handler);
|
|
if (mysql_get_server_version(runner->get_low_level_connection()) < 50708)
|
|
{
|
|
std::cerr << "Server version is not compatible. Server version should "
|
|
"be 5.7.8 or above.";
|
|
delete runner;
|
|
delete message_handler;
|
|
delete connection_provider;
|
|
return 0;
|
|
}
|
|
|
|
Simple_id_generator* id_generator= new Simple_id_generator();
|
|
|
|
boost::chrono::high_resolution_clock::time_point start_time=
|
|
boost::chrono::high_resolution_clock::now();
|
|
|
|
I_progress_watcher* progress_watcher= NULL;
|
|
|
|
if (m_watch_progress)
|
|
{
|
|
progress_watcher= new Standard_progress_watcher(
|
|
message_handler, id_generator);
|
|
}
|
|
I_crawler* crawler= new Mysql_crawler(
|
|
connection_provider, message_handler, id_generator,
|
|
m_mysql_chain_element_options, this);
|
|
m_mysqldump_tool_chain_maker_options->process_positional_options(
|
|
positional_options);
|
|
check_mutually_exclusive_options();
|
|
I_chain_maker* chain_maker= new Mysqldump_tool_chain_maker(
|
|
connection_provider, message_handler, id_generator,
|
|
m_mysqldump_tool_chain_maker_options, this);
|
|
|
|
crawler->register_chain_maker(chain_maker);
|
|
if (progress_watcher != NULL)
|
|
{
|
|
crawler->register_progress_watcher(progress_watcher);
|
|
chain_maker->register_progress_watcher(progress_watcher);
|
|
}
|
|
|
|
crawler->enumerate_objects();
|
|
|
|
delete runner;
|
|
delete crawler;
|
|
if (progress_watcher != NULL)
|
|
delete progress_watcher;
|
|
delete id_generator;
|
|
delete connection_provider;
|
|
delete message_handler;
|
|
delete chain_maker;
|
|
|
|
if (!get_error_code())
|
|
{
|
|
std::cerr << "Dump completed in " <<
|
|
boost::chrono::duration_cast<boost::chrono::milliseconds>(
|
|
boost::chrono::high_resolution_clock::now() - start_time) << std::endl;
|
|
}
|
|
return get_error_code();
|
|
}
|
|
|
|
std::string Program::get_description()
|
|
{
|
|
return "MySQL utility for dumping data from databases to external file.";
|
|
}
|
|
|
|
int Program::get_first_release_year()
|
|
{
|
|
return 2014;
|
|
}
|
|
|
|
std::string Program::get_version()
|
|
{
|
|
return "1.0.0";
|
|
}
|
|
|
|
Program::~Program()
|
|
{
|
|
delete m_mysql_chain_element_options;
|
|
delete m_mysqldump_tool_chain_maker_options;
|
|
this->close_redirected_stderr();
|
|
}
|
|
|
|
void Program::short_usage()
|
|
{
|
|
std::cout << "Usage: " << get_name() <<" [OPTIONS] [--all-databases]"
|
|
<< std::endl;
|
|
std::cout << "OR " << get_name() <<" [OPTIONS] --databases DB1 [DB2 DB3...]"
|
|
<< std::endl;
|
|
std::cout << "OR " << get_name() <<" [OPTIONS] database [tables]"
|
|
<< std::endl;
|
|
}
|
|
|
|
Program::Program()
|
|
: Abstract_connection_program(),
|
|
m_stderr(NULL),
|
|
m_error_code(0)
|
|
{
|
|
m_mysql_chain_element_options= new Mysql_chain_element_options(this);
|
|
m_mysqldump_tool_chain_maker_options=
|
|
new Mysqldump_tool_chain_maker_options(m_mysql_chain_element_options);
|
|
|
|
this->add_provider(m_mysql_chain_element_options);
|
|
this->add_provider(m_mysqldump_tool_chain_maker_options);
|
|
}
|
|
|
|
const char *load_default_groups[]=
|
|
{
|
|
"client", /* Read settings how to connect to server. */
|
|
"mysql_dump", /* Read special settings for mysql_dump. */
|
|
0
|
|
};
|
|
|
|
static Program program;
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
::program.run(argc, argv);
|
|
return 0;
|
|
}
|