log.cc 32.5 KB
Newer Older
unknown's avatar
unknown committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
   
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.
   
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
   
   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */


/* logging of commands */
19
/* TODO: Abort logging when we get an error in reading or writing log files */
unknown's avatar
unknown committed
20

21 22 23 24
#ifdef __EMX__
#include <io.h>
#endif

unknown's avatar
unknown committed
25 26
#include "mysql_priv.h"
#include "sql_acl.h"
unknown's avatar
unknown committed
27
#include "sql_repl.h"
unknown's avatar
unknown committed
28 29 30 31

#include <my_dir.h>
#include <stdarg.h>
#include <m_ctype.h>				// For test_if_number
32
#include <assert.h>
unknown's avatar
unknown committed
33 34 35

MYSQL_LOG mysql_log,mysql_update_log,mysql_slow_log,mysql_bin_log;
extern I_List<i_string> binlog_do_db, binlog_ignore_db;
36
extern ulong max_binlog_size;
unknown's avatar
unknown committed
37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59

static bool test_if_number(const char *str,
			   long *res, bool allow_wildcards);

/****************************************************************************
** Find a uniq filename for 'filename.#'.
** Set # to a number as low as possible
** returns != 0 if not possible to get uniq filename
****************************************************************************/

static int find_uniq_filename(char *name)
{
  long		number;
  uint		i,length;
  char		buff[FN_REFLEN];
  struct st_my_dir *dir_info;
  reg1 struct fileinfo *file_info;
  ulong		max_found=0;
  DBUG_ENTER("find_uniq_filename");

  length=dirname_part(buff,name);
  char *start=name+length,*end=strend(start);
  *end='.';
unknown's avatar
unknown committed
60
  length= (uint) (end-start+1);
unknown's avatar
unknown committed
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82

  if (!(dir_info = my_dir(buff,MYF(MY_DONT_SORT))))
  {						// This shouldn't happen
    strmov(end,".1");				// use name+1
    DBUG_RETURN(0);
  }
  file_info= dir_info->dir_entry;
  for (i=dir_info->number_off_files ; i-- ; file_info++)
  {
    if (bcmp(file_info->name,start,length) == 0 &&
	test_if_number(file_info->name+length, &number,0))
    {
      set_if_bigger(max_found,(ulong) number);
    }
  }
  my_dirend(dir_info);

  *end++='.';
  sprintf(end,"%03ld",max_found+1);
  DBUG_RETURN(0);
}

unknown's avatar
unknown committed
83
MYSQL_LOG::MYSQL_LOG(): last_time(0), query_start(0),index_file(-1),
84
			name(0), log_type(LOG_CLOSED),write_error(0),
85
			inited(0), file_id(1),no_rotate(0),
unknown's avatar
unknown committed
86
			need_start_event(1),bytes_written(0)
unknown's avatar
unknown committed
87 88 89 90 91
{
  /*
    We don't want to intialize LOCK_Log here as the thread system may
    not have been initailized yet. We do it instead at 'open'.
  */
92 93
  index_file_name[0] = 0;
  bzero((char*) &log_file,sizeof(log_file));
unknown's avatar
unknown committed
94 95 96 97 98
}

MYSQL_LOG::~MYSQL_LOG()
{
  if (inited)
99 100 101
  {
    (void) pthread_mutex_destroy(&LOCK_log);
    (void) pthread_mutex_destroy(&LOCK_index);
unknown's avatar
unknown committed
102
    (void) pthread_cond_destroy(&update_cond);
103
  }
unknown's avatar
unknown committed
104 105 106 107 108
}

void MYSQL_LOG::set_index_file_name(const char* index_file_name)
{
  if (index_file_name)
109
    fn_format(this->index_file_name,index_file_name,mysql_data_home,".index",
unknown's avatar
unknown committed
110 111 112 113 114
	      4);
  else
    this->index_file_name[0] = 0;
}

115

unknown's avatar
unknown committed
116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134
int MYSQL_LOG::generate_new_name(char *new_name, const char *log_name)
{      
  if (log_type == LOG_NORMAL)
    fn_format(new_name,log_name,mysql_data_home,"",4);
  else
  {
    fn_format(new_name,log_name,mysql_data_home,"",4);
    if (!fn_ext(log_name)[0])
    {
      if (find_uniq_filename(new_name))
      {
	sql_print_error(ER(ER_NO_UNIQUE_LOGFILE), log_name);
	return 1;
      }
    }
  }
  return 0;
}

135 136 137 138 139 140 141
bool MYSQL_LOG::open_index( int options)
{
  return (index_file < 0 && 
	 (index_file = my_open(index_file_name, options | O_BINARY ,
			       MYF(MY_WME))) < 0);
}

142
void MYSQL_LOG::init(enum_log_type log_type_arg,
143 144
		     enum cache_type io_cache_type_arg,
		     bool no_auto_events_arg)
145 146
{
  log_type = log_type_arg;
147
  io_cache_type = io_cache_type_arg;
148
  no_auto_events = no_auto_events_arg;
149 150 151 152 153
  if (!inited)
  {
    inited=1;
    (void) pthread_mutex_init(&LOCK_log,MY_MUTEX_INIT_SLOW);
    (void) pthread_mutex_init(&LOCK_index, MY_MUTEX_INIT_SLOW);
154
    (void) pthread_cond_init(&update_cond, 0);
155 156 157 158 159
  }
}

void MYSQL_LOG::close_index()
{
160 161 162 163 164
  if (index_file >= 0)
  {
    my_close(index_file, MYF(0));
    index_file = -1;
  }
165
}
unknown's avatar
unknown committed
166 167

void MYSQL_LOG::open(const char *log_name, enum_log_type log_type_arg,
168 169
		     const char *new_name, enum cache_type io_cache_type_arg,
		     bool no_auto_events_arg)
unknown's avatar
unknown committed
170
{
171 172
  MY_STAT tmp_stat;
  char buff[512];
173 174
  File file= -1;
  bool do_magic;
175
  int open_flags = O_CREAT | O_APPEND | O_BINARY;
176
  if (!inited && log_type_arg == LOG_BIN && *fn_ext(log_name))
unknown's avatar
unknown committed
177
      no_rotate = 1;
178
  init(log_type_arg,io_cache_type_arg,no_auto_events_arg);
179 180 181
  
  if (!(name=my_strdup(log_name,MYF(MY_WME))))
    goto err;
unknown's avatar
unknown committed
182 183 184
  if (new_name)
    strmov(log_file_name,new_name);
  else if (generate_new_name(log_file_name, name))
185
    goto err;
186 187 188 189 190 191
  
  if (io_cache_type == SEQ_READ_APPEND)
    open_flags |= O_RDWR;
  else
    open_flags |= O_WRONLY;
  
unknown's avatar
unknown committed
192 193 194 195
  if (log_type == LOG_BIN && !index_file_name[0])
    fn_format(index_file_name, name, mysql_data_home, ".index", 6);
  
  db[0]=0;
196 197
  do_magic = ((log_type == LOG_BIN) && !my_stat(log_file_name,
						&tmp_stat, MYF(0)));
unknown's avatar
unknown committed
198
  
199
  if ((file=my_open(log_file_name,open_flags,
200
		    MYF(MY_WME | ME_WAITTANG))) < 0 ||
201
      init_io_cache(&log_file, file, IO_SIZE, io_cache_type,
202 203
		    my_tell(file,MYF(MY_WME)), 0, MYF(MY_WME | MY_NABP)))
    goto err;
unknown's avatar
unknown committed
204 205 206

  if (log_type == LOG_NORMAL)
  {
207
    char *end;
unknown's avatar
unknown committed
208
#ifdef __NT__
209
    sprintf(buff, "%s, Version: %s, started with:\nTCP Port: %d, Named Pipe: %s\n", my_progname, server_version, mysql_port, mysql_unix_port);
unknown's avatar
unknown committed
210
#else
211
    sprintf(buff, "%s, Version: %s, started with:\nTcp port: %d  Unix socket: %s\n", my_progname,server_version,mysql_port,mysql_unix_port);
unknown's avatar
unknown committed
212
#endif
213
    end=strmov(strend(buff),"Time                 Id Command    Argument\n");
unknown's avatar
unknown committed
214
    if (my_b_write(&log_file, (byte*) buff,(uint) (end-buff)) ||
215 216
	flush_io_cache(&log_file))
      goto err;
unknown's avatar
unknown committed
217 218 219 220 221 222
  }
  else if (log_type == LOG_NEW)
  {
    time_t skr=time(NULL);
    struct tm tm_tmp;
    localtime_r(&skr,&tm_tmp);
223
    sprintf(buff,"# %s, Version: %s at %02d%02d%02d %2d:%02d:%02d\n",
unknown's avatar
unknown committed
224 225 226 227 228 229 230
	    my_progname,server_version,
	    tm_tmp.tm_year % 100,
	    tm_tmp.tm_mon+1,
	    tm_tmp.tm_mday,
	    tm_tmp.tm_hour,
	    tm_tmp.tm_min,
	    tm_tmp.tm_sec);
unknown's avatar
unknown committed
231
    if (my_b_write(&log_file, (byte*) buff,(uint) strlen(buff)) ||
232 233
	flush_io_cache(&log_file))
      goto err;
unknown's avatar
unknown committed
234 235 236
  }
  else if (log_type == LOG_BIN)
  {
unknown's avatar
unknown committed
237 238 239 240
    bool error;
    if (do_magic)
    {
      if (my_b_write(&log_file, (byte*) BINLOG_MAGIC, 4) ||
241
	open_index(O_APPEND | O_RDWR | O_CREAT))
unknown's avatar
unknown committed
242 243 244
        goto err;
      bytes_written += 4;
    }
unknown's avatar
unknown committed
245

246
    if (need_start_event && !no_auto_events)
247 248
    {
      Start_log_event s;
249
      s.set_log_pos(this);
250 251 252
      s.write(&log_file);
      need_start_event=0;
    }
unknown's avatar
unknown committed
253
    flush_io_cache(&log_file);
unknown's avatar
unknown committed
254
    pthread_mutex_lock(&LOCK_index);
unknown's avatar
unknown committed
255
    error=(my_write(index_file, (byte*) log_file_name, strlen(log_file_name),
unknown's avatar
unknown committed
256
		    MYF(MY_NABP | MY_WME)) ||
unknown's avatar
unknown committed
257
	   my_write(index_file, (byte*) "\n", 1, MYF(MY_NABP | MY_WME)));
unknown's avatar
unknown committed
258
    pthread_mutex_unlock(&LOCK_index);
unknown's avatar
unknown committed
259 260
    if (error)
    {
261
      close_index();
unknown's avatar
unknown committed
262 263
      goto err;
    }
unknown's avatar
unknown committed
264
  }
265 266 267
  return;

err:
unknown's avatar
unknown committed
268
  sql_print_error("Could not use %s for logging (error %d)", log_name,errno);
269 270 271 272 273 274
  if (file >= 0)
    my_close(file,MYF(0));
  end_io_cache(&log_file);
  x_free(name); name=0;
  log_type=LOG_CLOSED;
  return;
unknown's avatar
unknown committed
275 276 277 278 279
}

int MYSQL_LOG::get_current_log(LOG_INFO* linfo)
{
  pthread_mutex_lock(&LOCK_log);
280 281
  strmake(linfo->log_file_name, log_file_name, sizeof(linfo->log_file_name)-1);
  linfo->pos = my_b_tell(&log_file);
unknown's avatar
unknown committed
282 283 284 285 286
  pthread_mutex_unlock(&LOCK_log);
  return 0;
}

// if log_name is "" we stop at the first entry
287 288
int MYSQL_LOG::find_first_log(LOG_INFO* linfo, const char* log_name,
			      bool need_mutex)
unknown's avatar
unknown committed
289
{
290 291
  if (index_file < 0)
    return LOG_INFO_INVALID;
unknown's avatar
unknown committed
292 293
  int error = 0;
  char* fname = linfo->log_file_name;
unknown's avatar
unknown committed
294
  uint log_name_len = (uint) strlen(log_name);
295
  IO_CACHE io_cache;
unknown's avatar
unknown committed
296

297 298
  // mutex needed because we need to make sure the file pointer does not move
  // from under our feet
299 300
  if (need_mutex)
    pthread_mutex_lock(&LOCK_index);
301 302
  if (init_io_cache(&io_cache, index_file, IO_SIZE, READ_CACHE, (my_off_t) 0,
		    0, MYF(MY_WME)))
303 304 305 306 307 308
  {
    error = LOG_INFO_SEEK;
    goto err;
  }
  for(;;)
  {
309
    uint length;
unknown's avatar
unknown committed
310
    if (!(length=my_b_gets(&io_cache, fname, FN_REFLEN-1)))
unknown's avatar
unknown committed
311
    {
312
      error = !io_cache.error ? LOG_INFO_EOF : LOG_INFO_IO;
unknown's avatar
unknown committed
313 314 315
      goto err;
    }

316 317
    // if the log entry matches, empty string matching anything
    if (!log_name_len ||
unknown's avatar
unknown committed
318
	(log_name_len == length-1 && fname[log_name_len] == '\n' &&
319
	 !memcmp(fname, log_name, log_name_len)))
unknown's avatar
unknown committed
320
    {
321 322
      fname[length-1]=0;			// remove last \n
      linfo->index_file_offset = my_b_tell(&io_cache);
323
      break;
unknown's avatar
unknown committed
324
    }
325
  }
unknown's avatar
unknown committed
326
  error = 0;
327

unknown's avatar
unknown committed
328
err:
329 330
  if (need_mutex)
    pthread_mutex_unlock(&LOCK_index);
331
  end_io_cache(&io_cache);
unknown's avatar
unknown committed
332 333 334
  return error;
     
}
unknown's avatar
unknown committed
335

336

337
int MYSQL_LOG::find_next_log(LOG_INFO* linfo, bool need_lock)
unknown's avatar
unknown committed
338 339 340
{
  // mutex needed because we need to make sure the file pointer does not move
  // from under our feet
unknown's avatar
unknown committed
341
  if (index_file < 0) return LOG_INFO_INVALID;
unknown's avatar
unknown committed
342 343
  int error = 0;
  char* fname = linfo->log_file_name;
344 345
  IO_CACHE io_cache;
  uint length;
346 347
  if (need_lock)
    pthread_mutex_lock(&LOCK_index);
348 349 350 351 352 353 354 355 356 357 358 359 360 361
  if (init_io_cache(&io_cache, index_file, IO_SIZE, 
		    READ_CACHE, (my_off_t) linfo->index_file_offset, 0,
		    MYF(MY_WME)))
  {
    error = LOG_INFO_SEEK;
    goto err;
  }
  if (!(length=my_b_gets(&io_cache, fname, FN_REFLEN)))
  {
    error = !io_cache.error ? LOG_INFO_EOF : LOG_INFO_IO;
    goto err;
  }
  fname[length-1]=0;				// kill /n
  linfo->index_file_offset = my_b_tell(&io_cache);
unknown's avatar
unknown committed
362
  error = 0;
363

unknown's avatar
unknown committed
364
err:
365 366
  if (need_lock)
    pthread_mutex_unlock(&LOCK_index);
367
  end_io_cache(&io_cache);
unknown's avatar
unknown committed
368 369 370
  return error;
}

unknown's avatar
unknown committed
371

372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404
int MYSQL_LOG::reset_logs(THD* thd)
{
  LOG_INFO linfo;
  int error=0;
  const char* save_name;
  enum_log_type save_log_type;
  pthread_mutex_lock(&LOCK_log);
  if (find_first_log(&linfo,""))
  {
    error=1;
    goto err;
  }
  
  for(;;)
  {
    my_delete(linfo.log_file_name, MYF(MY_WME));
    if (find_next_log(&linfo))
      break;
  }
  save_name=name;
  name=0;
  save_log_type=log_type;
  close(1);
  my_delete(index_file_name, MYF(MY_WME));
  if (thd && !thd->slave_thread)
    need_start_event=1;
  open(save_name,save_log_type,0,io_cache_type,no_auto_events);
  my_free((gptr)save_name,MYF(0));
err:  
  pthread_mutex_unlock(&LOCK_log);
  return error;
}

unknown's avatar
unknown committed
405

406 407 408 409 410 411 412
int MYSQL_LOG::purge_first_log(struct st_relay_log_info* rli)
{
  // pre-conditions
  DBUG_ASSERT(is_open());
  DBUG_ASSERT(index_file >= 0);
  DBUG_ASSERT(rli->slave_running == 1);
  DBUG_ASSERT(!strcmp(rli->linfo.log_file_name,rli->relay_log_name));
unknown's avatar
unknown committed
413 414 415 416
  /*
    Assume that we have previously read the first log and
    stored it in rli->relay_log_name
  */
417 418 419 420 421
  DBUG_ASSERT(rli->linfo.index_file_offset ==
	      strlen(rli->relay_log_name) + 1);
  int tmp_fd;
  char* fname, *io_buf;
  int error = 0;
unknown's avatar
unknown committed
422 423

  if (!(fname= (char*) my_malloc(IO_SIZE+FN_REFLEN, MYF(MY_WME))))
424 425 426 427 428 429 430 431 432 433 434 435 436 437 438
    return 1;
  pthread_mutex_lock(&LOCK_index);
  my_seek(index_file,rli->linfo.index_file_offset,
	  MY_SEEK_SET, MYF(MY_WME));
  io_buf = fname + FN_REFLEN;
  strxmov(fname,rli->relay_log_name,".tmp",NullS);
  
  if ((tmp_fd = my_open(fname,O_CREAT|O_BINARY|O_RDWR, MYF(MY_WME))) < 0)
  {
    error = 1;
    goto err;
  }
  for (;;)
  {
    int bytes_read;
unknown's avatar
unknown committed
439 440
    bytes_read = my_read(index_file, (byte*) io_buf, IO_SIZE, MYF(0));
    if (bytes_read < 0)				// error
441 442 443 444 445
    {
      error=1;
      goto err;
    }
    if (!bytes_read)
unknown's avatar
unknown committed
446
      break;					// end of file
447
    // otherwise, we've read something and need to write it out
unknown's avatar
unknown committed
448
    if (my_write(tmp_fd, (byte*) io_buf, bytes_read, MYF(MY_WME|MY_NABP)))
449 450 451 452 453
    {
      error=1;
      goto err;
    }
  }
unknown's avatar
unknown committed
454

455 456 457 458 459 460 461
err:
  if (tmp_fd)
    my_close(tmp_fd, MYF(MY_WME));
  if (error)
    my_delete(fname, MYF(0)); // do not report error if the file is not there
  else
  {
unknown's avatar
unknown committed
462
    MY_STAT s;
463
    my_close(index_file, MYF(MY_WME));
unknown's avatar
unknown committed
464 465 466 467 468 469 470
    if (!my_stat(rli->relay_log_name,&s,MYF(0)))
    {
      sql_print_error("The first log %s failed to stat during purge",
		      rli->relay_log_name);
      error=1;
      goto err;
    }
471 472 473 474 475
    if (my_rename(fname,index_file_name,MYF(MY_WME)) ||
	(index_file=my_open(index_file_name,O_BINARY|O_RDWR|O_APPEND,
			    MYF(MY_WME)))<0 ||
	my_delete(rli->relay_log_name, MYF(MY_WME)))
      error=1;
unknown's avatar
unknown committed
476 477 478 479 480 481 482 483 484
    
    pthread_mutex_lock(&rli->log_space_lock);
    rli->log_space_total -= s.st_size;
    pthread_mutex_unlock(&rli->log_space_lock);
    // ok to broadcast after the critical region as there is no risk of
    // the mutex being destroyed by this thread later - this helps save
    // context switches
    pthread_cond_broadcast(&rli->log_space_cond);
    
485 486 487 488 489 490 491 492 493 494 495
    if ((error=find_first_log(&rli->linfo,"",0/*no mutex*/)))
    {
      char buff[22];
      sql_print_error("next log error=%d,offset=%s,log=%s",error,
		      llstr(rli->linfo.index_file_offset,buff),
		      rli->linfo.log_file_name);
      goto err2;
    }
    rli->relay_log_pos = 4;
    strnmov(rli->relay_log_name,rli->linfo.log_file_name,
	    sizeof(rli->relay_log_name));
496
    flush_relay_log_info(rli);
497
  }
unknown's avatar
unknown committed
498 499 500 501 502
  /*
    No need to free io_buf because we allocated both fname and io_buf in
    one malloc()
  */

503 504 505 506 507 508
err2:
  pthread_mutex_unlock(&LOCK_index);
  my_free(fname, MYF(MY_WME));
  return error;
}

unknown's avatar
unknown committed
509

unknown's avatar
unknown committed
510 511 512 513
int MYSQL_LOG::purge_logs(THD* thd, const char* to_log)
{
  int error;
  char fname[FN_REFLEN];
unknown's avatar
unknown committed
514
  char *p;
unknown's avatar
unknown committed
515 516 517 518
  uint fname_len, i;
  bool logs_to_purge_inited = 0, logs_to_keep_inited = 0, found_log = 0;
  DYNAMIC_ARRAY logs_to_purge, logs_to_keep;
  my_off_t purge_offset ;
unknown's avatar
unknown committed
519
  LINT_INIT(purge_offset);
520
  IO_CACHE io_cache;
unknown's avatar
unknown committed
521
  
unknown's avatar
unknown committed
522 523 524 525
  if (index_file < 0)
    return LOG_INFO_INVALID;
  if (no_rotate)
    return LOG_INFO_PURGE_NO_ROTATE;
unknown's avatar
unknown committed
526 527
  pthread_mutex_lock(&LOCK_index);
  
528 529 530 531 532 533
  if (init_io_cache(&io_cache,index_file, IO_SIZE*2, READ_CACHE, (my_off_t) 0,
		    0, MYF(MY_WME)))
  {
    error = LOG_INFO_MEM;
    goto err;
  }
534
  if (my_init_dynamic_array(&logs_to_purge, sizeof(char*), 1024, 1024))
535 536 537 538
  {
    error = LOG_INFO_MEM;
    goto err;
  }
unknown's avatar
unknown committed
539 540
  logs_to_purge_inited = 1;
  
541
  if (my_init_dynamic_array(&logs_to_keep, sizeof(char*), 1024, 1024))
542 543 544 545
  {
    error = LOG_INFO_MEM;
    goto err;
  }
unknown's avatar
unknown committed
546 547
  logs_to_keep_inited = 1;
  
548
  for (;;)
549 550 551
  {
    my_off_t init_purge_offset= my_b_tell(&io_cache);
    if (!(fname_len=my_b_gets(&io_cache, fname, FN_REFLEN)))
unknown's avatar
unknown committed
552
    {
553 554 555 556 557 558 559
      if(!io_cache.error)
	break;
      error = LOG_INFO_IO;
      goto err;
    }

    fname[--fname_len]=0;			// kill \n
560
    if (!memcmp(fname, to_log, fname_len + 1 ))
561 562 563 564
    {
      found_log = 1;
      purge_offset = init_purge_offset;
    }
unknown's avatar
unknown committed
565
      
566
    // if one of the logs before the target is in use
567
    if (!found_log && log_in_use(fname))
568 569 570 571
    {
      error = LOG_INFO_IN_USE;
      goto err;
    }
unknown's avatar
unknown committed
572
      
unknown's avatar
unknown committed
573
    if (!(p = sql_memdup(fname, fname_len+1)) ||
574 575
	insert_dynamic(found_log ? &logs_to_keep : &logs_to_purge,
		       (gptr) &p))
unknown's avatar
unknown committed
576
    {
577
      error = LOG_INFO_MEM;
unknown's avatar
unknown committed
578 579
      goto err;
    }
580 581 582
  }
  
  end_io_cache(&io_cache);
583
  if (!found_log)
584 585 586 587
  {
    error = LOG_INFO_EOF;
    goto err;
  }
unknown's avatar
unknown committed
588
  
589
  for (i = 0; i < logs_to_purge.elements; i++)
590 591 592 593 594 595
  {
    char* l;
    get_dynamic(&logs_to_purge, (gptr)&l, i);
    if (my_delete(l, MYF(MY_WME)))
      sql_print_error("Error deleting %s during purge", l);
  }
unknown's avatar
unknown committed
596
  
unknown's avatar
unknown committed
597 598 599 600
  /*
    If we get killed -9 here, the sysadmin would have to edit
    the log index file after restart - otherwise, this should be safe
  */
601 602 603
#ifdef HAVE_FTRUNCATE
  if (ftruncate(index_file,0))
  {
unknown's avatar
unknown committed
604
    sql_print_error("Could not truncate the binlog index file \
605 606 607 608 609 610 611 612
during log purge for write");
    error = LOG_INFO_FATAL;
    goto err;
  }
  my_seek(index_file, 0, MY_SEEK_CUR,MYF(MY_WME));
#else
  my_close(index_file, MYF(MY_WME));
  my_delete(index_file_name, MYF(MY_WME));
613
  if ((index_file = my_open(index_file_name,
unknown's avatar
unknown committed
614
			    O_CREAT | O_BINARY | O_RDWR | O_APPEND,
615
			    MYF(MY_WME)))<0)
unknown's avatar
unknown committed
616
  {
unknown's avatar
unknown committed
617
    sql_print_error("Could not re-open the binlog index file \
unknown's avatar
unknown committed
618 619 620 621
during log purge for write");
    error = LOG_INFO_FATAL;
    goto err;
  }
622
#endif
unknown's avatar
unknown committed
623
  
624
  for (i = 0; i < logs_to_keep.elements; i++)
625 626 627
  {
    char* l;
    get_dynamic(&logs_to_keep, (gptr)&l, i);
unknown's avatar
unknown committed
628 629
    if (my_write(index_file, (byte*) l, strlen(l), MYF(MY_WME|MY_NABP)) ||
	my_write(index_file, (byte*) "\n", 1, MYF(MY_WME|MY_NABP)))
unknown's avatar
unknown committed
630
    {
631 632
      error = LOG_INFO_FATAL;
      goto err;
unknown's avatar
unknown committed
633 634
    }
  }
635

unknown's avatar
unknown committed
636 637 638
  // now update offsets
  adjust_linfo_offsets(purge_offset);
  error = 0;
639

unknown's avatar
unknown committed
640 641
err:
  pthread_mutex_unlock(&LOCK_index);
642
  if (logs_to_purge_inited)
unknown's avatar
unknown committed
643
    delete_dynamic(&logs_to_purge);
644
  if (logs_to_keep_inited)
unknown's avatar
unknown committed
645
    delete_dynamic(&logs_to_keep);
646
  end_io_cache(&io_cache);
unknown's avatar
unknown committed
647 648 649
  return error;
}

unknown's avatar
unknown committed
650 651 652
// we assume that buf has at least FN_REFLEN bytes alloced
void MYSQL_LOG::make_log_name(char* buf, const char* log_ident)
{
653
  buf[0] = 0;					// In case of error
654
  if (inited)
655 656 657 658 659
  {
    int dir_len = dirname_length(log_file_name); 
    int ident_len = (uint) strlen(log_ident);
    if (dir_len + ident_len + 1 > FN_REFLEN)
      return; // protection agains malicious buffer overflow
unknown's avatar
unknown committed
660
      
661 662 663 664
    memcpy(buf, log_file_name, dir_len);
    // copy filename + end null
    memcpy(buf + dir_len, log_ident, ident_len + 1);
  }
unknown's avatar
unknown committed
665 666 667 668 669 670 671
}

bool MYSQL_LOG::is_active(const char* log_file_name)
{
  return inited && !strcmp(log_file_name, this->log_file_name);
}

672
void MYSQL_LOG::new_file(bool inside_mutex)
unknown's avatar
unknown committed
673
{
unknown's avatar
unknown committed
674
  if (is_open())
unknown's avatar
unknown committed
675 676
  {
    char new_name[FN_REFLEN], *old_name=name;
677 678
    if (!inside_mutex)
      VOID(pthread_mutex_lock(&LOCK_log));
unknown's avatar
unknown committed
679 680

    if (!no_rotate)
unknown's avatar
unknown committed
681 682
    {
      /*
unknown's avatar
unknown committed
683 684
	only rotate open logs that are marked non-rotatable
	(binlog with constant name are non-rotatable)
unknown's avatar
unknown committed
685
      */
unknown's avatar
unknown committed
686 687 688 689 690 691 692 693
      if (generate_new_name(new_name, name))
      {
	if (!inside_mutex)
	  VOID(pthread_mutex_unlock(&LOCK_log));
	return;					// Something went wrong
      }
      if (log_type == LOG_BIN)
      {
694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711
	if (!no_auto_events)
	{
	  /*
	    We log the whole file name for log file as the user may decide
	    to change base names at some point.
	  */
	  THD* thd = current_thd;
	  Rotate_log_event r(thd,new_name+dirname_length(new_name));
	  r.set_log_pos(this);

	  /*
	    This log rotation could have been initiated by a master of
	    the slave running with log-bin we set the flag on rotate
	    event to prevent inifinite log rotation loop
	  */
	  if (thd && thd->slave_thread)
	    r.flags |= LOG_EVENT_FORCED_ROTATE_F;
	  r.write(&log_file);
unknown's avatar
unknown committed
712
	  bytes_written += r.get_event_len();
713 714 715 716 717
	}
	// update needs to be signaled even if there is no rotate event
	// log rotation should give the waiting thread a signal to
	// discover EOF and move on to the next log
	signal_update(); 
unknown's avatar
unknown committed
718
      }
unknown's avatar
unknown committed
719 720
      else
	strmov(new_name, old_name);		// Reopen old file name
unknown's avatar
unknown committed
721 722 723
    }
    name=0;
    close();
724
    open(old_name, log_type, new_name, io_cache_type, no_auto_events);
unknown's avatar
unknown committed
725 726 727
    my_free(old_name,MYF(0));
    last_time=query_start=0;
    write_error=0;
728 729
    if (!inside_mutex)
      VOID(pthread_mutex_unlock(&LOCK_log));
unknown's avatar
unknown committed
730 731 732
  }
}

733 734 735 736 737 738 739 740 741 742 743 744 745
bool MYSQL_LOG::append(Log_event* ev)
{
  bool error = 0;
  pthread_mutex_lock(&LOCK_log);
  
  DBUG_ASSERT(log_file.type == SEQ_READ_APPEND);
  // Log_event::write() is smart enough to use my_b_write() or
  // my_b_append() depending on the kind of cache we have
  if (ev->write(&log_file))
  {
    error=1;
    goto err;
  }
unknown's avatar
unknown committed
746
  bytes_written += ev->get_event_len();
747 748 749 750 751 752 753 754 755 756
  if ((uint)my_b_append_tell(&log_file) > max_binlog_size)
  {
    new_file(1);
  }
  signal_update();
err:  
  pthread_mutex_unlock(&LOCK_log);
  return error;
}

757 758 759 760 761 762
bool MYSQL_LOG::appendv(const char* buf, uint len,...)
{
  bool error = 0;
  va_list(args);
  va_start(args,len);
  
763 764
  DBUG_ASSERT(log_file.type == SEQ_READ_APPEND);
  
765 766 767
  pthread_mutex_lock(&LOCK_log);
  do
  {
unknown's avatar
unknown committed
768
    if (my_b_append(&log_file,(byte*) buf,len))
769 770 771 772
    {
      error = 1;
      break;
    }
unknown's avatar
unknown committed
773
    bytes_written += len;
774 775
  } while ((buf=va_arg(args,const char*)) && (len=va_arg(args,uint)));
  
unknown's avatar
unknown committed
776
  if ((uint) my_b_append_tell(&log_file) > max_binlog_size)
777 778 779 780
  {
    new_file(1);
  }
  
781 782 783 784 785
  if (!error)
    signal_update();
  pthread_mutex_unlock(&LOCK_log);
  return error;
}
unknown's avatar
unknown committed
786

unknown's avatar
unknown committed
787

788
bool MYSQL_LOG::write(THD *thd,enum enum_server_command command,
unknown's avatar
unknown committed
789 790
		      const char *format,...)
{
791
  if (is_open() && (what_to_log & (1L << (uint) command)))
unknown's avatar
unknown committed
792
  {
793
    int error=0;
unknown's avatar
unknown committed
794
    VOID(pthread_mutex_lock(&LOCK_log));
795 796

    /* Test if someone closed after the is_open test */
unknown's avatar
unknown committed
797 798 799 800
    if (log_type != LOG_CLOSED)
    {
      time_t skr;
      ulong id;
801 802 803 804
      va_list args;
      va_start(args,format);
      char buff[32];

unknown's avatar
unknown committed
805 806 807 808 809 810
      if (thd)
      {						// Normal thread
	if ((thd->options & OPTION_LOG_OFF) &&
	    (thd->master_access & PROCESS_ACL))
	{
	  VOID(pthread_mutex_unlock(&LOCK_log));
811
	  return 0;				// No logging
unknown's avatar
unknown committed
812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828
	}
	id=thd->thread_id;
	if (thd->user_time || !(skr=thd->query_start()))
	  skr=time(NULL);			// Connected
      }
      else
      {						// Log from connect handler
	skr=time(NULL);
	id=0;
      }
      if (skr != last_time)
      {
	last_time=skr;
	struct tm tm_tmp;
	struct tm *start;
	localtime_r(&skr,&tm_tmp);
	start=&tm_tmp;
829 830 831 832 833 834 835 836
	/* Note that my_b_write() assumes it knows the length for this */
	sprintf(buff,"%02d%02d%02d %2d:%02d:%02d\t",
		start->tm_year % 100,
		start->tm_mon+1,
		start->tm_mday,
		start->tm_hour,
		start->tm_min,
		start->tm_sec);
unknown's avatar
unknown committed
837
	if (my_b_write(&log_file, (byte*) buff,16))
unknown's avatar
unknown committed
838 839
	  error=errno;
      }
unknown's avatar
unknown committed
840
      else if (my_b_write(&log_file, (byte*) "\t\t",2) < 0)
unknown's avatar
unknown committed
841
	error=errno;
842
      sprintf(buff,"%7ld %-11.11s", id,command_name[(uint) command]);
unknown's avatar
unknown committed
843
      if (my_b_write(&log_file, (byte*) buff,strlen(buff)))
unknown's avatar
unknown committed
844 845 846
	error=errno;
      if (format)
      {
unknown's avatar
unknown committed
847
	if (my_b_write(&log_file, (byte*) " ",1) ||
848
	    my_b_vprintf(&log_file,format,args) == (uint) -1)
unknown's avatar
unknown committed
849 850
	  error=errno;
      }
unknown's avatar
unknown committed
851
      if (my_b_write(&log_file, (byte*) "\n",1) ||
852
	  flush_io_cache(&log_file))
unknown's avatar
unknown committed
853 854 855 856 857 858
	error=errno;
      if (error && ! write_error)
      {
	write_error=1;
	sql_print_error(ER(ER_ERROR_ON_WRITE),name,error);
      }
859
      va_end(args);
unknown's avatar
unknown committed
860 861
    }
    VOID(pthread_mutex_unlock(&LOCK_log));
862
    return error != 0;
unknown's avatar
unknown committed
863
  }
864
  return 0;
unknown's avatar
unknown committed
865 866 867
}


868
bool MYSQL_LOG::write(Log_event* event_info)
unknown's avatar
unknown committed
869
{
870
  /* In most cases this is only called if 'is_open()' is true */
unknown's avatar
unknown committed
871
  bool error=0;
872 873
  bool should_rotate = 0;
  
unknown's avatar
unknown committed
874 875
  if (!inited)					// Can't use mutex if not init
    return 0;
876
  VOID(pthread_mutex_lock(&LOCK_log));
877
  if (is_open())
unknown's avatar
unknown committed
878
  {
879
    THD *thd=event_info->thd;
880
    const char* db = event_info->get_db();
unknown's avatar
unknown committed
881
#ifdef USING_TRANSACTIONS    
unknown's avatar
unknown committed
882
    IO_CACHE *file = ((event_info->get_cache_stmt() && thd) ?
883
		      &thd->transaction.trans_log :
884
		      &log_file);
unknown's avatar
unknown committed
885 886 887
#else
    IO_CACHE *file = &log_file;
#endif    
888
    if ((thd && !(thd->options & OPTION_BIN_LOG) &&
889
	 (thd->master_access & PROCESS_ACL)) ||
890
	(db && !db_ok(db, binlog_do_db, binlog_ignore_db)))
unknown's avatar
unknown committed
891
    {
892 893 894
      VOID(pthread_mutex_unlock(&LOCK_log));
      return 0;
    }
895

unknown's avatar
unknown committed
896
    error=1;
unknown's avatar
unknown committed
897 898 899 900
    /*
      No check for auto events flag here - this write method should
      never be called if auto-events are enabled
    */
901
    if (thd && thd->last_insert_id_used)
902
    {
903
      Intvar_log_event e(thd,(uchar)LAST_INSERT_ID_EVENT,thd->last_insert_id);
904
      e.set_log_pos(this);
unknown's avatar
unknown committed
905
      if (thd->server_id)
unknown's avatar
merge  
unknown committed
906
        e.server_id = thd->server_id;
907 908 909
      if (e.write(file))
	goto err;
    }
910
    if (thd && thd->insert_id_used)
911
    {
912
      Intvar_log_event e(thd,(uchar)INSERT_ID_EVENT,thd->last_insert_id);
913
      e.set_log_pos(this);
unknown's avatar
unknown committed
914 915
      if (thd->server_id)
        e.server_id = thd->server_id;
916 917 918
      if (e.write(file))
	goto err;
    }
919
    if (thd && thd->convert_set)
920 921 922 923 924 925 926 927
    {
      char buf[1024] = "SET CHARACTER SET ";
      char* p = strend(buf);
      p = strmov(p, thd->convert_set->name);
      int save_query_length = thd->query_length;
      // just in case somebody wants it later
      thd->query_length = (uint)(p - buf);
      Query_log_event e(thd, buf);
928
      e.set_log_pos(this);
929 930 931 932
      if (e.write(file))
	goto err;
      thd->query_length = save_query_length; // clean up
    }
933
    event_info->set_log_pos(this);
934 935 936 937
    if (event_info->write(file) ||
	file == &log_file && flush_io_cache(file))
      goto err;
    error=0;
938

unknown's avatar
unknown committed
939 940 941 942 943 944 945 946 947
    /*
      Tell for transactional table handlers up to which position in the
      binlog file we wrote. The table handler can store this info, and
      after crash recovery print for the user the offset of the last
      transactions which were recovered. Actually, we must also call
      the table handler commit here, protected by the LOCK_log mutex,
      because otherwise the transactions may end up in a different order
      in the table handler log!
    */
948

unknown's avatar
unknown committed
949 950
    if (file == &log_file)
    {
951
      error = ha_report_binlog_offset_and_commit(thd, log_file_name,
unknown's avatar
unknown committed
952 953
                                                 file->pos_in_file);
      should_rotate= (my_b_tell(file) >= (my_off_t) max_binlog_size); 
954 955
    }

956 957 958 959 960 961 962 963 964 965
err:
    if (error)
    {
      if (my_errno == EFBIG)
	my_error(ER_TRANS_CACHE_FULL, MYF(0));
      else
	my_error(ER_ERROR_ON_WRITE, MYF(0), name, errno);
      write_error=1;
    }
    if (file == &log_file)
966
      signal_update();
967
  }
968
  if (should_rotate)
969 970
    new_file(1); // inside mutex
  VOID(pthread_mutex_unlock(&LOCK_log));
971 972 973
  return error;
}

unknown's avatar
unknown committed
974 975 976 977 978 979 980 981 982
uint MYSQL_LOG::next_file_id()
{
  uint res;
  pthread_mutex_lock(&LOCK_log);
  res = file_id++;
  pthread_mutex_unlock(&LOCK_log);
  return res;
}

983 984 985 986 987 988
/*
  Write a cached log entry to the binary log
  We only come here if there is something in the cache.
  'cache' needs to be reinitialized after this functions returns.
*/

989
bool MYSQL_LOG::write(THD *thd, IO_CACHE *cache)
990 991 992
{
  VOID(pthread_mutex_lock(&LOCK_log));
  bool error=1;
993
  
994 995 996
  if (is_open())
  {
    uint length;
997
    //QQ: this looks like a bug - why READ_CACHE?
unknown's avatar
unknown committed
998
    if (reinit_io_cache(cache, READ_CACHE, 0, 0, 0))
999
    {
unknown's avatar
unknown committed
1000
      sql_print_error(ER(ER_ERROR_ON_WRITE), cache->file_name, errno);
1001 1002
      goto err;
    }
1003 1004
    length=my_b_bytes_in_cache(cache);
    do
1005
    {
unknown's avatar
unknown committed
1006
      if (my_b_write(&log_file, cache->read_pos, length))
1007
      {
1008
	if (!write_error)
1009
	  sql_print_error(ER(ER_ERROR_ON_WRITE), name, errno);
1010
	goto err;
1011
      }
unknown's avatar
unknown committed
1012
      cache->read_pos=cache->read_end;		// Mark buffer used up
1013
    } while ((length=my_b_fill(cache)));
1014 1015 1016
    if (flush_io_cache(&log_file))
    {
      if (!write_error)
unknown's avatar
unknown committed
1017
	sql_print_error(ER(ER_ERROR_ON_WRITE), name, errno);
1018 1019 1020 1021
      goto err;
    }
    if (cache->error)				// Error on read
    {
unknown's avatar
unknown committed
1022
      sql_print_error(ER(ER_ERROR_ON_READ), cache->file_name, errno);
1023
      goto err;
unknown's avatar
unknown committed
1024
    }
1025 1026 1027 1028
    error = ha_report_binlog_offset_and_commit(thd, log_file_name,
					       log_file.pos_in_file);
    if (error)
      goto err;
unknown's avatar
unknown committed
1029
  }
1030 1031 1032 1033 1034 1035
  error=0;

err:
  if (error)
    write_error=1;
  else
1036
    signal_update();
1037
    
1038 1039
  VOID(pthread_mutex_unlock(&LOCK_log));
  
1040
  return error;
unknown's avatar
unknown committed
1041 1042
}

1043

unknown's avatar
unknown committed
1044 1045
/* Write update log in a format suitable for incremental backup */

1046
bool MYSQL_LOG::write(THD *thd,const char *query, uint query_length,
1047
		      time_t query_start)
unknown's avatar
unknown committed
1048
{
1049
  bool error=0;
1050
  if (is_open())
unknown's avatar
unknown committed
1051
  {
1052
    time_t current_time;
unknown's avatar
unknown committed
1053
    VOID(pthread_mutex_lock(&LOCK_log));
1054
    if (is_open())
unknown's avatar
unknown committed
1055
    {						// Safety agains reopen
1056
      int tmp_errno=0;
unknown's avatar
unknown committed
1057 1058 1059 1060 1061 1062
      char buff[80],*end;
      end=buff;
      if (!(thd->options & OPTION_UPDATE_LOG) &&
	  (thd->master_access & PROCESS_ACL))
      {
	VOID(pthread_mutex_unlock(&LOCK_log));
1063
	return 0;
unknown's avatar
unknown committed
1064
      }
unknown's avatar
unknown committed
1065
      if ((specialflag & SPECIAL_LONG_LOG_FORMAT) || query_start)
unknown's avatar
unknown committed
1066
      {
1067 1068
	current_time=time(NULL);
	if (current_time != last_time)
unknown's avatar
unknown committed
1069
	{
1070
	  last_time=current_time;
unknown's avatar
unknown committed
1071 1072
	  struct tm tm_tmp;
	  struct tm *start;
1073
	  localtime_r(&current_time,&tm_tmp);
unknown's avatar
unknown committed
1074
	  start=&tm_tmp;
1075 1076 1077 1078 1079 1080 1081 1082
	  /* Note that my_b_write() assumes it knows the length for this */
	  sprintf(buff,"# Time: %02d%02d%02d %2d:%02d:%02d\n",
		  start->tm_year % 100,
		  start->tm_mon+1,
		  start->tm_mday,
		  start->tm_hour,
		  start->tm_min,
		  start->tm_sec);
unknown's avatar
unknown committed
1083
	  if (my_b_write(&log_file, (byte*) buff,24))
1084
	    tmp_errno=errno;
unknown's avatar
unknown committed
1085
	}
unknown's avatar
unknown committed
1086
	if (my_b_printf(&log_file, "# User@Host: %s[%s] @ %s [%s]\n",
1087 1088 1089
			thd->priv_user,
			thd->user,
			thd->host ? thd->host : "",
unknown's avatar
unknown committed
1090
			thd->ip ? thd->ip : "") == (uint) -1)
1091
	  tmp_errno=errno;
unknown's avatar
unknown committed
1092
      }
1093 1094 1095
      if (query_start)
      {
	/* For slow query log */
1096
	if (my_b_printf(&log_file,
1097
			"# Query_time: %lu  Lock_time: %lu  Rows_sent: %lu  Rows_examined: %lu\n",
1098 1099
			(ulong) (current_time - query_start),
			(ulong) (thd->time_after_lock - query_start),
1100 1101 1102
			(ulong) thd->sent_row_count,
			(ulong) thd->examined_row_count) == (uint) -1)
	  tmp_errno=errno;
1103
      }
unknown's avatar
unknown committed
1104 1105
      if (thd->db && strcmp(thd->db,db))
      {						// Database changed
unknown's avatar
unknown committed
1106
	if (my_b_printf(&log_file,"use %s;\n",thd->db) == (uint) -1)
1107
	  tmp_errno=errno;
unknown's avatar
unknown committed
1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137
	strmov(db,thd->db);
      }
      if (thd->last_insert_id_used)
      {
	end=strmov(end,",last_insert_id=");
	end=longlong10_to_str((longlong) thd->current_insert_id,end,-10);
      }
      // Save value if we do an insert.
      if (thd->insert_id_used)
      {
	if (specialflag & SPECIAL_LONG_LOG_FORMAT)
	{
	  end=strmov(end,",insert_id=");
	  end=longlong10_to_str((longlong) thd->last_insert_id,end,-10);
	}
      }
      if (thd->query_start_used)
      {
	if (query_start != thd->query_start())
	{
	  query_start=thd->query_start();
	  end=strmov(end,",timestamp=");
	  end=int10_to_str((long) query_start,end,10);
	}
      }
      if (end != buff)
      {
	*end++=';';
	*end++='\n';
	*end=0;
unknown's avatar
unknown committed
1138 1139
	if (my_b_write(&log_file, (byte*) "SET ",4) ||
	    my_b_write(&log_file, (byte*) buff+1,(uint) (end-buff)-1))
1140
	  tmp_errno=errno;
unknown's avatar
unknown committed
1141 1142 1143 1144 1145 1146
      }
      if (!query)
      {
	query="#adminstrator command";
	query_length=21;
      }
unknown's avatar
unknown committed
1147 1148
      if (my_b_write(&log_file, (byte*) query,query_length) ||
	  my_b_write(&log_file, (byte*) ";\n",2) ||
1149
	  flush_io_cache(&log_file))
1150 1151
	tmp_errno=errno;
      if (tmp_errno)
unknown's avatar
unknown committed
1152
      {
1153 1154 1155 1156 1157 1158
	error=1;
	if (! write_error)
	{
	  write_error=1;
	  sql_print_error(ER(ER_ERROR_ON_WRITE),name,error);
	}
unknown's avatar
unknown committed
1159 1160 1161 1162
      }
    }
    VOID(pthread_mutex_unlock(&LOCK_log));
  }
1163
  return error;
unknown's avatar
unknown committed
1164 1165
}

1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182
void MYSQL_LOG:: wait_for_update(THD* thd)
{
  const char* old_msg = thd->enter_cond(&update_cond, &LOCK_log,
					"Slave: waiting for binlog update");
  pthread_cond_wait(&update_cond, &LOCK_log);
  // this is not a bug - we unlock the mutex for the caller, and expect him
  // to lock it and then not unlock it upon return. This is a rather odd
  // way of doing things, but this is the cleanest way I could think of to
  // solve the race deadlock caused by THD::awake() first acquiring mysys_var
  // mutex and then the current mutex, while wait_for_update being called with
  // the current mutex already aquired and THD::exit_cond() trying to acquire
  // mysys_var mutex. We do need the mutex to be acquired prior to the
  // invocation of wait_for_update in all cases, so mutex acquisition inside
  // wait_for_update() is not an option
  pthread_mutex_unlock(&LOCK_log);
  thd->exit_cond(old_msg);
}  
unknown's avatar
unknown committed
1183 1184 1185

void MYSQL_LOG::close(bool exiting)
{					// One can't set log_type here!
1186
  if (is_open())
unknown's avatar
unknown committed
1187
  {
1188
    if (log_type == LOG_BIN && !no_auto_events)
unknown's avatar
unknown committed
1189 1190
    {
      Stop_log_event s;
1191
      s.set_log_pos(this);
1192
      s.write(&log_file);
1193
      signal_update();
unknown's avatar
unknown committed
1194
    }
1195
    end_io_cache(&log_file);
1196
    if (my_close(log_file.file,MYF(0)) < 0 && ! write_error)
unknown's avatar
unknown committed
1197 1198 1199 1200 1201
    {
      write_error=1;
      sql_print_error(ER(ER_ERROR_ON_WRITE),name,errno);
    }
  }
1202
  if (exiting && index_file >= 0)
1203
  {
1204
    if (my_close(index_file,MYF(0)) < 0 && ! write_error)
unknown's avatar
unknown committed
1205
    {
1206 1207
      write_error=1;
      sql_print_error(ER(ER_ERROR_ON_WRITE),name,errno);
unknown's avatar
unknown committed
1208
    }
unknown's avatar
unknown committed
1209 1210
    index_file=-1;
    log_type=LOG_CLOSED;
1211
  }
1212
  safeFree(name);
unknown's avatar
unknown committed
1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263
}


	/* Check if a string is a valid number */
	/* Output: TRUE -> number */

static bool test_if_number(register const char *str,
			   long *res, bool allow_wildcards)
{
  reg2 int flag;
  const char *start;
  DBUG_ENTER("test_if_number");

  flag=0; start=str;
  while (*str++ == ' ') ;
  if (*--str == '-' || *str == '+')
    str++;
  while (isdigit(*str) || (allow_wildcards &&
			   (*str == wild_many || *str == wild_one)))
  {
    flag=1;
    str++;
  }
  if (*str == '.')
  {
    for (str++ ;
	 isdigit(*str) ||
	   (allow_wildcards && (*str == wild_many || *str == wild_one)) ;
	 str++, flag=1) ;
  }
  if (*str != 0 || flag == 0)
    DBUG_RETURN(0);
  if (res)
    *res=atol(start);
  DBUG_RETURN(1);			/* Number ok */
} /* test_if_number */


void sql_print_error(const char *format,...)
{
  va_list args;
  time_t skr;
  struct tm tm_tmp;
  struct tm *start;
  va_start(args,format);
  DBUG_ENTER("sql_print_error");

  VOID(pthread_mutex_lock(&LOCK_error_log));
#ifndef DBUG_OFF
  {
    char buff[1024];
1264
    my_vsnprintf(buff,sizeof(buff)-1,format,args);
unknown's avatar
unknown committed
1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296
    DBUG_PRINT("error",("%s",buff));
  }
#endif
  skr=time(NULL);
  localtime_r(&skr,&tm_tmp);
  start=&tm_tmp;
  fprintf(stderr,"%02d%02d%02d %2d:%02d:%02d  ",
	  start->tm_year % 100,
	  start->tm_mon+1,
	  start->tm_mday,
	  start->tm_hour,
	  start->tm_min,
	  start->tm_sec);
  (void) vfprintf(stderr,format,args);
  (void) fputc('\n',stderr);
  fflush(stderr);
  va_end(args);

  VOID(pthread_mutex_unlock(&LOCK_error_log));
  DBUG_VOID_RETURN;
}



void sql_perror(const char *message)
{
#ifdef HAVE_STRERROR
  sql_print_error("%s: %s",message, strerror(errno));
#else
  perror(message);
#endif
}