mirror of
https://github.com/MariaDB/server.git
synced 2025-07-30 16:24:05 +03:00
Merge pchardin@bk-internal.mysql.com:/home/bk/mysql-5.1
into mysql.com:/home/cps/mysql/devel/5.1-csv-remove-mmap
This commit is contained in:
@ -4944,10 +4944,10 @@ val
|
|||||||
UPDATE bug13894 SET val=6 WHERE val=10;
|
UPDATE bug13894 SET val=6 WHERE val=10;
|
||||||
SELECT * FROM bug13894;
|
SELECT * FROM bug13894;
|
||||||
val
|
val
|
||||||
|
6
|
||||||
|
6
|
||||||
5
|
5
|
||||||
11
|
11
|
||||||
6
|
|
||||||
6
|
|
||||||
DROP TABLE bug13894;
|
DROP TABLE bug13894;
|
||||||
DROP TABLE IF EXISTS bug14672;
|
DROP TABLE IF EXISTS bug14672;
|
||||||
CREATE TABLE bug14672 (c1 integer) engine = CSV;
|
CREATE TABLE bug14672 (c1 integer) engine = CSV;
|
||||||
|
@ -453,7 +453,7 @@ static void ndbcluster_binlog_wait(THD *thd)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Called from MYSQL_LOG::reset_logs in log.cc when binlog is emptied
|
Called from MYSQL_BIN_LOG::reset_logs in log.cc when binlog is emptied
|
||||||
*/
|
*/
|
||||||
static int ndbcluster_reset_logs(THD *thd)
|
static int ndbcluster_reset_logs(THD *thd)
|
||||||
{
|
{
|
||||||
@ -477,7 +477,7 @@ static int ndbcluster_reset_logs(THD *thd)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Called from MYSQL_LOG::purge_logs in log.cc when the binlog "file"
|
Called from MYSQL_BIN_LOG::purge_logs in log.cc when the binlog "file"
|
||||||
is removed
|
is removed
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
1098
sql/log.cc
1098
sql/log.cc
File diff suppressed because it is too large
Load Diff
133
sql/log.h
133
sql/log.h
@ -147,33 +147,85 @@ typedef struct st_log_info
|
|||||||
class Log_event;
|
class Log_event;
|
||||||
class Rows_log_event;
|
class Rows_log_event;
|
||||||
|
|
||||||
enum enum_log_type { LOG_CLOSED, LOG_TO_BE_OPENED, LOG_NORMAL, LOG_NEW, LOG_BIN};
|
enum enum_log_type { LOG_UNKNOWN, LOG_NORMAL, LOG_BIN };
|
||||||
|
enum enum_log_state { LOG_OPENED, LOG_CLOSED, LOG_TO_BE_OPENED };
|
||||||
|
|
||||||
/*
|
/*
|
||||||
TODO split MYSQL_LOG into base MYSQL_LOG and
|
|
||||||
MYSQL_QUERY_LOG, MYSQL_SLOW_LOG, MYSQL_BIN_LOG
|
|
||||||
most of the code from MYSQL_LOG should be in the MYSQL_BIN_LOG
|
|
||||||
only (TC_LOG included)
|
|
||||||
|
|
||||||
TODO use mmap instead of IO_CACHE for binlog
|
TODO use mmap instead of IO_CACHE for binlog
|
||||||
(mmap+fsync is two times faster than write+fsync)
|
(mmap+fsync is two times faster than write+fsync)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
class MYSQL_LOG: public TC_LOG
|
class MYSQL_LOG
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MYSQL_LOG();
|
||||||
|
void init_pthread_objects();
|
||||||
|
void cleanup();
|
||||||
|
bool open(const char *log_name,
|
||||||
|
enum_log_type log_type,
|
||||||
|
const char *new_name,
|
||||||
|
enum cache_type io_cache_type_arg);
|
||||||
|
void init(enum_log_type log_type_arg,
|
||||||
|
enum cache_type io_cache_type_arg);
|
||||||
|
void close(uint exiting);
|
||||||
|
inline bool is_open() { return log_state != LOG_CLOSED; }
|
||||||
|
const char *generate_name(const char *log_name, const char *suffix,
|
||||||
|
bool strip_ext, char *buff);
|
||||||
|
int generate_new_name(char *new_name, const char *log_name);
|
||||||
|
protected:
|
||||||
|
/* LOCK_log is inited by init_pthread_objects() */
|
||||||
|
pthread_mutex_t LOCK_log;
|
||||||
|
char *name;
|
||||||
|
char log_file_name[FN_REFLEN];
|
||||||
|
char time_buff[20], db[NAME_LEN + 1];
|
||||||
|
bool write_error, inited;
|
||||||
|
IO_CACHE log_file;
|
||||||
|
enum_log_type log_type;
|
||||||
|
volatile enum_log_state log_state;
|
||||||
|
enum cache_type io_cache_type;
|
||||||
|
friend class Log_event;
|
||||||
|
};
|
||||||
|
|
||||||
|
class MYSQL_QUERY_LOG: public MYSQL_LOG
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MYSQL_QUERY_LOG() : last_time(0) {}
|
||||||
|
void reopen_file();
|
||||||
|
bool write(time_t event_time, const char *user_host,
|
||||||
|
uint user_host_len, int thread_id,
|
||||||
|
const char *command_type, uint command_type_len,
|
||||||
|
const char *sql_text, uint sql_text_len);
|
||||||
|
bool write(THD *thd, time_t current_time, time_t query_start_arg,
|
||||||
|
const char *user_host, uint user_host_len,
|
||||||
|
longlong query_time, longlong lock_time, bool is_command,
|
||||||
|
const char *sql_text, uint sql_text_len);
|
||||||
|
bool open_slow_log(const char *log_name)
|
||||||
|
{
|
||||||
|
char buf[FN_REFLEN];
|
||||||
|
return open(generate_name(log_name, "-slow.log", 0, buf), LOG_NORMAL, 0,
|
||||||
|
WRITE_CACHE);
|
||||||
|
}
|
||||||
|
bool open_query_log(const char *log_name)
|
||||||
|
{
|
||||||
|
char buf[FN_REFLEN];
|
||||||
|
return open(generate_name(log_name, ".log", 0, buf), LOG_NORMAL, 0,
|
||||||
|
WRITE_CACHE);
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
time_t last_time;
|
||||||
|
};
|
||||||
|
|
||||||
|
class MYSQL_BIN_LOG: public TC_LOG, private MYSQL_LOG
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
/* LOCK_log and LOCK_index are inited by init_pthread_objects() */
|
/* LOCK_log and LOCK_index are inited by init_pthread_objects() */
|
||||||
pthread_mutex_t LOCK_log, LOCK_index;
|
pthread_mutex_t LOCK_index;
|
||||||
pthread_mutex_t LOCK_prep_xids;
|
pthread_mutex_t LOCK_prep_xids;
|
||||||
pthread_cond_t COND_prep_xids;
|
pthread_cond_t COND_prep_xids;
|
||||||
pthread_cond_t update_cond;
|
pthread_cond_t update_cond;
|
||||||
ulonglong bytes_written;
|
ulonglong bytes_written;
|
||||||
time_t last_time,query_start;
|
|
||||||
IO_CACHE log_file;
|
|
||||||
IO_CACHE index_file;
|
IO_CACHE index_file;
|
||||||
char *name;
|
char index_file_name[FN_REFLEN];
|
||||||
char time_buff[20],db[NAME_LEN+1];
|
|
||||||
char log_file_name[FN_REFLEN],index_file_name[FN_REFLEN];
|
|
||||||
/*
|
/*
|
||||||
The max size before rotation (usable only if log_type == LOG_BIN: binary
|
The max size before rotation (usable only if log_type == LOG_BIN: binary
|
||||||
logs and relay logs).
|
logs and relay logs).
|
||||||
@ -186,13 +238,10 @@ class MYSQL_LOG: public TC_LOG
|
|||||||
*/
|
*/
|
||||||
ulong max_size;
|
ulong max_size;
|
||||||
ulong prepared_xids; /* for tc log - number of xids to remember */
|
ulong prepared_xids; /* for tc log - number of xids to remember */
|
||||||
volatile enum_log_type log_type;
|
|
||||||
enum cache_type io_cache_type;
|
|
||||||
// current file sequence number for load data infile binary logging
|
// current file sequence number for load data infile binary logging
|
||||||
uint file_id;
|
uint file_id;
|
||||||
uint open_count; // For replication
|
uint open_count; // For replication
|
||||||
int readers_count;
|
int readers_count;
|
||||||
bool write_error, inited;
|
|
||||||
bool need_start_event;
|
bool need_start_event;
|
||||||
/*
|
/*
|
||||||
no_auto_events means we don't want any of these automatic events :
|
no_auto_events means we don't want any of these automatic events :
|
||||||
@ -202,13 +251,21 @@ class MYSQL_LOG: public TC_LOG
|
|||||||
In 5.0 it's 0 for relay logs too!
|
In 5.0 it's 0 for relay logs too!
|
||||||
*/
|
*/
|
||||||
bool no_auto_events;
|
bool no_auto_events;
|
||||||
friend class Log_event;
|
|
||||||
|
|
||||||
ulonglong m_table_map_version;
|
ulonglong m_table_map_version;
|
||||||
|
|
||||||
int write_to_file(IO_CACHE *cache);
|
int write_to_file(IO_CACHE *cache);
|
||||||
|
/*
|
||||||
|
This is used to start writing to a new log file. The difference from
|
||||||
|
new_file() is locking. new_file_without_locking() does not acquire
|
||||||
|
LOCK_log.
|
||||||
|
*/
|
||||||
|
void new_file_without_locking();
|
||||||
|
void new_file_impl(bool need_lock);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
MYSQL_LOG::generate_name;
|
||||||
|
MYSQL_LOG::is_open;
|
||||||
/*
|
/*
|
||||||
These describe the log's format. This is used only for relay logs.
|
These describe the log's format. This is used only for relay logs.
|
||||||
_for_exec is used by the SQL thread, _for_queue by the I/O thread. It's
|
_for_exec is used by the SQL thread, _for_queue by the I/O thread. It's
|
||||||
@ -220,9 +277,9 @@ public:
|
|||||||
Format_description_log_event *description_event_for_exec,
|
Format_description_log_event *description_event_for_exec,
|
||||||
*description_event_for_queue;
|
*description_event_for_queue;
|
||||||
|
|
||||||
MYSQL_LOG();
|
MYSQL_BIN_LOG();
|
||||||
/*
|
/*
|
||||||
note that there's no destructor ~MYSQL_LOG() !
|
note that there's no destructor ~MYSQL_BIN_LOG() !
|
||||||
The reason is that we don't want it to be automatically called
|
The reason is that we don't want it to be automatically called
|
||||||
on exit() - but only during the correct shutdown process
|
on exit() - but only during the correct shutdown process
|
||||||
*/
|
*/
|
||||||
@ -264,9 +321,7 @@ public:
|
|||||||
void signal_update();
|
void signal_update();
|
||||||
void wait_for_update(THD* thd, bool master_or_slave);
|
void wait_for_update(THD* thd, bool master_or_slave);
|
||||||
void set_need_start_event() { need_start_event = 1; }
|
void set_need_start_event() { need_start_event = 1; }
|
||||||
void init(enum_log_type log_type_arg,
|
void init(bool no_auto_events_arg, ulong max_size);
|
||||||
enum cache_type io_cache_type_arg,
|
|
||||||
bool no_auto_events_arg, ulong max_size);
|
|
||||||
void init_pthread_objects();
|
void init_pthread_objects();
|
||||||
void cleanup();
|
void cleanup();
|
||||||
bool open(const char *log_name,
|
bool open(const char *log_name,
|
||||||
@ -275,35 +330,10 @@ public:
|
|||||||
enum cache_type io_cache_type_arg,
|
enum cache_type io_cache_type_arg,
|
||||||
bool no_auto_events_arg, ulong max_size,
|
bool no_auto_events_arg, ulong max_size,
|
||||||
bool null_created);
|
bool null_created);
|
||||||
const char *generate_name(const char *log_name, const char *suffix,
|
|
||||||
bool strip_ext, char *buff);
|
|
||||||
/* simplified open_xxx wrappers for the gigantic open above */
|
|
||||||
bool open_query_log(const char *log_name)
|
|
||||||
{
|
|
||||||
char buf[FN_REFLEN];
|
|
||||||
return open(generate_name(log_name, ".log", 0, buf),
|
|
||||||
LOG_NORMAL, 0, WRITE_CACHE, 0, 0, 0);
|
|
||||||
}
|
|
||||||
bool open_slow_log(const char *log_name)
|
|
||||||
{
|
|
||||||
char buf[FN_REFLEN];
|
|
||||||
return open(generate_name(log_name, "-slow.log", 0, buf),
|
|
||||||
LOG_NORMAL, 0, WRITE_CACHE, 0, 0, 0);
|
|
||||||
}
|
|
||||||
bool open_index_file(const char *index_file_name_arg,
|
bool open_index_file(const char *index_file_name_arg,
|
||||||
const char *log_name);
|
const char *log_name);
|
||||||
void new_file(bool need_lock);
|
/* Use this to start writing a new log file */
|
||||||
/* log a command to the old-fashioned general log */
|
void new_file();
|
||||||
bool write(time_t event_time, const char *user_host,
|
|
||||||
uint user_host_len, int thread_id,
|
|
||||||
const char *command_type, uint command_type_len,
|
|
||||||
const char *sql_text, uint sql_text_len);
|
|
||||||
|
|
||||||
/* log a query to the old-fashioned slow query log */
|
|
||||||
bool write(THD *thd, time_t current_time, time_t query_start_arg,
|
|
||||||
const char *user_host, uint user_host_len,
|
|
||||||
longlong query_time, longlong lock_time, bool is_command,
|
|
||||||
const char *sql_text, uint sql_text_len);
|
|
||||||
|
|
||||||
bool write(Log_event* event_info); // binary log write
|
bool write(Log_event* event_info); // binary log write
|
||||||
bool write(THD *thd, IO_CACHE *cache, Log_event *commit_event);
|
bool write(THD *thd, IO_CACHE *cache, Log_event *commit_event);
|
||||||
@ -319,7 +349,6 @@ public:
|
|||||||
bool appendv(const char* buf,uint len,...);
|
bool appendv(const char* buf,uint len,...);
|
||||||
bool append(Log_event* ev);
|
bool append(Log_event* ev);
|
||||||
|
|
||||||
int generate_new_name(char *new_name,const char *old_name);
|
|
||||||
void make_log_name(char* buf, const char* log_ident);
|
void make_log_name(char* buf, const char* log_ident);
|
||||||
bool is_active(const char* log_file_name);
|
bool is_active(const char* log_file_name);
|
||||||
int update_log_index(LOG_INFO* linfo, bool need_update_threads);
|
int update_log_index(LOG_INFO* linfo, bool need_update_threads);
|
||||||
@ -339,7 +368,6 @@ public:
|
|||||||
int find_next_log(LOG_INFO* linfo, bool need_mutex);
|
int find_next_log(LOG_INFO* linfo, bool need_mutex);
|
||||||
int get_current_log(LOG_INFO* linfo);
|
int get_current_log(LOG_INFO* linfo);
|
||||||
uint next_file_id();
|
uint next_file_id();
|
||||||
inline bool is_open() { return log_type != LOG_CLOSED; }
|
|
||||||
inline char* get_index_fname() { return index_file_name;}
|
inline char* get_index_fname() { return index_file_name;}
|
||||||
inline char* get_log_fname() { return log_file_name; }
|
inline char* get_log_fname() { return log_file_name; }
|
||||||
inline char* get_name() { return name; }
|
inline char* get_name() { return name; }
|
||||||
@ -416,7 +444,8 @@ public:
|
|||||||
|
|
||||||
class Log_to_file_event_handler: public Log_event_handler
|
class Log_to_file_event_handler: public Log_event_handler
|
||||||
{
|
{
|
||||||
MYSQL_LOG mysql_log, mysql_slow_log;
|
MYSQL_QUERY_LOG mysql_log;
|
||||||
|
MYSQL_QUERY_LOG mysql_slow_log;
|
||||||
bool is_initialized;
|
bool is_initialized;
|
||||||
public:
|
public:
|
||||||
Log_to_file_event_handler(): is_initialized(FALSE)
|
Log_to_file_event_handler(): is_initialized(FALSE)
|
||||||
|
@ -470,7 +470,7 @@ enum Int_event_type
|
|||||||
|
|
||||||
#ifndef MYSQL_CLIENT
|
#ifndef MYSQL_CLIENT
|
||||||
class String;
|
class String;
|
||||||
class MYSQL_LOG;
|
class MYSQL_BIN_LOG;
|
||||||
class THD;
|
class THD;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -1537,7 +1537,7 @@ extern char *default_tz_name;
|
|||||||
extern my_bool opt_large_pages;
|
extern my_bool opt_large_pages;
|
||||||
extern uint opt_large_page_size;
|
extern uint opt_large_page_size;
|
||||||
|
|
||||||
extern MYSQL_LOG mysql_bin_log;
|
extern MYSQL_BIN_LOG mysql_bin_log;
|
||||||
extern LOGGER logger;
|
extern LOGGER logger;
|
||||||
extern TABLE_LIST general_log, slow_log;
|
extern TABLE_LIST general_log, slow_log;
|
||||||
extern FILE *bootstrap_file;
|
extern FILE *bootstrap_file;
|
||||||
|
@ -2635,10 +2635,10 @@ static int init_common_variables(const char *conf_file_name, int argc,
|
|||||||
global_system_variables.time_zone= my_tz_SYSTEM;
|
global_system_variables.time_zone= my_tz_SYSTEM;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Init mutexes for the global MYSQL_LOG objects.
|
Init mutexes for the global MYSQL_BIN_LOG objects.
|
||||||
As safe_mutex depends on what MY_INIT() does, we can't init the mutexes of
|
As safe_mutex depends on what MY_INIT() does, we can't init the mutexes of
|
||||||
global MYSQL_LOGs in their constructors, because then they would be inited
|
global MYSQL_BIN_LOGs in their constructors, because then they would be
|
||||||
before MY_INIT(). So we do it here.
|
inited before MY_INIT(). So we do it here.
|
||||||
*/
|
*/
|
||||||
mysql_bin_log.init_pthread_objects();
|
mysql_bin_log.init_pthread_objects();
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@
|
|||||||
|
|
||||||
/* inline since it's called below */
|
/* inline since it's called below */
|
||||||
inline
|
inline
|
||||||
injector::transaction::transaction(MYSQL_LOG *log, THD *thd)
|
injector::transaction::transaction(MYSQL_BIN_LOG *log, THD *thd)
|
||||||
: m_state(START_STATE), m_thd(thd)
|
: m_state(START_STATE), m_thd(thd)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
|
@ -26,7 +26,7 @@
|
|||||||
|
|
||||||
/* Forward declarations */
|
/* Forward declarations */
|
||||||
class handler;
|
class handler;
|
||||||
class MYSQL_LOG;
|
class MYSQL_BIN_LOG;
|
||||||
class st_table;
|
class st_table;
|
||||||
|
|
||||||
typedef st_table TABLE;
|
typedef st_table TABLE;
|
||||||
@ -219,7 +219,7 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
/* Only the injector may construct these object */
|
/* Only the injector may construct these object */
|
||||||
transaction(MYSQL_LOG *, THD *);
|
transaction(MYSQL_BIN_LOG *, THD *);
|
||||||
|
|
||||||
void swap(transaction& o) {
|
void swap(transaction& o) {
|
||||||
/* std::swap(m_start_pos, o.m_start_pos); */
|
/* std::swap(m_start_pos, o.m_start_pos); */
|
||||||
|
@ -69,7 +69,7 @@ typedef struct st_relay_log_info
|
|||||||
Protected with internal locks.
|
Protected with internal locks.
|
||||||
Must get data_lock when resetting the logs.
|
Must get data_lock when resetting the logs.
|
||||||
*/
|
*/
|
||||||
MYSQL_LOG relay_log;
|
MYSQL_BIN_LOG relay_log;
|
||||||
LOG_INFO linfo;
|
LOG_INFO linfo;
|
||||||
IO_CACHE cache_buf,*cur_log;
|
IO_CACHE cache_buf,*cur_log;
|
||||||
|
|
||||||
|
@ -4658,7 +4658,7 @@ static Log_event* next_event(RELAY_LOG_INFO* rli)
|
|||||||
When the relay log is created when the I/O thread starts, easy: the
|
When the relay log is created when the I/O thread starts, easy: the
|
||||||
master will send the description event and we will queue it.
|
master will send the description event and we will queue it.
|
||||||
But if the relay log is created by new_file(): then the solution is:
|
But if the relay log is created by new_file(): then the solution is:
|
||||||
MYSQL_LOG::open() will write the buffered description event.
|
MYSQL_BIN_LOG::open() will write the buffered description event.
|
||||||
*/
|
*/
|
||||||
if ((ev=Log_event::read_log_event(cur_log,0,
|
if ((ev=Log_event::read_log_event(cur_log,0,
|
||||||
rli->relay_log.description_event_for_exec)))
|
rli->relay_log.description_event_for_exec)))
|
||||||
@ -4920,7 +4920,8 @@ err:
|
|||||||
Rotate a relay log (this is used only by FLUSH LOGS; the automatic rotation
|
Rotate a relay log (this is used only by FLUSH LOGS; the automatic rotation
|
||||||
because of size is simpler because when we do it we already have all relevant
|
because of size is simpler because when we do it we already have all relevant
|
||||||
locks; here we don't, so this function is mainly taking locks).
|
locks; here we don't, so this function is mainly taking locks).
|
||||||
Returns nothing as we cannot catch any error (MYSQL_LOG::new_file() is void).
|
Returns nothing as we cannot catch any error (MYSQL_BIN_LOG::new_file()
|
||||||
|
is void).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void rotate_relay_log(MASTER_INFO* mi)
|
void rotate_relay_log(MASTER_INFO* mi)
|
||||||
@ -4942,7 +4943,7 @@ void rotate_relay_log(MASTER_INFO* mi)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* If the relay log is closed, new_file() will do nothing. */
|
/* If the relay log is closed, new_file() will do nothing. */
|
||||||
rli->relay_log.new_file(1);
|
rli->relay_log.new_file();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
We harvest now, because otherwise BIN_LOG_HEADER_SIZE will not immediately
|
We harvest now, because otherwise BIN_LOG_HEADER_SIZE will not immediately
|
||||||
|
@ -73,7 +73,7 @@
|
|||||||
run_lock protects all information about the run state: slave_running, and the
|
run_lock protects all information about the run state: slave_running, and the
|
||||||
existence of the I/O thread (to stop/start it, you need this mutex).
|
existence of the I/O thread (to stop/start it, you need this mutex).
|
||||||
data_lock protects some moving members of the struct: counters (log name,
|
data_lock protects some moving members of the struct: counters (log name,
|
||||||
position) and relay log (MYSQL_LOG object).
|
position) and relay log (MYSQL_BIN_LOG object).
|
||||||
|
|
||||||
In RELAY_LOG_INFO: run_lock, data_lock
|
In RELAY_LOG_INFO: run_lock, data_lock
|
||||||
see MASTER_INFO
|
see MASTER_INFO
|
||||||
@ -81,7 +81,7 @@
|
|||||||
Order of acquisition: if you want to have LOCK_active_mi and a run_lock, you
|
Order of acquisition: if you want to have LOCK_active_mi and a run_lock, you
|
||||||
must acquire LOCK_active_mi first.
|
must acquire LOCK_active_mi first.
|
||||||
|
|
||||||
In MYSQL_LOG: LOCK_log, LOCK_index of the binlog and the relay log
|
In MYSQL_BIN_LOG: LOCK_log, LOCK_index of the binlog and the relay log
|
||||||
LOCK_log: when you write to it. LOCK_index: when you create/delete a binlog
|
LOCK_log: when you write to it. LOCK_index: when you create/delete a binlog
|
||||||
(so that you have to update the .index file).
|
(so that you have to update the .index file).
|
||||||
*/
|
*/
|
||||||
|
@ -61,7 +61,7 @@ TODO:
|
|||||||
|
|
||||||
/* The file extension */
|
/* The file extension */
|
||||||
#define CSV_EXT ".CSV" // The data file
|
#define CSV_EXT ".CSV" // The data file
|
||||||
#define CSN_EXT ".CSN" // Files used during repair
|
#define CSN_EXT ".CSN" // Files used during repair and update
|
||||||
#define CSM_EXT ".CSM" // Meta file
|
#define CSM_EXT ".CSM" // Meta file
|
||||||
|
|
||||||
|
|
||||||
@ -77,6 +77,53 @@ static int tina_init= 0;
|
|||||||
static handler *tina_create_handler(TABLE_SHARE *table, MEM_ROOT *mem_root);
|
static handler *tina_create_handler(TABLE_SHARE *table, MEM_ROOT *mem_root);
|
||||||
static int tina_init_func();
|
static int tina_init_func();
|
||||||
|
|
||||||
|
off_t Transparent_file::read_next()
|
||||||
|
{
|
||||||
|
off_t bytes_read;
|
||||||
|
|
||||||
|
/*
|
||||||
|
No need to seek here, as the file managed by Transparent_file class
|
||||||
|
always points to upper_bound byte
|
||||||
|
*/
|
||||||
|
if ((bytes_read= my_read(filedes, buff, buff_size, MYF(0))) == MY_FILE_ERROR)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
/* end of file */
|
||||||
|
if (!bytes_read)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
lower_bound= upper_bound;
|
||||||
|
upper_bound+= bytes_read;
|
||||||
|
|
||||||
|
return lower_bound;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
char Transparent_file::get_value(off_t offset)
|
||||||
|
{
|
||||||
|
off_t bytes_read;
|
||||||
|
|
||||||
|
/* check boundaries */
|
||||||
|
if ((lower_bound <= offset) && (offset < upper_bound))
|
||||||
|
return buff[offset - lower_bound];
|
||||||
|
else
|
||||||
|
{
|
||||||
|
VOID(my_seek(filedes, offset, MY_SEEK_SET, MYF(0)));
|
||||||
|
/* read appropriate portion of the file */
|
||||||
|
if ((bytes_read= my_read(filedes, buff, buff_size,
|
||||||
|
MYF(0))) == MY_FILE_ERROR)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
lower_bound= offset;
|
||||||
|
upper_bound= lower_bound + bytes_read;
|
||||||
|
|
||||||
|
/* end of file */
|
||||||
|
if (upper_bound == offset)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return buff[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
handlerton tina_hton;
|
handlerton tina_hton;
|
||||||
|
|
||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
@ -92,7 +139,7 @@ int sort_set (tina_set *a, tina_set *b)
|
|||||||
We assume that intervals do not intersect. So, it is enought to compare
|
We assume that intervals do not intersect. So, it is enought to compare
|
||||||
any two points. Here we take start of intervals for comparison.
|
any two points. Here we take start of intervals for comparison.
|
||||||
*/
|
*/
|
||||||
return ( a->begin > b->begin ? -1 : ( a->begin < b->begin ? 1 : 0 ) );
|
return ( a->begin > b->begin ? 1 : ( a->begin < b->begin ? -1 : 0 ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
static byte* tina_get_key(TINA_SHARE *share,uint *length,
|
static byte* tina_get_key(TINA_SHARE *share,uint *length,
|
||||||
@ -102,55 +149,6 @@ static byte* tina_get_key(TINA_SHARE *share,uint *length,
|
|||||||
return (byte*) share->table_name;
|
return (byte*) share->table_name;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
Reloads the mmap file.
|
|
||||||
*/
|
|
||||||
int get_mmap(TINA_SHARE *share, int write)
|
|
||||||
{
|
|
||||||
DBUG_ENTER("ha_tina::get_mmap");
|
|
||||||
#ifdef __NETWARE__
|
|
||||||
my_message(errno, "Sorry, no mmap() on Netware", 0);
|
|
||||||
DBUG_ASSERT(0);
|
|
||||||
DBUG_RETURN(1);
|
|
||||||
#else
|
|
||||||
if (share->mapped_file && my_munmap(share->mapped_file,
|
|
||||||
share->file_stat.st_size))
|
|
||||||
DBUG_RETURN(1);
|
|
||||||
|
|
||||||
if (my_fstat(share->data_file, &share->file_stat, MYF(MY_WME)) == -1)
|
|
||||||
DBUG_RETURN(1);
|
|
||||||
|
|
||||||
if (share->file_stat.st_size)
|
|
||||||
{
|
|
||||||
if (write)
|
|
||||||
share->mapped_file= (byte *)my_mmap(NULL, share->file_stat.st_size,
|
|
||||||
PROT_READ|PROT_WRITE, MAP_SHARED,
|
|
||||||
share->data_file, 0);
|
|
||||||
else
|
|
||||||
share->mapped_file= (byte *)my_mmap(NULL, share->file_stat.st_size,
|
|
||||||
PROT_READ, MAP_PRIVATE,
|
|
||||||
share->data_file, 0);
|
|
||||||
if ((share->mapped_file == MAP_FAILED))
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
Bad idea you think? See the problem is that nothing actually checks
|
|
||||||
the return value of ::rnd_init(), so tossing an error is about
|
|
||||||
it for us.
|
|
||||||
Never going to happen right? :)
|
|
||||||
*/
|
|
||||||
my_message(errno, "Woops, blew up opening a mapped file", 0);
|
|
||||||
DBUG_ASSERT(0);
|
|
||||||
DBUG_RETURN(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
share->mapped_file= NULL;
|
|
||||||
|
|
||||||
DBUG_RETURN(0);
|
|
||||||
#endif /* __NETWARE__ */
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int tina_init_func()
|
static int tina_init_func()
|
||||||
{
|
{
|
||||||
if (!tina_init)
|
if (!tina_init)
|
||||||
@ -191,6 +189,7 @@ static TINA_SHARE *get_share(const char *table_name, TABLE *table)
|
|||||||
{
|
{
|
||||||
TINA_SHARE *share;
|
TINA_SHARE *share;
|
||||||
char meta_file_name[FN_REFLEN];
|
char meta_file_name[FN_REFLEN];
|
||||||
|
MY_STAT file_stat; /* Stat information for the data file */
|
||||||
char *tmp_name;
|
char *tmp_name;
|
||||||
uint length;
|
uint length;
|
||||||
|
|
||||||
@ -223,6 +222,8 @@ static TINA_SHARE *get_share(const char *table_name, TABLE *table)
|
|||||||
share->table_name= tmp_name;
|
share->table_name= tmp_name;
|
||||||
share->crashed= FALSE;
|
share->crashed= FALSE;
|
||||||
share->rows_recorded= 0;
|
share->rows_recorded= 0;
|
||||||
|
share->update_file_opened= FALSE;
|
||||||
|
share->tina_write_opened= FALSE;
|
||||||
strmov(share->table_name, table_name);
|
strmov(share->table_name, table_name);
|
||||||
fn_format(share->data_file_name, table_name, "", CSV_EXT,
|
fn_format(share->data_file_name, table_name, "", CSV_EXT,
|
||||||
MY_REPLACE_EXT|MY_UNPACK_FILENAME);
|
MY_REPLACE_EXT|MY_UNPACK_FILENAME);
|
||||||
@ -244,33 +245,21 @@ static TINA_SHARE *get_share(const char *table_name, TABLE *table)
|
|||||||
share->crashed= TRUE;
|
share->crashed= TRUE;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
After we read, we set the file to dirty. When we close, we will do the
|
If the meta file will not open we assume it is crashed and
|
||||||
opposite. If the meta file will not open we assume it is crashed and
|
|
||||||
mark it as such.
|
mark it as such.
|
||||||
*/
|
*/
|
||||||
if (read_meta_file(share->meta_file, &share->rows_recorded))
|
if (read_meta_file(share->meta_file, &share->rows_recorded))
|
||||||
share->crashed= TRUE;
|
share->crashed= TRUE;
|
||||||
else
|
|
||||||
(void)write_meta_file(share->meta_file, share->rows_recorded, TRUE);
|
|
||||||
|
|
||||||
if ((share->data_file= my_open(share->data_file_name, O_RDWR|O_APPEND,
|
if (my_stat(share->data_file_name, &file_stat, MYF(MY_WME)) == NULL)
|
||||||
MYF(0))) == -1)
|
|
||||||
goto error2;
|
goto error2;
|
||||||
|
share->saved_data_file_length= file_stat.st_size;
|
||||||
share->mapped_file= NULL; // We don't know the state as we just allocated it
|
|
||||||
if (get_mmap(share, 0) > 0)
|
|
||||||
goto error3;
|
|
||||||
|
|
||||||
/* init file length value used by readers */
|
|
||||||
share->saved_data_file_length= share->file_stat.st_size;
|
|
||||||
}
|
}
|
||||||
share->use_count++;
|
share->use_count++;
|
||||||
pthread_mutex_unlock(&tina_mutex);
|
pthread_mutex_unlock(&tina_mutex);
|
||||||
|
|
||||||
return share;
|
return share;
|
||||||
|
|
||||||
error3:
|
|
||||||
my_close(share->data_file,MYF(0));
|
|
||||||
error2:
|
error2:
|
||||||
thr_lock_delete(&share->lock);
|
thr_lock_delete(&share->lock);
|
||||||
pthread_mutex_destroy(&share->mutex);
|
pthread_mutex_destroy(&share->mutex);
|
||||||
@ -398,6 +387,30 @@ bool ha_tina::check_and_repair(THD *thd)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int ha_tina::init_tina_writer()
|
||||||
|
{
|
||||||
|
DBUG_ENTER("ha_tina::init_tina_writer");
|
||||||
|
|
||||||
|
/*
|
||||||
|
Mark the file as crashed. We will set the flag back when we close
|
||||||
|
the file. In the case of the crash it will remain marked crashed,
|
||||||
|
which enforce recovery.
|
||||||
|
*/
|
||||||
|
(void)write_meta_file(share->meta_file, share->rows_recorded, TRUE);
|
||||||
|
|
||||||
|
if ((share->tina_write_filedes=
|
||||||
|
my_open(share->data_file_name, O_RDWR|O_APPEND, MYF(0))) == -1)
|
||||||
|
{
|
||||||
|
DBUG_PRINT("info", ("Could not open tina file writes"));
|
||||||
|
share->crashed= TRUE;
|
||||||
|
DBUG_RETURN(1);
|
||||||
|
}
|
||||||
|
share->tina_write_opened= TRUE;
|
||||||
|
|
||||||
|
DBUG_RETURN(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool ha_tina::is_crashed() const
|
bool ha_tina::is_crashed() const
|
||||||
{
|
{
|
||||||
DBUG_ENTER("ha_tina::is_crashed");
|
DBUG_ENTER("ha_tina::is_crashed");
|
||||||
@ -418,10 +431,13 @@ static int free_share(TINA_SHARE *share)
|
|||||||
share->crashed ? TRUE :FALSE);
|
share->crashed ? TRUE :FALSE);
|
||||||
if (my_close(share->meta_file, MYF(0)))
|
if (my_close(share->meta_file, MYF(0)))
|
||||||
result_code= 1;
|
result_code= 1;
|
||||||
if (share->mapped_file)
|
if (share->tina_write_opened)
|
||||||
my_munmap(share->mapped_file, share->file_stat.st_size);
|
{
|
||||||
share->mapped_file= NULL;
|
if (my_close(share->tina_write_filedes, MYF(0)))
|
||||||
result_code= my_close(share->data_file,MYF(0));
|
result_code= 1;
|
||||||
|
share->tina_write_opened= FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
hash_delete(&tina_open_tables, (byte*) share);
|
hash_delete(&tina_open_tables, (byte*) share);
|
||||||
thr_lock_delete(&share->lock);
|
thr_lock_delete(&share->lock);
|
||||||
pthread_mutex_destroy(&share->mutex);
|
pthread_mutex_destroy(&share->mutex);
|
||||||
@ -437,30 +453,41 @@ int tina_end(ha_panic_function type)
|
|||||||
return tina_done_func();
|
return tina_done_func();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
Finds the end of a line.
|
|
||||||
Supports DOS, Unix, or Mac OS line endings.
|
|
||||||
*/
|
|
||||||
byte * find_eoln(byte *data, off_t begin, off_t end, int *eoln_len)
|
|
||||||
{
|
|
||||||
off_t dataend= begin;
|
|
||||||
*eoln_len= 0;
|
|
||||||
|
|
||||||
for (off_t x= begin; x < end; x++)
|
|
||||||
if (data[x] == '\r' || data[x] == '\n')
|
|
||||||
(*eoln_len)++;
|
|
||||||
else if (!(*eoln_len))
|
|
||||||
dataend++;
|
|
||||||
else
|
|
||||||
return data+dataend;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
if we only have one record in the file then our for loop will break
|
This function finds the end of a line and returns the length
|
||||||
before we return. we should still have seen end of line markers and
|
of the line ending.
|
||||||
so we just return the line here
|
|
||||||
*/
|
We support three kinds of line endings:
|
||||||
if (*eoln_len > 0)
|
'\r' -- Old Mac OS line ending
|
||||||
return data+dataend;
|
'\n' -- Traditional Unix and Mac OS X line ending
|
||||||
|
'\r''\n' -- DOS\Windows line ending
|
||||||
|
*/
|
||||||
|
|
||||||
|
off_t find_eoln_buff(Transparent_file *data_buff, off_t begin,
|
||||||
|
off_t end, int *eoln_len)
|
||||||
|
{
|
||||||
|
*eoln_len= 0;
|
||||||
|
|
||||||
|
for (off_t x= begin; x < end; x++)
|
||||||
|
{
|
||||||
|
/* Unix (includes Mac OS X) */
|
||||||
|
if (data_buff->get_value(x) == '\n')
|
||||||
|
*eoln_len= 1;
|
||||||
|
else
|
||||||
|
if (data_buff->get_value(x) == '\r') // Mac or Dos
|
||||||
|
{
|
||||||
|
/* old Mac line ending */
|
||||||
|
if (x + 1 == end || (data_buff->get_value(x + 1) != '\n'))
|
||||||
|
*eoln_len= 1;
|
||||||
|
else // DOS style ending
|
||||||
|
*eoln_len= 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*eoln_len) // end of line was found
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -478,12 +505,13 @@ ha_tina::ha_tina(TABLE_SHARE *table_arg)
|
|||||||
They are not probably completely right.
|
They are not probably completely right.
|
||||||
*/
|
*/
|
||||||
current_position(0), next_position(0), local_saved_data_file_length(0),
|
current_position(0), next_position(0), local_saved_data_file_length(0),
|
||||||
chain_alloced(0), chain_size(DEFAULT_CHAIN_LENGTH),
|
file_buff(0), chain_alloced(0), chain_size(DEFAULT_CHAIN_LENGTH),
|
||||||
records_is_known(0)
|
records_is_known(0)
|
||||||
{
|
{
|
||||||
/* Set our original buffers from pre-allocated memory */
|
/* Set our original buffers from pre-allocated memory */
|
||||||
buffer.set((char*)byte_buffer, IO_SIZE, system_charset_info);
|
buffer.set((char*)byte_buffer, IO_SIZE, system_charset_info);
|
||||||
chain= chain_buffer;
|
chain= chain_buffer;
|
||||||
|
file_buff= new Transparent_file();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -609,20 +637,18 @@ int ha_tina::chain_append()
|
|||||||
*/
|
*/
|
||||||
int ha_tina::find_current_row(byte *buf)
|
int ha_tina::find_current_row(byte *buf)
|
||||||
{
|
{
|
||||||
byte *mapped_ptr;
|
off_t end_offset, curr_offset= current_position;
|
||||||
byte *end_ptr;
|
|
||||||
int eoln_len;
|
int eoln_len;
|
||||||
my_bitmap_map *org_bitmap;
|
my_bitmap_map *org_bitmap;
|
||||||
DBUG_ENTER("ha_tina::find_current_row");
|
DBUG_ENTER("ha_tina::find_current_row");
|
||||||
|
|
||||||
mapped_ptr= (byte *)share->mapped_file + current_position;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
We do not read further then local_saved_data_file_length in order
|
We do not read further then local_saved_data_file_length in order
|
||||||
not to conflict with undergoing concurrent insert.
|
not to conflict with undergoing concurrent insert.
|
||||||
*/
|
*/
|
||||||
if ((end_ptr= find_eoln(share->mapped_file, current_position,
|
if ((end_offset=
|
||||||
local_saved_data_file_length, &eoln_len)) == 0)
|
find_eoln_buff(file_buff, current_position,
|
||||||
|
local_saved_data_file_length, &eoln_len)) == 0)
|
||||||
DBUG_RETURN(HA_ERR_END_OF_FILE);
|
DBUG_RETURN(HA_ERR_END_OF_FILE);
|
||||||
|
|
||||||
/* Avoid asserts in ::store() for columns that are not going to be updated */
|
/* Avoid asserts in ::store() for columns that are not going to be updated */
|
||||||
@ -631,36 +657,39 @@ int ha_tina::find_current_row(byte *buf)
|
|||||||
for (Field **field=table->field ; *field ; field++)
|
for (Field **field=table->field ; *field ; field++)
|
||||||
{
|
{
|
||||||
buffer.length(0);
|
buffer.length(0);
|
||||||
if (*mapped_ptr == '"')
|
if (file_buff->get_value(curr_offset) == '"')
|
||||||
mapped_ptr++; // Increment past the first quote
|
curr_offset++; // Incrementpast the first quote
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
dbug_tmp_restore_column_map(table->write_set, org_bitmap);
|
dbug_tmp_restore_column_map(table->write_set, org_bitmap);
|
||||||
DBUG_RETURN(HA_ERR_CRASHED_ON_USAGE);
|
DBUG_RETURN(HA_ERR_CRASHED_ON_USAGE);
|
||||||
}
|
}
|
||||||
for(;mapped_ptr != end_ptr; mapped_ptr++)
|
for(;curr_offset != end_offset; curr_offset++)
|
||||||
{
|
{
|
||||||
// Need to convert line feeds!
|
// Need to convert line feeds!
|
||||||
if (*mapped_ptr == '"' &&
|
if (file_buff->get_value(curr_offset) == '"' &&
|
||||||
(((mapped_ptr[1] == ',') && (mapped_ptr[2] == '"')) ||
|
(((file_buff->get_value(curr_offset + 1) == ',') &&
|
||||||
(mapped_ptr == end_ptr -1 )))
|
(file_buff->get_value(curr_offset + 2) == '"')) ||
|
||||||
|
(curr_offset == end_offset -1 )))
|
||||||
{
|
{
|
||||||
mapped_ptr += 2; // Move past the , and the "
|
curr_offset+= 2; // Move past the , and the "
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (*mapped_ptr == '\\' && mapped_ptr != (end_ptr - 1))
|
if (file_buff->get_value(curr_offset) == '\\' &&
|
||||||
|
curr_offset != (end_offset - 1))
|
||||||
{
|
{
|
||||||
mapped_ptr++;
|
curr_offset++;
|
||||||
if (*mapped_ptr == 'r')
|
if (file_buff->get_value(curr_offset) == 'r')
|
||||||
buffer.append('\r');
|
buffer.append('\r');
|
||||||
else if (*mapped_ptr == 'n' )
|
else if (file_buff->get_value(curr_offset) == 'n' )
|
||||||
buffer.append('\n');
|
buffer.append('\n');
|
||||||
else if ((*mapped_ptr == '\\') || (*mapped_ptr == '"'))
|
else if ((file_buff->get_value(curr_offset) == '\\') ||
|
||||||
buffer.append(*mapped_ptr);
|
(file_buff->get_value(curr_offset) == '"'))
|
||||||
|
buffer.append(file_buff->get_value(curr_offset));
|
||||||
else /* This could only happed with an externally created file */
|
else /* This could only happed with an externally created file */
|
||||||
{
|
{
|
||||||
buffer.append('\\');
|
buffer.append('\\');
|
||||||
buffer.append(*mapped_ptr);
|
buffer.append(file_buff->get_value(curr_offset));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else // ordinary symbol
|
else // ordinary symbol
|
||||||
@ -669,18 +698,18 @@ int ha_tina::find_current_row(byte *buf)
|
|||||||
We are at final symbol and no last quote was found =>
|
We are at final symbol and no last quote was found =>
|
||||||
we are working with a damaged file.
|
we are working with a damaged file.
|
||||||
*/
|
*/
|
||||||
if (mapped_ptr == end_ptr -1)
|
if (curr_offset == end_offset - 1)
|
||||||
{
|
{
|
||||||
dbug_tmp_restore_column_map(table->write_set, org_bitmap);
|
dbug_tmp_restore_column_map(table->write_set, org_bitmap);
|
||||||
DBUG_RETURN(HA_ERR_CRASHED_ON_USAGE);
|
DBUG_RETURN(HA_ERR_CRASHED_ON_USAGE);
|
||||||
}
|
}
|
||||||
buffer.append(*mapped_ptr);
|
buffer.append(file_buff->get_value(curr_offset));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (bitmap_is_set(table->read_set, (*field)->field_index))
|
if (bitmap_is_set(table->read_set, (*field)->field_index))
|
||||||
(*field)->store(buffer.ptr(), buffer.length(), system_charset_info);
|
(*field)->store(buffer.ptr(), buffer.length(), system_charset_info);
|
||||||
}
|
}
|
||||||
next_position= (end_ptr - share->mapped_file)+eoln_len;
|
next_position= end_offset + eoln_len;
|
||||||
/* Maybe use \N for null? */
|
/* Maybe use \N for null? */
|
||||||
memset(buf, 0, table->s->null_bytes); /* We do not implement nulls! */
|
memset(buf, 0, table->s->null_bytes); /* We do not implement nulls! */
|
||||||
dbug_tmp_restore_column_map(table->write_set, org_bitmap);
|
dbug_tmp_restore_column_map(table->write_set, org_bitmap);
|
||||||
@ -779,7 +808,7 @@ void ha_tina::get_status()
|
|||||||
void ha_tina::update_status()
|
void ha_tina::update_status()
|
||||||
{
|
{
|
||||||
/* correct local_saved_data_file_length for writers */
|
/* correct local_saved_data_file_length for writers */
|
||||||
share->saved_data_file_length= share->file_stat.st_size;
|
share->saved_data_file_length= local_saved_data_file_length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -830,6 +859,9 @@ int ha_tina::open(const char *name, int mode, uint open_options)
|
|||||||
DBUG_RETURN(HA_ERR_CRASHED_ON_USAGE);
|
DBUG_RETURN(HA_ERR_CRASHED_ON_USAGE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((data_file= my_open(share->data_file_name, O_RDONLY, MYF(0))) == -1)
|
||||||
|
DBUG_RETURN(0);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Init locking. Pass handler object to the locking routines,
|
Init locking. Pass handler object to the locking routines,
|
||||||
so that they could save/update local_saved_data_file_length value
|
so that they could save/update local_saved_data_file_length value
|
||||||
@ -848,12 +880,14 @@ int ha_tina::open(const char *name, int mode, uint open_options)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
Close a database file. We remove ourselves from the shared strucutre.
|
Close a database file. We remove ourselves from the shared strucutre.
|
||||||
If it is empty we destroy it and free the mapped file.
|
If it is empty we destroy it.
|
||||||
*/
|
*/
|
||||||
int ha_tina::close(void)
|
int ha_tina::close(void)
|
||||||
{
|
{
|
||||||
|
int rc= 0;
|
||||||
DBUG_ENTER("ha_tina::close");
|
DBUG_ENTER("ha_tina::close");
|
||||||
DBUG_RETURN(free_share(share));
|
rc= my_close(data_file, MYF(0));
|
||||||
|
DBUG_RETURN(free_share(share) || rc);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -876,22 +910,17 @@ int ha_tina::write_row(byte * buf)
|
|||||||
|
|
||||||
size= encode_quote(buf);
|
size= encode_quote(buf);
|
||||||
|
|
||||||
if (my_write(share->data_file, (byte*)buffer.ptr(), size,
|
if (!share->tina_write_opened)
|
||||||
|
if (init_tina_writer())
|
||||||
|
DBUG_RETURN(-1);
|
||||||
|
|
||||||
|
/* use pwrite, as concurrent reader could have changed the position */
|
||||||
|
if (my_write(share->tina_write_filedes, (byte*)buffer.ptr(), size,
|
||||||
MYF(MY_WME | MY_NABP)))
|
MYF(MY_WME | MY_NABP)))
|
||||||
DBUG_RETURN(-1);
|
DBUG_RETURN(-1);
|
||||||
|
|
||||||
/*
|
|
||||||
Ok, this is means that we will be doing potentially bad things
|
|
||||||
during a bulk insert on some OS'es. What we need is a cleanup
|
|
||||||
call for ::write_row that would let us fix up everything after the bulk
|
|
||||||
insert. The archive handler does this with an extra mutx call, which
|
|
||||||
might be a solution for this.
|
|
||||||
*/
|
|
||||||
if (get_mmap(share, 0) > 0)
|
|
||||||
DBUG_RETURN(-1);
|
|
||||||
|
|
||||||
/* update local copy of the max position to see our own changes */
|
/* update local copy of the max position to see our own changes */
|
||||||
local_saved_data_file_length= share->file_stat.st_size;
|
local_saved_data_file_length+= size;
|
||||||
|
|
||||||
/* update shared info */
|
/* update shared info */
|
||||||
pthread_mutex_lock(&share->mutex);
|
pthread_mutex_lock(&share->mutex);
|
||||||
@ -906,6 +935,23 @@ int ha_tina::write_row(byte * buf)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int ha_tina::open_update_temp_file_if_needed()
|
||||||
|
{
|
||||||
|
char updated_fname[FN_REFLEN];
|
||||||
|
|
||||||
|
if (!share->update_file_opened)
|
||||||
|
{
|
||||||
|
if ((update_temp_file=
|
||||||
|
my_create(fn_format(updated_fname, share->table_name,
|
||||||
|
"", CSN_EXT,
|
||||||
|
MY_REPLACE_EXT | MY_UNPACK_FILENAME),
|
||||||
|
0, O_RDWR | O_TRUNC, MYF(MY_WME))) < 0)
|
||||||
|
return 1;
|
||||||
|
share->update_file_opened= TRUE;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
This is called for an update.
|
This is called for an update.
|
||||||
Make sure you put in code to increment the auto increment, also
|
Make sure you put in code to increment the auto increment, also
|
||||||
@ -929,16 +975,16 @@ int ha_tina::update_row(const byte * old_data, byte * new_data)
|
|||||||
if (chain_append())
|
if (chain_append())
|
||||||
DBUG_RETURN(-1);
|
DBUG_RETURN(-1);
|
||||||
|
|
||||||
if (my_write(share->data_file, (byte*)buffer.ptr(), size,
|
if (open_update_temp_file_if_needed())
|
||||||
|
DBUG_RETURN(-1);
|
||||||
|
|
||||||
|
if (my_write(update_temp_file, (byte*)buffer.ptr(), size,
|
||||||
MYF(MY_WME | MY_NABP)))
|
MYF(MY_WME | MY_NABP)))
|
||||||
DBUG_RETURN(-1);
|
DBUG_RETURN(-1);
|
||||||
|
|
||||||
/* UPDATE should never happen on the log tables */
|
/* UPDATE should never happen on the log tables */
|
||||||
DBUG_ASSERT(!share->is_log_table);
|
DBUG_ASSERT(!share->is_log_table);
|
||||||
|
|
||||||
/* update local copy of the max position to see our own changes */
|
|
||||||
local_saved_data_file_length= share->file_stat.st_size;
|
|
||||||
|
|
||||||
DBUG_RETURN(0);
|
DBUG_RETURN(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1004,6 +1050,8 @@ int ha_tina::rnd_init(bool scan)
|
|||||||
{
|
{
|
||||||
DBUG_ENTER("ha_tina::rnd_init");
|
DBUG_ENTER("ha_tina::rnd_init");
|
||||||
|
|
||||||
|
/* set buffer to the beginning of the file */
|
||||||
|
file_buff->init_buff(data_file);
|
||||||
if (share->crashed)
|
if (share->crashed)
|
||||||
DBUG_RETURN(HA_ERR_CRASHED_ON_USAGE);
|
DBUG_RETURN(HA_ERR_CRASHED_ON_USAGE);
|
||||||
|
|
||||||
@ -1011,11 +1059,6 @@ int ha_tina::rnd_init(bool scan)
|
|||||||
stats.records= 0;
|
stats.records= 0;
|
||||||
records_is_known= 0;
|
records_is_known= 0;
|
||||||
chain_ptr= chain;
|
chain_ptr= chain;
|
||||||
#ifdef HAVE_MADVISE
|
|
||||||
if (scan)
|
|
||||||
(void) madvise(share->mapped_file, share->file_stat.st_size,
|
|
||||||
MADV_SEQUENTIAL);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
DBUG_RETURN(0);
|
DBUG_RETURN(0);
|
||||||
}
|
}
|
||||||
@ -1045,8 +1088,11 @@ int ha_tina::rnd_next(byte *buf)
|
|||||||
ha_statistic_increment(&SSV::ha_read_rnd_next_count);
|
ha_statistic_increment(&SSV::ha_read_rnd_next_count);
|
||||||
|
|
||||||
current_position= next_position;
|
current_position= next_position;
|
||||||
if (!share->mapped_file)
|
|
||||||
|
/* don't scan an empty file */
|
||||||
|
if (!local_saved_data_file_length)
|
||||||
DBUG_RETURN(HA_ERR_END_OF_FILE);
|
DBUG_RETURN(HA_ERR_END_OF_FILE);
|
||||||
|
|
||||||
if ((rc= find_current_row(buf)))
|
if ((rc= find_current_row(buf)))
|
||||||
DBUG_RETURN(rc);
|
DBUG_RETURN(rc);
|
||||||
|
|
||||||
@ -1115,6 +1161,22 @@ int ha_tina::extra(enum ha_extra_function operation)
|
|||||||
DBUG_RETURN(0);
|
DBUG_RETURN(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Set end_pos to the last valid byte of continuous area, closest
|
||||||
|
to the given "hole", stored in the buffer. "Valid" here means,
|
||||||
|
not listed in the chain of deleted records ("holes").
|
||||||
|
*/
|
||||||
|
bool ha_tina::get_write_pos(off_t *end_pos, tina_set *closest_hole)
|
||||||
|
{
|
||||||
|
if (closest_hole == chain_ptr) /* no more chains */
|
||||||
|
*end_pos= file_buff->end();
|
||||||
|
else
|
||||||
|
*end_pos= min(file_buff->end(),
|
||||||
|
closest_hole->begin);
|
||||||
|
return (closest_hole != chain_ptr) && (*end_pos == closest_hole->begin);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Called after each table scan. In particular after deletes,
|
Called after each table scan. In particular after deletes,
|
||||||
and updates. In the last case we employ chain of deleted
|
and updates. In the last case we employ chain of deleted
|
||||||
@ -1123,53 +1185,107 @@ int ha_tina::extra(enum ha_extra_function operation)
|
|||||||
*/
|
*/
|
||||||
int ha_tina::rnd_end()
|
int ha_tina::rnd_end()
|
||||||
{
|
{
|
||||||
|
char updated_fname[FN_REFLEN];
|
||||||
|
off_t file_buffer_start= 0;
|
||||||
DBUG_ENTER("ha_tina::rnd_end");
|
DBUG_ENTER("ha_tina::rnd_end");
|
||||||
|
|
||||||
records_is_known= 1;
|
records_is_known= 1;
|
||||||
|
|
||||||
/* First position will be truncate position, second will be increment */
|
|
||||||
if ((chain_ptr - chain) > 0)
|
if ((chain_ptr - chain) > 0)
|
||||||
{
|
{
|
||||||
tina_set *ptr;
|
tina_set *ptr= chain;
|
||||||
size_t length;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Setting up writable map, this will contain all of the data after the
|
Re-read the beginning of a file (as the buffer should point to the
|
||||||
get_mmap call that we have added to the file.
|
end of file after the scan).
|
||||||
*/
|
*/
|
||||||
if (get_mmap(share, 1) > 0)
|
file_buff->init_buff(data_file);
|
||||||
DBUG_RETURN(-1);
|
|
||||||
length= share->file_stat.st_size;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
The sort handles updates/deletes with random orders.
|
The sort is needed when there were updates/deletes with random orders.
|
||||||
It also sorts so that we move the final blocks to the
|
It sorts so that we move the firts blocks to the beginning.
|
||||||
beginning so that we move the smallest amount of data possible.
|
|
||||||
*/
|
*/
|
||||||
qsort(chain, (size_t)(chain_ptr - chain), sizeof(tina_set),
|
qsort(chain, (size_t)(chain_ptr - chain), sizeof(tina_set),
|
||||||
(qsort_cmp)sort_set);
|
(qsort_cmp)sort_set);
|
||||||
for (ptr= chain; ptr < chain_ptr; ptr++)
|
|
||||||
|
off_t write_begin= 0, write_end;
|
||||||
|
|
||||||
|
/* create the file to write updated table if it wasn't yet created */
|
||||||
|
if (open_update_temp_file_if_needed())
|
||||||
|
DBUG_RETURN(-1);
|
||||||
|
|
||||||
|
/* write the file with updated info */
|
||||||
|
while ((file_buffer_start != -1)) // while not end of file
|
||||||
{
|
{
|
||||||
memmove(share->mapped_file + ptr->begin, share->mapped_file + ptr->end,
|
bool in_hole= get_write_pos(&write_end, ptr);
|
||||||
length - (size_t)ptr->end);
|
|
||||||
length= length - (size_t)(ptr->end - ptr->begin);
|
/* if there is something to write, write it */
|
||||||
|
if ((write_end - write_begin) &&
|
||||||
|
(my_write(update_temp_file,
|
||||||
|
(byte*)(file_buff->ptr() +
|
||||||
|
(write_begin - file_buff->start())),
|
||||||
|
write_end - write_begin, MYF_RW)))
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
if (in_hole)
|
||||||
|
{
|
||||||
|
/* skip hole */
|
||||||
|
while (file_buff->end() <= ptr->end && file_buffer_start != -1)
|
||||||
|
file_buffer_start= file_buff->read_next();
|
||||||
|
write_begin= ptr->end;
|
||||||
|
ptr++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
write_begin= write_end;
|
||||||
|
|
||||||
|
if (write_end == file_buff->end())
|
||||||
|
file_buffer_start= file_buff->read_next(); /* shift the buffer */
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Unmap the file before the new size is set */
|
if (my_sync(update_temp_file, MYF(MY_WME)) ||
|
||||||
if (my_munmap(share->mapped_file, share->file_stat.st_size))
|
my_close(update_temp_file, MYF(0)))
|
||||||
DBUG_RETURN(-1);
|
|
||||||
/* We set it to null so that get_mmap() won't try to unmap it */
|
|
||||||
share->mapped_file= NULL;
|
|
||||||
|
|
||||||
/* Set the file to the new size */
|
|
||||||
if (my_chsize(share->data_file, length, 0, MYF(MY_WME)))
|
|
||||||
DBUG_RETURN(-1);
|
DBUG_RETURN(-1);
|
||||||
|
|
||||||
if (get_mmap(share, 0) > 0)
|
share->update_file_opened= FALSE;
|
||||||
|
|
||||||
|
if (share->tina_write_opened)
|
||||||
|
{
|
||||||
|
if (my_close(share->tina_write_filedes, MYF(0)))
|
||||||
|
DBUG_RETURN(-1);
|
||||||
|
/*
|
||||||
|
Mark that the writer fd is closed, so that init_tina_writer()
|
||||||
|
will reopen it later.
|
||||||
|
*/
|
||||||
|
share->tina_write_opened= FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Close opened fildes's. Then move updated file in place
|
||||||
|
of the old datafile.
|
||||||
|
*/
|
||||||
|
if (my_close(data_file, MYF(0)) ||
|
||||||
|
my_rename(fn_format(updated_fname, share->table_name, "", CSN_EXT,
|
||||||
|
MY_REPLACE_EXT | MY_UNPACK_FILENAME),
|
||||||
|
share->data_file_name, MYF(0)))
|
||||||
DBUG_RETURN(-1);
|
DBUG_RETURN(-1);
|
||||||
|
|
||||||
|
/* Open the file again */
|
||||||
|
if (((data_file= my_open(share->data_file_name, O_RDONLY, MYF(0))) == -1))
|
||||||
|
DBUG_RETURN(-1);
|
||||||
|
/*
|
||||||
|
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.
|
||||||
|
Here we record this fact to the meta-file.
|
||||||
|
*/
|
||||||
|
(void)write_meta_file(share->meta_file, share->rows_recorded, FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
DBUG_RETURN(0);
|
DBUG_RETURN(0);
|
||||||
|
error:
|
||||||
|
my_close(update_temp_file, MYF(0));
|
||||||
|
share->update_file_opened= FALSE;
|
||||||
|
DBUG_RETURN(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1198,10 +1314,11 @@ int ha_tina::repair(THD* thd, HA_CHECK_OPT* check_opt)
|
|||||||
File repair_file;
|
File repair_file;
|
||||||
int rc;
|
int rc;
|
||||||
ha_rows rows_repaired= 0;
|
ha_rows rows_repaired= 0;
|
||||||
|
off_t write_begin= 0, write_end;
|
||||||
DBUG_ENTER("ha_tina::repair");
|
DBUG_ENTER("ha_tina::repair");
|
||||||
|
|
||||||
/* empty file */
|
/* empty file */
|
||||||
if (!share->mapped_file)
|
if (!share->saved_data_file_length)
|
||||||
{
|
{
|
||||||
share->rows_recorded= 0;
|
share->rows_recorded= 0;
|
||||||
goto end;
|
goto end;
|
||||||
@ -1212,12 +1329,15 @@ int ha_tina::repair(THD* thd, HA_CHECK_OPT* check_opt)
|
|||||||
if (!(buf= (byte*) my_malloc(table->s->reclength, MYF(MY_WME))))
|
if (!(buf= (byte*) my_malloc(table->s->reclength, MYF(MY_WME))))
|
||||||
DBUG_RETURN(HA_ERR_OUT_OF_MEM);
|
DBUG_RETURN(HA_ERR_OUT_OF_MEM);
|
||||||
|
|
||||||
|
/* position buffer to the start of the file */
|
||||||
|
file_buff->init_buff(data_file);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Local_saved_data_file_length is initialized during the lock phase.
|
Local_saved_data_file_length is initialized during the lock phase.
|
||||||
Sometimes this is not getting executed before ::repair (e.g. for
|
Sometimes this is not getting executed before ::repair (e.g. for
|
||||||
the log tables). We set it manually here.
|
the log tables). We set it manually here.
|
||||||
*/
|
*/
|
||||||
local_saved_data_file_length= share->file_stat.st_size;
|
local_saved_data_file_length= share->saved_data_file_length;
|
||||||
/* set current position to the beginning of the file */
|
/* set current position to the beginning of the file */
|
||||||
current_position= next_position= 0;
|
current_position= next_position= 0;
|
||||||
|
|
||||||
@ -1232,11 +1352,10 @@ int ha_tina::repair(THD* thd, HA_CHECK_OPT* check_opt)
|
|||||||
|
|
||||||
if (rc == HA_ERR_END_OF_FILE)
|
if (rc == HA_ERR_END_OF_FILE)
|
||||||
{
|
{
|
||||||
/* All rows were read ok until end of file, the file does not need repair. */
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
If rows_recorded != rows_repaired, we should update
|
All rows were read ok until end of file, the file does not need repair.
|
||||||
rows_recorded value to the current amount of rows.
|
If rows_recorded != rows_repaired, we should update rows_recorded value
|
||||||
|
to the current amount of rows.
|
||||||
*/
|
*/
|
||||||
share->rows_recorded= rows_repaired;
|
share->rows_recorded= rows_repaired;
|
||||||
goto end;
|
goto end;
|
||||||
@ -1252,36 +1371,45 @@ int ha_tina::repair(THD* thd, HA_CHECK_OPT* check_opt)
|
|||||||
0, O_RDWR | O_TRUNC,MYF(MY_WME))) < 0)
|
0, O_RDWR | O_TRUNC,MYF(MY_WME))) < 0)
|
||||||
DBUG_RETURN(HA_ERR_CRASHED_ON_REPAIR);
|
DBUG_RETURN(HA_ERR_CRASHED_ON_REPAIR);
|
||||||
|
|
||||||
if (my_write(repair_file, (byte*)share->mapped_file, current_position,
|
file_buff->init_buff(data_file);
|
||||||
MYF(MY_NABP)))
|
|
||||||
DBUG_RETURN(HA_ERR_CRASHED_ON_USAGE);
|
|
||||||
my_close(repair_file, MYF(0));
|
|
||||||
/* we just truncated the file up to the first bad row. update rows count. */
|
/* we just truncated the file up to the first bad row. update rows count. */
|
||||||
share->rows_recorded= rows_repaired;
|
share->rows_recorded= rows_repaired;
|
||||||
|
|
||||||
if (my_munmap(share->mapped_file, share->file_stat.st_size))
|
/* write repaired file */
|
||||||
DBUG_RETURN(-1);
|
while (1)
|
||||||
/* We set it to null so that get_mmap() won't try to unmap it */
|
{
|
||||||
share->mapped_file= NULL;
|
write_end= min(file_buff->end(), current_position);
|
||||||
|
if ((write_end - write_begin) &&
|
||||||
|
(my_write(repair_file, (byte*)file_buff->ptr(),
|
||||||
|
write_end - write_begin, MYF_RW)))
|
||||||
|
DBUG_RETURN(-1);
|
||||||
|
|
||||||
|
write_begin= write_end;
|
||||||
|
if (write_end== current_position)
|
||||||
|
break;
|
||||||
|
else
|
||||||
|
file_buff->read_next(); /* shift the buffer */
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Close the "to"-file before renaming
|
Close the files and rename repaired file to the datafile.
|
||||||
On Windows one cannot rename a file, which descriptor
|
We have to close the files, as on Windows one cannot rename
|
||||||
is still open. EACCES will be returned when trying to delete
|
a file, which descriptor is still open. EACCES will be returned
|
||||||
the "to"-file in my_rename()
|
when trying to delete the "to"-file in my_rename().
|
||||||
*/
|
*/
|
||||||
my_close(share->data_file,MYF(0));
|
if (my_close(data_file,MYF(0)) || my_close(repair_file, MYF(0)) ||
|
||||||
|
my_rename(repaired_fname, share->data_file_name, MYF(0)))
|
||||||
if (my_rename(repaired_fname, share->data_file_name, MYF(0)))
|
|
||||||
DBUG_RETURN(-1);
|
DBUG_RETURN(-1);
|
||||||
|
|
||||||
/* Open the file again, it should now be repaired */
|
/* Open the file again, it should now be repaired */
|
||||||
if ((share->data_file= my_open(share->data_file_name, O_RDWR|O_APPEND,
|
if ((data_file= my_open(share->data_file_name, O_RDWR|O_APPEND,
|
||||||
MYF(0))) == -1)
|
MYF(0))) == -1)
|
||||||
DBUG_RETURN(-1);
|
DBUG_RETURN(-1);
|
||||||
|
|
||||||
if (get_mmap(share, 0) > 0)
|
/* Set new file size. The file size will be updated by ::update_status() */
|
||||||
DBUG_RETURN(-1);
|
local_saved_data_file_length= (size_t) current_position;
|
||||||
|
|
||||||
end:
|
end:
|
||||||
share->crashed= FALSE;
|
share->crashed= FALSE;
|
||||||
@ -1300,17 +1428,12 @@ int ha_tina::delete_all_rows()
|
|||||||
if (!records_is_known)
|
if (!records_is_known)
|
||||||
DBUG_RETURN(my_errno=HA_ERR_WRONG_COMMAND);
|
DBUG_RETURN(my_errno=HA_ERR_WRONG_COMMAND);
|
||||||
|
|
||||||
/* Unmap the file before the new size is set */
|
if (!share->tina_write_opened)
|
||||||
if (share->mapped_file && my_munmap(share->mapped_file,
|
if (init_tina_writer())
|
||||||
share->file_stat.st_size))
|
DBUG_RETURN(-1);
|
||||||
DBUG_RETURN(-1);
|
|
||||||
share->mapped_file= NULL;
|
|
||||||
|
|
||||||
/* Truncate the file to zero size */
|
/* Truncate the file to zero size */
|
||||||
rc= my_chsize(share->data_file, 0, 0, MYF(MY_WME));
|
rc= my_chsize(share->tina_write_filedes, 0, 0, MYF(MY_WME));
|
||||||
|
|
||||||
if (get_mmap(share, 0) > 0)
|
|
||||||
DBUG_RETURN(-1);
|
|
||||||
|
|
||||||
stats.records=0;
|
stats.records=0;
|
||||||
DBUG_RETURN(rc);
|
DBUG_RETURN(rc);
|
||||||
@ -1372,12 +1495,15 @@ int ha_tina::check(THD* thd, HA_CHECK_OPT* check_opt)
|
|||||||
if (!(buf= (byte*) my_malloc(table->s->reclength, MYF(MY_WME))))
|
if (!(buf= (byte*) my_malloc(table->s->reclength, MYF(MY_WME))))
|
||||||
DBUG_RETURN(HA_ERR_OUT_OF_MEM);
|
DBUG_RETURN(HA_ERR_OUT_OF_MEM);
|
||||||
|
|
||||||
|
/* position buffer to the start of the file */
|
||||||
|
file_buff->init_buff(data_file);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Local_saved_data_file_length is initialized during the lock phase.
|
Local_saved_data_file_length is initialized during the lock phase.
|
||||||
Check does not use store_lock in certain cases. So, we set it
|
Check does not use store_lock in certain cases. So, we set it
|
||||||
manually here.
|
manually here.
|
||||||
*/
|
*/
|
||||||
local_saved_data_file_length= share->file_stat.st_size;
|
local_saved_data_file_length= share->saved_data_file_length;
|
||||||
/* set current position to the beginning of the file */
|
/* set current position to the beginning of the file */
|
||||||
current_position= next_position= 0;
|
current_position= next_position= 0;
|
||||||
/* Read the file row-by-row. If everything is ok, repair is not needed. */
|
/* Read the file row-by-row. If everything is ok, repair is not needed. */
|
||||||
|
@ -29,15 +29,12 @@
|
|||||||
typedef struct st_tina_share {
|
typedef struct st_tina_share {
|
||||||
char *table_name;
|
char *table_name;
|
||||||
char data_file_name[FN_REFLEN];
|
char data_file_name[FN_REFLEN];
|
||||||
byte *mapped_file; /* mapped region of file */
|
|
||||||
uint table_name_length, use_count;
|
uint table_name_length, use_count;
|
||||||
/*
|
/*
|
||||||
Below flag is needed to make log tables work with concurrent insert.
|
Below flag is needed to make log tables work with concurrent insert.
|
||||||
For more details see comment to ha_tina::update_status.
|
For more details see comment to ha_tina::update_status.
|
||||||
*/
|
*/
|
||||||
my_bool is_log_table;
|
my_bool is_log_table;
|
||||||
MY_STAT file_stat; /* Stat information for the data file */
|
|
||||||
File data_file; /* Current open data file */
|
|
||||||
/*
|
/*
|
||||||
Here we save the length of the file for readers. This is updated by
|
Here we save the length of the file for readers. This is updated by
|
||||||
inserts, updates and deletes. The var is initialized along with the
|
inserts, updates and deletes. The var is initialized along with the
|
||||||
@ -46,7 +43,10 @@ typedef struct st_tina_share {
|
|||||||
off_t saved_data_file_length;
|
off_t saved_data_file_length;
|
||||||
pthread_mutex_t mutex;
|
pthread_mutex_t mutex;
|
||||||
THR_LOCK lock;
|
THR_LOCK lock;
|
||||||
|
bool update_file_opened;
|
||||||
|
bool tina_write_opened;
|
||||||
File meta_file; /* Meta file we use */
|
File meta_file; /* Meta file we use */
|
||||||
|
File tina_write_filedes; /* File handler for readers */
|
||||||
bool crashed; /* Meta file is crashed */
|
bool crashed; /* Meta file is crashed */
|
||||||
ha_rows rows_recorded; /* Number of rows in tables */
|
ha_rows rows_recorded; /* Number of rows in tables */
|
||||||
} TINA_SHARE;
|
} TINA_SHARE;
|
||||||
@ -56,6 +56,49 @@ struct tina_set {
|
|||||||
off_t end;
|
off_t end;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class Transparent_file
|
||||||
|
{
|
||||||
|
File filedes;
|
||||||
|
byte *buff; /* in-memory window to the file or mmaped area */
|
||||||
|
/* current window sizes */
|
||||||
|
off_t lower_bound;
|
||||||
|
off_t upper_bound;
|
||||||
|
uint buff_size;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
Transparent_file() : lower_bound(0), buff_size(IO_SIZE)
|
||||||
|
{ buff= (byte *) my_malloc(buff_size*sizeof(byte), MYF(MY_WME)); }
|
||||||
|
|
||||||
|
~Transparent_file()
|
||||||
|
{ my_free((gptr)buff, MYF(MY_ALLOW_ZERO_PTR)); }
|
||||||
|
|
||||||
|
void init_buff(File filedes_arg)
|
||||||
|
{
|
||||||
|
filedes= filedes_arg;
|
||||||
|
/* read the beginning of the file */
|
||||||
|
lower_bound= 0;
|
||||||
|
VOID(my_seek(filedes, 0, MY_SEEK_SET, MYF(0)));
|
||||||
|
if (filedes && buff)
|
||||||
|
upper_bound= my_read(filedes, buff, buff_size, MYF(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
byte *ptr()
|
||||||
|
{ return buff; }
|
||||||
|
|
||||||
|
off_t start()
|
||||||
|
{ return lower_bound; }
|
||||||
|
|
||||||
|
off_t end()
|
||||||
|
{ return upper_bound; }
|
||||||
|
|
||||||
|
/* get a char from the given position in the file */
|
||||||
|
char get_value (off_t offset);
|
||||||
|
/* shift a buffer windows to see the next part of the file */
|
||||||
|
off_t read_next();
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
class ha_tina: public handler
|
class ha_tina: public handler
|
||||||
{
|
{
|
||||||
THR_LOCK_DATA lock; /* MySQL lock */
|
THR_LOCK_DATA lock; /* MySQL lock */
|
||||||
@ -64,6 +107,9 @@ class ha_tina: public handler
|
|||||||
off_t next_position; /* Next position in the file scan */
|
off_t next_position; /* Next position in the file scan */
|
||||||
off_t local_saved_data_file_length; /* save position for reads */
|
off_t local_saved_data_file_length; /* save position for reads */
|
||||||
byte byte_buffer[IO_SIZE];
|
byte byte_buffer[IO_SIZE];
|
||||||
|
Transparent_file *file_buff;
|
||||||
|
File data_file; /* File handler for readers */
|
||||||
|
File update_temp_file;
|
||||||
String buffer;
|
String buffer;
|
||||||
/*
|
/*
|
||||||
The chain contains "holes" in the file, occured because of
|
The chain contains "holes" in the file, occured because of
|
||||||
@ -77,12 +123,19 @@ class ha_tina: public handler
|
|||||||
uint32 chain_size;
|
uint32 chain_size;
|
||||||
bool records_is_known;
|
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();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ha_tina(TABLE_SHARE *table_arg);
|
ha_tina(TABLE_SHARE *table_arg);
|
||||||
~ha_tina()
|
~ha_tina()
|
||||||
{
|
{
|
||||||
if (chain_alloced)
|
if (chain_alloced)
|
||||||
my_free((gptr)chain,0);
|
my_free((gptr)chain, 0);
|
||||||
|
if (file_buff)
|
||||||
|
delete file_buff;
|
||||||
}
|
}
|
||||||
const char *table_type() const { return "CSV"; }
|
const char *table_type() const { return "CSV"; }
|
||||||
const char *index_type(uint inx) { return "NONE"; }
|
const char *index_type(uint inx) { return "NONE"; }
|
||||||
|
Reference in New Issue
Block a user