diff options
Diffstat (limited to 'sql/log.cc')
-rw-r--r-- | sql/log.cc | 463 |
1 files changed, 344 insertions, 119 deletions
diff --git a/sql/log.cc b/sql/log.cc index adc83c9b12c..fb990d60186 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -1506,7 +1506,7 @@ binlog_end_trans(THD *thd, binlog_trx_data *trx_data, if (all || !(thd->options & (OPTION_BEGIN | OPTION_NOT_AUTOCOMMIT))) { if (trx_data->has_incident()) - mysql_bin_log.write_incident(thd, TRUE); + error= mysql_bin_log.write_incident(thd, TRUE); trx_data->reset(); } else // ...statement @@ -1979,6 +1979,22 @@ void MYSQL_LOG::init(enum_log_type log_type_arg, } +bool MYSQL_LOG::init_and_set_log_file_name(const char *log_name, + const char *new_name, + enum_log_type log_type_arg, + enum cache_type io_cache_type_arg) +{ + init(log_type_arg, io_cache_type_arg); + + if (new_name && !strmov(log_file_name, new_name)) + return TRUE; + else if (!new_name && generate_new_name(log_file_name, log_name)) + return TRUE; + + return FALSE; +} + + /* Open a (new) log file. @@ -2011,17 +2027,14 @@ bool MYSQL_LOG::open(const char *log_name, enum_log_type log_type_arg, write_error= 0; - init(log_type_arg, io_cache_type_arg); - if (!(name= my_strdup(log_name, MYF(MY_WME)))) { name= (char *)log_name; // for the error message goto err; } - if (new_name) - strmov(log_file_name, new_name); - else if (generate_new_name(log_file_name, name)) + if (init_and_set_log_file_name(name, new_name, + log_type_arg, io_cache_type_arg)) goto err; if (io_cache_type == SEQ_READ_APPEND) @@ -2519,7 +2532,7 @@ MYSQL_BIN_LOG::MYSQL_BIN_LOG(uint *sync_period) */ index_file_name[0] = 0; bzero((char*) &index_file, sizeof(index_file)); - bzero((char*) &purge_temp, sizeof(purge_temp)); + bzero((char*) &purge_index_file, sizeof(purge_index_file)); } /* this is called only once */ @@ -2563,7 +2576,7 @@ void MYSQL_BIN_LOG::init_pthread_objects() bool MYSQL_BIN_LOG::open_index_file(const char *index_file_name_arg, - const char *log_name) + const char *log_name, bool need_mutex) { File index_file_nr= -1; DBUG_ASSERT(!my_b_inited(&index_file)); @@ -2588,7 +2601,8 @@ bool MYSQL_BIN_LOG::open_index_file(const char *index_file_name_arg, init_io_cache(&index_file, index_file_nr, IO_SIZE, WRITE_CACHE, my_seek(index_file_nr,0L,MY_SEEK_END,MYF(0)), - 0, MYF(MY_WME | MY_WAIT_IF_FULL))) + 0, MYF(MY_WME | MY_WAIT_IF_FULL)) || + DBUG_EVALUATE_IF("fault_injection_openning_index", 1, 0)) { /* TODO: all operations creating/deleting the index file or a log, should @@ -2599,6 +2613,28 @@ bool MYSQL_BIN_LOG::open_index_file(const char *index_file_name_arg, my_close(index_file_nr,MYF(0)); return TRUE; } + +#ifdef HAVE_REPLICATION + /* + Sync the index by purging any binary log file that is not registered. + In other words, either purge binary log files that were removed from + the index but not purged from the file system due to a crash or purge + any binary log file that was created but not register in the index + due to a crash. + */ + + if (set_purge_index_file_name(index_file_name_arg) || + open_purge_index_file(FALSE) || + purge_index_entry(NULL, NULL, need_mutex) || + close_purge_index_file() || + DBUG_EVALUATE_IF("fault_injection_recovering_index", 1, 0)) + { + sql_print_error("MYSQL_BIN_LOG::open_index_file failed to sync the index " + "file."); + return TRUE; + } +#endif + return FALSE; } @@ -2623,17 +2659,44 @@ bool MYSQL_BIN_LOG::open(const char *log_name, enum cache_type io_cache_type_arg, bool no_auto_events_arg, ulong max_size_arg, - bool null_created_arg) + bool null_created_arg, + bool need_mutex) { File file= -1; + DBUG_ENTER("MYSQL_BIN_LOG::open"); DBUG_PRINT("enter",("log_type: %d",(int) log_type_arg)); - write_error=0; + if (init_and_set_log_file_name(log_name, new_name, log_type_arg, + io_cache_type_arg)) + { + sql_print_error("MSYQL_BIN_LOG::open failed to generate new file name."); + DBUG_RETURN(1); + } + +#ifdef HAVE_REPLICATION + if (open_purge_index_file(TRUE) || + register_create_index_entry(log_file_name) || + sync_purge_index_file() || + DBUG_EVALUATE_IF("fault_injection_registering_index", 1, 0)) + { + sql_print_error("MSYQL_BIN_LOG::open failed to sync the index file."); + DBUG_RETURN(1); + } + DBUG_EXECUTE_IF("crash_create_non_critical_before_update_index", abort();); +#endif + + write_error= 0; /* open the main log file */ - if (MYSQL_LOG::open(log_name, log_type_arg, new_name, io_cache_type_arg)) + if (MYSQL_LOG::open(log_name, log_type_arg, new_name, + io_cache_type_arg)) + { +#ifdef HAVE_REPLICATION + close_purge_index_file(); +#endif DBUG_RETURN(1); /* all warnings issued */ + } init(no_auto_events_arg, max_size_arg); @@ -2659,9 +2722,6 @@ bool MYSQL_BIN_LOG::open(const char *log_name, write_file_name_to_index_file= 1; } - DBUG_ASSERT(my_b_inited(&index_file) != 0); - reinit_io_cache(&index_file, WRITE_CACHE, - my_b_filelength(&index_file), 0, 0); if (need_start_event && !no_auto_events) { /* @@ -2719,23 +2779,44 @@ bool MYSQL_BIN_LOG::open(const char *log_name, if (write_file_name_to_index_file) { +#ifdef HAVE_REPLICATION + DBUG_EXECUTE_IF("crash_create_critical_before_update_index", abort();); +#endif + + DBUG_ASSERT(my_b_inited(&index_file) != 0); + reinit_io_cache(&index_file, WRITE_CACHE, + my_b_filelength(&index_file), 0, 0); /* As this is a new log file, we write the file name to the index file. As every time we write to the index file, we sync it. */ - if (my_b_write(&index_file, (uchar*) log_file_name, - strlen(log_file_name)) || - my_b_write(&index_file, (uchar*) "\n", 1) || - flush_io_cache(&index_file) || + if (DBUG_EVALUATE_IF("fault_injection_updating_index", 1, 0) || + my_b_write(&index_file, (uchar*) log_file_name, + strlen(log_file_name)) || + my_b_write(&index_file, (uchar*) "\n", 1) || + flush_io_cache(&index_file) || my_sync(index_file.file, MYF(MY_WME))) - goto err; + goto err; + +#ifdef HAVE_REPLICATION + DBUG_EXECUTE_IF("crash_create_after_update_index", abort();); +#endif } } log_state= LOG_OPENED; +#ifdef HAVE_REPLICATION + close_purge_index_file(); +#endif + DBUG_RETURN(0); err: +#ifdef HAVE_REPLICATION + if (is_inited_purge_index_file()) + purge_index_entry(NULL, NULL, need_mutex); + close_purge_index_file(); +#endif sql_print_error("Could not use %s for logging (error %d). \ Turning logging off for the whole duration of the MySQL server process. \ To turn it on again: fix the cause, \ @@ -2995,7 +3076,15 @@ bool MYSQL_BIN_LOG::reset_logs(THD* thd) name=0; // Protect against free close(LOG_CLOSE_TO_BE_OPENED); - /* First delete all old log files */ + /* + First delete all old log files and then update the index file. + As we first delete the log files and do not use sort of logging, + a crash may lead to an inconsistent state where the index has + references to non-existent files. + + We need to invert the steps and use the purge_index_file methods + in order to make the operation safe. + */ if ((err= find_log_pos(&linfo, NullS, 0)) != 0) { @@ -3066,8 +3155,8 @@ bool MYSQL_BIN_LOG::reset_logs(THD* thd) } if (!thd->slave_thread) need_start_event=1; - if (!open_index_file(index_file_name, 0)) - open(save_name, log_type, 0, io_cache_type, no_auto_events, max_size, 0); + if (!open_index_file(index_file_name, 0, FALSE)) + open(save_name, log_type, 0, io_cache_type, no_auto_events, max_size, 0, FALSE); my_free((uchar*) save_name, MYF(0)); err: @@ -3256,7 +3345,7 @@ int MYSQL_BIN_LOG::purge_logs(const char *to_log, bool need_update_threads, ulonglong *decrease_log_space) { - int error; + int error= 0; bool exit_loop= 0; LOG_INFO log_info; THD *thd= current_thd; @@ -3267,33 +3356,15 @@ int MYSQL_BIN_LOG::purge_logs(const char *to_log, pthread_mutex_lock(&LOCK_index); if ((error=find_log_pos(&log_info, to_log, 0 /*no mutex*/))) { - sql_print_error("MYSQL_LOG::purge_logs was called with file %s not " + sql_print_error("MYSQL_BIN_LOG::purge_logs was called with file %s not " "listed in the index.", to_log); goto err; } - /* - For crash recovery reasons the index needs to be updated before - any files are deleted. Move files to be deleted into a temp file - to be processed after the index is updated. - */ - if (!my_b_inited(&purge_temp)) - { - if ((error=open_cached_file(&purge_temp, mysql_tmpdir, TEMP_PREFIX, - DISK_BUFFER_SIZE, MYF(MY_WME)))) - { - sql_print_error("MYSQL_LOG::purge_logs failed to open purge_temp"); - goto err; - } - } - else + if ((error= open_purge_index_file(TRUE))) { - if ((error=reinit_io_cache(&purge_temp, WRITE_CACHE, 0, 0, 1))) - { - sql_print_error("MYSQL_LOG::purge_logs failed to reinit purge_temp " - "for write"); - goto err; - } + sql_print_error("MYSQL_BIN_LOG::purge_logs failed to sync the index file."); + goto err; } /* @@ -3303,51 +3374,177 @@ int MYSQL_BIN_LOG::purge_logs(const char *to_log, if ((error=find_log_pos(&log_info, NullS, 0 /*no mutex*/))) goto err; while ((strcmp(to_log,log_info.log_file_name) || (exit_loop=included)) && + !is_active(log_info.log_file_name) && !log_in_use(log_info.log_file_name)) { - if ((error=my_b_write(&purge_temp, (const uchar*)log_info.log_file_name, - strlen(log_info.log_file_name))) || - (error=my_b_write(&purge_temp, (const uchar*)"\n", 1))) + if ((error= register_purge_index_entry(log_info.log_file_name))) { - sql_print_error("MYSQL_LOG::purge_logs failed to copy %s to purge_temp", + sql_print_error("MYSQL_BIN_LOG::purge_logs failed to copy %s to register file.", log_info.log_file_name); goto err; } if (find_next_log(&log_info, 0) || exit_loop) break; - } + } + + DBUG_EXECUTE_IF("crash_purge_before_update_index", abort();); + + if ((error= sync_purge_index_file())) + { + sql_print_error("MSYQL_BIN_LOG::purge_logs failed to flush register file."); + goto err; + } /* We know how many files to delete. Update index file. */ if ((error=update_log_index(&log_info, need_update_threads))) { - sql_print_error("MSYQL_LOG::purge_logs failed to update the index file"); + sql_print_error("MSYQL_BIN_LOG::purge_logs failed to update the index file"); goto err; } - DBUG_EXECUTE_IF("crash_after_update_index", abort();); + DBUG_EXECUTE_IF("crash_purge_critical_after_update_index", abort();); + +err: + /* Read each entry from purge_index_file and delete the file. */ + if (is_inited_purge_index_file() && + (error= purge_index_entry(thd, decrease_log_space, FALSE))) + sql_print_error("MSYQL_BIN_LOG::purge_logs failed to process registered files" + " that would be purged."); + close_purge_index_file(); + + DBUG_EXECUTE_IF("crash_purge_non_critical_after_update_index", abort();); + + if (need_mutex) + pthread_mutex_unlock(&LOCK_index); + DBUG_RETURN(error); +} + +int MYSQL_BIN_LOG::set_purge_index_file_name(const char *base_file_name) +{ + int error= 0; + DBUG_ENTER("MYSQL_BIN_LOG::set_purge_index_file_name"); + if (fn_format(purge_index_file_name, base_file_name, mysql_data_home, + ".~rec~", MYF(MY_UNPACK_FILENAME | MY_SAFE_PATH | + MY_REPLACE_EXT)) == NULL) + { + error= 1; + sql_print_error("MYSQL_BIN_LOG::set_purge_index_file_name failed to set " + "file name."); + } + DBUG_RETURN(error); +} + +int MYSQL_BIN_LOG::open_purge_index_file(bool destroy) +{ + int error= 0; + File file= -1; - /* Switch purge_temp for read. */ - if ((error=reinit_io_cache(&purge_temp, READ_CACHE, 0, 0, 0))) + DBUG_ENTER("MYSQL_BIN_LOG::open_purge_index_file"); + + if (destroy) + close_purge_index_file(); + + if (!my_b_inited(&purge_index_file)) { - sql_print_error("MSYQL_LOG::purge_logs failed to reinit purge_temp " + if ((file= my_open(purge_index_file_name, O_RDWR | O_CREAT | O_BINARY, + MYF(MY_WME | ME_WAITTANG))) < 0 || + init_io_cache(&purge_index_file, file, IO_SIZE, + (destroy ? WRITE_CACHE : READ_CACHE), + 0, 0, MYF(MY_WME | MY_NABP | MY_WAIT_IF_FULL))) + { + error= 1; + sql_print_error("MYSQL_BIN_LOG::open_purge_index_file failed to open register " + " file."); + } + } + DBUG_RETURN(error); +} + +int MYSQL_BIN_LOG::close_purge_index_file() +{ + int error= 0; + + DBUG_ENTER("MYSQL_BIN_LOG::close_purge_index_file"); + + if (my_b_inited(&purge_index_file)) + { + end_io_cache(&purge_index_file); + error= my_close(purge_index_file.file, MYF(0)); + } + my_delete(purge_index_file_name, MYF(0)); + bzero((char*) &purge_index_file, sizeof(purge_index_file)); + + DBUG_RETURN(error); +} + +bool MYSQL_BIN_LOG::is_inited_purge_index_file() +{ + DBUG_ENTER("MYSQL_BIN_LOG::is_inited_purge_index_file"); + DBUG_RETURN (my_b_inited(&purge_index_file)); +} + +int MYSQL_BIN_LOG::sync_purge_index_file() +{ + int error= 0; + DBUG_ENTER("MYSQL_BIN_LOG::sync_purge_index_file"); + + if ((error= flush_io_cache(&purge_index_file)) || + (error= my_sync(purge_index_file.file, MYF(MY_WME)))) + DBUG_RETURN(error); + + DBUG_RETURN(error); +} + +int MYSQL_BIN_LOG::register_purge_index_entry(const char *entry) +{ + int error= 0; + DBUG_ENTER("MYSQL_BIN_LOG::register_purge_index_entry"); + + if ((error=my_b_write(&purge_index_file, (const uchar*)entry, strlen(entry))) || + (error=my_b_write(&purge_index_file, (const uchar*)"\n", 1))) + DBUG_RETURN (error); + + DBUG_RETURN(error); +} + +int MYSQL_BIN_LOG::register_create_index_entry(const char *entry) +{ + DBUG_ENTER("MYSQL_BIN_LOG::register_create_index_entry"); + DBUG_RETURN(register_purge_index_entry(entry)); +} + +int MYSQL_BIN_LOG::purge_index_entry(THD *thd, ulonglong *decrease_log_space, + bool need_mutex) +{ + MY_STAT s; + int error= 0; + LOG_INFO log_info; + LOG_INFO check_log_info; + + DBUG_ENTER("MYSQL_BIN_LOG:purge_index_entry"); + + DBUG_ASSERT(my_b_inited(&purge_index_file)); + + if ((error=reinit_io_cache(&purge_index_file, READ_CACHE, 0, 0, 0))) + { + sql_print_error("MSYQL_BIN_LOG::purge_index_entry failed to reinit register file " "for read"); goto err; } - /* Read each entry from purge_temp and delete the file. */ for (;;) { uint length; - if ((length=my_b_gets(&purge_temp, log_info.log_file_name, + if ((length=my_b_gets(&purge_index_file, log_info.log_file_name, FN_REFLEN)) <= 1) { - if (purge_temp.error) + if (purge_index_file.error) { - error= purge_temp.error; - sql_print_error("MSYQL_LOG::purge_logs error %d reading from " - "purge_temp", error); + error= purge_index_file.error; + sql_print_error("MSYQL_BIN_LOG::purge_index_entry error %d reading from " + "register file.", error); goto err; } @@ -3358,9 +3555,6 @@ int MYSQL_BIN_LOG::purge_logs(const char *to_log, /* Get rid of the trailing '\n' */ log_info.log_file_name[length-1]= 0; - ha_binlog_index_purge_file(current_thd, log_info.log_file_name); - - MY_STAT s; if (!my_stat(log_info.log_file_name, &s, MYF(0))) { if (my_errno == ENOENT) @@ -3408,64 +3602,92 @@ int MYSQL_BIN_LOG::purge_logs(const char *to_log, } else { - DBUG_PRINT("info",("purging %s",log_info.log_file_name)); - if (!my_delete(log_info.log_file_name, MYF(0))) - { - if (decrease_log_space) - *decrease_log_space-= s.st_size; - } - else + if ((error= find_log_pos(&check_log_info, log_info.log_file_name, need_mutex))) { - if (my_errno == ENOENT) + if (error != LOG_INFO_EOF) { if (thd) { push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, - ER_LOG_PURGE_NO_FILE, ER(ER_LOG_PURGE_NO_FILE), + ER_BINLOG_PURGE_FATAL_ERR, + "a problem with deleting %s and " + "reading the binlog index file", log_info.log_file_name); } - sql_print_information("Failed to delete file '%s'", - log_info.log_file_name); - my_errno= 0; + else + { + sql_print_information("Failed to delete file '%s' and " + "read the binlog index file", + log_info.log_file_name); + } + goto err; + } + + error= 0; + if (!need_mutex) + { + /* + This is to avoid triggering an error in NDB. + */ + ha_binlog_index_purge_file(current_thd, log_info.log_file_name); + } + + DBUG_PRINT("info",("purging %s",log_info.log_file_name)); + if (!my_delete(log_info.log_file_name, MYF(0))) + { + if (decrease_log_space) + *decrease_log_space-= s.st_size; } else { - if (thd) + if (my_errno == ENOENT) { - push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, - ER_BINLOG_PURGE_FATAL_ERR, - "a problem with deleting %s; " - "consider examining correspondence " - "of your binlog index file " - "to the actual binlog files", - log_info.log_file_name); + if (thd) + { + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_LOG_PURGE_NO_FILE, ER(ER_LOG_PURGE_NO_FILE), + log_info.log_file_name); + } + sql_print_information("Failed to delete file '%s'", + log_info.log_file_name); + my_errno= 0; } else { - sql_print_information("Failed to delete file '%s'; " + if (thd) + { + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_BINLOG_PURGE_FATAL_ERR, + "a problem with deleting %s; " "consider examining correspondence " "of your binlog index file " "to the actual binlog files", log_info.log_file_name); - } - if (my_errno == EMFILE) - { - DBUG_PRINT("info", - ("my_errno: %d, set ret = LOG_INFO_EMFILE", my_errno)); - error= LOG_INFO_EMFILE; + } + else + { + sql_print_information("Failed to delete file '%s'; " + "consider examining correspondence " + "of your binlog index file " + "to the actual binlog files", + log_info.log_file_name); + } + if (my_errno == EMFILE) + { + DBUG_PRINT("info", + ("my_errno: %d, set ret = LOG_INFO_EMFILE", my_errno)); + error= LOG_INFO_EMFILE; + goto err; + } + error= LOG_INFO_FATAL; goto err; } - error= LOG_INFO_FATAL; - goto err; } } } } err: - close_cached_file(&purge_temp); - if (need_mutex) - pthread_mutex_unlock(&LOCK_index); DBUG_RETURN(error); } @@ -3505,7 +3727,8 @@ int MYSQL_BIN_LOG::purge_logs_before_date(time_t purge_time) goto err; while (strcmp(log_file_name, log_info.log_file_name) && - !log_in_use(log_info.log_file_name)) + !is_active(log_info.log_file_name) && + !log_in_use(log_info.log_file_name)) { if (!my_stat(log_info.log_file_name, &stat_area, MYF(0))) { @@ -3514,14 +3737,6 @@ int MYSQL_BIN_LOG::purge_logs_before_date(time_t purge_time) /* It's not fatal if we can't stat a log file that does not exist. */ - if (thd) - { - push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, - ER_LOG_PURGE_NO_FILE, ER(ER_LOG_PURGE_NO_FILE), - log_info.log_file_name); - } - sql_print_information("Failed to execute my_stat on file '%s'", - log_info.log_file_name); my_errno= 0; } else @@ -3716,9 +3931,9 @@ void MYSQL_BIN_LOG::new_file_impl(bool need_lock) */ /* reopen index binlog file, BUG#34582 */ - if (!open_index_file(index_file_name, 0)) - open(old_name, log_type, new_name_ptr, - io_cache_type, no_auto_events, max_size, 1); + if (!open_index_file(index_file_name, 0, FALSE)) + open(old_name, log_type, new_name_ptr, + io_cache_type, no_auto_events, max_size, 1, FALSE); my_free(old_name,MYF(0)); end: @@ -4380,6 +4595,9 @@ bool general_log_write(THD *thd, enum enum_server_command command, void MYSQL_BIN_LOG::rotate_and_purge(uint flags) { +#ifdef HAVE_REPLICATION + bool check_purge= false; +#endif if (!(flags & RP_LOCK_LOG_IS_ALREADY_LOCKED)) pthread_mutex_lock(&LOCK_log); if ((flags & RP_FORCE_ROTATE) || @@ -4387,16 +4605,24 @@ void MYSQL_BIN_LOG::rotate_and_purge(uint flags) { new_file_without_locking(); #ifdef HAVE_REPLICATION - if (expire_logs_days) - { - time_t purge_time= my_time(0) - expire_logs_days*24*60*60; - if (purge_time >= 0) - purge_logs_before_date(purge_time); - } + check_purge= true; #endif } if (!(flags & RP_LOCK_LOG_IS_ALREADY_LOCKED)) pthread_mutex_unlock(&LOCK_log); + +#ifdef HAVE_REPLICATION + /* + NOTE: Run purge_logs wo/ holding LOCK_log + as it otherwise will deadlock in ndbcluster_binlog_index_purge_file + */ + if (check_purge && expire_logs_days) + { + time_t purge_time= my_time(0) - expire_logs_days*24*60*60; + if (purge_time >= 0) + purge_logs_before_date(purge_time); + } +#endif } uint MYSQL_BIN_LOG::next_file_id() @@ -4589,7 +4815,7 @@ bool MYSQL_BIN_LOG::write_incident(THD *thd, bool lock) Incident_log_event ev(thd, incident, write_error_msg); if (lock) pthread_mutex_lock(&LOCK_log); - ev.write(&log_file); + error= ev.write(&log_file); if (lock) { if (!error && !(error= flush_and_sync(0))) @@ -5674,7 +5900,7 @@ int TC_LOG_BINLOG::open(const char *opt_name) if (using_heuristic_recover()) { /* generate a new binlog to mask a corrupted one */ - open(opt_name, LOG_BIN, 0, WRITE_CACHE, 0, max_binlog_size, 0); + open(opt_name, LOG_BIN, 0, WRITE_CACHE, 0, max_binlog_size, 0, TRUE); cleanup(); return 1; } @@ -5802,9 +6028,8 @@ int TC_LOG_BINLOG::recover(IO_CACHE *log, Format_description_log_event *fdle) Xid_log_event *xev=(Xid_log_event *)ev; uchar *x= (uchar *) memdup_root(&mem_root, (uchar*) &xev->xid, sizeof(xev->xid)); - if (! x) + if (!x || my_hash_insert(&xids, x)) goto err2; - my_hash_insert(&xids, x); } delete ev; } |