summaryrefslogtreecommitdiffstats
path: root/storage/maria/aria_s3_copy.cc
diff options
context:
space:
mode:
Diffstat (limited to 'storage/maria/aria_s3_copy.cc')
-rw-r--r--storage/maria/aria_s3_copy.cc348
1 files changed, 348 insertions, 0 deletions
diff --git a/storage/maria/aria_s3_copy.cc b/storage/maria/aria_s3_copy.cc
new file mode 100644
index 00000000..77c41ba4
--- /dev/null
+++ b/storage/maria/aria_s3_copy.cc
@@ -0,0 +1,348 @@
+/* Copyright (C) 2019 MariaDB corporation
+
+ 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 Street, Fifth Floor, Boston, MA 02111-1301 USA */
+
+/*
+ Allow copying of Aria tables to and from S3 and also delete them from S3
+*/
+
+#include <my_global.h>
+#include <m_string.h>
+#include "maria_def.h"
+#include <aria_backup.h>
+#include <my_getopt.h>
+#include <my_check_opt.h>
+#include <mysys_err.h>
+#include <mysqld_error.h>
+#include <zlib.h>
+#include <libmarias3/marias3.h>
+#include "s3_func.h"
+
+static const char *op_types[]= {"to_s3", "from_s3", "delete_from_s3", NullS};
+static TYPELIB op_typelib= {array_elements(op_types)-1,"", op_types, NULL};
+#define OP_IMPOSSIBLE array_elements(op_types)
+
+static const char *load_default_groups[]= { "aria_s3_copy", 0 };
+static const char *opt_s3_access_key, *opt_s3_secret_key;
+static const char *opt_s3_region="eu-north-1";
+static const char *opt_s3_host_name= DEFAULT_AWS_HOST_NAME;
+static const char *opt_database;
+static const char *opt_s3_bucket="MariaDB";
+static my_bool opt_compression, opt_verbose, opt_force, opt_s3_debug;
+static my_bool opt_s3_use_http;
+static ulong opt_operation= OP_IMPOSSIBLE, opt_protocol_version= 1;
+static ulong opt_block_size;
+static ulong opt_s3_port;
+static char **default_argv=0;
+static ms3_st *global_s3_client= 0;
+
+
+static struct my_option my_long_options[] =
+{
+ {"help", '?', "Display this help and exit.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0,
+ 0, 0, 0, 0, 0},
+ {"s3_access_key", 'k', "AWS access key ID",
+ (char**) &opt_s3_access_key, (char**) &opt_s3_access_key, 0,
+ GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+ {"s3_region", 'r', "AWS region",
+ (char**) &opt_s3_region, (char**) &opt_s3_region, 0,
+ GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+ {"s3_secret_key", 'K', "AWS secret access key ID",
+ (char**) &opt_s3_secret_key, (char**) &opt_s3_secret_key, 0,
+ GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+ {"s3_bucket", 'b', "AWS prefix for tables",
+ (char**) &opt_s3_bucket, (char**) &opt_s3_bucket, 0,
+ GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+ {"s3_host_name", 'h', "Host name to S3 provider",
+ (char**) &opt_s3_host_name, (char**) &opt_s3_host_name, 0,
+ GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+ {"s3_port", 'p', "Port number to connect to (0 means use default)",
+ (char**) &opt_s3_port, (char**) &opt_s3_port, 0, GET_ULONG, REQUIRED_ARG,
+ 0, 0, 65536, 0, 1, 0 },
+ {"s3_use_http", 'P', "If true, force use of HTTP protocol",
+ (char**) &opt_s3_use_http, (char**) &opt_s3_use_http,
+ 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
+ {"compress", 'c', "Use compression", &opt_compression, &opt_compression,
+ 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
+ {"op", 'o', "Operation to execute. One of 'from_s3', 'to_s3' or "
+ "'delete_from_s3'",
+ &opt_operation, &opt_operation, &op_typelib,
+ GET_ENUM, REQUIRED_ARG, OP_IMPOSSIBLE, 0, 0, 0, 0, 0},
+ {"database", 'd',
+ "Database for copied table (second prefix). "
+ "If not given, the directory of the table file is used",
+ &opt_database, &opt_database, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+ {"s3_block_size", 'B', "Block size for data/index blocks in s3",
+ &opt_block_size, &opt_block_size, 0, GET_ULONG, REQUIRED_ARG,
+ 4*1024*1024, 64*1024, 16*1024*1024, MALLOC_OVERHEAD, 1024, 0 },
+ {"s3_protocol_version", 'L',
+ "Protocol used to communication with S3. One of \"Auto\", \"Amazon\" or \"Original\".",
+ &opt_protocol_version, &opt_protocol_version, &s3_protocol_typelib,
+ GET_ENUM, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+ {"force", 'f', "Force copy even if target exists",
+ &opt_force, &opt_force, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
+ {"verbose", 'v', "Write more information", &opt_verbose, &opt_verbose,
+ 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
+ {"version", 'V', "Print version and exit.",
+ 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
+#ifndef DBUG_OFF
+ {"debug", '#', "Output debug log. Often this is 'd:t:o,filename'.",
+ 0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
+#endif
+ {"s3_debug",0, "Output debug log from marias3 to stdout",
+ &opt_s3_debug, &opt_s3_debug, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
+ { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
+};
+
+
+static bool get_database_from_path(char *to, size_t to_length, const char *path);
+
+
+static void print_version(void)
+{
+ printf("%s Ver 1.0 for %s on %s\n", my_progname, SYSTEM_TYPE,
+ MACHINE_TYPE);
+}
+
+static void usage(void)
+{
+ print_version();
+ puts("\nThis software comes with NO WARRANTY: "
+ " see the PUBLIC for details.\n");
+ puts("Copy an Aria table to and from s3");
+ printf("Usage: %s --aws-access-key=# --aws-secret-access-key=# --aws-region=# "
+ "--op=(from_s3 | to_s3 | delete_from_s3) [OPTIONS] tables[.MAI]\n",
+ my_progname_short);
+ print_defaults("my", load_default_groups);
+ puts("");
+ my_print_help(my_long_options);
+ my_print_variables(my_long_options);
+}
+
+
+ATTRIBUTE_NORETURN static void my_exit(int exit_code)
+{
+ if (global_s3_client)
+ {
+ ms3_deinit(global_s3_client);
+ global_s3_client= 0;
+ }
+ free_defaults(default_argv);
+ s3_deinit_library();
+ my_end(MY_CHECK_ERROR);
+ exit(exit_code);
+}
+
+extern "C" my_bool get_one_option(const struct my_option *opt
+ __attribute__((unused)),
+ const char *argument, const char *filename)
+{
+ switch (opt->id) {
+ case 'V':
+ print_version();
+ my_exit(0);
+ case '?':
+ usage();
+ my_exit(0);
+ case '#':
+ DBUG_SET_INITIAL(argument ? argument : "d:t:o,/tmp/aria_s3_copy.trace");
+ break;
+ }
+ return 0;
+}
+
+
+static void get_options(int *argc, char ***argv)
+{
+ int ho_error;
+
+ load_defaults_or_exit("my", load_default_groups, argc, argv);
+ default_argv= *argv;
+
+ if ((ho_error=handle_options(argc, argv, my_long_options, get_one_option)))
+ my_exit(ho_error);
+
+ if (*argc == 0)
+ {
+ usage();
+ my_exit(-1);
+ }
+
+ if (!opt_s3_access_key)
+ {
+ fprintf(stderr, "--aws-access-key was not given\n");
+ my_exit(-1);
+ }
+ if (!opt_s3_secret_key)
+ {
+ fprintf(stderr, "--aws-secret-access-key was not given\n");
+ my_exit(-1);
+ }
+ if (opt_operation == OP_IMPOSSIBLE)
+ {
+ fprintf(stderr, "You must specify an operation with --op=[from_s3|to_s3|delete_from_s3]\n");
+ my_exit(-1);
+ }
+ if (opt_s3_debug)
+ ms3_debug();
+
+} /* get_options */
+
+
+int main(int argc, char** argv)
+{
+ MY_INIT(argv[0]);
+ get_options(&argc,(char***) &argv);
+ size_t block_size= opt_block_size;
+
+ s3_init_library();
+ if (!(global_s3_client= ms3_init(opt_s3_access_key,
+ opt_s3_secret_key,
+ opt_s3_region, opt_s3_host_name)))
+ {
+ fprintf(stderr, "Can't open connection to S3, error: %d %s", errno,
+ ms3_error(errno));
+ my_exit(1);
+ }
+
+ ms3_set_option(global_s3_client, MS3_OPT_BUFFER_CHUNK_SIZE, &block_size);
+
+ if (opt_protocol_version)
+ {
+ uint8_t protocol_version= (uint8_t) opt_protocol_version;
+ ms3_set_option(global_s3_client, MS3_OPT_FORCE_PROTOCOL_VERSION,
+ &protocol_version);
+ }
+ if (opt_s3_port)
+ {
+ int port= (int) opt_s3_port;
+ ms3_set_option(global_s3_client, MS3_OPT_PORT_NUMBER, &port);
+ }
+ if (opt_s3_use_http)
+ ms3_set_option(global_s3_client, MS3_OPT_USE_HTTP, NULL);
+
+
+ for (; *argv ; argv++)
+ {
+ char database[FN_REFLEN], table_name[FN_REFLEN], *path;
+ const char *db;
+
+ path= *argv;
+
+ fn_format(table_name, path, "", "", MY_REPLACE_DIR | MY_REPLACE_EXT);
+
+ /* Get database from option, path or current directory */
+ if (!(db= opt_database))
+ {
+ if (get_database_from_path(database, sizeof(database), path))
+ {
+ fprintf(stderr, "Aborting copying of %s\n", path);
+ my_exit(-1);
+ }
+ db= database;
+ }
+
+ switch (opt_operation) {
+ case 0:
+ /* Don't copy .frm file for partioned table */
+ if (aria_copy_to_s3(global_s3_client, opt_s3_bucket, path,
+ db, table_name, opt_block_size, opt_compression,
+ opt_force, opt_verbose, !strstr(table_name, "#P#")))
+ {
+ fprintf(stderr, "Aborting copying of %s\n", path);
+ my_exit(-1);
+ }
+ break;
+ case 1:
+ if (aria_copy_from_s3(global_s3_client, opt_s3_bucket, path,
+ db, opt_compression, opt_force, opt_verbose))
+ {
+ fprintf(stderr, "Aborting copying of %s\n", path);
+ my_exit(-1);
+ }
+ break;
+ case 2:
+ if (aria_delete_from_s3(global_s3_client, opt_s3_bucket, db,
+ table_name, opt_verbose))
+ {
+ fprintf(stderr, "Aborting copying of %s\n", path);
+ my_exit(-1);
+ }
+ break;
+ }
+ }
+ my_exit(0);
+ return 0;
+}
+
+
+/**
+ Calculate database name base on path of Aria file
+
+ @return 0 ok
+ @return 1 error
+*/
+
+static bool get_database_from_path(char *to, size_t to_length,
+ const char *path)
+{
+ S3_INFO s3;
+ if (!set_database_and_table_from_path(&s3, path))
+ {
+ strmake(to, s3.database.str, MY_MIN(s3.database.length, to_length-1));
+ return 0;
+ }
+
+ if (my_getwd(to, to_length-1, MYF(MY_WME)))
+ return 1;
+ return get_database_from_path(to, to_length, to);
+}
+
+
+#include "ma_check_standalone.h"
+
+/*
+ Declare all symbols from libmyisam.a, to ensure that we don't have
+ to include the library as it pulls in ha_myisam.cc
+*/
+
+const char *ft_boolean_syntax= 0;
+ulong ft_min_word_len=0, ft_max_word_len=0;
+const HA_KEYSEG ft_keysegs[FT_SEGS]= {
+{
+ 0, /* charset */
+ HA_FT_WLEN, /* start */
+ 0, /* null_pos */
+ 0, /* Bit pos */
+ HA_VAR_LENGTH_PART | HA_PACK_KEY, /* flag */
+ HA_FT_MAXBYTELEN, /* length */
+ 63, /* language (will be overwritten
+) */
+ HA_KEYTYPE_VARTEXT2, /* type */
+ 0, /* null_bit */
+ 2, 0 /* bit_start, bit_length */
+},
+{
+ 0, 0, 0, 0, HA_NO_SORT, HA_FT_WLEN, 63, HA_FT_WTYPE, 0, 0, 0
+}
+};
+
+struct st_mysql_ftparser ft_default_parser=
+{
+ MYSQL_FTPARSER_INTERFACE_VERSION, 0, 0, 0
+};
+
+C_MODE_START
+int is_stopword(const char *word, size_t len) { return 0; }
+C_MODE_END