diff --git a/mysql-test/suite/s3/discovery_filename.result b/mysql-test/suite/s3/discovery_filename.result new file mode 100644 index 0000000000000000000000000000000000000000..721ddedfa3fce8d9ec35bf0aaab8c83d0103052c --- /dev/null +++ b/mysql-test/suite/s3/discovery_filename.result @@ -0,0 +1,66 @@ +set names utf8mb4; +create table `t-@002d` (a int, b int) engine=Aria; +insert into `t-@002d` values (1, 10), (2, 20); +alter table `t-@002d` engine=S3; +select * from `t-@002d` order by a; +a b +1 10 +2 20 +select count(*) from `t-@002d`; +count(*) +2 +flush tables; +show tables; +Tables_in_database +t-@002d +select * from `t-@002d` order by a; +a b +1 10 +2 20 +create table `t-é` (a int) engine=Aria; +insert into `t-é` values (3); +alter table `t-é` engine=S3; +flush tables; +show tables; +Tables_in_database +t-@002d +t-é +select * from `t-é`; +a +3 +drop table `t-é`; +alter table `t-@002d` change b c int not null; +flush tables; +select * from `t-@002d` order by a; +a c +1 10 +2 20 +flush tables; +create table `t-@002d` (a int) engine=Aria; +ERROR 42S01: Table 't-@002d' already exists +select * from `t-@002d` order by a; +a c +1 10 +2 20 +create table `p-table` (a int) engine=Aria +partition by range(a) (partition p0 values less than (10), +partition p1 values less than MAXVALUE); +insert into `p-table` values (1), (11); +alter table `p-table` engine=S3; +select * from `p-table` order by a; +a +1 +11 +select count(*) from `p-table`; +count(*) +2 +flush tables; +select * from `p-table` order by a; +a +1 +11 +drop table `p-table`; +flush tables; +drop table `t-@002d`; +select * from `t-@002d`; +ERROR 42S02: Table 'database.t-@002d' doesn't exist diff --git a/mysql-test/suite/s3/discovery_filename.test b/mysql-test/suite/s3/discovery_filename.test new file mode 100644 index 0000000000000000000000000000000000000000..6862403bd96a68c656764a6a7e981b1cd43a8f73 --- /dev/null +++ b/mysql-test/suite/s3/discovery_filename.test @@ -0,0 +1,77 @@ +--source include/have_s3.inc +--source include/have_partition.inc + +# The writer has always used filesystem-encoded names. Rediscovery, listing, +# existence checks and metadata-only ALTER must use that same namespace. +--disable_query_log +let $database= `select concat('s3_test_', replace(uuid(), '-', ''), '-db')`; +let $disk_database= `select replace('$database', '-', '@002d')`; +let $datadir= `select @@datadir`; +eval create database `$database`; +eval use `$database`; +--enable_query_log + +set names utf8mb4; +create table `t-@002d` (a int, b int) engine=Aria; +insert into `t-@002d` values (1, 10), (2, 20); +alter table `t-@002d` engine=S3; +select * from `t-@002d` order by a; +# Cached open must check the encoded base table, not report a false deletion. +select count(*) from `t-@002d`; +flush tables; +--remove_file $datadir/$disk_database/t@002d@0040002d.frm +--replace_result $database database +show tables; +select * from `t-@002d` order by a; + +# Unicode filenames must round trip through discovery and listing as well. +create table `t-é` (a int) engine=Aria; +insert into `t-é` values (3); +alter table `t-é` engine=S3; +--disable_query_log +let $unicode_file= `select convert(convert('t-é' using filename) using binary)`; +--enable_query_log +flush tables; +--remove_file $datadir/$disk_database/$unicode_file.frm +--replace_result $database database +show tables; +select * from `t-é`; +drop table `t-é`; + +# Metadata-only ALTER must update the existing encoded frm object. +alter table `t-@002d` change b c int not null; +flush tables; +--remove_file $datadir/$disk_database/t@002d@0040002d.frm +select * from `t-@002d` order by a; + +# An existing remote table must prevent CREATE after local eviction. +flush tables; +--remove_file $datadir/$disk_database/t@002d@0040002d.frm +--error ER_TABLE_EXISTS_ERROR +create table `t-@002d` (a int) engine=Aria; +select * from `t-@002d` order by a; + +# Verify partition parent metadata and partition data use their existing names. +create table `p-table` (a int) engine=Aria +partition by range(a) (partition p0 values less than (10), + partition p1 values less than MAXVALUE); +insert into `p-table` values (1), (11); +alter table `p-table` engine=S3; +select * from `p-table` order by a; +select count(*) from `p-table`; +flush tables; +--remove_file $datadir/$disk_database/p@002dtable.frm +--remove_file $datadir/$disk_database/p@002dtable.par +select * from `p-table` order by a; +drop table `p-table`; +flush tables; +--remove_file $datadir/$disk_database/t@002d@0040002d.frm +drop table `t-@002d`; +--replace_result $database database +--error ER_NO_SUCH_TABLE +select * from `t-@002d`; + +--disable_query_log +use test; +eval drop database `$database`; +--enable_query_log diff --git a/mysql-test/suite/s3/discovery_read_error.result b/mysql-test/suite/s3/discovery_read_error.result new file mode 100644 index 0000000000000000000000000000000000000000..2c1b6b1ec51bebd07d23af01c31dd06b9ef8fa62 --- /dev/null +++ b/mysql-test/suite/s3/discovery_read_error.result @@ -0,0 +1,68 @@ +create table t1 (a int) engine=Aria; +insert into t1 values (1), (2); +alter table t1 engine=S3; +select * from t1 order by a; +a +1 +2 +set debug_dbug='+d,s3_get_object_error'; +select * from t1; +ERROR HY000: Got error 157 "Could not connect to the storage engine" from storage engine S3 +set debug_dbug=''; +select * from t1 order by a; +a +1 +2 +flush tables; +set debug_dbug='+d,s3_get_object_error'; +select * from t1; +ERROR HY000: Got error 157 "Could not connect to the storage engine" from storage engine S3 +set debug_dbug=''; +select * from t1 order by a; +a +1 +2 +flush tables; +set debug_dbug='+d,s3_get_object_error'; +select * from t1; +ERROR HY000: Got error 157 "Could not connect to the storage engine" from storage engine S3 +set debug_dbug=''; +select * from t1 order by a; +a +1 +2 +flush tables; +set debug_dbug='+d,s3_frm_exists_error'; +create table t1 (a int) engine=Aria; +Got one of the listed errors +set debug_dbug=''; +select * from t1 order by a; +a +1 +2 +drop table t1; +create table p1 (a int) engine=Aria partition by hash(a) partitions 2; +insert into p1 values (1), (2); +alter table p1 engine=S3; +select * from p1 order by a; +a +1 +2 +set debug_dbug='+d,s3_get_object_error'; +select * from p1; +ERROR HY000: Got error 157 "Could not connect to the storage engine" from storage engine S3 +set debug_dbug=''; +select * from p1 order by a; +a +1 +2 +flush tables; +set debug_dbug='+d,s3_get_object_error'; +select * from p1; +ERROR HY000: Got error 157 "Could not connect to the storage engine" from storage engine S3 +set debug_dbug=''; +select * from p1 order by a; +a +1 +2 +drop table p1; diff --git a/mysql-test/suite/s3/discovery_read_error.test b/mysql-test/suite/s3/discovery_read_error.test new file mode 100644 index 0000000000000000000000000000000000000000..b911d89245bab2e723cc23fb23ad186fbb531d41 --- /dev/null +++ b/mysql-test/suite/s3/discovery_read_error.test @@ -0,0 +1,66 @@ +--source include/have_s3.inc +--source include/have_debug.inc +--source include/have_partition.inc +--source create_database.inc +let $datadir= `select @@datadir`; +create table t1 (a int) engine=Aria; +insert into t1 values (1), (2); +alter table t1 engine=S3; +select * from t1 order by a; + +# A failed cached version check must fail without deleting the local frm. +set debug_dbug='+d,s3_get_object_error'; +--error ER_GET_ERRNO +select * from t1; +--file_exists $datadir/$database/t1.frm +set debug_dbug=''; +select * from t1 order by a; + +# The cold Aria open path must not ignore version fetch errors either. +flush tables; +set debug_dbug='+d,s3_get_object_error'; +--error ER_GET_ERRNO +select * from t1; +--file_exists $datadir/$database/t1.frm +set debug_dbug=''; +select * from t1 order by a; + +# Discovery must report a read error rather than pretend the archive is absent. +flush tables; +--remove_file $datadir/$database/t1.frm +set debug_dbug='+d,s3_get_object_error'; +--error ER_GET_ERRNO +select * from t1; +set debug_dbug=''; +select * from t1 order by a; + +# A failed existence probe must not authorize CREATE over an existing archive. +flush tables; +--remove_file $datadir/$database/t1.frm +set debug_dbug='+d,s3_frm_exists_error'; +--error ER_GET_ERRNO,ER_TABLE_EXISTS_ERROR +create table t1 (a int) engine=Aria; +set debug_dbug=''; +select * from t1 order by a; +drop table t1; + +# Partition handlers forward the same version error contract to the server. +create table p1 (a int) engine=Aria partition by hash(a) partitions 2; +insert into p1 values (1), (2); +alter table p1 engine=S3; +select * from p1 order by a; +set debug_dbug='+d,s3_get_object_error'; +--error ER_GET_ERRNO +select * from p1; +--file_exists $datadir/$database/p1.frm +set debug_dbug=''; +select * from p1 order by a; +flush tables; +set debug_dbug='+d,s3_get_object_error'; +--error ER_GET_ERRNO +select * from p1; +--file_exists $datadir/$database/p1.frm +set debug_dbug=''; +select * from p1 order by a; +drop table p1; +--source drop_database.inc diff --git a/sql/handler.h b/sql/handler.h index 3ab9e0bcd1a8e20e3f6afdb776646a07a258809a..3107b1d46406767a07c4ffe6e499ccdbaa316874 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -3603,7 +3603,11 @@ class handler :public Sql_alloc public: virtual void unbind_psi(); virtual void rebind_psi(); - /* Return error if definition doesn't match for already opened table */ + /* + Check an already opened table's definition. Return 0 if unchanged, + HA_ERR_TABLE_DEF_CHANGED to rediscover it, or another handler error + to fail the open without discarding the local definition. + */ virtual int discover_check_version() { return 0; } /** diff --git a/sql/sql_base.cc b/sql/sql_base.cc index f189ecef385ab9bd275503e2299a79a931291188..5a1adf2529396a450f50fc04d55713afb8bac69d 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -2299,11 +2299,16 @@ bool open_table(THD *thd, TABLE_LIST *table_list, Open_table_context *ot_ctx) if (table) { DBUG_ASSERT(table->file != NULL); - if (table->file->discover_check_version()) + int version_error= table->file->discover_check_version(); + if (version_error) { + /* Only a changed definition warrants destructive rediscovery. */ + if (version_error != HA_ERR_TABLE_DEF_CHANGED && !thd->is_error()) + table->file->print_error(version_error, MYF(0)); tc_release_table(table); - (void) ot_ctx->request_backoff_action(Open_table_context::OT_DISCOVER, - table_list); + if (version_error == HA_ERR_TABLE_DEF_CHANGED) + (void) ot_ctx->request_backoff_action(Open_table_context::OT_DISCOVER, + table_list); DBUG_RETURN(TRUE); } table->file->rebind_psi(); diff --git a/storage/maria/ha_s3.cc b/storage/maria/ha_s3.cc index b49293e5bbe70049835c0bb205070cd1a5ce0a85..a8364b628325bbc4f40134b55cd42a5f8c78e4e3 100644 --- a/storage/maria/ha_s3.cc +++ b/storage/maria/ha_s3.cc @@ -68,6 +68,7 @@ #include #include "maria_def.h" #include "sql_class.h" +#include "sql_table.h" #include #include #include @@ -621,6 +622,7 @@ int ha_s3::open(const char *name, int mode, uint open_flags) bool internal_tmp_table= 0; int res; S3_INFO s3_info; + char base_table[FN_REFLEN]; DBUG_ENTER("ha_s3:open"); if (!s3_usable()) @@ -655,7 +657,10 @@ int ha_s3::open(const char *name, int mode, uint open_flags) { (void) s3_info_init(&s3_info); s3_info.tabledef_version= table->s->tabledef_version; - s3_info.base_table= table->s->table_name; + s3_info.base_table.str= base_table; + s3_info.base_table.length= + tablename_to_filename(table->s->table_name.str, base_table, + sizeof(base_table)); /* Pass the above arguments to maria_open() */ open_args= &s3_info; @@ -798,6 +803,7 @@ static int s3_hton_panic(handlerton *hton, ha_panic_function flag) static int s3_discover_table(handlerton *hton, THD* thd, TABLE_SHARE *share) { S3_INFO s3_info; + char database[FN_REFLEN], table_name[FN_REFLEN]; S3_BLOCK frm_block, par_block; ms3_st *s3_client; int error; @@ -808,17 +814,29 @@ static int s3_discover_table(handlerton *hton, THD* thd, TABLE_SHARE *share) if (!(s3_client= s3_open_connection(&s3_info))) DBUG_RETURN(HA_ERR_NO_CONNECTION); - s3_info.database= share->db; - s3_info.table= share->table_name; - s3_info.base_table= share->table_name; + /* Archives use filesystem names, just like ALTER TABLE ... ENGINE=S3. */ + s3_info.database.str= database; + s3_info.database.length= + tablename_to_filename(share->db.str, database, sizeof(database)); + s3_info.table.str= table_name; + s3_info.table.length= + tablename_to_filename(share->table_name.str, table_name, sizeof(table_name)); + s3_info.base_table= s3_info.table; - if (s3_get_def(s3_client, &s3_info, &frm_block, "frm")) + if ((error= s3_get_def(s3_client, &s3_info, &frm_block, "frm"))) { s3_free(&frm_block); s3_deinit(s3_client); - DBUG_RETURN(HA_ERR_NO_SUCH_TABLE); + DBUG_RETURN(error == HA_ERR_NO_SUCH_TABLE ? error : HA_ERR_NO_CONNECTION); + } + error= s3_get_def(s3_client, &s3_info, &par_block, "par"); + if (error && error != HA_ERR_NO_SUCH_TABLE) + { + s3_free(&frm_block); + s3_free(&par_block); + s3_deinit(s3_client); + DBUG_RETURN(HA_ERR_NO_CONNECTION); } - (void) s3_get_def(s3_client, &s3_info, &par_block, "par"); error= share->init_from_binary_frm_image(thd, 1, frm_block.str, frm_block.length, @@ -841,6 +859,7 @@ static int s3_discover_table_existence(handlerton *hton, const char *db, const char *table_name) { S3_INFO s3_info; + char database[FN_REFLEN], filename[FN_REFLEN]; ms3_st *s3_client; int res; DBUG_ENTER("s3_discover_table_existence"); @@ -852,17 +871,22 @@ static int s3_discover_table_existence(handlerton *hton, const char *db, if (s3_info_init(&s3_info)) DBUG_RETURN(0); if (!(s3_client= s3_open_connection(&s3_info))) - DBUG_RETURN(0); + DBUG_RETURN(1); // An error does not prove absence - s3_info.database.str= db; - s3_info.database.length= strlen(db); - s3_info.table.str= table_name; - s3_info.table.length= strlen(table_name); + s3_info.database.str= database; + s3_info.database.length= + tablename_to_filename(db, database, sizeof(database)); + s3_info.table.str= filename; + s3_info.table.length= + tablename_to_filename(table_name, filename, sizeof(filename)); res= s3_frm_exists(s3_client, &s3_info); + if (res && res != MS3_ERR_NOT_FOUND) + my_error(ER_GET_ERRNO, MYF(0), HA_ERR_NO_CONNECTION, "S3"); s3_deinit(s3_client); - DBUG_PRINT("exit", ("exists: %d", res == 0)); - DBUG_RETURN(res == 0); // Return 1 if exists + DBUG_PRINT("exit", ("exists: %d", res != MS3_ERR_NOT_FOUND)); + /* ha_table_exists() must only allow CREATE after confirmed absence. */ + DBUG_RETURN(res != MS3_ERR_NOT_FOUND); } @@ -878,6 +902,8 @@ static int s3_discover_table_names(handlerton *hton __attribute__((unused)), handlerton::discovered_list *result) { char aws_path[AWS_PATH_LENGTH]; + char database[FN_REFLEN], filename[FN_REFLEN]; + size_t prefix_length; S3_INFO s3_info; ms3_st *s3_client; ms3_list_st *list, *org_list= 0; @@ -893,25 +919,36 @@ static int s3_discover_table_names(handlerton *hton __attribute__((unused)), if (!(s3_client= s3_open_connection(&s3_info))) DBUG_RETURN(0); - strxnmov(aws_path, sizeof(aws_path)-1, db->str, "/", NullS); + tablename_to_filename(db->str, database, sizeof(database)); + prefix_length= strxnmov(aws_path, sizeof(aws_path)-1, database, "/", NullS) - + aws_path; if ((error= ms3_list_dir(s3_client, s3_info.bucket.str, aws_path, &org_list))) + { + my_error(ER_GET_ERRNO, MYF(0), HA_ERR_NO_CONNECTION, "S3"); goto end; + } for (list= org_list ; list ; list= list->next) { - const char *name= list->key + db->length + 1; // Skip database and '/' - if (!strstr(name, "#P#")) + const char *name= list->key + prefix_length; // Skip database and '/' + size_t name_length= strlen(name); + if (name_length && name_length <= sizeof(filename) && + name[name_length-1] == '/' && !strstr(name, "#P#")) { - size_t name_length= strlen(name)-1; // Remove end '/' - result->add_table(name, name_length); + strmake(filename, name, name_length-1); // Remove end '/' + if (result->add_file(filename)) + { + error= 1; + break; + } } } if (org_list) ms3_list_free(org_list); end: s3_deinit(s3_client); - DBUG_RETURN(0); + DBUG_RETURN(error); } /* @@ -927,15 +964,18 @@ static int s3_discover_table_names(handlerton *hton __attribute__((unused)), int ha_s3::discover_check_version() { S3_INFO s3_info= *file->s->s3_path; + char base_table[FN_REFLEN]; s3_info.tabledef_version= table->s->tabledef_version; /* We have to change the database and table as the table may part of a partitioned table. In this case we want to check the frm file for the partitioned table, not the part table. */ - s3_info.base_table= table->s->table_name; - return (s3_check_frm_version(file->s3, &s3_info) ? - HA_ERR_TABLE_DEF_CHANGED : 0); + s3_info.base_table.str= base_table; + s3_info.base_table.length= + tablename_to_filename(table->s->table_name.str, base_table, + sizeof(base_table)); + return s3_frm_error(s3_check_frm_version(file->s3, &s3_info)); } @@ -950,6 +990,7 @@ static int s3_notify_tabledef_changed(handlerton *, handler *) { char aws_path[AWS_PATH_LENGTH]; + char database[FN_REFLEN], table_name[FN_REFLEN]; S3_INFO s3_info; ms3_st *s3_client; int error= 0; @@ -963,8 +1004,12 @@ static int s3_notify_tabledef_changed(handlerton *, if (!(s3_client= s3_open_connection(&s3_info))) DBUG_RETURN(0); - s3_info.database= *db; - s3_info.base_table= *table; + s3_info.database.str= database; + s3_info.database.length= + tablename_to_filename(db->str, database, sizeof(database)); + s3_info.base_table.str= table_name; + s3_info.base_table.length= + tablename_to_filename(table->str, table_name, sizeof(table_name)); s3_info.tabledef_version= *org_tabledef_version; if (s3_check_frm_version(s3_client, &s3_info)) { @@ -972,8 +1017,7 @@ static int s3_notify_tabledef_changed(handlerton *, goto err; } - strxnmov(aws_path, sizeof(aws_path)-1, db->str, "/", table->str, "/frm", - NullS); + strxnmov(aws_path, sizeof(aws_path)-1, database, "/", table_name, "/frm", NullS); if (s3_put_object(s3_client, s3_info.bucket.str, aws_path, (uchar*) frm->str, frm->length, 0)) diff --git a/storage/maria/ma_open.c b/storage/maria/ma_open.c index b27bc0d4e284bf6f8b0931ab48e7093f19a6771a..03ff31743ce83482988d6a5900ff821901e8720d 100644 --- a/storage/maria/ma_open.c +++ b/storage/maria/ma_open.c @@ -391,9 +391,8 @@ MARIA_HA *maria_open(const char *name, int mode, uint open_flags, goto err; /* EiOM */ /* Check if table has changed in S3 */ - if (s3f.check_frm_version(s3_client, share_s3) == 1) + if ((my_errno= s3_frm_error(s3f.check_frm_version(s3_client, share_s3)))) { - my_errno= HA_ERR_TABLE_DEF_CHANGED; goto err; } diff --git a/storage/maria/s3_func.c b/storage/maria/s3_func.c index 1fa0636ccd5820c74caec33170bf638f70f87df9..719b3f0ed378afb7c701e97cc5eda4bec13750be 100644 --- a/storage/maria/s3_func.c +++ b/storage/maria/s3_func.c @@ -1021,6 +1021,9 @@ int s3_get_object(ms3_st *s3_client, const char *aws_bucket, DBUG_PRINT("enter", ("name: %s compression: %d", name, compression)); block->str= block->alloc_ptr= 0; + block->length= 0; + DBUG_EXECUTE_IF("s3_get_object_error", + error= MS3_ERR_SERVER; goto read_error;); if (likely(!(error= ms3_get(s3_client, aws_bucket, name, (uint8_t**) &block->alloc_ptr, &block->length)))) @@ -1079,7 +1082,10 @@ int s3_get_object(ms3_st *s3_client, const char *aws_bucket, DBUG_RETURN(0); } - if (error == 9) +#ifndef DBUG_OFF +read_error: +#endif + if (error == MS3_ERR_NOT_FOUND) { result= my_errno= (print_error == 1 ? EE_FILENOTFOUND : HA_ERR_NO_SUCH_TABLE); @@ -1403,10 +1409,10 @@ static int s3_read_file_from_disk(const char *filename, uchar **to, Get .frm or par from S3 @return 0 ok - @return 1 error + @return HA_ERR_NO_SUCH_TABLE if the definition is absent, or a read error */ -my_bool s3_get_def(ms3_st *s3_client, S3_INFO *s3_info, S3_BLOCK *block, +int s3_get_def(ms3_st *s3_client, S3_INFO *s3_info, S3_BLOCK *block, const char *ext) { char aws_path[AWS_PATH_LENGTH]; @@ -1422,14 +1428,16 @@ my_bool s3_get_def(ms3_st *s3_client, S3_INFO *s3_info, S3_BLOCK *block, Check if .frm exits in S3 @return 0 frm exists - @return 1 error + @return MS3_ERR_NOT_FOUND if absent, or another libmarias3 error */ -my_bool s3_frm_exists(ms3_st *s3_client, S3_INFO *s3_info) +int s3_frm_exists(ms3_st *s3_client, S3_INFO *s3_info) { char aws_path[AWS_PATH_LENGTH]; ms3_status_st status; + DBUG_EXECUTE_IF("s3_frm_exists_error", return MS3_ERR_SERVER;); + strxnmov(aws_path, sizeof(aws_path)-1, s3_info->database.str, "/", s3_info->table.str, "/frm", NullS); @@ -1464,7 +1472,7 @@ static my_bool get_tabledef_version_from_frm(char *out, const uchar *frm_image, { uint segment_len; const uchar *extra, *extra_end; - if (!is_binary_frm_header(frm_image) || frm_length <= FRM_HEADER_SIZE) + if (frm_length <= FRM_HEADER_SIZE || !is_binary_frm_header(frm_image)) return 1; /* Length of the MariaDB extra2 segment in the form file. */ @@ -1508,8 +1516,9 @@ static my_bool get_tabledef_version_from_frm(char *out, const uchar *frm_image, @return 0 table definitions matches @return 1 table definitions doesn't match - @return 2 Can't find the frm version - @return 3 Can't read the frm version + @return S3_FRM_NOT_FOUND Definition is absent (S3 returned 404) + @return S3_FRM_INVALID Definition is malformed + @return S3_FRM_READ_ERROR Definition could not be fetched */ int s3_check_frm_version(ms3_st *s3_client, S3_INFO *s3_info) @@ -1518,15 +1527,17 @@ int s3_check_frm_version(ms3_st *s3_client, S3_INFO *s3_info) char aws_path[AWS_PATH_LENGTH]; char uuid[MY_UUID_SIZE]; S3_BLOCK block; + int error; DBUG_ENTER("s3_check_frm_version"); strxnmov(aws_path, sizeof(aws_path)-1, s3_info->database.str, "/", s3_info->base_table.str, "/frm", NullS); - if (s3_get_object(s3_client, s3_info->bucket.str, aws_path, &block, 0, 0)) + if ((error= s3_get_object(s3_client, s3_info->bucket.str, aws_path, + &block, 0, 0))) { - DBUG_PRINT("exit", ("No object found")); - DBUG_RETURN(2); /* Ignore check, use old frm */ + DBUG_RETURN(error == HA_ERR_NO_SUCH_TABLE ? S3_FRM_NOT_FOUND : + S3_FRM_READ_ERROR); } if (get_tabledef_version_from_frm(uuid, (uchar*) block.str, block.length) || @@ -1534,7 +1545,7 @@ int s3_check_frm_version(ms3_st *s3_client, S3_INFO *s3_info) { s3_free(&block); DBUG_PRINT("error", ("Wrong definition")); - DBUG_RETURN(3); /* Wrong definition */ + DBUG_RETURN(S3_FRM_INVALID); } /* res is set to 1 if versions numbers doesn't match */ res= bcmp(s3_info->tabledef_version.str, uuid, MY_UUID_SIZE) != 0; diff --git a/storage/maria/s3_func.h b/storage/maria/s3_func.h index 9c0831b158d8ee3630d5d9b87e43dc40b4c33ae1..ef3affef02d5f161b7196335fc1ae847c95254af 100644 --- a/storage/maria/s3_func.h +++ b/storage/maria/s3_func.h @@ -130,9 +130,34 @@ int partition_copy_to_s3(ms3_st *s3_client, const char *aws_bucket, S3_INFO *s3_info_copy(S3_INFO *old); my_bool set_database_and_table_from_path(S3_INFO *s3, const char *path); -my_bool s3_get_def(ms3_st *s3_client, S3_INFO *S3_info, S3_BLOCK *block, +int s3_get_def(ms3_st *s3_client, S3_INFO *S3_info, S3_BLOCK *block, const char *ext); -my_bool s3_frm_exists(ms3_st *s3_client, S3_INFO *s3_info); +int s3_frm_exists(ms3_st *s3_client, S3_INFO *s3_info); + +enum s3_frm_status +{ + S3_FRM_OK= 0, + S3_FRM_CHANGED= 1, + S3_FRM_NOT_FOUND= 2, + S3_FRM_INVALID= 3, + S3_FRM_READ_ERROR= 4 +}; + +static inline int s3_frm_error(int status) +{ + switch (status) { + case S3_FRM_OK: + return 0; + case S3_FRM_CHANGED: + case S3_FRM_NOT_FOUND: + return HA_ERR_TABLE_DEF_CHANGED; + case S3_FRM_INVALID: + return HA_ERR_NOT_A_TABLE; + default: + return HA_ERR_NO_CONNECTION; + } +} + int s3_check_frm_version(ms3_st *s3_client, S3_INFO *s3_info); my_bool read_index_header(ms3_st *client, S3_INFO *s3, S3_BLOCK *block); int32 s3_unique_file_number(void);