home *** CD-ROM | disk | FTP | other *** search
/ Complete Linux / Complete Linux.iso / docs / apps / database / postgres / postgre4.z / postgre4 / src / storage / page / bufpage.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-08-27  |  14.2 KB  |  576 lines

  1. /* ----------------------------------------------------------------
  2.  *   FILE
  3.  *    bufpage.c
  4.  *
  5.  *   DESCRIPTION
  6.  *    POSTGRES standard buffer page code.
  7.  *
  8.  *   IDENTIFICATION
  9.  *    $Header: /private/postgres/src/storage/page/RCS/bufpage.c,v 1.17 1992/07/07 23:56:15 mao Exp $
  10.  * ----------------------------------------------------------------
  11.  */
  12. #include <sys/types.h>
  13. #include <sys/file.h>
  14. #include "tmp/align.h"
  15.  
  16. #include "tmp/c.h"
  17. #include "tmp/clib.h"
  18.  
  19. #include "storage/item.h"
  20.  
  21. #include "storage/buf.h"
  22. #include "storage/bufmgr.h"
  23. #include "utils/log.h"
  24. #include "storage/page.h"
  25. #include "storage/pagenum.h"
  26. #include "storage/part.h"
  27.  
  28. #include "storage/bufpage.h"
  29.  
  30. RcsId("$Header: /private/postgres/src/storage/page/RCS/bufpage.c,v 1.17 1992/07/07 23:56:15 mao Exp $");
  31.  
  32. static bool PageManagerShuffle = true;    /* default is shuffle mode */
  33.  
  34. void PageRepairFragmentation ARGS((Page    page));
  35.     
  36. /* ----------------------------------------------------------------
  37.  *            Buffer support functions
  38.  * ----------------------------------------------------------------
  39.  */
  40. PageSize
  41. BufferGetPageSize(buffer)
  42.     Buffer    buffer;
  43. {
  44.     PageSize    pageSize;
  45.     
  46.     Assert(BufferIsValid(buffer));
  47.     pageSize = PageGetPageSize((Page)BufferGetBlock(buffer));
  48.     
  49.     Assert(PageSizeIsValid(pageSize));
  50.     return (pageSize);
  51. }
  52.  
  53. Page
  54. BufferGetPage(buffer, pageNumber)
  55.     Buffer    buffer;
  56.     PageNumber    pageNumber;
  57. {
  58.     Assert(pageNumber == FirstPageNumber);
  59.     return (Page) BufferGetBlock(buffer);
  60. }
  61.  
  62. Page
  63. BufferGetPageDebug(buffer, pageNumber)
  64.     Buffer    buffer;
  65.     PageNumber    pageNumber;
  66. {
  67.     Page         page;
  68.     LocationIndex    lower, upper, special;
  69.    
  70.     page = BufferGetPage(buffer, pageNumber);
  71.  
  72.     lower =   ((PageHeader)page)->pd_lower;
  73.     upper =   ((PageHeader)page)->pd_upper;
  74.     special = ((PageHeader)page)->pd_special;
  75.  
  76.     Assert((lower > 7));
  77.     Assert((lower <= upper));
  78.     Assert((upper <= special));
  79.    
  80.     return page;
  81. }
  82.  
  83. /* ----------------------------------------------------------------
  84.  *            Page support functions
  85.  * ----------------------------------------------------------------
  86.  */
  87.  
  88. #define OpaqueSetInternalFragmentation(opaque, frag) \
  89.     Assert(frag >= 0); \
  90.     Assert(frag <= MaxInternalFragmentation); \
  91.     (opaque)->fragmentation = (frag)
  92.  
  93. static
  94. void
  95. OpaqueSetPageSize(opaque, pageSize)
  96.     Opaque    opaque;
  97.     PageSize    pageSize;
  98. {
  99.     int    i;
  100.     Assert(PageSizeIsValid(pageSize));
  101.  
  102.     pageSize >>= 1;
  103.     for (i = 0; pageSize >>= 1; i++);
  104.     opaque->pageSize = i;
  105. }
  106.  
  107. /* ----------------
  108.  *    PageInit
  109.  * ----------------
  110.  */
  111. void
  112. PageInit(page, pageSize, specialSize)
  113.     Page        page;
  114.     PageSize    pageSize;
  115.     SpecialSize    specialSize;
  116. {
  117.     Assert(pageSize == BLCKSZ);
  118.  
  119.     Assert(pageSize>specialSize+sizeof(PageHeaderData)-sizeof (ItemIdData));
  120.  
  121.     ((PageHeader)page)->pd_lower =
  122.     sizeof (PageHeaderData) - sizeof(ItemIdData);
  123.     
  124.     ((PageHeader)page)->pd_upper = pageSize - LONGALIGN(specialSize);
  125.     ((PageHeader)page)->pd_special = pageSize - specialSize;
  126.  
  127.     OpaqueSetPageSize((Opaque)&((PageHeader)page)->opaque, pageSize);
  128.     
  129.     OpaqueSetInternalFragmentation((Opaque)&((PageHeader)page)->opaque,
  130.                    (InternalFragmentation)0);
  131. }
  132.  
  133. /* ----------------
  134.  *    PageGetItem
  135.  * ----------------
  136.  */
  137. Item
  138. PageGetItem(page, itemId)
  139.     Page    page;
  140.     ItemId    itemId;
  141. {
  142.     Item    item;
  143.  
  144.     Assert(PageIsValid(page));
  145.     Assert((*itemId).lp_flags & LP_USED);
  146.     Assert(!((*itemId).lp_flags & LP_CTUP));
  147.  
  148.     if ((*itemId).lp_flags & LP_DOCNT) {
  149.     item = (Item)(((char *)page) + (*itemId).lp_off + TCONTPAGELEN);
  150.     } else {
  151.     item = (Item)(((char *)page) + (*itemId).lp_off);
  152.     }
  153.  
  154.     return (item);
  155. }
  156.  
  157. /* ----------------
  158.  *    PageAddItem
  159.  *
  160.  *    add an item to a page.
  161.  *
  162.  *   Notes on interface:
  163.  *      If offsetNumber is valid, shuffle ItemId's down to make room
  164.  *     to use it, if PageManagerShuffle is true.  If PageManagerShuffle is
  165.  *      false, then overwrite the specified ItemId.  (PageManagerShuffle is
  166.  *      true by default, and is modified by calling PageManagerModeSet.)
  167.  *      If offsetNumber is not valid, then assign one by finding the first 
  168.  *      one that is both unused and deallocated.
  169.  *
  170.  *   NOTE: If offsetNumber is valid, and PageManagerShuffle is true, it
  171.  *      is assumed that there is room on the page to shuffle the ItemId's
  172.  *      down by one.
  173.  * ----------------
  174.  */
  175. OffsetNumber
  176. PageAddItem(page, item, size, offsetNumber, flags)
  177.     Page        page;
  178.     Item        item;
  179.     Size        size;
  180.     OffsetNumber    offsetNumber;
  181.     ItemIdFlags        flags;
  182. {
  183.     register         i;
  184.     Size        alignedSize;
  185.     Offset        lower;
  186.     Offset        upper;
  187.     ItemId        itemId;
  188.     ItemId        fromitemId, toitemId;
  189.     OffsetNumber     limit;
  190.     
  191.     bool shuffled = false;
  192.  
  193.     /*
  194.      *  Find first unallocated offsetNumber
  195.      */
  196.     limit = 2 + PageGetMaxOffsetIndex(page);
  197.  
  198.     /* was offsetNumber passed in? */
  199.     if (OffsetNumberIsValid(offsetNumber)) {
  200.     if (PageManagerShuffle == true) {
  201.         /* shuffle ItemId's (Do the PageManager Shuffle...) */
  202.         for (i = (limit - 1); i >= offsetNumber; i--) {
  203.         fromitemId = &((PageHeader)page)->pd_linp[i - 1];
  204.         toitemId = &((PageHeader)page)->pd_linp[i];
  205.         *toitemId = *fromitemId;
  206.         }
  207.         shuffled = true;    /* need to increase "lower" */
  208.     } else { /* overwrite mode */
  209.         itemId = &((PageHeader)page)->pd_linp[offsetNumber - 1];
  210.         if (((*itemId).lp_flags & LP_USED)  || 
  211.         ((*itemId).lp_len != 0)) {
  212.         elog(WARN, "PageAddItem: tried overwrite of used ItemId");
  213.         return (InvalidOffsetNumber);
  214.         }
  215.     }
  216.     } else {    /* offsetNumber was not passed in, so find one */
  217.     /* look for "recyclable" (unused & deallocated) ItemId */
  218.     for (offsetNumber = 1; offsetNumber < limit; offsetNumber++) {
  219.         itemId = &((PageHeader)page)->pd_linp[offsetNumber - 1];
  220.         if ((((*itemId).lp_flags & LP_USED) == 0) && 
  221.         ((*itemId).lp_len == 0)) 
  222.         break;
  223.     }
  224.     }
  225.     if (offsetNumber > limit)
  226.     lower = (Offset) (((char *) (&((PageHeader)page)->pd_linp[offsetNumber])) - ((char *) page));
  227.     else if (offsetNumber == limit || shuffled == true)
  228.     lower = ((PageHeader)page)->pd_lower + sizeof (ItemIdData);
  229.     else
  230.     lower = ((PageHeader)page)->pd_lower;
  231.  
  232.     alignedSize = LONGALIGN(size);
  233.  
  234.     upper = ((PageHeader)page)->pd_upper - alignedSize;
  235.     
  236.     if (lower > upper) {
  237.     return (InvalidOffsetNumber);
  238.     }
  239.  
  240.     itemId = &((PageHeader)page)->pd_linp[offsetNumber - 1];
  241.     (*itemId).lp_off = upper;
  242.     (*itemId).lp_len = size;
  243.     (*itemId).lp_flags = flags;
  244.     bcopy(item, (char *)page + upper, size);
  245.     ((PageHeader)page)->pd_lower = lower;
  246.     ((PageHeader)page)->pd_upper = upper;
  247.  
  248.     return (offsetNumber);
  249. }
  250.  
  251. /* ----------------
  252.  *    PageRemoveItem
  253.  * ----------------
  254.  */
  255. ReturnStatus
  256. PageRemoveItem(page, itemId)
  257.     Page        page;
  258.     ItemId        itemId;
  259. {
  260.     Size        alignedSize;
  261.     Offset        lower;
  262.     Offset        upper;
  263.  
  264.     Assert(PageIsValid(page));
  265.     Assert(ItemIdIsUsed(itemId));
  266.     Assert(!ItemIdIsContinuation(itemId) || !ItemIdIsContinuing(itemId));
  267.     /* cannot handle long tuples yet. */
  268.  
  269.     itemId->lp_flags &= ~LP_USED;    /* XXX should have function call */
  270.  
  271.     PageRepairFragmentation(page);
  272. }
  273.  
  274. /* ----------------
  275.  *    PageGetTempPage
  276.  * ----------------
  277.  */
  278. Page
  279. PageGetTempPage(page, specialSize)
  280.     Page    page;
  281.     Size    specialSize;
  282. {
  283.     PageSize    pageSize;
  284.     PageSize    size;
  285.     Page        temp;
  286.     PageHeader    thdr;
  287.  
  288.     pageSize = PageGetPageSize(page);
  289.  
  290.     if ((temp = (Page) palloc(pageSize)) == (Page) NULL)
  291.     elog(FATAL, "Cannot allocate %d bytes for temp page.", pageSize);
  292.     thdr = (PageHeader) temp;
  293.  
  294.     /* copy old page in */
  295.     bcopy(page, temp, pageSize);
  296.  
  297.     /* clear out the middle */
  298.     size = (pageSize - sizeof(PageHeaderData)) + sizeof(ItemIdData);
  299.     size -= specialSize;
  300.     bzero((char *) &(thdr->pd_linp[0]), size);
  301.  
  302.     /* set high, low water marks */
  303.     thdr->pd_lower = sizeof (PageHeaderData) - sizeof (ItemIdData);
  304.     thdr->pd_upper = pageSize - LONGALIGN(specialSize);
  305.  
  306.     return (temp);
  307. }
  308.  
  309. /* ----------------
  310.  *    PageRestoreTempPage
  311.  * ----------------
  312.  */
  313. void
  314. PageRestoreTempPage(tempPage, oldPage)
  315.     Page    tempPage;
  316.     Page    oldPage;
  317. {
  318.     PageSize    pageSize;
  319.  
  320.     pageSize = PageGetPageSize(tempPage);
  321.     bcopy((char *) tempPage, (char *) oldPage, pageSize);
  322.  
  323.     pfree(tempPage);
  324. }
  325.  
  326. /* ----------------
  327.  *    PageGetMaxOffsetIndex
  328.  * ----------------
  329.  */
  330. OffsetIndex
  331. PageGetMaxOffsetIndex(page)
  332.     Page    page;
  333. {
  334.     LocationIndex    low;
  335.     OffsetIndex        i;
  336.  
  337.     low = ((PageHeader) page)->pd_lower;
  338.     i = (low - (sizeof(PageHeaderData) - sizeof(ItemIdData))) / sizeof(ItemIdData);
  339.  
  340.     return(--i);
  341. }    
  342.  
  343. /* ----------------
  344.  *    idemid stuff for PageRepairFragmentation
  345.  * ----------------
  346.  */
  347.  
  348.  
  349. struct itemIdData {
  350.     OffsetIndex offsetindex;
  351.     ItemIdData  itemiddata;
  352. };
  353.  
  354. static
  355. itemidcompare(itemidp1, itemidp2)
  356.     struct itemIdData *itemidp1, *itemidp2;
  357. {
  358.     if (itemidp1->itemiddata.lp_off == itemidp2->itemiddata.lp_off)
  359.         return(0);
  360.     else if (itemidp1->itemiddata.lp_off < itemidp2->itemiddata.lp_off)
  361.         return(1);
  362.     else
  363.         return(-1);
  364. }
  365.  
  366. /* ----------------
  367.  *    PageRepairFragmentation
  368.  * ----------------
  369.  */
  370. void
  371. PageRepairFragmentation(page)
  372.     Page    page;
  373. {
  374.     int         i;
  375.     struct itemIdData     *itemidbase, *itemidptr;
  376.     ItemId         lp;
  377.     int         nline, nused;
  378.     OffsetIndex     offsetindex;
  379.     int         itemidcompare();
  380.     Offset         upper;
  381.     Size         alignedSize;
  382.  
  383.     nline = 1 + (int16)PageGetMaxOffsetIndex(page);
  384.     nused = 0;
  385.     for (i=0; i<nline; i++) {
  386.     lp = ((PageHeader)page)->pd_linp + i;
  387.     if ((*lp).lp_flags & LP_USED)
  388.         nused++;
  389.     }
  390.  
  391.     if (nused == 0) {
  392.     for (i=0; i<nline; i++) {
  393.         lp = ((PageHeader)page)->pd_linp + i;
  394.         if ((*lp).lp_len > 0)     /* unused, but allocated */
  395.         (*lp).lp_len = 0;    /* indicate unused & deallocated */
  396.     }
  397.  
  398.     ((PageHeader)page)->pd_upper = ((PageHeader)page)->pd_special;
  399.  
  400.     /* the following function may need to be added to bufpage.[hc] */
  401.     /* PageSetInternalFragmentation(page, (InternalFragmentation)0); */
  402.  
  403.     } else {    /* nused != 0 */
  404.     itemidbase = (struct itemIdData *) 
  405.         palloc(sizeof(struct itemIdData) * nused);
  406.     bzero((char *) itemidbase, sizeof(struct itemIdData) * nused);
  407.     itemidptr = itemidbase;
  408.     for (i=0; i<nline; i++) {
  409.         lp = ((PageHeader)page)->pd_linp + i;
  410.         if ((*lp).lp_flags & LP_USED) {
  411.         itemidptr->offsetindex = i;
  412.         itemidptr->itemiddata = *lp;
  413.         itemidptr++;
  414.         } else {
  415.         if ((*lp).lp_len > 0)     /* unused, but allocated */
  416.             (*lp).lp_len = 0;    /* indicate unused & deallocated */
  417.         }
  418.     }
  419.  
  420.     /* sort itemIdData array...*/
  421.     qsort((char *) itemidbase, nused, sizeof(struct itemIdData),
  422.           itemidcompare);
  423.  
  424.     /* compactify page */
  425.     ((PageHeader)page)->pd_upper = ((PageHeader)page)->pd_special;
  426.  
  427.     /* the following function may need to be added to bufpage.[hc] */
  428.     /* PageSetInternalFragmentation(page, (InternalFragmentation)0); */
  429.  
  430.     for (i=0, itemidptr = itemidbase; i<nused; i++, itemidptr++) {
  431.         lp = ((PageHeader)page)->pd_linp + itemidptr->offsetindex;
  432.         alignedSize = LONGALIGN((*lp).lp_len);
  433.         upper = ((PageHeader)page)->pd_upper - alignedSize;
  434.         bcopy((char *)page + (*lp).lp_off, (char *) page + upper,
  435.           (*lp).lp_len);
  436.         (*lp).lp_off = upper;
  437.         ((PageHeader)page)->pd_upper = upper;
  438.     }
  439.  
  440.     pfree(itemidbase);
  441.     }
  442. }
  443.  
  444. /* ----------------
  445.  *    PageGetFreeSpace
  446.  * ----------------
  447.  */
  448. PageFreeSpace
  449. PageGetFreeSpace(page)
  450.     Page    page;
  451. {
  452.     PageFreeSpace    space;
  453.  
  454.  
  455.     space = ((PageHeader)page)->pd_upper - ((PageHeader)page)->pd_lower;
  456.  
  457.     if (space < sizeof (ItemIdData)) {
  458.     return (0);
  459.     }
  460.     space -= sizeof (ItemIdData);        /* XXX not always true */
  461.  
  462.     return (space);
  463. }
  464.  
  465. /* ----------------
  466.  *    PageManagerModeSet
  467.  * ----------------
  468.  */
  469. void
  470. PageManagerModeSet(mode)
  471.     PageManagerMode mode;
  472. {
  473.     if (mode == ShufflePageManagerMode)
  474.     PageManagerShuffle = true;
  475.     else if (mode == OverwritePageManagerMode)
  476.     PageManagerShuffle = false;
  477. }
  478.  
  479. /*
  480.  *----------------------------------------------------------------
  481.  * PageIndexTupleDelete
  482.  *----------------------------------------------------------------
  483.  *
  484.  *    This routine does the work of removing a tuple from an index page.
  485.  */
  486.  
  487. PageIndexTupleDelete(page, offset)
  488.     Page page;
  489.     OffsetNumber offset;
  490. {
  491.     PageHeader     phdr;
  492.     char     *addr;
  493.     ItemId     tup;
  494.     Size     size;
  495.     char     *locn;
  496.     int     nbytes;
  497.  
  498.     phdr = (PageHeader) page;
  499.  
  500.     /* change offset number to offset index */
  501.     offset--;
  502.  
  503.     tup = PageGetItemId(page, offset);
  504.     size = ItemIdGetLength(tup);
  505.     size = LONGALIGN(size);
  506.  
  507.     nbytes = phdr->pd_lower - sizeof (*phdr);
  508.  
  509.     /* location of deleted tuple data */
  510.     locn = (char *) (page + ItemIdGetOffset(tup));
  511.  
  512.     /*
  513.      * First, we want to get rid of the pd_linp entry for the index
  514.      * tuple.  We copy all subsequent linp's back one slot in the
  515.      * array.
  516.      */
  517.     bcopy((char *) &(phdr->pd_linp[offset + 1]),
  518.       (char *) &(phdr->pd_linp[offset]),
  519.       nbytes);
  520.  
  521.     /*
  522.      * Now move everything between the old lower bound (end of linp
  523.      * space) and the beginning of the deleted tuple forward, so that
  524.      * space in the middle of the page is left free.
  525.      */
  526.  
  527.     /* end of linp space */
  528.     addr = (char *) (page + phdr->pd_lower);
  529.  
  530.     bcopy(addr, addr + size, (int) (locn - addr));
  531.  
  532.     /* adjust free space boundary pointers */
  533.     phdr->pd_upper += size;
  534.     phdr->pd_lower -= sizeof (ItemIdData);
  535.  
  536.     /* finally, we need to adjust the linp entries that remain */
  537.     if (!PageIsEmpty(page))
  538.     PageIndexTupleDeleteAdjustLinePointers(phdr, locn, size);
  539. }
  540.  
  541. /*
  542.  *----------------------------------------------------------------
  543.  * PageIndexTupleDeleteAdjustLinePointers
  544.  *----------------------------------------------------------------
  545.  *
  546.  *    Once the line pointers and tuple data have been shifted around
  547.  *    on the page, we need to go down the line pointer vector and
  548.  *    adjust pointers to reflect new locations.  Anything that used
  549.  *    to be before the deleted tuple's data was moved forward by the
  550.  *    size of the deleted tuple.
  551.  *
  552.  *    This routine does the work of adjusting the line pointers.
  553.  *    Location is where the tuple data used to lie; size is how
  554.  *    much space it occupied.  We assume that size has been aligned
  555.  *    as required by the time we get here.
  556.  *
  557.  *    This routine should never be called on an empty page.
  558.  */
  559.  
  560. PageIndexTupleDeleteAdjustLinePointers(phdr, location, size)
  561.     register PageHeader phdr;
  562.     char         *location;
  563.     Size         size;
  564. {
  565.     int i;
  566.  
  567.     /* location is an index into the page... */
  568.     location -= (int) phdr;
  569.  
  570.     for (i = PageGetMaxOffsetIndex((Page) phdr); i >= 0; i--)    {
  571.     if (phdr->pd_linp[i].lp_off <= (unsigned) location) {
  572.         phdr->pd_linp[i].lp_off += size;
  573.     }
  574.     }
  575. }
  576.