From e4b46e7af637b6b7b2fe0573f4885904aa6b495d Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 14 Jul 2007 00:13:37 +0500 Subject: Fix for bug #29253: csv table reportedly marked as crashed Problem: the data file changes made during delete/update are not visible to other threads as the file is reopened, so reading data with old descriptors might miss the changes. Fix: reopen the data file before reading if it was reopened during delete/update to ensure there's no data behind. Note: there's no simple test case. storage/csv/ha_tina.cc: Fix for bug #29253: csv table reportedly marked as crashed - use the data file version technic to ensure we always see changes made by other threads: a) increase share->data_file_version each time we reopen the data file, i.e. at the end of update/delete. b) compare the local data file version with the shared one each time we want to read data, reopen it if they differ. storage/csv/ha_tina.h: Fix for bug #29253: csv table reportedly marked as crashed - use the data file version technic to ensure we always see changes made by other threads: a) increase share->data_file_version each time we reopen the data file, i.e. at the end og update/delete. b) compare the local data file version with shared one each time we want to read data, reopen it if they differ. --- storage/csv/ha_tina.cc | 52 ++++++++++++++++++++++++++++++++++++++++++++------ storage/csv/ha_tina.h | 3 +++ 2 files changed, 49 insertions(+), 6 deletions(-) (limited to 'storage/csv') diff --git a/storage/csv/ha_tina.cc b/storage/csv/ha_tina.cc index 07bd28f8e65..34c1fcde58d 100644 --- a/storage/csv/ha_tina.cc +++ b/storage/csv/ha_tina.cc @@ -163,6 +163,7 @@ static TINA_SHARE *get_share(const char *table_name, TABLE *table) share->rows_recorded= 0; share->update_file_opened= FALSE; share->tina_write_opened= FALSE; + share->data_file_version= 0; strmov(share->table_name, table_name); fn_format(share->data_file_name, table_name, "", CSV_EXT, MY_REPLACE_EXT|MY_UNPACK_FILENAME); @@ -440,7 +441,7 @@ ha_tina::ha_tina(handlerton *hton, TABLE_SHARE *table_arg) */ current_position(0), next_position(0), local_saved_data_file_length(0), file_buff(0), chain_alloced(0), chain_size(DEFAULT_CHAIN_LENGTH), - records_is_known(0) + local_data_file_version(0), records_is_known(0) { /* Set our original buffers from pre-allocated memory */ buffer.set((char*)byte_buffer, IO_SIZE, &my_charset_bin); @@ -815,6 +816,7 @@ int ha_tina::open(const char *name, int mode, uint open_options) DBUG_RETURN(HA_ERR_CRASHED_ON_USAGE); } + local_data_file_version= share->data_file_version; if ((data_file= my_open(share->data_file_name, O_RDONLY, MYF(0))) == -1) DBUG_RETURN(0); @@ -985,6 +987,33 @@ int ha_tina::delete_row(const uchar * buf) } +/** + @brief Initialize the data file. + + @details Compare the local version of the data file with the shared one. + If they differ, there are some changes behind and we have to reopen + the data file to make the changes visible. + Call @c file_buff->init_buff() at the end to read the beginning of the + data file into buffer. + + @retval 0 OK. + @retval 1 There was an error. +*/ + +int ha_tina::init_data_file() +{ + if (local_data_file_version != share->data_file_version) + { + local_data_file_version= share->data_file_version; + if (my_close(data_file, MYF(0)) || + (data_file= my_open(share->data_file_name, O_RDONLY, MYF(0))) == -1) + return 1; + } + file_buff->init_buff(data_file); + return 0; +} + + /* All table scans call this first. The order of a table scan is: @@ -1021,9 +1050,8 @@ int ha_tina::rnd_init(bool scan) DBUG_ENTER("ha_tina::rnd_init"); /* set buffer to the beginning of the file */ - file_buff->init_buff(data_file); - if (share->crashed) - DBUG_RETURN(HA_ERR_CRASHED_ON_USAGE); + if (share->crashed || init_data_file()) + DBUG_RETURN(HA_ERR_CRASHED_ON_USAGE); current_position= next_position= 0; stats.records= 0; @@ -1246,6 +1274,16 @@ int ha_tina::rnd_end() /* Open the file again */ if (((data_file= my_open(share->data_file_name, O_RDONLY, MYF(0))) == -1)) DBUG_RETURN(-1); + /* + As we reopened the data file, increase share->data_file_version + in order to force other threads waiting on a table lock and + have already opened the table to reopen the data file. + That makes the latest changes become visible to them. + Update local_data_file_version as no need to reopen it in the + current thread. + */ + share->data_file_version++; + local_data_file_version= share->data_file_version; /* The datafile is consistent at this point and the write filedes is closed, so nothing worrying will happen to it in case of a crash. @@ -1308,7 +1346,8 @@ int ha_tina::repair(THD* thd, HA_CHECK_OPT* check_opt) DBUG_RETURN(HA_ERR_OUT_OF_MEM); /* position buffer to the start of the file */ - file_buff->init_buff(data_file); + if (init_data_file()) + DBUG_RETURN(HA_ERR_CRASHED_ON_REPAIR); /* Local_saved_data_file_length is initialized during the lock phase. @@ -1480,7 +1519,8 @@ int ha_tina::check(THD* thd, HA_CHECK_OPT* check_opt) DBUG_RETURN(HA_ERR_OUT_OF_MEM); /* position buffer to the start of the file */ - file_buff->init_buff(data_file); + if (init_data_file()) + DBUG_RETURN(HA_ERR_CRASHED); /* Local_saved_data_file_length is initialized during the lock phase. diff --git a/storage/csv/ha_tina.h b/storage/csv/ha_tina.h index 2e43f1a2307..5bb3e9a79a0 100644 --- a/storage/csv/ha_tina.h +++ b/storage/csv/ha_tina.h @@ -49,6 +49,7 @@ typedef struct st_tina_share { File tina_write_filedes; /* File handler for readers */ bool crashed; /* Meta file is crashed */ ha_rows rows_recorded; /* Number of rows in tables */ + uint data_file_version; /* Version of the data file used */ } TINA_SHARE; struct tina_set { @@ -79,12 +80,14 @@ class ha_tina: public handler tina_set *chain_ptr; uchar chain_alloced; uint32 chain_size; + uint local_data_file_version; /* Saved version of the data file used */ bool records_is_known; private: bool get_write_pos(off_t *end_pos, tina_set *closest_hole); int open_update_temp_file_if_needed(); int init_tina_writer(); + int init_data_file(); public: ha_tina(handlerton *hton, TABLE_SHARE *table_arg); -- cgit v1.2.1