~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to server/sql_table.cc

  • Committer: Brian Aker
  • Date: 2008-07-19 07:02:30 UTC
  • Revision ID: brian@tangent.org-20080719070230-2tbzbybcochk7f0g
Remove dead DDL log code.

Show diffs side-by-side

added added

removed removed

Lines of Context:
225
225
}
226
226
 
227
227
/*
228
 
--------------------------------------------------------------------------
229
 
 
230
 
   MODULE: DDL log
231
 
   -----------------
232
 
 
233
 
   This module is used to ensure that we can recover from crashes that occur
234
 
   in the middle of a meta-data operation in MySQL. E.g. DROP TABLE t1, t2;
235
 
   We need to ensure that both t1 and t2 are dropped and not only t1 and
236
 
   also that each table drop is entirely done and not "half-baked".
237
 
 
238
 
   To support this we create log entries for each meta-data statement in the
239
 
   ddl log while we are executing. These entries are dropped when the
240
 
   operation is completed.
241
 
 
242
 
   At recovery those entries that were not completed will be executed.
243
 
 
244
 
   There is only one ddl log in the system and it is protected by a mutex
245
 
   and there is a global struct that contains information about its current
246
 
   state.
247
 
 
248
 
   History:
249
 
   First version written in 2006 by Mikael Ronstrom
250
 
--------------------------------------------------------------------------
251
 
*/
252
 
 
253
 
 
254
 
struct st_global_ddl_log
255
 
{
256
 
  /*
257
 
    We need to adjust buffer size to be able to handle downgrades/upgrades
258
 
    where IO_SIZE has changed. We'll set the buffer size such that we can
259
 
    handle that the buffer size was upto 4 times bigger in the version
260
 
    that wrote the DDL log.
261
 
  */
262
 
  char file_entry_buf[4*IO_SIZE];
263
 
  char file_name_str[FN_REFLEN];
264
 
  char *file_name;
265
 
  DDL_LOG_MEMORY_ENTRY *first_free;
266
 
  DDL_LOG_MEMORY_ENTRY *first_used;
267
 
  uint num_entries;
268
 
  File file_id;
269
 
  uint name_len;
270
 
  uint io_size;
271
 
  bool inited;
272
 
  bool do_release;
273
 
  bool recovery_phase;
274
 
  st_global_ddl_log() : inited(false), do_release(false) {}
275
 
};
276
 
 
277
 
st_global_ddl_log global_ddl_log;
278
 
 
279
 
pthread_mutex_t LOCK_gdl;
280
 
 
281
 
#define DDL_LOG_ENTRY_TYPE_POS 0
282
 
#define DDL_LOG_ACTION_TYPE_POS 1
283
 
#define DDL_LOG_PHASE_POS 2
284
 
#define DDL_LOG_NEXT_ENTRY_POS 4
285
 
#define DDL_LOG_NAME_POS 8
286
 
 
287
 
#define DDL_LOG_NUM_ENTRY_POS 0
288
 
#define DDL_LOG_NAME_LEN_POS 4
289
 
#define DDL_LOG_IO_SIZE_POS 8
290
 
 
291
 
/*
292
 
  Read one entry from ddl log file
293
 
  SYNOPSIS
294
 
    read_ddl_log_file_entry()
295
 
    entry_no                     Entry number to read
296
 
  RETURN VALUES
297
 
    true                         Error
298
 
    false                        Success
299
 
*/
300
 
 
301
 
static bool read_ddl_log_file_entry(uint entry_no)
302
 
{
303
 
  bool error= false;
304
 
  File file_id= global_ddl_log.file_id;
305
 
  uchar *file_entry_buf= (uchar*)global_ddl_log.file_entry_buf;
306
 
  ssize_t io_size= (ssize_t)global_ddl_log.io_size;
307
 
  
308
 
  if (pread(file_id, file_entry_buf, io_size, io_size * entry_no) != io_size)
309
 
    error= true;
310
 
  return(error);
311
 
}
312
 
 
313
 
 
314
 
/*
315
 
  Write one entry from ddl log file
316
 
  SYNOPSIS
317
 
    write_ddl_log_file_entry()
318
 
    entry_no                     Entry number to read
319
 
  RETURN VALUES
320
 
    true                         Error
321
 
    false                        Success
322
 
*/
323
 
 
324
 
static bool write_ddl_log_file_entry(uint entry_no)
325
 
{
326
 
  bool error= false;
327
 
  File file_id= global_ddl_log.file_id;
328
 
  char *file_entry_buf= (char*)global_ddl_log.file_entry_buf;
329
 
 
330
 
  if (pwrite(file_id, (uchar*)file_entry_buf,
331
 
                IO_SIZE, IO_SIZE * entry_no) != IO_SIZE)
332
 
    error= true;
333
 
  return(error);
334
 
}
335
 
 
336
 
 
337
 
/*
338
 
  Write ddl log header
339
 
  SYNOPSIS
340
 
    write_ddl_log_header()
341
 
  RETURN VALUES
342
 
    true                      Error
343
 
    false                     Success
344
 
*/
345
 
 
346
 
static bool write_ddl_log_header()
347
 
{
348
 
  uint16 const_var;
349
 
  bool error= false;
350
 
 
351
 
  int4store(&global_ddl_log.file_entry_buf[DDL_LOG_NUM_ENTRY_POS],
352
 
            global_ddl_log.num_entries);
353
 
  const_var= FN_LEN;
354
 
  int4store(&global_ddl_log.file_entry_buf[DDL_LOG_NAME_LEN_POS],
355
 
            (ulong) const_var);
356
 
  const_var= IO_SIZE;
357
 
  int4store(&global_ddl_log.file_entry_buf[DDL_LOG_IO_SIZE_POS],
358
 
            (ulong) const_var);
359
 
  if (write_ddl_log_file_entry(0UL))
360
 
  {
361
 
    sql_print_error("Error writing ddl log header");
362
 
    return(true);
363
 
  }
364
 
  VOID(sync_ddl_log());
365
 
  return(error);
366
 
}
367
 
 
368
 
 
369
 
/*
370
 
  Create ddl log file name
371
 
  SYNOPSIS
372
 
    create_ddl_log_file_name()
373
 
    file_name                   Filename setup
374
 
  RETURN VALUES
375
 
    NONE
376
 
*/
377
 
 
378
 
static inline void create_ddl_log_file_name(char *file_name)
379
 
{
380
 
  strxmov(file_name, mysql_data_home, "/", "ddl_log.log", NullS);
381
 
}
382
 
 
383
 
 
384
 
/*
385
 
  Read header of ddl log file
386
 
  SYNOPSIS
387
 
    read_ddl_log_header()
388
 
  RETURN VALUES
389
 
    > 0                  Last entry in ddl log
390
 
    0                    No entries in ddl log
391
 
  DESCRIPTION
392
 
    When we read the ddl log header we get information about maximum sizes
393
 
    of names in the ddl log and we also get information about the number
394
 
    of entries in the ddl log.
395
 
*/
396
 
 
397
 
static uint read_ddl_log_header()
398
 
{
399
 
  char *file_entry_buf= (char*)global_ddl_log.file_entry_buf;
400
 
  char file_name[FN_REFLEN];
401
 
  uint entry_no;
402
 
  bool successful_open= false;
403
 
 
404
 
  create_ddl_log_file_name(file_name);
405
 
  if ((global_ddl_log.file_id= my_open(file_name,
406
 
                                        O_RDWR | O_BINARY, MYF(0))) >= 0)
407
 
  {
408
 
    if (read_ddl_log_file_entry(0UL))
409
 
    {
410
 
      /* Write message into error log */
411
 
      sql_print_error("Failed to read ddl log file in recovery");
412
 
    }
413
 
    else
414
 
      successful_open= true;
415
 
  }
416
 
  entry_no= uint4korr(&file_entry_buf[DDL_LOG_NUM_ENTRY_POS]);
417
 
  global_ddl_log.name_len= uint4korr(&file_entry_buf[DDL_LOG_NAME_LEN_POS]);
418
 
  if (successful_open)
419
 
  {
420
 
    global_ddl_log.io_size= uint4korr(&file_entry_buf[DDL_LOG_IO_SIZE_POS]);
421
 
    assert(global_ddl_log.io_size <=
422
 
                sizeof(global_ddl_log.file_entry_buf));
423
 
  }
424
 
  else
425
 
  {
426
 
    entry_no= 0;
427
 
  }
428
 
  global_ddl_log.first_free= NULL;
429
 
  global_ddl_log.first_used= NULL;
430
 
  global_ddl_log.num_entries= 0;
431
 
  VOID(pthread_mutex_init(&LOCK_gdl, MY_MUTEX_INIT_FAST));
432
 
  global_ddl_log.do_release= true;
433
 
  return(entry_no);
434
 
}
435
 
 
436
 
 
437
 
/*
438
 
  Read a ddl log entry
439
 
  SYNOPSIS
440
 
    read_ddl_log_entry()
441
 
    read_entry               Number of entry to read
442
 
    out:entry_info           Information from entry
443
 
  RETURN VALUES
444
 
    true                     Error
445
 
    false                    Success
446
 
  DESCRIPTION
447
 
    Read a specified entry in the ddl log
448
 
*/
449
 
 
450
 
bool read_ddl_log_entry(uint read_entry, DDL_LOG_ENTRY *ddl_log_entry)
451
 
{
452
 
  char *file_entry_buf= (char*)&global_ddl_log.file_entry_buf;
453
 
  uint inx;
454
 
  uchar single_char;
455
 
 
456
 
  if (read_ddl_log_file_entry(read_entry))
457
 
  {
458
 
    return(true);
459
 
  }
460
 
  ddl_log_entry->entry_pos= read_entry;
461
 
  single_char= file_entry_buf[DDL_LOG_ENTRY_TYPE_POS];
462
 
  ddl_log_entry->entry_type= (enum ddl_log_entry_code)single_char;
463
 
  single_char= file_entry_buf[DDL_LOG_ACTION_TYPE_POS];
464
 
  ddl_log_entry->action_type= (enum ddl_log_action_code)single_char;
465
 
  ddl_log_entry->phase= file_entry_buf[DDL_LOG_PHASE_POS];
466
 
  ddl_log_entry->next_entry= uint4korr(&file_entry_buf[DDL_LOG_NEXT_ENTRY_POS]);
467
 
  ddl_log_entry->name= &file_entry_buf[DDL_LOG_NAME_POS];
468
 
  inx= DDL_LOG_NAME_POS + global_ddl_log.name_len;
469
 
  ddl_log_entry->from_name= &file_entry_buf[inx];
470
 
  inx+= global_ddl_log.name_len;
471
 
  ddl_log_entry->handler_name= &file_entry_buf[inx];
472
 
  return(false);
473
 
}
474
 
 
475
 
 
476
 
/*
477
 
  Initialise ddl log
478
 
  SYNOPSIS
479
 
    init_ddl_log()
480
 
 
481
 
  DESCRIPTION
482
 
    Write the header of the ddl log file and length of names. Also set
483
 
    number of entries to zero.
484
 
 
485
 
  RETURN VALUES
486
 
    true                     Error
487
 
    false                    Success
488
 
*/
489
 
 
490
 
static bool init_ddl_log()
491
 
{
492
 
  char file_name[FN_REFLEN];
493
 
 
494
 
  if (global_ddl_log.inited)
495
 
    goto end;
496
 
 
497
 
  global_ddl_log.io_size= IO_SIZE;
498
 
  create_ddl_log_file_name(file_name);
499
 
  if ((global_ddl_log.file_id= my_create(file_name,
500
 
                                         CREATE_MODE,
501
 
                                         O_RDWR | O_TRUNC | O_BINARY,
502
 
                                         MYF(MY_WME))) < 0)
503
 
  {
504
 
    /* Couldn't create ddl log file, this is serious error */
505
 
    sql_print_error("Failed to open ddl log file");
506
 
    return(true);
507
 
  }
508
 
  global_ddl_log.inited= true;
509
 
  if (write_ddl_log_header())
510
 
  {
511
 
    VOID(my_close(global_ddl_log.file_id, MYF(MY_WME)));
512
 
    global_ddl_log.inited= false;
513
 
    return(true);
514
 
  }
515
 
 
516
 
end:
517
 
  return(false);
518
 
}
519
 
 
520
 
 
521
 
/*
522
 
  Execute one action in a ddl log entry
523
 
  SYNOPSIS
524
 
    execute_ddl_log_action()
525
 
    ddl_log_entry              Information in action entry to execute
526
 
  RETURN VALUES
527
 
    true                       Error
528
 
    false                      Success
529
 
*/
530
 
 
531
 
static int execute_ddl_log_action(THD *thd, DDL_LOG_ENTRY *ddl_log_entry)
532
 
{
533
 
  bool frm_action= false;
534
 
  LEX_STRING handler_name;
535
 
  handler *file= NULL;
536
 
  MEM_ROOT mem_root;
537
 
  int error= true;
538
 
  char to_path[FN_REFLEN];
539
 
  char from_path[FN_REFLEN];
540
 
  handlerton *hton;
541
 
 
542
 
  if (ddl_log_entry->entry_type == DDL_IGNORE_LOG_ENTRY_CODE)
543
 
  {
544
 
    return(false);
545
 
  }
546
 
  handler_name.str= (char*)ddl_log_entry->handler_name;
547
 
  handler_name.length= strlen(ddl_log_entry->handler_name);
548
 
  init_sql_alloc(&mem_root, TABLE_ALLOC_BLOCK_SIZE, 0); 
549
 
  if (!strcmp(ddl_log_entry->handler_name, reg_ext))
550
 
    frm_action= true;
551
 
  else
552
 
  {
553
 
    plugin_ref plugin= ha_resolve_by_name(thd, &handler_name);
554
 
    if (!plugin)
555
 
    {
556
 
      my_error(ER_ILLEGAL_HA, MYF(0), ddl_log_entry->handler_name);
557
 
      goto error;
558
 
    }
559
 
    hton= plugin_data(plugin, handlerton*);
560
 
    file= get_new_handler((TABLE_SHARE*)0, &mem_root, hton);
561
 
    if (!file)
562
 
    {
563
 
      my_error(ER_OUTOFMEMORY, MYF(0), sizeof(handler));
564
 
      goto error;
565
 
    }
566
 
  }
567
 
  switch (ddl_log_entry->action_type)
568
 
  {
569
 
    case DDL_LOG_REPLACE_ACTION:
570
 
    case DDL_LOG_DELETE_ACTION:
571
 
    {
572
 
      if (ddl_log_entry->phase == 0)
573
 
      {
574
 
        if (frm_action)
575
 
        {
576
 
          strxmov(to_path, ddl_log_entry->name, reg_ext, NullS);
577
 
          if ((error= my_delete(to_path, MYF(MY_WME))))
578
 
          {
579
 
            if (my_errno != ENOENT)
580
 
              break;
581
 
          }
582
 
        }
583
 
        else
584
 
        {
585
 
          if ((error= file->ha_delete_table(ddl_log_entry->name)))
586
 
          {
587
 
            if (error != ENOENT && error != HA_ERR_NO_SUCH_TABLE)
588
 
              break;
589
 
          }
590
 
        }
591
 
        if ((deactivate_ddl_log_entry(ddl_log_entry->entry_pos)))
592
 
          break;
593
 
        VOID(sync_ddl_log());
594
 
        error= false;
595
 
        if (ddl_log_entry->action_type == DDL_LOG_DELETE_ACTION)
596
 
          break;
597
 
      }
598
 
      assert(ddl_log_entry->action_type == DDL_LOG_REPLACE_ACTION);
599
 
      /*
600
 
        Fall through and perform the rename action of the replace
601
 
        action. We have already indicated the success of the delete
602
 
        action in the log entry by stepping up the phase.
603
 
      */
604
 
    }
605
 
    case DDL_LOG_RENAME_ACTION:
606
 
    {
607
 
      error= true;
608
 
      if (frm_action)
609
 
      {
610
 
        strxmov(to_path, ddl_log_entry->name, reg_ext, NullS);
611
 
        strxmov(from_path, ddl_log_entry->from_name, reg_ext, NullS);
612
 
        if (my_rename(from_path, to_path, MYF(MY_WME)))
613
 
          break;
614
 
      }
615
 
      else
616
 
      {
617
 
        if (file->ha_rename_table(ddl_log_entry->from_name,
618
 
                                  ddl_log_entry->name))
619
 
          break;
620
 
      }
621
 
      if ((deactivate_ddl_log_entry(ddl_log_entry->entry_pos)))
622
 
        break;
623
 
      VOID(sync_ddl_log());
624
 
      error= false;
625
 
      break;
626
 
    }
627
 
    default:
628
 
      assert(0);
629
 
      break;
630
 
  }
631
 
  delete file;
632
 
error:
633
 
  free_root(&mem_root, MYF(0)); 
634
 
  return(error);
635
 
}
636
 
 
637
 
 
638
 
/*
639
 
  Get a free entry in the ddl log
640
 
  SYNOPSIS
641
 
    get_free_ddl_log_entry()
642
 
    out:active_entry                A ddl log memory entry returned
643
 
  RETURN VALUES
644
 
    true                       Error
645
 
    false                      Success
646
 
*/
647
 
 
648
 
static bool get_free_ddl_log_entry(DDL_LOG_MEMORY_ENTRY **active_entry,
649
 
                                   bool *write_header)
650
 
{
651
 
  DDL_LOG_MEMORY_ENTRY *used_entry;
652
 
  DDL_LOG_MEMORY_ENTRY *first_used= global_ddl_log.first_used;
653
 
 
654
 
  if (global_ddl_log.first_free == NULL)
655
 
  {
656
 
    if (!(used_entry= (DDL_LOG_MEMORY_ENTRY*)my_malloc(
657
 
                              sizeof(DDL_LOG_MEMORY_ENTRY), MYF(MY_WME))))
658
 
    {
659
 
      sql_print_error("Failed to allocate memory for ddl log free list");
660
 
      return(true);
661
 
    }
662
 
    global_ddl_log.num_entries++;
663
 
    used_entry->entry_pos= global_ddl_log.num_entries;
664
 
    *write_header= true;
665
 
  }
666
 
  else
667
 
  {
668
 
    used_entry= global_ddl_log.first_free;
669
 
    global_ddl_log.first_free= used_entry->next_log_entry;
670
 
    *write_header= false;
671
 
  }
672
 
  /*
673
 
    Move from free list to used list
674
 
  */
675
 
  used_entry->next_log_entry= first_used;
676
 
  used_entry->prev_log_entry= NULL;
677
 
  global_ddl_log.first_used= used_entry;
678
 
  if (first_used)
679
 
    first_used->prev_log_entry= used_entry;
680
 
 
681
 
  *active_entry= used_entry;
682
 
  return(false);
683
 
}
684
 
 
685
 
 
686
 
/*
687
 
  External interface methods for the DDL log Module
688
 
  ---------------------------------------------------
689
 
*/
690
 
 
691
 
/*
692
 
  SYNOPSIS
693
 
    write_ddl_log_entry()
694
 
    ddl_log_entry         Information about log entry
695
 
    out:entry_written     Entry information written into   
696
 
 
697
 
  RETURN VALUES
698
 
    true                      Error
699
 
    false                     Success
700
 
 
701
 
  DESCRIPTION
702
 
    A careful write of the ddl log is performed to ensure that we can
703
 
    handle crashes occurring during CREATE and ALTER TABLE processing.
704
 
*/
705
 
 
706
 
bool write_ddl_log_entry(DDL_LOG_ENTRY *ddl_log_entry,
707
 
                         DDL_LOG_MEMORY_ENTRY **active_entry)
708
 
{
709
 
  bool error, write_header;
710
 
 
711
 
  if (init_ddl_log())
712
 
  {
713
 
    return(true);
714
 
  }
715
 
  global_ddl_log.file_entry_buf[DDL_LOG_ENTRY_TYPE_POS]=
716
 
                                    (char)DDL_LOG_ENTRY_CODE;
717
 
  global_ddl_log.file_entry_buf[DDL_LOG_ACTION_TYPE_POS]=
718
 
                                    (char)ddl_log_entry->action_type;
719
 
  global_ddl_log.file_entry_buf[DDL_LOG_PHASE_POS]= 0;
720
 
  int4store(&global_ddl_log.file_entry_buf[DDL_LOG_NEXT_ENTRY_POS],
721
 
            ddl_log_entry->next_entry);
722
 
  assert(strlen(ddl_log_entry->name) < FN_LEN);
723
 
  strmake(&global_ddl_log.file_entry_buf[DDL_LOG_NAME_POS],
724
 
          ddl_log_entry->name, FN_LEN - 1);
725
 
  if (ddl_log_entry->action_type == DDL_LOG_RENAME_ACTION ||
726
 
      ddl_log_entry->action_type == DDL_LOG_REPLACE_ACTION)
727
 
  {
728
 
    assert(strlen(ddl_log_entry->from_name) < FN_LEN);
729
 
    strmake(&global_ddl_log.file_entry_buf[DDL_LOG_NAME_POS + FN_LEN],
730
 
          ddl_log_entry->from_name, FN_LEN - 1);
731
 
  }
732
 
  else
733
 
    global_ddl_log.file_entry_buf[DDL_LOG_NAME_POS + FN_LEN]= 0;
734
 
  assert(strlen(ddl_log_entry->handler_name) < FN_LEN);
735
 
  strmake(&global_ddl_log.file_entry_buf[DDL_LOG_NAME_POS + (2*FN_LEN)],
736
 
          ddl_log_entry->handler_name, FN_LEN - 1);
737
 
  if (get_free_ddl_log_entry(active_entry, &write_header))
738
 
  {
739
 
    return(true);
740
 
  }
741
 
  error= false;
742
 
  if (write_ddl_log_file_entry((*active_entry)->entry_pos))
743
 
  {
744
 
    error= true;
745
 
    sql_print_error("Failed to write entry_no = %u",
746
 
                    (*active_entry)->entry_pos);
747
 
  }
748
 
  if (write_header && !error)
749
 
  {
750
 
    VOID(sync_ddl_log());
751
 
    if (write_ddl_log_header())
752
 
      error= true;
753
 
  }
754
 
  if (error)
755
 
    release_ddl_log_memory_entry(*active_entry);
756
 
  return(error);
757
 
}
758
 
 
759
 
 
760
 
/*
761
 
  Write final entry in the ddl log
762
 
  SYNOPSIS
763
 
    write_execute_ddl_log_entry()
764
 
    first_entry                    First entry in linked list of entries
765
 
                                   to execute, if 0 = NULL it means that
766
 
                                   the entry is removed and the entries
767
 
                                   are put into the free list.
768
 
    complete                       Flag indicating we are simply writing
769
 
                                   info about that entry has been completed
770
 
    in:out:active_entry            Entry to execute, 0 = NULL if the entry
771
 
                                   is written first time and needs to be
772
 
                                   returned. In this case the entry written
773
 
                                   is returned in this parameter
774
 
  RETURN VALUES
775
 
    true                           Error
776
 
    false                          Success
777
 
 
778
 
  DESCRIPTION
779
 
    This is the last write in the ddl log. The previous log entries have
780
 
    already been written but not yet synched to disk.
781
 
    We write a couple of log entries that describes action to perform.
782
 
    This entries are set-up in a linked list, however only when a first
783
 
    execute entry is put as the first entry these will be executed.
784
 
    This routine writes this first 
785
 
*/ 
786
 
 
787
 
bool write_execute_ddl_log_entry(uint first_entry,
788
 
                                 bool complete,
789
 
                                 DDL_LOG_MEMORY_ENTRY **active_entry)
790
 
{
791
 
  bool write_header= false;
792
 
  char *file_entry_buf= (char*)global_ddl_log.file_entry_buf;
793
 
 
794
 
  if (init_ddl_log())
795
 
  {
796
 
    return(true);
797
 
  }
798
 
  if (!complete)
799
 
  {
800
 
    /*
801
 
      We haven't synched the log entries yet, we synch them now before
802
 
      writing the execute entry. If complete is true we haven't written
803
 
      any log entries before, we are only here to write the execute
804
 
      entry to indicate it is done.
805
 
    */
806
 
    VOID(sync_ddl_log());
807
 
    file_entry_buf[DDL_LOG_ENTRY_TYPE_POS]= (char)DDL_LOG_EXECUTE_CODE;
808
 
  }
809
 
  else
810
 
    file_entry_buf[DDL_LOG_ENTRY_TYPE_POS]= (char)DDL_IGNORE_LOG_ENTRY_CODE;
811
 
  file_entry_buf[DDL_LOG_ACTION_TYPE_POS]= 0; /* Ignored for execute entries */
812
 
  file_entry_buf[DDL_LOG_PHASE_POS]= 0;
813
 
  int4store(&file_entry_buf[DDL_LOG_NEXT_ENTRY_POS], first_entry);
814
 
  file_entry_buf[DDL_LOG_NAME_POS]= 0;
815
 
  file_entry_buf[DDL_LOG_NAME_POS + FN_LEN]= 0;
816
 
  file_entry_buf[DDL_LOG_NAME_POS + 2*FN_LEN]= 0;
817
 
  if (!(*active_entry))
818
 
  {
819
 
    if (get_free_ddl_log_entry(active_entry, &write_header))
820
 
    {
821
 
      return(true);
822
 
    }
823
 
  }
824
 
  if (write_ddl_log_file_entry((*active_entry)->entry_pos))
825
 
  {
826
 
    sql_print_error("Error writing execute entry in ddl log");
827
 
    release_ddl_log_memory_entry(*active_entry);
828
 
    return(true);
829
 
  }
830
 
  VOID(sync_ddl_log());
831
 
  if (write_header)
832
 
  {
833
 
    if (write_ddl_log_header())
834
 
    {
835
 
      release_ddl_log_memory_entry(*active_entry);
836
 
      return(true);
837
 
    }
838
 
  }
839
 
  return(false);
840
 
}
841
 
 
842
 
 
843
 
/*
844
 
  For complex rename operations we need to deactivate individual entries.
845
 
  SYNOPSIS
846
 
    deactivate_ddl_log_entry()
847
 
    entry_no                      Entry position of record to change
848
 
  RETURN VALUES
849
 
    true                         Error
850
 
    false                        Success
851
 
  DESCRIPTION
852
 
    During replace operations where we start with an existing table called
853
 
    t1 and a replacement table called t1#temp or something else and where
854
 
    we want to delete t1 and rename t1#temp to t1 this is not possible to
855
 
    do in a safe manner unless the ddl log is informed of the phases in
856
 
    the change.
857
 
 
858
 
    Delete actions are 1-phase actions that can be ignored immediately after
859
 
    being executed.
860
 
    Rename actions from x to y is also a 1-phase action since there is no
861
 
    interaction with any other handlers named x and y.
862
 
    Replace action where drop y and x -> y happens needs to be a two-phase
863
 
    action. Thus the first phase will drop y and the second phase will
864
 
    rename x -> y.
865
 
*/
866
 
 
867
 
bool deactivate_ddl_log_entry(uint entry_no)
868
 
{
869
 
  char *file_entry_buf= (char*)global_ddl_log.file_entry_buf;
870
 
 
871
 
  if (!read_ddl_log_file_entry(entry_no))
872
 
  {
873
 
    if (file_entry_buf[DDL_LOG_ENTRY_TYPE_POS] == DDL_LOG_ENTRY_CODE)
874
 
    {
875
 
      if (file_entry_buf[DDL_LOG_ACTION_TYPE_POS] == DDL_LOG_DELETE_ACTION ||
876
 
          file_entry_buf[DDL_LOG_ACTION_TYPE_POS] == DDL_LOG_RENAME_ACTION ||
877
 
          (file_entry_buf[DDL_LOG_ACTION_TYPE_POS] == DDL_LOG_REPLACE_ACTION &&
878
 
           file_entry_buf[DDL_LOG_PHASE_POS] == 1))
879
 
        file_entry_buf[DDL_LOG_ENTRY_TYPE_POS]= DDL_IGNORE_LOG_ENTRY_CODE;
880
 
      else if (file_entry_buf[DDL_LOG_ACTION_TYPE_POS] == DDL_LOG_REPLACE_ACTION)
881
 
      {
882
 
        assert(file_entry_buf[DDL_LOG_PHASE_POS] == 0);
883
 
        file_entry_buf[DDL_LOG_PHASE_POS]= 1;
884
 
      }
885
 
      else
886
 
      {
887
 
        assert(0);
888
 
      }
889
 
      if (write_ddl_log_file_entry(entry_no))
890
 
      {
891
 
        sql_print_error("Error in deactivating log entry. Position = %u",
892
 
                        entry_no);
893
 
        return(true);
894
 
      }
895
 
    }
896
 
  }
897
 
  else
898
 
  {
899
 
    sql_print_error("Failed in reading entry before deactivating it");
900
 
    return(true);
901
 
  }
902
 
  return(false);
903
 
}
904
 
 
905
 
 
906
 
/*
907
 
  Sync ddl log file
908
 
  SYNOPSIS
909
 
    sync_ddl_log()
910
 
  RETURN VALUES
911
 
    true                      Error
912
 
    false                     Success
913
 
*/
914
 
 
915
 
bool sync_ddl_log()
916
 
{
917
 
  bool error= false;
918
 
 
919
 
  if ((!global_ddl_log.recovery_phase) &&
920
 
      init_ddl_log())
921
 
  {
922
 
    return(true);
923
 
  }
924
 
  if (my_sync(global_ddl_log.file_id, MYF(0)))
925
 
  {
926
 
    /* Write to error log */
927
 
    sql_print_error("Failed to sync ddl log");
928
 
    error= true;
929
 
  }
930
 
  return(error);
931
 
}
932
 
 
933
 
 
934
 
/*
935
 
  Release a log memory entry
936
 
  SYNOPSIS
937
 
    release_ddl_log_memory_entry()
938
 
    log_memory_entry                Log memory entry to release
939
 
  RETURN VALUES
940
 
    NONE
941
 
*/
942
 
 
943
 
void release_ddl_log_memory_entry(DDL_LOG_MEMORY_ENTRY *log_entry)
944
 
{
945
 
  DDL_LOG_MEMORY_ENTRY *first_free= global_ddl_log.first_free;
946
 
  DDL_LOG_MEMORY_ENTRY *next_log_entry= log_entry->next_log_entry;
947
 
  DDL_LOG_MEMORY_ENTRY *prev_log_entry= log_entry->prev_log_entry;
948
 
 
949
 
  global_ddl_log.first_free= log_entry;
950
 
  log_entry->next_log_entry= first_free;
951
 
 
952
 
  if (prev_log_entry)
953
 
    prev_log_entry->next_log_entry= next_log_entry;
954
 
  else
955
 
    global_ddl_log.first_used= next_log_entry;
956
 
  if (next_log_entry)
957
 
    next_log_entry->prev_log_entry= prev_log_entry;
958
 
  return;
959
 
}
960
 
 
961
 
 
962
 
/*
963
 
  Execute one entry in the ddl log. Executing an entry means executing
964
 
  a linked list of actions.
965
 
  SYNOPSIS
966
 
    execute_ddl_log_entry()
967
 
    first_entry                Reference to first action in entry
968
 
  RETURN VALUES
969
 
    true                       Error
970
 
    false                      Success
971
 
*/
972
 
 
973
 
bool execute_ddl_log_entry(THD *thd, uint first_entry)
974
 
{
975
 
  DDL_LOG_ENTRY ddl_log_entry;
976
 
  uint read_entry= first_entry;
977
 
 
978
 
  pthread_mutex_lock(&LOCK_gdl);
979
 
  do
980
 
  {
981
 
    if (read_ddl_log_entry(read_entry, &ddl_log_entry))
982
 
    {
983
 
      /* Write to error log and continue with next log entry */
984
 
      sql_print_error("Failed to read entry = %u from ddl log",
985
 
                      read_entry);
986
 
      break;
987
 
    }
988
 
    assert(ddl_log_entry.entry_type == DDL_LOG_ENTRY_CODE ||
989
 
                ddl_log_entry.entry_type == DDL_IGNORE_LOG_ENTRY_CODE);
990
 
 
991
 
    if (execute_ddl_log_action(thd, &ddl_log_entry))
992
 
    {
993
 
      /* Write to error log and continue with next log entry */
994
 
      sql_print_error("Failed to execute action for entry = %u from ddl log",
995
 
                      read_entry);
996
 
      break;
997
 
    }
998
 
    read_entry= ddl_log_entry.next_entry;
999
 
  } while (read_entry);
1000
 
  pthread_mutex_unlock(&LOCK_gdl);
1001
 
  return(false);
1002
 
}
1003
 
 
1004
 
 
1005
 
/*
1006
 
  Close the ddl log
1007
 
  SYNOPSIS
1008
 
    close_ddl_log()
1009
 
  RETURN VALUES
1010
 
    NONE
1011
 
*/
1012
 
 
1013
 
static void close_ddl_log()
1014
 
{
1015
 
  if (global_ddl_log.file_id >= 0)
1016
 
  {
1017
 
    VOID(my_close(global_ddl_log.file_id, MYF(MY_WME)));
1018
 
    global_ddl_log.file_id= (File) -1;
1019
 
  }
1020
 
  return;
1021
 
}
1022
 
 
1023
 
 
1024
 
/*
1025
 
  Execute the ddl log at recovery of MySQL Server
1026
 
  SYNOPSIS
1027
 
    execute_ddl_log_recovery()
1028
 
  RETURN VALUES
1029
 
    NONE
1030
 
*/
1031
 
 
1032
 
void execute_ddl_log_recovery()
1033
 
{
1034
 
  uint num_entries, i;
1035
 
  THD *thd;
1036
 
  DDL_LOG_ENTRY ddl_log_entry;
1037
 
  char file_name[FN_REFLEN];
1038
 
 
1039
 
  /*
1040
 
    Initialise global_ddl_log struct
1041
 
  */
1042
 
  bzero(global_ddl_log.file_entry_buf, sizeof(global_ddl_log.file_entry_buf));
1043
 
  global_ddl_log.inited= false;
1044
 
  global_ddl_log.recovery_phase= true;
1045
 
  global_ddl_log.io_size= IO_SIZE;
1046
 
  global_ddl_log.file_id= (File) -1;
1047
 
 
1048
 
  /*
1049
 
    To be able to run this from boot, we allocate a temporary THD
1050
 
  */
1051
 
  if (!(thd=new THD))
1052
 
    return;
1053
 
  thd->thread_stack= (char*) &thd;
1054
 
  thd->store_globals();
1055
 
 
1056
 
  num_entries= read_ddl_log_header();
1057
 
  for (i= 1; i < num_entries + 1; i++)
1058
 
  {
1059
 
    if (read_ddl_log_entry(i, &ddl_log_entry))
1060
 
    {
1061
 
      sql_print_error("Failed to read entry no = %u from ddl log",
1062
 
                       i);
1063
 
      continue;
1064
 
    }
1065
 
    if (ddl_log_entry.entry_type == DDL_LOG_EXECUTE_CODE)
1066
 
    {
1067
 
      if (execute_ddl_log_entry(thd, ddl_log_entry.next_entry))
1068
 
      {
1069
 
        /* Real unpleasant scenario but we continue anyways.  */
1070
 
        continue;
1071
 
      }
1072
 
    }
1073
 
  }
1074
 
  close_ddl_log();
1075
 
  create_ddl_log_file_name(file_name);
1076
 
  VOID(my_delete(file_name, MYF(0)));
1077
 
  global_ddl_log.recovery_phase= false;
1078
 
  delete thd;
1079
 
  /* Remember that we don't have a THD */
1080
 
  my_pthread_setspecific_ptr(THR_THD,  0);
1081
 
  return;
1082
 
}
1083
 
 
1084
 
 
1085
 
/*
1086
 
  Release all memory allocated to the ddl log
1087
 
  SYNOPSIS
1088
 
    release_ddl_log()
1089
 
  RETURN VALUES
1090
 
    NONE
1091
 
*/
1092
 
 
1093
 
void release_ddl_log()
1094
 
{
1095
 
  DDL_LOG_MEMORY_ENTRY *free_list= global_ddl_log.first_free;
1096
 
  DDL_LOG_MEMORY_ENTRY *used_list= global_ddl_log.first_used;
1097
 
 
1098
 
  if (!global_ddl_log.do_release)
1099
 
    return;
1100
 
 
1101
 
  pthread_mutex_lock(&LOCK_gdl);
1102
 
  while (used_list)
1103
 
  {
1104
 
    DDL_LOG_MEMORY_ENTRY *tmp= used_list->next_log_entry;
1105
 
    my_free(used_list, MYF(0));
1106
 
    used_list= tmp;
1107
 
  }
1108
 
  while (free_list)
1109
 
  {
1110
 
    DDL_LOG_MEMORY_ENTRY *tmp= free_list->next_log_entry;
1111
 
    my_free(free_list, MYF(0));
1112
 
    free_list= tmp;
1113
 
  }
1114
 
  close_ddl_log();
1115
 
  global_ddl_log.inited= 0;
1116
 
  pthread_mutex_unlock(&LOCK_gdl);
1117
 
  VOID(pthread_mutex_destroy(&LOCK_gdl));
1118
 
  global_ddl_log.do_release= false;
1119
 
  return;
1120
 
}
1121
 
 
1122
 
 
1123
 
/*
1124
 
---------------------------------------------------------------------------
1125
 
 
1126
 
  END MODULE DDL log
1127
 
  --------------------
1128
 
 
1129
 
---------------------------------------------------------------------------
1130
 
*/
1131
 
 
1132
 
 
1133
 
/*
1134
228
  SYNOPSIS
1135
229
    write_bin_log()
1136
230
    thd                           Thread object