home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 3: Developer Tools / Linux Cubed Series 3 - Developer Tools.iso / devel / db / esm-3.1 / esm-3 / usr / local / sm / src / serverlib / log / checkPoint.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-05-05  |  11.5 KB  |  429 lines

  1. /*
  2.  *   $RCSfile: checkPoint.c,v $  
  3.  *   $Revision: 1.1.1.1 $  
  4.  *   $Date: 1996/05/04 21:55:50 $      
  5.  */ 
  6. /**********************************************************************
  7. * EXODUS Database Toolkit Software
  8. * Copyright (c) 1991 Computer Sciences Department, University of
  9. *                    Wisconsin -- Madison
  10. * All Rights Reserved.
  11. *
  12. * Permission to use, copy, modify and distribute this software and its
  13. * documentation is hereby granted, provided that both the copyright
  14. * notice and this permission notice appear in all copies of the
  15. * software, derivative works or modified versions, and any portions
  16. * thereof, and that both notices appear in supporting documentation.
  17. *
  18. * THE COMPUTER SCIENCES DEPARTMENT OF THE UNIVERSITY OF WISCONSIN --
  19. * MADISON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" CONDITION.  
  20. * THE DEPARTMENT DISCLAIMS ANY LIABILITY OF ANY KIND FOR ANY DAMAGES
  21. * WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
  22. *
  23. * The EXODUS Project Group requests users of this software to return 
  24. * any improvements or extensions that they make to:
  25. *
  26. *   EXODUS Project Group 
  27. *     c/o David J. DeWitt and Michael J. Carey
  28. *   Computer Sciences Department
  29. *   University of Wisconsin -- Madison
  30. *   Madison, WI 53706
  31. *
  32. *     or exodus@cs.wisc.edu
  33. *
  34. * In addition, the EXODUS Project Group requests that users grant the 
  35. * Computer Sciences Department rights to redistribute these changes.
  36. **********************************************************************/
  37. #include "sysdefs.h"
  38. #include "ess.h"
  39. #include "checking.h"
  40. #include "trace.h"
  41. #include "error.h"
  42. #include "list.h"
  43. #include "pool.h"
  44. #include "tid.h"
  45. #include "io.h"
  46. #include "lock.h"
  47. #include "object.h"
  48. #include "msgdefs.h"
  49. #include "thread.h"
  50. #include "semaphore.h"
  51. #include "latch.h"
  52. #include "link.h"
  53. #include "lsn.h"
  54. #include "bf.h"
  55. #include "volume.h"
  56. #include "openlog.h"
  57. #include "trans.h"
  58. #include "logrecs.h"
  59. #include "logaction.h"
  60. #include "log.h"
  61. #include "threadstate.h"
  62. #include "util_funcs.h"
  63. #include "bf_extfuncs.h"
  64. #include "io_extfuncs.h"
  65. #include "log_intfuncs.h"
  66. #include "log_extfuncs.h"
  67. #include "thread_funcs.h"
  68. #include "thread_globals.h"
  69. #include "log_globals.h"
  70. #include "trans_globals.h"
  71.  
  72.  
  73.  int
  74. checkPoint (
  75.     BOOL                syncForce
  76. )
  77. {
  78.  
  79.     register OPENLOG    *openLog;
  80.     CHECKPOINTMASTER    *checkMaster;
  81.     CHECKPOINTINFO        checkInfo;
  82.     CHECKPOINTDPTINFO    dirtyPageInfoRecord;
  83.     LOGRECORDINFO        recordInfo;
  84.     LOGRECORDHDR        recordHeader;
  85.     static CHECKTRANS            transList[MAXTRANSCHKPNT];
  86.     LSN                    lsn;
  87.     LSNOFFSET            tempLSN;
  88.     int                    offset;
  89.     int                    dirtyPages;
  90.     FORCEMARK            forceMark;
  91.     int                    recordNum;
  92.     int                    totalDPTLogged;
  93.     int                    maxDPTPerRecord;
  94.     int                    numToLog;
  95.     BOOL                checkpointStartRecorded;
  96.     LSN                    tempOldestLSN;
  97.     int                    i;
  98.  
  99.     TRPRINT(TR_LOG, TR_LEVEL_1, ("sync force:%d", syncForce));
  100.  
  101.  
  102.     /*
  103.      *    get a pointer to the log
  104.      */
  105.     openLog = &OpenLog;
  106.  
  107.     /*
  108.      *    get the latch on the log
  109.      */
  110.     if (waitLatch( &(openLog->logLatch), SHARE_LATCH ))    {
  111.  
  112.         SM_ERROR(TYPE_FATAL, Active->errno);
  113.     }
  114.  
  115.     /*
  116.      *    check to see if the log is in use
  117.      */
  118.     if (waitSemaphore( &(openLog->writeSemaphore) ))    {
  119.  
  120.         signalLatch( &(openLog->logLatch) );
  121.         return(esmFAILURE);
  122.     }
  123.  
  124.     /*
  125.      *    set the information in the master record
  126.      */
  127.     checkMaster = (CHECKPOINTMASTER *) openLog->controlBuffer->bufFrame;
  128.  
  129.     /* get the list of dirty pages */
  130.     dirtyPages = (int)(checkInfo.numDirtyPages  = checkPointDirtyPages());
  131.  
  132.     /*
  133.      *    check to see if a synchronous force is called for
  134.      */
  135.     if (syncForce)    {
  136.  
  137.         /*
  138.          *    synchronously force dirty pages
  139.          */
  140.         forceDirtyPages(checkInfo.numDirtyPages);
  141.  
  142.         /*
  143.          *    there should be zero dirty pages
  144.          */
  145.         dirtyPages = (int) (checkInfo.numDirtyPages = 0);
  146.     }    
  147.  
  148.     /*
  149.      * Make sure all pages written to unix file based volumes are
  150.      * actually on disk.
  151.      */
  152.     if (io_SyncUnixFileVolumes() != esmNOERROR) {
  153.         SM_ERROR(TYPE_FATAL, esmINTERNAL);    
  154.     }
  155.  
  156.     /*
  157.      *    get the list of active transactions and the log information
  158.      */
  159.     checkInfo.numActiveTrans = checkPointTrans(transList);
  160.     checkInfo.wrapCount      = openLog->wrapCount;
  161.  
  162.     /*
  163.      *    Get a list of all mounted volume id's
  164.      */
  165.     checkInfo.mountedVolCount = checkPointVolumes(CheckpointVolumes);
  166.  
  167.     /*
  168.      *    Log the dirty page table as a series of 
  169.      *    LOG_ACTION_CKPNT_DIRTY_PAGES type log records.
  170.      */
  171.     totalDPTLogged = 0;
  172.     recordNum = 0;
  173.     maxDPTPerRecord = MAX_LOGIMAGE_LEN / 2; /* very conservative */
  174.     checkpointStartRecorded = FALSE;
  175.     while (totalDPTLogged < dirtyPages) {
  176.  
  177.         /*
  178.          *    initialize the fields of the record header
  179.          */
  180.         recordHeader.magic        = LOGRECORD_MAGIC;
  181.         recordHeader.type        = LOG_REC_TYPE_CHECKPOINT;
  182.         recordHeader.action        = LOG_ACTION_CKPNT_DIRTY_PAGES;
  183.         recordHeader.imageCount    = 2;
  184.         recordInfo.imageCount     = 2;
  185.         recordHeader.flags        = NOFLAGS;
  186.  
  187.         numToLog = MIN(maxDPTPerRecord, dirtyPages - totalDPTLogged);
  188.  
  189.         /*
  190.          *    set the image for the checkpoint DPT info
  191.          */
  192.         dirtyPageInfoRecord.numDirtyPages = numToLog;
  193.         dirtyPageInfoRecord.recordNum = recordNum;
  194.         recordHeader.imageSize[0]    = sizeof(dirtyPageInfoRecord);
  195.         recordHeader.imageOffset[0] = 0;
  196.         recordInfo.imageSize[0]        = sizeof(dirtyPageInfoRecord);
  197.         recordInfo.imageData[0]        = (VOID *) &dirtyPageInfoRecord;
  198.  
  199.         /*
  200.          *    set the alignment for the next image
  201.          */
  202.         offset = ALIGN(sizeof(dirtyPageInfoRecord), 4);
  203.         TRPRINT(TR_LOG, TR_LEVEL_2, ("offset:%d", offset));
  204.  
  205.         /*
  206.          *    setup the image for the dirty pages information
  207.          */
  208.         recordHeader.imageSize[1]     = numToLog * sizeof(DIRTYPAGEINFO);
  209.         recordHeader.imageOffset[1] = offset;
  210.         recordInfo.imageSize[1]     = recordHeader.imageSize[1];
  211.         recordInfo.imageData[1]     = (VOID *) (&(DirtyPageTable[totalDPTLogged]));
  212.  
  213.         /*
  214.          *    calculate the size of the record
  215.          */
  216.         recordHeader.length = sizeof(LOGRECORDHDR) + ALIGN(offset + recordHeader.imageSize[1], 4);
  217.         TRPRINT(TR_LOG, TR_LEVEL_2, ("DPT record length:%d", recordHeader.length));
  218.  
  219.         /*
  220.          *    write the record to the log
  221.          */
  222.         lsn = writeLogRecordHeader(openLog, &recordHeader, &tempLSN);
  223.  
  224.         /*
  225.          *    write the images to the log
  226.          */
  227.         writeImage(openLog, &recordInfo, 0, &tempLSN);
  228.         writeImage(openLog, &recordInfo, 1, &tempLSN);
  229.  
  230.         if ( !checkpointStartRecorded ) {
  231.             /* record the checkpoint information in the openlog structure */
  232.             openLog->checkPointUnique = openLog->logRecordCount;
  233.             openLog->checkPointLSN      = lsn;
  234.             openLog->checkPointPid      = LSN_TO_LOG_PAGE(lsn.offset, openLog);
  235.             checkpointStartRecorded = TRUE;
  236.         }
  237.  
  238.         /* Record the next LSN to be generated */
  239.         openLog->nextValidLSN.wrapCount = openLog->wrapCount;
  240.         openLog->nextValidLSN.offset = 
  241.             FIRST_LSN_ON_PAGE(openLog->tailLSN, openLog);
  242.                 
  243.         totalDPTLogged += numToLog;
  244.         recordNum++;
  245.     }
  246.     SM_ASSERT(LEVEL_3, totalDPTLogged == dirtyPages);
  247.     SM_ASSERT(LEVEL_3, checkInfo.numDirtyPages < DirtyPageTableMaxSize);
  248.  
  249.  
  250.     /*
  251.      *    NOW LOG THE CHECKPOINT RECORD
  252.      */
  253.  
  254.     /*
  255.      *    Remember the mark to force to and increment the log's
  256.      *    count of log records.  This is similar to the sequence of
  257.      *    events in writeLogRecord()
  258.      */
  259.     forceMark = ++(openLog->logRecordCount);
  260.  
  261.     /*
  262.      *    initialize the fields of the record header
  263.      */
  264.     recordHeader.magic        = LOGRECORD_MAGIC;
  265.     recordHeader.type        = LOG_REC_TYPE_CHECKPOINT;
  266.     recordHeader.action        = LOG_ACTION_NO_ACTION;
  267.     recordHeader.imageCount    = 3;
  268.     recordInfo.imageCount     = 3;
  269.     recordHeader.flags        = NOFLAGS;
  270.  
  271.     /*
  272.      *    set the image for the checkpoint body
  273.      */
  274.     recordHeader.imageSize[0]    = sizeof(CHECKPOINTINFO);
  275.     recordHeader.imageOffset[0] = 0;
  276.     recordInfo.imageSize[0]        = sizeof(CHECKPOINTINFO);
  277.     recordInfo.imageData[0]        = (VOID *) &checkInfo;
  278.  
  279.     /*
  280.      *    set the alignment for the next image
  281.      */
  282.     offset = ALIGN(sizeof(CHECKPOINTINFO), 4);
  283.     TRPRINT(TR_LOG, TR_LEVEL_2, ("offset:%d", offset));
  284.  
  285.     /*
  286.      *    setup the image for the active transaction information
  287.      */
  288.     recordHeader.imageSize[1]     = checkInfo.numActiveTrans * sizeof(CHECKTRANS);
  289.     recordHeader.imageOffset[1] = offset;
  290.     recordInfo.imageSize[1]     = recordHeader.imageSize[1];
  291.     recordInfo.imageData[1]     = (VOID *) transList;
  292.  
  293.     /*
  294.      *    set the alignment for the next image
  295.      */
  296.     offset = ALIGN(offset + recordHeader.imageSize[1], 4);
  297.     TRPRINT(TR_LOG, TR_LEVEL_2, ("offset:%d", offset));
  298.  
  299.     /*
  300.      *    Set up the image for the mounted volumes info
  301.      */
  302.     recordHeader.imageSize[2]     = checkInfo.mountedVolCount * sizeof(*CheckpointVolumes);
  303.     recordHeader.imageOffset[2] = offset;
  304.     recordInfo.imageSize[2]     = recordHeader.imageSize[2];
  305.     recordInfo.imageData[2]     = (VOID *) CheckpointVolumes;
  306.  
  307.     /*
  308.      *    calculate the size of the record
  309.      */
  310.     recordHeader.length = sizeof(LOGRECORDHDR) + ALIGN(offset + recordHeader.imageSize[2], 4);
  311.     TRPRINT(TR_LOG, TR_LEVEL_2, ("record length:%d", recordHeader.length));
  312.  
  313.     /*
  314.      *    write the record to the log
  315.      */
  316.     lsn = writeLogRecordHeader(openLog, &recordHeader, &tempLSN);
  317.  
  318.     /*
  319.      *    write the images to the log
  320.      */
  321.     writeImage(openLog, &recordInfo, 0, &tempLSN);
  322.     writeImage(openLog, &recordInfo, 1, &tempLSN);
  323.     writeImage(openLog, &recordInfo, 2, &tempLSN);
  324.  
  325.     if ( !checkpointStartRecorded ) {
  326.         /* record the checkpoint information in the openlog structure */
  327.         openLog->checkPointUnique = openLog->logRecordCount;
  328.         openLog->checkPointLSN      = lsn;
  329.         openLog->checkPointPid      = LSN_TO_LOG_PAGE(lsn.offset, openLog);
  330.         checkpointStartRecorded = TRUE;
  331.     }
  332.  
  333.     /* Record the next LSN to be generated */
  334.      openLog->nextValidLSN.wrapCount = openLog->wrapCount;
  335.     openLog->nextValidLSN.offset = 
  336.             FIRST_LSN_ON_PAGE(openLog->tailLSN, openLog);
  337.  
  338.     PRINT_PROGRESS( ("Logging CHECKPOINT at LSN:%d:%d\n", openLog->checkPointLSN.offset, openLog->checkPointLSN.wrapCount));
  339.  
  340.     /*
  341.      *    force the log
  342.      */
  343.     forceLog(forceMark);
  344.  
  345.     /*
  346.      *    set the information in the master record
  347.      */
  348.     checkMaster                    = (CHECKPOINTMASTER *) openLog->controlBuffer->bufFrame;
  349.     checkMaster->magic            = CHECKPOINTMASTER_MAGIC;
  350.     checkMaster->wrapCount        = openLog->wrapCount;
  351.     checkMaster->checkRecordLSN = openLog->checkPointLSN;
  352.     SM_ASSERT(LEVEL_3, checkInfo.numDirtyPages < DirtyPageTableMaxSize);
  353.     checkMaster->oldestDirtyLSN = findOldestLSN(openLog, openLog->checkPointLSN,
  354.                                               checkInfo.numDirtyPages);
  355.  
  356.     /*
  357.      *    dirty the page
  358.      */
  359.     DIRTY_PAGE(openLog->controlBuffer->pageHash);
  360.  
  361.     /*
  362.      *    force the master information to disk
  363.      */
  364.     bf_ForcePage(openLog->controlBuffer->pageHash, BF_SEM);
  365.  
  366.     /*
  367.      *  Find the LSN of the oldest dirty buffer page.  If no page is
  368.      *  dirty, the the current checkpoint record LSN will be remembered.
  369.      *  This is used to determine where log space can be reused.
  370.      */
  371.     tempOldestLSN = openLog->checkPointLSN;
  372.     for (i = 0; i < dirtyPages; i++) {
  373.         if ( compareLSN(&DirtyPageTable[i].lsn, &tempOldestLSN) < 0) {
  374.             tempOldestLSN = DirtyPageTable[i].lsn;
  375.         }
  376.     }
  377.     OldestDirtyPageLSN = tempOldestLSN;
  378.     PRINT_PROGRESS(("Checkpoint oldest dirty page lsn:%d:%d\n", OldestDirtyPageLSN.wrapCount, OldestDirtyPageLSN.offset));
  379.  
  380.     /*
  381.      *    check to see if a synchronous force is called for
  382.      */
  383.     if (syncForce)    {
  384.  
  385.         /*
  386.          *    mark the checkpoint as done
  387.          */
  388.         openLog->flags ^= LOG_CHECKPOINT_IN_PROGRESS;
  389.  
  390.         /*
  391.          *    signal any waiters
  392.          */
  393.         notify( &(openLog->checkPointList), esmNOERROR, esmNOERROR);
  394.  
  395.         /* since all pages were flushed, remember this checkpoint */
  396.         LastFlushedCheckpoint = checkMaster->checkRecordLSN;
  397.  
  398.     } else {
  399.  
  400.         /*
  401.          *    start the thread which asynchronously forces the dirty
  402.          *    page table.
  403.          */
  404.         notify(&DirtyPageFlushWaitList, esmNOERROR, esmNOERROR);
  405.  
  406.         /*
  407.          *    signal any waiters for the checkpoint
  408.          */
  409.         notify( &(openLog->checkPointList), esmNOERROR, esmNOERROR);
  410.     }    
  411.  
  412.     /*
  413.      *    reset the number of records since checkpoint
  414.      */
  415.     openLog->checkPointCount = 0;
  416.  
  417.     /*
  418.      *    give the semaphore back
  419.      */
  420.     signalSemaphore( &(openLog->writeSemaphore) );
  421.  
  422.     /*
  423.      *    give the log latch back
  424.      */
  425.     signalLatch( &(openLog->logLatch) );
  426.  
  427.     return(esmNOERROR);
  428. }
  429.