Commit e4b46e7a authored by unknown's avatar unknown

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.
parent 43d25648
......@@ -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.
......
......@@ -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);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment