~james-page/ubuntu/precise/mysql-5.5/misc-fixes

« back to all changes in this revision

Viewing changes to storage/innobase/buf/buf0lru.c

  • Committer: Package Import Robot
  • Author(s): Marc Deslauriers
  • Date: 2012-06-11 07:34:33 UTC
  • mfrom: (1.1.6)
  • Revision ID: package-import@ubuntu.com-20120611073433-l9za2ni4ipp848y3
Tags: 5.5.24-0ubuntu0.12.04.1
* SECURITY UPDATE: Update to 5.5.24 to fix security issues (LP: #1011371)
  - http://dev.mysql.com/doc/refman/5.5/en/news-5-5-24.html

Show diffs side-by-side

added added

removed removed

Lines of Context:
335
335
}
336
336
 
337
337
/******************************************************************//**
 
338
While flushing (or removing dirty) pages from a tablespace we don't
 
339
want to hog the CPU and resources. Release the buffer pool and block
 
340
mutex and try to force a context switch. Then reacquire the same mutexes.
 
341
The current page is "fixed" before the release of the mutexes and then
 
342
"unfixed" again once we have reacquired the mutexes. */
 
343
static
 
344
void
 
345
buf_flush_yield(
 
346
/*============*/
 
347
        buf_pool_t*     buf_pool,       /*!< in/out: buffer pool instance */
 
348
        buf_page_t*     bpage)          /*!< in/out: current page */
 
349
{
 
350
        mutex_t*        block_mutex;
 
351
 
 
352
        ut_ad(buf_pool_mutex_own(buf_pool));
 
353
        ut_ad(buf_page_in_file(bpage));
 
354
 
 
355
        block_mutex = buf_page_get_mutex(bpage);
 
356
 
 
357
        mutex_enter(block_mutex);
 
358
        /* "Fix" the block so that the position cannot be
 
359
        changed after we release the buffer pool and
 
360
        block mutexes. */
 
361
        buf_page_set_sticky(bpage);
 
362
 
 
363
        /* Now it is safe to release the buf_pool->mutex. */
 
364
        buf_pool_mutex_exit(buf_pool);
 
365
 
 
366
        mutex_exit(block_mutex);
 
367
        /* Try and force a context switch. */
 
368
        os_thread_yield();
 
369
 
 
370
        buf_pool_mutex_enter(buf_pool);
 
371
 
 
372
        mutex_enter(block_mutex);
 
373
        /* "Unfix" the block now that we have both the
 
374
        buffer pool and block mutex again. */
 
375
        buf_page_unset_sticky(bpage);
 
376
        mutex_exit(block_mutex);
 
377
}
 
378
 
 
379
/******************************************************************//**
 
380
If we have hogged the resources for too long then release the buffer
 
381
pool and flush list mutex and do a thread yield. Set the current page
 
382
to "sticky" so that it is not relocated during the yield.
 
383
@return TRUE if yielded */
 
384
static
 
385
ibool
 
386
buf_flush_try_yield(
 
387
/*================*/
 
388
        buf_pool_t*     buf_pool,       /*!< in/out: buffer pool instance */
 
389
        buf_page_t*     bpage,          /*!< in/out: bpage to remove */
 
390
        ulint           processed)      /*!< in: number of pages processed */
 
391
{
 
392
        /* Every BUF_LRU_DROP_SEARCH_SIZE iterations in the
 
393
        loop we release buf_pool->mutex to let other threads
 
394
        do their job but only if the block is not IO fixed. This
 
395
        ensures that the block stays in its position in the
 
396
        flush_list. */
 
397
 
 
398
        if (bpage != NULL
 
399
            && processed >= BUF_LRU_DROP_SEARCH_SIZE
 
400
            && buf_page_get_io_fix(bpage) == BUF_IO_NONE) {
 
401
 
 
402
                buf_flush_list_mutex_exit(buf_pool);
 
403
 
 
404
                /* Release the buffer pool and block mutex
 
405
                to give the other threads a go. */
 
406
 
 
407
                buf_flush_yield(buf_pool, bpage);
 
408
 
 
409
                buf_flush_list_mutex_enter(buf_pool);
 
410
 
 
411
                /* Should not have been removed from the flush
 
412
                list during the yield. However, this check is
 
413
                not sufficient to catch a remove -> add. */
 
414
 
 
415
                ut_ad(bpage->in_flush_list);
 
416
 
 
417
                return(TRUE);
 
418
        }
 
419
 
 
420
        return(FALSE);
 
421
}
 
422
 
 
423
/******************************************************************//**
 
424
Removes a single page from a given tablespace inside a specific
 
425
buffer pool instance.
 
426
@return TRUE if page was removed. */
 
427
static
 
428
ibool
 
429
buf_flush_or_remove_page(
 
430
/*=====================*/
 
431
        buf_pool_t*     buf_pool,       /*!< in/out: buffer pool instance */
 
432
        buf_page_t*     bpage)          /*!< in/out: bpage to remove */
 
433
{
 
434
        mutex_t*        block_mutex;
 
435
        ibool           processed = FALSE;
 
436
 
 
437
        ut_ad(buf_pool_mutex_own(buf_pool));
 
438
        ut_ad(buf_flush_list_mutex_own(buf_pool));
 
439
 
 
440
        block_mutex = buf_page_get_mutex(bpage);
 
441
 
 
442
        /* bpage->space and bpage->io_fix are protected by
 
443
        buf_pool->mutex and block_mutex. It is safe to check
 
444
        them while holding buf_pool->mutex only. */
 
445
 
 
446
        if (buf_page_get_io_fix(bpage) != BUF_IO_NONE) {
 
447
 
 
448
                /* We cannot remove this page during this scan
 
449
                yet; maybe the system is currently reading it
 
450
                in, or flushing the modifications to the file */
 
451
 
 
452
        } else {
 
453
 
 
454
                /* We have to release the flush_list_mutex to obey the
 
455
                latching order. We are however guaranteed that the page
 
456
                will stay in the flush_list because buf_flush_remove()
 
457
                needs buf_pool->mutex as well (for the non-flush case). */
 
458
 
 
459
                buf_flush_list_mutex_exit(buf_pool);
 
460
 
 
461
                mutex_enter(block_mutex);
 
462
 
 
463
                ut_ad(bpage->oldest_modification != 0);
 
464
 
 
465
                if (bpage->buf_fix_count == 0) {
 
466
 
 
467
                        buf_flush_remove(bpage);
 
468
 
 
469
                        processed = TRUE;
 
470
                }
 
471
 
 
472
                mutex_exit(block_mutex);
 
473
 
 
474
                buf_flush_list_mutex_enter(buf_pool);
 
475
        }
 
476
 
 
477
        ut_ad(!mutex_own(block_mutex));
 
478
 
 
479
        return(processed);
 
480
}
 
481
 
 
482
/******************************************************************//**
338
483
Remove all dirty pages belonging to a given tablespace inside a specific
339
484
buffer pool instance when we are deleting the data file(s) of that
340
485
tablespace. The pages still remain a part of LRU and are evicted from
341
 
the list as they age towards the tail of the LRU. */
342
 
static
343
 
void
344
 
buf_LRU_remove_dirty_pages_for_tablespace(
345
 
/*======================================*/
 
486
the list as they age towards the tail of the LRU.
 
487
@return TRUE if all freed. */
 
488
static
 
489
ibool
 
490
buf_flush_or_remove_pages(
 
491
/*======================*/
 
492
        buf_pool_t*     buf_pool,       /*!< buffer pool instance */
 
493
        ulint           id)             /*!< in: target space id for which
 
494
                                        to remove or flush pages */
 
495
{
 
496
        buf_page_t*     prev;
 
497
        buf_page_t*     bpage;
 
498
        ulint           processed = 0;
 
499
        ibool           all_freed = TRUE;
 
500
 
 
501
        buf_flush_list_mutex_enter(buf_pool);
 
502
 
 
503
        for (bpage = UT_LIST_GET_LAST(buf_pool->flush_list);
 
504
             bpage != NULL;
 
505
             bpage = prev) {
 
506
 
 
507
                ut_a(buf_page_in_file(bpage));
 
508
                ut_ad(bpage->in_flush_list);
 
509
 
 
510
                /* Save the previous link because once we free the
 
511
                page we can't rely on the links. */
 
512
 
 
513
                prev = UT_LIST_GET_PREV(list, bpage);
 
514
 
 
515
                if (buf_page_get_space(bpage) != id) {
 
516
 
 
517
                        /* Skip this block, as it does not belong to
 
518
                        the target space. */
 
519
 
 
520
                } else if (!buf_flush_or_remove_page(buf_pool, bpage)) {
 
521
 
 
522
                        /* Remove was unsuccessful, we have to try again
 
523
                        by scanning the entire list from the end. */
 
524
 
 
525
                        all_freed = FALSE;
 
526
                }
 
527
 
 
528
                ++processed;
 
529
 
 
530
                /* Yield if we have hogged the CPU and mutexes for too long. */
 
531
                if (buf_flush_try_yield(buf_pool, prev, processed)) {
 
532
 
 
533
                        /* Reset the batch size counter if we had to yield. */
 
534
 
 
535
                        processed = 0;
 
536
                }
 
537
 
 
538
        }
 
539
 
 
540
        buf_flush_list_mutex_exit(buf_pool);
 
541
 
 
542
        return(all_freed);
 
543
}
 
544
 
 
545
/******************************************************************//**
 
546
Remove or flush all the dirty pages that belong to a given tablespace
 
547
inside a specific buffer pool instance. The pages will remain in the LRU
 
548
list and will be evicted from the LRU list as they age and move towards
 
549
the tail of the LRU list. */
 
550
static
 
551
void
 
552
buf_flush_dirty_pages(
 
553
/*==================*/
 
554
        buf_pool_t*     buf_pool,       /*!< buffer pool instance */
 
555
        ulint           id)             /*!< in: space id */
 
556
{
 
557
        ibool   all_freed;
 
558
 
 
559
        do {
 
560
                buf_pool_mutex_enter(buf_pool);
 
561
 
 
562
                all_freed = buf_flush_or_remove_pages(buf_pool, id);
 
563
 
 
564
                buf_pool_mutex_exit(buf_pool);
 
565
 
 
566
                ut_ad(buf_flush_validate(buf_pool));
 
567
 
 
568
                if (!all_freed) {
 
569
                        os_thread_sleep(20000);
 
570
                }
 
571
 
 
572
        } while (!all_freed);
 
573
}
 
574
 
 
575
/******************************************************************//**
 
576
Remove all pages that belong to a given tablespace inside a specific
 
577
buffer pool instance when we are DISCARDing the tablespace. */
 
578
static
 
579
void
 
580
buf_LRU_remove_all_pages(
 
581
/*=====================*/
346
582
        buf_pool_t*     buf_pool,       /*!< buffer pool instance */
347
583
        ulint           id)             /*!< in: space id */
348
584
{
349
585
        buf_page_t*     bpage;
350
586
        ibool           all_freed;
351
 
        ulint           i;
352
587
 
353
588
scan_again:
354
589
        buf_pool_mutex_enter(buf_pool);
355
 
        buf_flush_list_mutex_enter(buf_pool);
356
590
 
357
591
        all_freed = TRUE;
358
592
 
359
 
        for (bpage = UT_LIST_GET_LAST(buf_pool->flush_list), i = 0;
360
 
             bpage != NULL; ++i) {
 
593
        for (bpage = UT_LIST_GET_LAST(buf_pool->LRU);
 
594
             bpage != NULL;
 
595
             /* No op */) {
361
596
 
362
597
                buf_page_t*     prev_bpage;
363
598
                mutex_t*        block_mutex = NULL;
364
599
 
365
600
                ut_a(buf_page_in_file(bpage));
 
601
                ut_ad(bpage->in_LRU_list);
366
602
 
367
 
                prev_bpage = UT_LIST_GET_PREV(list, bpage);
 
603
                prev_bpage = UT_LIST_GET_PREV(LRU, bpage);
368
604
 
369
605
                /* bpage->space and bpage->io_fix are protected by
370
 
                buf_pool->mutex and block_mutex. It is safe to check
 
606
                buf_pool->mutex and the block_mutex. It is safe to check
371
607
                them while holding buf_pool->mutex only. */
372
608
 
373
609
                if (buf_page_get_space(bpage) != id) {
381
617
 
382
618
                        all_freed = FALSE;
383
619
                        goto next_page;
384
 
                }
385
 
 
386
 
                /* We have to release the flush_list_mutex to obey the
387
 
                latching order. We are however guaranteed that the page
388
 
                will stay in the flush_list because buf_flush_remove()
389
 
                needs buf_pool->mutex as well. */
390
 
                buf_flush_list_mutex_exit(buf_pool);
391
 
                block_mutex = buf_page_get_mutex(bpage);
392
 
                mutex_enter(block_mutex);
393
 
 
394
 
                if (bpage->buf_fix_count > 0) {
395
 
                        mutex_exit(block_mutex);
396
 
                        buf_flush_list_mutex_enter(buf_pool);
397
 
 
398
 
                        /* We cannot remove this page during
399
 
                        this scan yet; maybe the system is
400
 
                        currently reading it in, or flushing
401
 
                        the modifications to the file */
402
 
 
403
 
                        all_freed = FALSE;
404
 
                        goto next_page;
405
 
                }
406
 
 
407
 
                ut_ad(bpage->oldest_modification != 0);
408
 
 
409
 
                buf_flush_remove(bpage);
410
 
 
411
 
                mutex_exit(block_mutex);
412
 
                buf_flush_list_mutex_enter(buf_pool);
 
620
                } else {
 
621
 
 
622
                        block_mutex = buf_page_get_mutex(bpage);
 
623
                        mutex_enter(block_mutex);
 
624
 
 
625
                        if (bpage->buf_fix_count > 0) {
 
626
 
 
627
                                mutex_exit(block_mutex);
 
628
 
 
629
                                /* We cannot remove this page during
 
630
                                this scan yet; maybe the system is
 
631
                                currently reading it in, or flushing
 
632
                                the modifications to the file */
 
633
 
 
634
                                all_freed = FALSE;
 
635
 
 
636
                                goto next_page;
 
637
                        }
 
638
                }
 
639
 
 
640
                ut_ad(mutex_own(block_mutex));
 
641
 
 
642
#ifdef UNIV_DEBUG
 
643
                if (buf_debug_prints) {
 
644
                        fprintf(stderr,
 
645
                                "Dropping space %lu page %lu\n",
 
646
                                (ulong) buf_page_get_space(bpage),
 
647
                                (ulong) buf_page_get_page_no(bpage));
 
648
                }
 
649
#endif
 
650
                if (buf_page_get_state(bpage) != BUF_BLOCK_FILE_PAGE) {
 
651
                        /* Do nothing, because the adaptive hash index
 
652
                        covers uncompressed pages only. */
 
653
                } else if (((buf_block_t*) bpage)->index) {
 
654
                        ulint   page_no;
 
655
                        ulint   zip_size;
 
656
 
 
657
                        buf_pool_mutex_exit(buf_pool);
 
658
 
 
659
                        zip_size = buf_page_get_zip_size(bpage);
 
660
                        page_no = buf_page_get_page_no(bpage);
 
661
 
 
662
                        mutex_exit(block_mutex);
 
663
 
 
664
                        /* Note that the following call will acquire
 
665
                        and release block->lock X-latch. */
 
666
 
 
667
                        btr_search_drop_page_hash_when_freed(
 
668
                                id, zip_size, page_no);
 
669
 
 
670
                        goto scan_again;
 
671
                }
 
672
 
 
673
                if (bpage->oldest_modification != 0) {
 
674
                        buf_flush_remove(bpage);
 
675
                }
 
676
 
 
677
                ut_ad(!bpage->in_flush_list);
 
678
 
 
679
                /* Remove from the LRU list. */
 
680
 
 
681
                if (buf_LRU_block_remove_hashed_page(bpage, TRUE)
 
682
                    != BUF_BLOCK_ZIP_FREE) {
 
683
 
 
684
                        buf_LRU_block_free_hashed_page((buf_block_t*) bpage);
 
685
                        mutex_exit(block_mutex);
 
686
 
 
687
                } else {
 
688
                        /* The block_mutex should have been released
 
689
                        by buf_LRU_block_remove_hashed_page() when it
 
690
                        returns BUF_BLOCK_ZIP_FREE. */
 
691
                        ut_ad(block_mutex == &buf_pool->zip_mutex);
 
692
                }
 
693
 
 
694
                ut_ad(!mutex_own(block_mutex));
 
695
 
413
696
next_page:
414
697
                bpage = prev_bpage;
415
 
 
416
 
                if (!bpage) {
417
 
                        break;
418
 
                }
419
 
 
420
 
                /* Every BUF_LRU_DROP_SEARCH_SIZE iterations in the
421
 
                loop we release buf_pool->mutex to let other threads
422
 
                do their job. */
423
 
                if (i < BUF_LRU_DROP_SEARCH_SIZE) {
424
 
                        continue;
425
 
                }
426
 
 
427
 
                /* We IO-fix the block to make sure that the block
428
 
                stays in its position in the flush_list. */
429
 
                if (buf_page_get_io_fix(bpage) != BUF_IO_NONE) {
430
 
                        /* Block is already IO-fixed. We don't
431
 
                        want to change the value. Lets leave
432
 
                        this block alone. */
433
 
                        continue;
434
 
                }
435
 
 
436
 
                buf_flush_list_mutex_exit(buf_pool);
437
 
                block_mutex = buf_page_get_mutex(bpage);
438
 
                mutex_enter(block_mutex);
439
 
                buf_page_set_sticky(bpage);
440
 
                mutex_exit(block_mutex);
441
 
 
442
 
                /* Now it is safe to release the buf_pool->mutex. */
443
 
                buf_pool_mutex_exit(buf_pool);
444
 
                os_thread_yield();
445
 
                buf_pool_mutex_enter(buf_pool);
446
 
 
447
 
                mutex_enter(block_mutex);
448
 
                buf_page_unset_sticky(bpage);
449
 
                mutex_exit(block_mutex);
450
 
 
451
 
                buf_flush_list_mutex_enter(buf_pool);
452
 
                ut_ad(bpage->in_flush_list);
453
 
 
454
 
                i = 0;
455
698
        }
456
699
 
457
700
        buf_pool_mutex_exit(buf_pool);
458
 
        buf_flush_list_mutex_exit(buf_pool);
459
 
 
460
 
        ut_ad(buf_flush_validate(buf_pool));
461
701
 
462
702
        if (!all_freed) {
463
703
                os_thread_sleep(20000);
467
707
}
468
708
 
469
709
/******************************************************************//**
470
 
Invalidates all pages belonging to a given tablespace when we are deleting
471
 
the data file(s) of that tablespace. */
 
710
Removes all pages belonging to a given tablespace. */
472
711
UNIV_INTERN
473
712
void
474
 
buf_LRU_invalidate_tablespace(
 
713
buf_LRU_flush_or_remove_pages(
475
714
/*==========================*/
476
 
        ulint   id)     /*!< in: space id */
 
715
        ulint                   id,     /*!< in: space id */
 
716
        enum buf_remove_t       buf_remove)/*!< in: remove or flush
 
717
                                        strategy */
477
718
{
478
 
        ulint   i;
 
719
        ulint           i;
479
720
 
480
 
        /* Before we attempt to drop pages one by one we first
481
 
        attempt to drop page hash index entries in batches to make
482
 
        it more efficient. The batching attempt is a best effort
483
 
        attempt and does not guarantee that all pages hash entries
484
 
        will be dropped. We get rid of remaining page hash entries
485
 
        one by one below. */
486
721
        for (i = 0; i < srv_buf_pool_instances; i++) {
487
722
                buf_pool_t*     buf_pool;
488
723
 
489
724
                buf_pool = buf_pool_from_array(i);
490
 
                buf_LRU_drop_page_hash_for_tablespace(buf_pool, id);
491
 
                buf_LRU_remove_dirty_pages_for_tablespace(buf_pool, id);
 
725
 
 
726
                switch (buf_remove) {
 
727
                case BUF_REMOVE_ALL_NO_WRITE:
 
728
                        /* A DISCARD tablespace case. Remove AHI entries
 
729
                        and evict all pages from LRU. */
 
730
 
 
731
                        /* Before we attempt to drop pages hash entries
 
732
                        one by one we first attempt to drop page hash
 
733
                        index entries in batches to make it more
 
734
                        efficient. The batching attempt is a best effort
 
735
                        attempt and does not guarantee that all pages
 
736
                        hash entries will be dropped. We get rid of
 
737
                        remaining page hash entries one by one below. */
 
738
                        buf_LRU_drop_page_hash_for_tablespace(buf_pool, id);
 
739
                        buf_LRU_remove_all_pages(buf_pool, id);
 
740
                        break;
 
741
 
 
742
                case BUF_REMOVE_FLUSH_NO_WRITE:
 
743
                        /* A DROP table case. AHI entries are already
 
744
                        removed. No need to evict all pages from LRU
 
745
                        list. Just evict pages from flush list without
 
746
                        writing. */
 
747
                        buf_flush_dirty_pages(buf_pool, id);
 
748
                        break;
 
749
                }
492
750
        }
493
751
}
494
752