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

  1. /*
  2.  * bufmgr.c -- buffer manager interface routines
  3.  *
  4.  * Identification:
  5.  *    $Header: /private/postgres/src/storage/buffer/RCS/bufmgr.c,v 1.74 1992/07/13 17:37:28 hong Exp $
  6.  *
  7.  * BufferAlloc() -- lookup a buffer in the buffer table.  If
  8.  *    it isn't there add it, but do not read it into memory.
  9.  *    This is used when we are about to reinitialize the
  10.  *    buffer so don't care what the current disk contents are.
  11.  *    BufferAlloc() pins the new buffer in memory.
  12.  *
  13.  * ReadBuffer() -- same as BufferAlloc() but reads the data
  14.  *    on a buffer cache miss.
  15.  *
  16.  * ReleaseBuffer() -- unpin the buffer
  17.  *
  18.  * WriteNoReleaseBuffer() -- mark the buffer contents as "dirty"
  19.  *    but don't unpin.  The disk IO is delayed until buffer
  20.  *    replacement if LateWrite flag is set.
  21.  *
  22.  * WriteBuffer() -- WriteNoReleaseBuffer() + ReleaseBuffer() 
  23.  *
  24.  * DirtyBufferCopy() -- For a given dbid/relid/blockno, if the buffer is
  25.  *            in the cache and is dirty, mark it clean and copy
  26.  *            it to the requested location.  This is a logical
  27.  *            write, and has been installed to support the cache
  28.  *            management code for write-once storage managers.
  29.  *
  30.  * FlushBuffer() -- as above but never delayed write.
  31.  *
  32.  * BufferSync() -- flush all dirty buffers in the buffer pool.
  33.  * 
  34.  * InitBufferPool() -- Init the buffer module.
  35.  *
  36.  * See other files:  
  37.  *     freelist.c -- chooses victim for buffer replacement 
  38.  *    buf_table.c -- manages the buffer lookup table
  39.  */
  40. #include <sys/file.h>
  41. #include <stdio.h>
  42. #include <math.h>
  43. #include <signal.h>
  44.  
  45. #include "storage/buf_internals.h"
  46. #include "storage/bufmgr.h"
  47.  
  48. #include "storage/fd.h"
  49. #include "storage/ipc.h"
  50. #include "storage/ipci.h"
  51. #include "storage/shmem.h"
  52. #include "storage/spin.h"
  53. #include "storage/smgr.h"
  54. #include "storage/lmgr.h"
  55. #include "tmp/miscadmin.h"
  56. #include "utils/hsearch.h"
  57. #include "utils/log.h"
  58.  
  59. /*
  60.  *  if BMTRACE is defined, we trace the last 200 buffer allocations and
  61.  *  deallocations in a circular buffer in shared memory.
  62.  */
  63. #ifdef    BMTRACE
  64. bmtrace    *TraceBuf;
  65. int    *CurTraceBuf;
  66. #define    BMT_LIMIT    200
  67. #endif /* BMTRACE */
  68.  
  69. int        NBuffers = NDBUFS;  /* NDBUFS defined in miscadmin.h */
  70. int        Data_Descriptors;
  71. int        Free_List_Descriptor;
  72. int        Lookup_List_Descriptor;
  73. int        Num_Descriptors;
  74.  
  75. BufferDesc     *BufferDescriptors;
  76. BufferBlock     BufferBlocks;
  77. #ifndef HAS_TEST_AND_SET
  78. static int    *NWaitIOBackendP;
  79. #endif
  80.  
  81. Buffer           BufferDescriptorGetBuffer();
  82.  
  83. int    *PrivateRefCount;
  84. int    *LastRefCount;  /* refcounts of last ExecMain level */
  85.  
  86. /*
  87.  * Data Structures:
  88.  *      buffers live in a freelist and a lookup data structure.
  89.  *    
  90.  *
  91.  * Buffer Lookup:
  92.  *    Two important notes.  First, the buffer has to be
  93.  *    available for lookup BEFORE an IO begins.  Otherwise
  94.  *    a second process trying to read the buffer will 
  95.  *    allocate its own copy and the buffeer pool will 
  96.  *    become inconsistent.
  97.  *
  98.  * Buffer Replacement:
  99.  *    see freelist.c.  A buffer cannot be replaced while in
  100.  *    use either by data manager or during IO.
  101.  *
  102.  * WriteBufferBack:
  103.  *    currently, a buffer is only written back at the time
  104.  *    it is selected for replacement.  It should 
  105.  *    be done sooner if possible to reduce latency of 
  106.  *    BufferAlloc().  Maybe there should be a daemon process.
  107.  *
  108.  * Synchronization/Locking:
  109.  *
  110.  * BufMgrLock lock -- must be acquired before manipulating the 
  111.  *     buffer queues (lookup/freelist).  Must be released 
  112.  *     before exit and before doing any IO.  
  113.  *
  114.  * IO_IN_PROGRESS -- this is a flag in the buffer descriptor.
  115.  *      It must be set when an IO is initiated and cleared at
  116.  *      the end of  the IO.  It is there to make sure that one
  117.  *    process doesn't start to use a buffer while another is
  118.  *    faulting it in.  see IOWait/IOSignal.
  119.  *
  120.  * refcount --  A buffer is pinned during IO and immediately
  121.  *    after a BufferAlloc().  A buffer is always either pinned
  122.  *    or on the freelist but never both.  The buffer must be
  123.  *    released, written, or flushed before the end of 
  124.  *     transaction.
  125.  *
  126.  * PrivateRefCount -- Each buffer also has a private refcount the keeps
  127.  *    track of the number of times the buffer is pinned in the current
  128.  *    processes.  This is used for two purposes, first, if we pin a
  129.  *    a buffer more than once, we only need to change the shared refcount
  130.  *    once, thus only lock the buffer pool once, second, when a transaction
  131.  *    aborts, it should only unpin the buffers exactly the number of times it
  132.  *    has pinned them, so that it will not blow away buffers of another
  133.  *    backend.
  134.  *
  135.  */
  136.  
  137. SPINLOCK BufMgrLock;
  138.  
  139. /* delayed write: TRUE on, FALSE off */
  140. int LateWrite = TRUE;
  141.  
  142. int ReadBufferCount;
  143. int BufferHitCount;
  144. int BufferFlushCount;
  145.  
  146. /* ---------------------------------------------------
  147.  * RelationGetBufferWithBuffer
  148.  *    see if the given buffer is what we want
  149.  *    if yes, we don't need to bother the buffer manager
  150.  * ---------------------------------------------------
  151.  */
  152. Buffer
  153. RelationGetBufferWithBuffer(relation, blockNumber, buffer)
  154. Relation relation;
  155. BlockNumber blockNumber;
  156. Buffer buffer;
  157. {
  158.     BufferDesc *bufHdr;
  159.     LRelId lrelId;
  160.  
  161.     if (BufferIsValid(buffer)) {
  162.         bufHdr = BufferGetBufferDescriptor(buffer);
  163.     lrelId = RelationGetLRelId(relation);
  164.     if (bufHdr->tag.blockNum == blockNumber &&
  165.         bufHdr->tag.relId.relId == lrelId.relId &&
  166.         bufHdr->tag.relId.dbId == lrelId.dbId)
  167.         return buffer;
  168.       }
  169.     return(ReadBuffer(relation,blockNumber));
  170. }
  171.  
  172. /*
  173.  * ReadBuffer -- returns a buffer containing the requested
  174.  *    block of the requested relation.  If the blknum
  175.  *    requested is NEW_BLOCK, extend the relation file and
  176.  *    allocate a new block.
  177.  *
  178.  * Returns: the buffer number for the buffer containing
  179.  *    the block read or NULL on an error.
  180.  *
  181.  * Assume when this function is called, that reln has been
  182.  *    opened already.
  183.  */
  184.  
  185. extern int ShowPinTrace;
  186. #undef ReadBuffer
  187.  
  188. Buffer
  189. ReadBuffer(reln, blockNum)
  190. Relation    reln;
  191. BlockNumber    blockNum;
  192. {
  193.     return ReadBufferWithBufferLock(reln, blockNum, false);
  194. }
  195.  
  196. bool
  197. is_userbuffer(buffer)
  198. Buffer buffer;
  199. {
  200.     BufferDesc *buf;
  201.     buf = BufferGetBufferDescriptor(buffer);
  202.     if (strncmp(&buf->sb_relname, "pg_", 3) == 0)
  203.     return false;
  204.     else
  205.     return true;
  206. }
  207.  
  208. Buffer
  209. ReadBuffer_Debug(file, line, reln, blockNum)
  210. String file;
  211. int line;
  212. Relation reln;
  213. BlockNumber blockNum;
  214. {
  215.     Buffer buffer;
  216.  
  217.     buffer = ReadBufferWithBufferLock(reln, blockNum, false);
  218.     if (ShowPinTrace && is_userbuffer(buffer)) {
  219.     BufferDesc *buf;
  220.     buf = BufferGetBufferDescriptor(buffer);
  221.     fprintf(stderr, "PIN(RD) %d relname = %s, blockNum = %d, refcount = %d, file: %s, line: %d\n", buffer, &(buf->sb_relname), buf->tag.blockNum, PrivateRefCount[buffer - 1], file, line);
  222.       }
  223.     return buffer;
  224. }
  225.  
  226. /*
  227.  * ReadBufferWithBufferLock -- does the work of 
  228.  *    ReadBuffer() but with the possibility that
  229.  *    the buffer lock has already been held. this
  230.  *    is yet another effort to reduce the number of
  231.  *    semops in the system.
  232.  *
  233.  *  This routine locks the buffer pool before calling BufferAlloc to
  234.  *  avoid two semops.
  235.  */
  236.  
  237. Buffer
  238. ReadBufferWithBufferLock(reln,blockNum, bufferLockHeld)
  239. Relation     reln;
  240. BlockNumber     blockNum;
  241. bool        bufferLockHeld;
  242. {
  243.   BufferDesc *    bufHdr;      
  244.   int        extend;   /* extending the file by one block */
  245.   int        status;
  246.   Boolean    found;
  247.  
  248.   ReadBufferCount++;
  249.   extend = (blockNum == NEW_BLOCK);
  250.   /* lookup the buffer.  IO_IN_PROGRESS is set if the requested
  251.    * block is not currently in memory.
  252.    */
  253.   bufHdr = BufferAlloc(reln, blockNum, &found, bufferLockHeld);
  254.   if (! bufHdr) {
  255.     return(InvalidBuffer);
  256.   }
  257.  
  258.   /* if its already in the buffer pool, we're done */
  259.   if (found) {
  260.     /*
  261.      * This happens when a bogus buffer was returned previously and is
  262.      * floating around in the buffer pool.  A routine calling this would
  263.      * want this extended.
  264.      */
  265.     if (extend) {
  266.       (void) smgrextend(bufHdr->bufsmgr, reln,
  267.             (char *) MAKE_PTR(bufHdr->data));
  268.     }
  269.     BufferHitCount++;
  270.     return(BufferDescriptorGetBuffer(bufHdr));
  271.   }
  272.  
  273.   /* 
  274.    * if we have gotten to this point, the reln pointer must be ok
  275.    * and the relation file must be open.
  276.    */
  277.  
  278.   if (extend) {
  279.     status = smgrextend(bufHdr->bufsmgr, reln,
  280.             (char *) MAKE_PTR(bufHdr->data));
  281.   } else {
  282.     status = smgrread(bufHdr->bufsmgr, reln, blockNum,
  283.               (char *) MAKE_PTR(bufHdr->data));
  284.   }
  285.  
  286.   /* lock buffer manager again to update IO IN PROGRESS */
  287.   SpinAcquire(BufMgrLock);
  288.  
  289.   if (status == SM_FAIL) {
  290.     /* IO Failed.  cleanup the data structures and go home */
  291.  
  292.     if (! BufTableDelete(bufHdr)) {
  293.       SpinRelease(BufMgrLock);
  294.       elog(FATAL,"BufRead: buffer table broken after IO error\n");
  295.     }
  296.     /* remember that BufferAlloc() pinned the buffer */
  297.     UnpinBuffer(bufHdr);
  298.  
  299.     /* 
  300.      * Have to reset the flag so that anyone waiting for
  301.      * the buffer can tell that the contents are invalid.
  302.      */
  303.     bufHdr->flags |= BM_IO_ERROR;
  304.  
  305.   } else {
  306.     /* IO Succeeded.  clear the flags, finish buffer update */
  307.  
  308.     bufHdr->flags &= ~(BM_IO_ERROR | BM_IO_IN_PROGRESS);
  309.   }
  310.  
  311.   /* If anyone was waiting for IO to complete, wake them up now */
  312. #ifdef HAS_TEST_AND_SET
  313.   S_UNLOCK(&(bufHdr->io_in_progress_lock));
  314. #else
  315.   if (bufHdr->refcount > 1)
  316.     SignalIO(bufHdr);
  317. #endif
  318.  
  319.   SpinRelease(BufMgrLock);
  320.     
  321.   return(BufferDescriptorGetBuffer(bufHdr));
  322. }
  323.  
  324. /*
  325.  * BufferAlloc -- Get a buffer from the buffer pool but dont
  326.  *    read it.
  327.  *
  328.  * Returns: descriptor for buffer
  329.  */
  330. BufferDesc *
  331. BufferAlloc(reln, blockNum, foundPtr, bufferLockHeld)
  332. Relation    reln;
  333. BlockNumber    blockNum;
  334. Boolean        *foundPtr;
  335. bool        bufferLockHeld;
  336. {
  337.   BufferDesc         *buf;      
  338.   BufferTag         newTag;     /* identity of requested block */
  339.   Boolean        inProgress; /* buffer undergoing IO */
  340.   int            status;
  341.   Boolean        newblock = FALSE;
  342.   BufferDesc        oldbufdesc;
  343.  
  344.  
  345.     /* create a new tag so we can lookup the buffer */
  346.     /* assume that the relation is already open */
  347.   if (blockNum == NEW_BLOCK) {
  348.       newblock = TRUE;
  349.       blockNum = smgrnblocks(reln->rd_rel->relsmgr, reln);
  350.   }
  351.  
  352.   INIT_BUFFERTAG(&newTag,reln,blockNum);
  353.  
  354.   if (!bufferLockHeld)
  355.       SpinAcquire(BufMgrLock);
  356.  
  357.   /* see if the block is in the buffer pool already */
  358.   buf = BufTableLookup(&newTag);
  359.   if (buf != NULL) {
  360.     /* Found it.  Now, (a) pin the buffer so no
  361.      * one steals it from the buffer pool, 
  362.      * (b) check IO_IN_PROGRESS, someone may be
  363.      * faulting the buffer into the buffer pool.
  364.      */
  365.  
  366.     PinBuffer(buf);
  367.     inProgress = (buf->flags & BM_IO_IN_PROGRESS);
  368.     
  369.     *foundPtr = TRUE;
  370.     if (inProgress) {
  371.       WaitIO(buf, BufMgrLock);
  372.       if (buf->flags & BM_IO_ERROR) {
  373.     /* wierd race condition: 
  374.      *
  375.      * We were waiting for someone else to read the buffer.  
  376.      * While we were waiting, the reader boof'd in some
  377.      *  way, so the contents of the buffer are still
  378.      * invalid.  By saying that we didn't find it, we can
  379.      * make the caller reinitialize the buffer.  If two
  380.      * processes are waiting for this block, both will
  381.      * read the block.  The second one to finish may overwrite 
  382.      * any updates made by the first.  (Assume higher level
  383.      * synchronization prevents this from happening).
  384.      *
  385.      * This is never going to happen, don't worry about it.
  386.      */
  387.     *foundPtr = FALSE;
  388.       }
  389.     }
  390. #ifdef BMTRACE
  391.     _bm_trace((reln->rd_rel->relisshared ? 0 : MyDatabaseId), reln->rd_id, blockNum, BufferDescriptorGetBuffer(buf), BMT_ALLOCFND);
  392. #endif BMTRACE
  393.  
  394.     SpinRelease(BufMgrLock);
  395.   
  396.     return(buf);
  397.   }
  398.  
  399.   *foundPtr = FALSE;
  400.  
  401.   /* Didn't find it in the buffer pool.  We'll have
  402.    * to initialize a new buffer.  First, grab one from
  403.    * the free list.  If it's dirty, flush it to disk.
  404.    * Remember to unlock BufMgr spinloc while doing the IOs.
  405.    */
  406.   buf = GetFreeBuffer();
  407.   if (! buf) {
  408.     /* out of free buffers.  In trouble now. */
  409.      SpinRelease(BufMgrLock);
  410.      return(NULL);
  411.    }
  412.  
  413.    /* There should be exactly one pin on the buffer
  414.     * after it is allocated.  It isnt in the buffer
  415.     * table yet so no one but us should have a pin.
  416.     */
  417.  
  418.    Assert(buf->refcount == 0);
  419.    buf->refcount = 1;           
  420.    PrivateRefCount[BufferDescriptorGetBuffer(buf) - 1] = 1;
  421.  
  422.   /* 
  423.    * Change the name of the buffer in the lookup table:
  424.    *  
  425.    * Need to update the lookup table before the read starts.
  426.    * If someone comes along looking for the buffer while
  427.    * we are reading it in, we don't want them to allocate
  428.    * a new buffer.  For the same reason, we didn't want
  429.    * to erase the buf table entry for the buffer we were
  430.    * writing back until now, either.
  431.    */
  432.  
  433.   if (! BufTableDelete(buf)) {
  434.     SpinRelease(BufMgrLock);
  435.     elog(FATAL,"buffer wasn't in the buffer table\n");
  436.   }
  437.  
  438.   /* save the old buffer descriptor */
  439.   oldbufdesc = *buf;
  440.   if (buf->flags & BM_DIRTY) {
  441.       /* must clear flag first because of wierd race 
  442.        * condition described below.  
  443.        */
  444.       buf->flags &= ~BM_DIRTY;
  445.     }
  446.  
  447.   /* record the database name and relation name for this buffer */
  448.   strncpy((char *)&(buf->sb_relname),
  449.           (char *)&(reln->rd_rel->relname),
  450.       sizeof (NameData));
  451.   strncpy((char *)&(buf->sb_dbname), MyDatabaseName, sizeof (NameData));
  452.  
  453.   /* remember which storage manager is responsible for it */
  454.   buf->bufsmgr = reln->rd_rel->relsmgr;
  455.  
  456.   INIT_BUFFERTAG(&(buf->tag),reln,blockNum);
  457.   if (! BufTableInsert(buf)) {
  458.     SpinRelease(BufMgrLock);
  459.     elog(FATAL,"Buffer in lookup table twice \n");
  460.   } 
  461.  
  462.   /* Buffer contents are currently invalid.  Have
  463.    * to mark IO IN PROGRESS so no one fiddles with
  464.    * them until the read completes.  If this routine
  465.    * has been called simply to allocate a buffer, no
  466.    * io will be attempted, so the flag isnt set.
  467.    */
  468.   buf->flags |= BM_IO_IN_PROGRESS; 
  469. #ifdef HAS_TEST_AND_SET
  470.   /* lock the io_in_progress_lock before the read so that
  471.    * other process will wait on it
  472.    */
  473.   Assert(!buf->io_in_progress_lock);
  474.   S_LOCK(&(buf->io_in_progress_lock));
  475. #endif
  476.  
  477. #ifdef BMTRACE
  478.   _bm_trace((reln->rd_rel->relisshared ? 0 : MyDatabaseId), reln->rd_id, blockNum, BufferDescriptorGetBuffer(buf), BMT_ALLOCNOTFND);
  479. #endif BMTRACE
  480.  
  481.   SpinRelease(BufMgrLock);
  482.  
  483.   /* XXX mao what is this? XXX */
  484.   if (oldbufdesc.flags & BM_DIRTY) {
  485.      (void) BufferReplace(&oldbufdesc);
  486.      BufferFlushCount++;
  487.   }
  488.   return (buf);
  489. }
  490.  
  491. /*
  492.  * WriteBuffer--
  493.  *
  494.  *    Pushes buffer contents to disk if LateWrite is
  495.  * not set.  Otherwise, marks contents as dirty.  
  496.  *
  497.  * Assume that buffer is pinned.  Assume that reln is
  498.  *    valid.
  499.  *
  500.  * Side Effects:
  501.  *        Pin count is decremented.
  502.  */
  503.  
  504. #undef WriteBuffer
  505.  
  506. WriteBuffer(buffer)
  507. Buffer    buffer;
  508. {
  509.   BufferDesc    *bufHdr;
  510.   
  511.   if (! LateWrite) {
  512.     return(FlushBuffer(buffer));
  513.   } else {
  514.  
  515.     if (BAD_BUFFER_ID(buffer)) {
  516.       return(FALSE);
  517.     }
  518.     bufHdr = BufferGetBufferDescriptor(buffer);
  519.  
  520.     Assert(bufHdr->refcount > 0);
  521.     SpinAcquire(BufMgrLock);
  522.     bufHdr->flags |= BM_DIRTY; 
  523.     UnpinBuffer(bufHdr);
  524.     SpinRelease(BufMgrLock);
  525.   }
  526.   return(TRUE);
  527.  
  528. WriteBuffer_Debug(file, line, buffer)
  529. String file;
  530. int line;
  531. Buffer buffer;
  532. {
  533.     WriteBuffer(buffer);
  534.     if (ShowPinTrace && is_userbuffer(buffer)) {
  535.     BufferDesc *buf;
  536.     buf = BufferGetBufferDescriptor(buffer);
  537.     fprintf(stderr, "UNPIN(WR) %d relname = %s, blockNum = %d, refcount = %d, file: %s, line: %d\n", buffer, &(buf->sb_relname), buf->tag.blockNum, PrivateRefCount[buffer - 1], file, line);
  538.       }
  539. }
  540.  
  541. /*
  542.  *  DirtyBufferCopy() -- Copy a given dirty buffer to the requested
  543.  *             destination.
  544.  *
  545.  *    We treat this as a write.  If the requested buffer is in the pool
  546.  *    and is dirty, we copy it to the location requested and mark it
  547.  *    clean.  This routine supports the Sony jukebox storage manager,
  548.  *    which agrees to take responsibility for the data once we mark
  549.  *    it clean.
  550.  */
  551.  
  552. DirtyBufferCopy(dbid, relid, blkno, dest)
  553.   ObjectId dbid;
  554.   ObjectId relid;
  555.   BlockNumber blkno;
  556.   char *dest;
  557. {
  558.   BufferDesc *buf;
  559.   BufferTag btag;
  560.  
  561.   btag.relId.relId = relid;
  562.   btag.relId.dbId = dbid;
  563.   btag.blockNum = blkno;
  564.  
  565.   SpinAcquire(BufMgrLock);
  566.   buf = BufTableLookup(&btag);
  567.  
  568.   if (buf == (BufferDesc *) NULL
  569.       || !(buf->flags & BM_DIRTY)
  570.       || !(buf->flags & BM_VALID)) {
  571.     SpinRelease(BufMgrLock);
  572.     return;
  573.   }
  574.  
  575.   /* hate to do this holding the lock, but release and reacquire is slower */
  576.   (void) bcopy((char *) MAKE_PTR(buf->data), dest, BLCKSZ);
  577.  
  578.   buf->flags &= ~BM_DIRTY;
  579.  
  580.   SpinRelease(BufMgrLock);
  581. }
  582.  
  583. /*
  584.  * BufferRewrite -- special version of WriteBuffer for
  585.  *    BufCopyCommit().  We want to write without
  586.  *    looking up the relation if possible.
  587.  */
  588. Boolean
  589. BufferRewrite(buffer)
  590. Buffer    buffer;
  591. {
  592.   BufferDesc    *bufHdr;
  593.   
  594.   if (BAD_BUFFER_ID(buffer)) {
  595.     return(STATUS_ERROR);
  596.   }
  597.   bufHdr = BufferGetBufferDescriptor(buffer);
  598.   Assert(bufHdr->refcount > 0);
  599.  
  600.   if (LateWrite) {
  601.     SpinAcquire(BufMgrLock); 
  602.     bufHdr->flags |= BM_DIRTY; 
  603.     UnpinBuffer(bufHdr);
  604.     SpinRelease(BufMgrLock); 
  605.   } else {
  606.     BufferReplace(bufHdr);
  607.   }
  608.  
  609.  
  610.   return(STATUS_OK);
  611.  
  612.  
  613. /*
  614.  * FlushBuffer -- like WriteBuffer, but force the page to disk.
  615.  */
  616. FlushBuffer(buffer)
  617. Buffer    buffer;
  618. {
  619.   BufferDesc    *bufHdr;
  620.   OID        bufdb;
  621.   OID        bufrel;
  622.   Relation    reln;
  623.   int        status;
  624.  
  625.  
  626.   if (BAD_BUFFER_ID(buffer)) {
  627.     return(STATUS_ERROR);
  628.   }
  629.  
  630.   bufHdr = BufferGetBufferDescriptor(buffer);
  631.  
  632.   /*
  633.    *  If the relation is not in our private cache, we don't bother trying
  634.    *  to instantiate it.  Instead, we call the storage manager routine that
  635.    *  does a blind write.  If we can get the reldesc, then we use the standard
  636.    *  write routine interface.
  637.    */
  638.  
  639.   bufdb = bufHdr->tag.relId.dbId;
  640.   bufrel = bufHdr->tag.relId.relId;
  641.  
  642.   if (bufdb == MyDatabaseId || bufdb == (OID) NULL)
  643.       reln = RelationIdCacheGetRelation(bufrel);
  644.   else
  645.       reln = (Relation) NULL;
  646.  
  647.   if (reln != (Relation) NULL) {
  648.       status = smgrflush(bufHdr->bufsmgr, reln, bufHdr->tag.blockNum,
  649.              (char *) MAKE_PTR(bufHdr->data));
  650.   } else {
  651.  
  652.       /* blind write always flushes */
  653.       status = smgrblindwrt(bufHdr->bufsmgr, &bufHdr->sb_dbname,
  654.                 &bufHdr->sb_relname, bufdb, bufrel,
  655.                 bufHdr->tag.blockNum,
  656.                 (char *) MAKE_PTR(bufHdr->data));
  657.   }
  658.  
  659.   if (status == SM_FAIL) {
  660.       elog(WARN, "FlushBuffer: cannot flush %d for %16s", bufHdr->tag.blockNum,
  661.          reln->rd_rel->relname);
  662.       /* NOTREACHED */
  663.       return (STATUS_ERROR);
  664.   }
  665.  
  666.   SpinAcquire(BufMgrLock);
  667.   bufHdr->flags &= ~BM_DIRTY; 
  668.   UnpinBuffer(bufHdr);
  669.   SpinRelease(BufMgrLock);
  670.  
  671.   return(STATUS_OK);
  672. }
  673.  
  674. /*
  675.  * WriteNoReleaseBuffer -- like WriteBuffer, but do not unpin the buffer
  676.  *                when the operation is complete.
  677.  *
  678.  *    We know that the buffer is for a relation in our private cache,
  679.  *    because this routine is called only to write out buffers that
  680.  *    were changed by the executing backend.
  681.  */
  682.  
  683. WriteNoReleaseBuffer(buffer)
  684. Buffer    buffer;
  685. {
  686.   BufferDesc    *bufHdr;
  687.   Relation    reln;
  688.  
  689.   if (! LateWrite) {
  690.     return(FlushBuffer(buffer));
  691.   } else {
  692.  
  693.     if (BAD_BUFFER_ID(buffer)){
  694.       return(STATUS_ERROR);
  695.     }
  696.     bufHdr = BufferGetBufferDescriptor(buffer);
  697.  
  698.     SpinAcquire(BufMgrLock);
  699.     bufHdr->flags |= BM_DIRTY; 
  700.     SpinRelease(BufMgrLock);
  701.   }
  702.   return(STATUS_OK);
  703. }
  704.  
  705.  
  706. #undef ReleaseAndReadBuffer
  707. /*
  708.  * ReleaseAndReadBuffer -- combine ReleaseBuffer() and ReadBuffer()
  709.  *     so that only one semop needs to be called.
  710.  *
  711.  */
  712. Buffer
  713. ReleaseAndReadBuffer(buffer, relation, blockNum)
  714. Buffer buffer;
  715. Relation relation;
  716. BlockNumber blockNum;
  717. {
  718.     BufferDesc    *bufHdr;
  719.     Buffer retbuf;
  720.     if (BufferIsValid(buffer)) {
  721.     bufHdr = BufferGetBufferDescriptor(buffer);
  722.     PrivateRefCount[buffer - 1]--;
  723.     if (PrivateRefCount[buffer - 1] == 0 && LastRefCount[buffer - 1] == 0) {
  724.     /* only release buffer if it is not pinned in previous ExecMain level */
  725.         SpinAcquire(BufMgrLock);
  726.         bufHdr->refcount--;
  727.         if (bufHdr->refcount == 0) {
  728.         AddBufferToFreelist(bufHdr);
  729.         bufHdr->flags |= BM_FREE;
  730.           }
  731.         retbuf = ReadBufferWithBufferLock(relation, blockNum, true);
  732.         return retbuf;
  733.      }
  734.       }
  735.     return(ReadBuffer(relation, blockNum));
  736. }
  737.  
  738. /*
  739.  * AcquireBuffer -- Pin a buffer that we know is valid.
  740.  *
  741.  * ---There is a race condition.  This routine doesnt make
  742.  * any sense.  We never really know the buffer is valid.
  743.  */
  744. BufferAcquire(bufHdr)
  745. BufferDesc    *bufHdr;
  746. {
  747.  
  748.   SpinAcquire(BufMgrLock);
  749.   PinBuffer(bufHdr);
  750.   SpinRelease(BufMgrLock);
  751.   return (TRUE);
  752. }
  753.  
  754. /*
  755.  * BufferRepin -- get a second pin on an already pinned buffer
  756.  */
  757. BufferRepin(buffer)
  758. Buffer    buffer;
  759. {
  760.   BufferDesc    *bufHdr;
  761.  
  762.   if (BAD_BUFFER_ID(buffer)) {
  763.     return(FALSE);
  764.   }
  765.   bufHdr = BufferGetBufferDescriptor(buffer);
  766.  
  767.   /* like we said -- already pinned */
  768.   Assert(bufHdr->refcount);
  769.  
  770.   SpinAcquire(BufMgrLock);
  771.   PinBuffer(bufHdr);
  772.   SpinRelease(BufMgrLock);
  773.   return (TRUE);
  774. }
  775.  
  776. /*
  777.  * BufferSync -- Flush all dirty buffers in the pool.
  778.  *
  779.  *    This is called at transaction commit time.  It does the wrong thing,
  780.  *    right now.  We should flush only our own changes to stable storage,
  781.  *    and we should obey the lock protocol on the buffer manager metadata
  782.  *    as we do it.  Also, we need to be sure that no other transaction is
  783.  *    modifying the page as we flush it.  This is only a problem for objects
  784.  *    that use a non-two-phase locking protocol, like btree indices.  For
  785.  *    those objects, we would like to set a write lock for the duration of
  786.  *    our IO.  Another possibility is to code updates to btree pages
  787.  *    carefully, so that writing them out out of order cannot cause
  788.  *    any unrecoverable errors.
  789.  *
  790.  *    I don't want to think hard about this right now, so I will try
  791.  *    to come back to it later.
  792.  */
  793. void
  794. BufferSync()
  795.   int i;
  796.   OID bufdb;
  797.   OID bufrel;
  798.   Relation reln;
  799.   BufferDesc *bufHdr;
  800.   int status;
  801.  
  802.   for (i=0, bufHdr = BufferDescriptors; i < NBuffers; i++, bufHdr++) {
  803.       if ((bufHdr->flags & BM_VALID) && (bufHdr->flags & BM_DIRTY)) {
  804.       bufdb = bufHdr->tag.relId.dbId;
  805.       bufrel = bufHdr->tag.relId.relId;
  806.       if (bufdb == MyDatabaseId || bufdb == (OID) 0) {
  807.           reln = RelationIdCacheGetRelation(bufrel);
  808.  
  809.           /*
  810.            *  If we didn't have the reldesc in our local cache, flush this
  811.            *  page out using the 'blind write' storage manager routine.  If
  812.            *  we did find it, use the standard interface.
  813.            */
  814.  
  815.           if (reln == (Relation) NULL) {
  816.           status = smgrblindwrt(bufHdr->bufsmgr, &bufHdr->sb_dbname,
  817.                     &bufHdr->sb_relname, bufdb, bufrel,
  818.                     bufHdr->tag.blockNum,
  819.                     (char *) MAKE_PTR(bufHdr->data));
  820.           } else {
  821.           status = smgrwrite(bufHdr->bufsmgr, reln,
  822.                      bufHdr->tag.blockNum,
  823.                      (char *) MAKE_PTR(bufHdr->data));
  824.           }
  825.  
  826.           if (status == SM_FAIL) {
  827.           elog(WARN, "cannot write %d for %16s",
  828.                bufHdr->tag.blockNum, bufHdr->sb_relname);
  829.           }
  830.  
  831.           bufHdr->flags &= ~BM_DIRTY;
  832.           if (reln != (Relation)NULL)
  833.           RelationDecrementReferenceCount(reln);
  834.       }
  835.       }
  836.   }
  837. }
  838.  
  839.  
  840. /*
  841.  * WaitIO -- Block until the IO_IN_PROGRESS flag on 'buf'
  842.  *     is cleared.  Because IO_IN_PROGRESS conflicts are
  843.  *    expected to be rare, there is only one BufferIO
  844.  *    lock in the entire system.  All processes block
  845.  *    on this semaphore when they try to use a buffer
  846.  *    that someone else is faulting in.  Whenever a
  847.  *    process finishes an IO and someone is waiting for
  848.  *    the buffer, BufferIO is signaled (SignalIO).  All
  849.  *    waiting processes then wake up and check to see
  850.  *    if their buffer is now ready.  This implementation
  851.  *    is simple, but efficient enough if WaitIO is
  852.  *    rarely called by multiple processes simultaneously.
  853.  *
  854.  *  ProcSleep atomically releases the spinlock and goes to
  855.  *    sleep.
  856.  *
  857.  *  Note: there is an easy fix if the queue becomes long.
  858.  *    save the id of the buffer we are waiting for in
  859.  *    the queue structure.  That way signal can figure
  860.  *    out which proc to wake up.
  861.  */
  862. #ifdef HAS_TEST_AND_SET
  863. WaitIO(buf, spinlock)
  864. BufferDesc *buf;
  865. SPINLOCK spinlock;
  866. {
  867.     SpinRelease(spinlock);
  868.     S_LOCK(&(buf->io_in_progress_lock));
  869.     S_UNLOCK(&(buf->io_in_progress_lock));
  870.     SpinAcquire(spinlock);
  871. }
  872.  
  873. #else /* HAS_TEST_AND_SET */
  874. static IpcSemaphoreId    WaitIOSemId;
  875.  
  876. WaitIO(buf,spinlock)
  877. BufferDesc *buf;
  878. SPINLOCK spinlock;
  879. {
  880.   Boolean     inProgress;
  881.  
  882.   for (;;) {
  883.  
  884.     /* wait until someone releases IO lock */
  885.     (*NWaitIOBackendP)++;
  886.     SpinRelease(spinlock);
  887.     IpcSemaphoreLock(WaitIOSemId, 0, 1);
  888.     SpinAcquire(spinlock);
  889.     inProgress = (buf->flags & BM_IO_IN_PROGRESS);
  890.     if (!inProgress) break;
  891.   }
  892. }
  893.  
  894. /*
  895.  * SignalIO --
  896.  */
  897. SignalIO(buf)
  898. BufferDesc *buf;
  899. {
  900.   /* somebody better be waiting. */
  901.   Assert( buf->refcount > 1);
  902.   IpcSemaphoreUnlock(WaitIOSemId, 0, *NWaitIOBackendP);
  903.   *NWaitIOBackendP = 0;
  904. }
  905. #endif /* HAS_TEST_AND_SET */
  906.  
  907. /*
  908.  * Initialize module:
  909.  *
  910.  * should calculate size of pool dynamically based on the
  911.  * amount of available memory.
  912.  */
  913. InitBufferPool(key)
  914. IPCKey key;
  915. {
  916.   Boolean foundBufs,foundDescs,foundNWaitIO;
  917.   int i;
  918.   int status;
  919.  
  920.  
  921.   Data_Descriptors = NBuffers;
  922.   Free_List_Descriptor = Data_Descriptors;
  923.   Lookup_List_Descriptor = Data_Descriptors + 1;
  924.   Num_Descriptors = Data_Descriptors + 1;
  925.  
  926.   SpinAcquire(BufMgrLock);
  927.  
  928. #ifdef BMTRACE
  929.   CurTraceBuf = (int *) ShmemInitStruct("Buffer trace",
  930.                 (BMT_LIMIT * sizeof(bmtrace)) + sizeof(int),
  931.                 &foundDescs);
  932.   if (!foundDescs)
  933.       bzero(CurTraceBuf, (BMT_LIMIT * sizeof(bmtrace)) + sizeof(int));
  934.  
  935.   TraceBuf = (bmtrace *) &(CurTraceBuf[1]);
  936. #endif
  937.  
  938.   BufferDescriptors = (BufferDesc *)
  939.     ShmemInitStruct("Buffer Descriptors",
  940.             Num_Descriptors*sizeof(BufferDesc),&foundDescs);
  941.  
  942.   BufferBlocks = (BufferBlock)
  943.     ShmemInitStruct("Buffer Blocks",
  944.             NBuffers*BLOCK_SIZE,&foundBufs);
  945.  
  946. #ifndef HAS_TEST_AND_SET
  947.   NWaitIOBackendP = (int*)ShmemInitStruct("#Backends Waiting IO",
  948.                       sizeof(int),
  949.                       &foundNWaitIO);
  950.   if (!foundNWaitIO)
  951.       *NWaitIOBackendP = 0;
  952. #endif
  953.  
  954.   if (foundDescs || foundBufs) {
  955.  
  956.     /* both should be present or neither */
  957.     Assert(foundDescs && foundBufs);
  958.  
  959.   } else {
  960.     BufferDesc *buf;
  961.     unsigned int block;
  962.  
  963.     buf = BufferDescriptors;
  964.     block = (unsigned int) BufferBlocks;
  965.  
  966.     /*
  967.      * link the buffers into a circular, doubly-linked list to
  968.      * initialize free list.  Still don't know anything about
  969.      * replacement strategy in this file.
  970.      */
  971.     for (i = 0; i < Data_Descriptors; block+=BLOCK_SIZE,buf++,i++) {
  972.       Assert(ShmemIsValid((unsigned int)block));
  973.  
  974.       buf->freeNext = i+1;
  975.       buf->freePrev = i-1;
  976.  
  977.       CLEAR_BUFFERTAG(&(buf->tag));
  978.       buf->data = MAKE_OFFSET(block);
  979.       buf->flags = (BM_DELETED | BM_FREE | BM_VALID);
  980.       buf->refcount = 0;
  981.       buf->id = i;
  982. #ifdef HAS_TEST_AND_SET
  983.       S_INIT_LOCK(&(buf->io_in_progress_lock));
  984. #endif
  985.     }
  986.  
  987.     /* close the circular queue */
  988.     BufferDescriptors[0].freePrev = Data_Descriptors-1;
  989.     BufferDescriptors[Data_Descriptors-1].freeNext = 0;
  990.   }
  991.  
  992.   /* Init the rest of the module */
  993.   InitBufTable();
  994.   InitFreeList(!foundDescs);
  995.  
  996.   SpinRelease(BufMgrLock);
  997.  
  998. #ifndef HAS_TEST_AND_SET
  999.   WaitIOSemId = IpcSemaphoreCreate(IPCKeyGetWaitIOSemaphoreKey(key),
  1000.                    1, IPCProtection, 0, &status);
  1001. #endif
  1002.   PrivateRefCount = (int*)malloc(NBuffers * sizeof(int));
  1003.   LastRefCount = (int*)malloc(NBuffers * sizeof(int));
  1004.   for (i = 0; i < NBuffers; i++) {
  1005.       PrivateRefCount[i] = 0;
  1006.       LastRefCount[i] = 0;
  1007.     }
  1008. }
  1009.  
  1010. int NDirectFileRead;    /* some I/O's are direct file access.  bypass bufmgr */
  1011. int NDirectFileWrite;   /* e.g., I/O in psort and hashjoin.             */
  1012.  
  1013. void
  1014. PrintBufferUsage(statfp)
  1015. FILE *statfp;
  1016. {
  1017.     float hitrate;
  1018.  
  1019.     if (ReadBufferCount==0)
  1020.         hitrate = 0.0;
  1021.     else
  1022.         hitrate = (float)BufferHitCount * 100.0/ReadBufferCount;
  1023.  
  1024.     fprintf(statfp, "!\t%d blocks read, %d blocks written, buffer hit rate = %.2f%%\n", 
  1025.         ReadBufferCount - BufferHitCount + NDirectFileRead,
  1026.         BufferFlushCount + NDirectFileWrite,
  1027.         hitrate);
  1028. }
  1029.  
  1030. void
  1031. ResetBufferUsage()
  1032. {
  1033.     BufferHitCount = 0;
  1034.     ReadBufferCount = 0;
  1035.     BufferFlushCount = 0;
  1036.     NDirectFileRead = 0;
  1037.     NDirectFileWrite = 0;
  1038. }
  1039.  
  1040. /* ----------------------------------------------
  1041.  *    ResetBufferPool
  1042.  *
  1043.  *    this routine is supposed to be called when a transaction aborts.
  1044.  *    it will release all the buffer pins held by the transaciton.
  1045.  *
  1046.  * ----------------------------------------------
  1047.  */
  1048. void
  1049. ResetBufferPool()
  1050. {
  1051.     register int i;
  1052.     for (i=1; i<=NBuffers; i++) {
  1053.     if (BufferIsValid(i)) {
  1054.         while(PrivateRefCount[i - 1] > 0) {
  1055.         ReleaseBuffer(i);
  1056.           }
  1057.       }
  1058.     LastRefCount[i - 1] = 0;
  1059.       }
  1060. }
  1061.  
  1062. /* -----------------------------------------------
  1063.  *    BufferPoolCheckLeak
  1064.  *
  1065.  *    check if there is buffer leak
  1066.  *
  1067.  * -----------------------------------------------
  1068.  */
  1069. int
  1070. BufferPoolCheckLeak()
  1071. {
  1072.     register int i;
  1073.     for (i=1; i<=NBuffers; i++) {
  1074.     if (BufferIsValid(i)) {
  1075.         elog(DEBUG, "BUFFER LEAK!!! send mail to wei.");
  1076.         return(1);
  1077.       }
  1078.       }
  1079.     return(0);
  1080. }
  1081.  
  1082. /* ------------------------------------------------
  1083.  *    FlushBufferPool
  1084.  *
  1085.  *    flush all dirty blocks in buffer pool to disk
  1086.  *
  1087.  * ------------------------------------------------
  1088.  */
  1089. void
  1090. FlushBufferPool(StableMainMemoryFlag)
  1091. int StableMainMemoryFlag;
  1092. {
  1093.     if (!StableMainMemoryFlag) {
  1094.         BufferSync();
  1095.     smgrcommit();
  1096.     }
  1097. }
  1098.  
  1099. /**************************************************
  1100.   BufferDescriptorIsValid
  1101.  
  1102.  **************************************************/
  1103.  
  1104. bool
  1105. BufferDescriptorIsValid(bufdesc)
  1106.      BufferDesc *bufdesc;
  1107. {
  1108.     int temp;
  1109.     
  1110.     Assert(PointerIsValid(bufdesc));
  1111.     
  1112.     temp = (bufdesc-BufferDescriptors)/sizeof(BufferDesc);
  1113.     if (temp >= 0 && temp<NBuffers)
  1114.         return(true);
  1115.     else
  1116.         return(false);
  1117.     
  1118. } /*BufferDescriptorIsValid*/
  1119.  
  1120. /**************************************************
  1121.   BufferIsValid
  1122.   returns true iff the refcnt of the local
  1123.   buffer is > 0
  1124.  **************************************************/
  1125. bool
  1126. BufferIsValid(bufnum)
  1127.     Buffer bufnum;
  1128. {
  1129.     if (BAD_BUFFER_ID(bufnum)) {
  1130.         return(false);
  1131.     }
  1132.     return((bool)(PrivateRefCount[bufnum - 1] > 0));
  1133. } /* BufferIsValid */
  1134.  
  1135. BlockSize
  1136. BufferGetBlockSize(buffer)
  1137.     Buffer      buffer;
  1138. {
  1139.     Assert(BufferIsValid(buffer));
  1140.   /* Apparently, POSTGRES was supposed to have variable
  1141.    * sized buffer blocks.  Current buffer manager will need
  1142.    * extensive redesign if that is ever to come to pass, so
  1143.    * for now hardwire it to BLCKSZ
  1144.    */
  1145.     return (BLCKSZ);
  1146. }
  1147.  
  1148. BlockNumber
  1149. BufferGetBlockNumber(buffer)
  1150.     Buffer      buffer;
  1151. {
  1152.     Assert(BufferIsValid(buffer));
  1153.     return (BufferGetBufferDescriptor(buffer)->tag.blockNum);
  1154. }
  1155.  
  1156. Relation
  1157. BufferGetRelation(buffer)
  1158.     Buffer      buffer;
  1159. {
  1160.     Relation    relation;
  1161.  
  1162.     Assert(BufferIsValid(buffer));
  1163.  
  1164.     relation = RelationIdGetRelation(LRelIdGetRelationId
  1165.                 (BufferGetBufferDescriptor(buffer)->tag.relId));
  1166.  
  1167.     RelationDecrementReferenceCount(relation);
  1168.  
  1169.     if (RelationHasReferenceCountZero(relation)) {
  1170.        /*
  1171.         elog(NOTICE, "BufferGetRelation: 0->1");
  1172.     */
  1173.  
  1174.         RelationIncrementReferenceCount(relation);
  1175.     }
  1176.  
  1177.     return (relation);
  1178. }
  1179.  
  1180. /**************************************************
  1181.   BufferDescriptorGetBuffer
  1182.  
  1183.  **************************************************/
  1184.  
  1185.  
  1186. Buffer
  1187. BufferDescriptorGetBuffer(descriptor)
  1188.     BufferDesc *descriptor;
  1189. {
  1190.     Assert(BufferDescriptorIsValid(descriptor));
  1191.  
  1192.     return(1+descriptor - BufferDescriptors);
  1193. }
  1194.  
  1195. BufferReplace(bufHdr)
  1196.     BufferDesc     *bufHdr;
  1197. {
  1198.     int        blockSize;
  1199.     int        blockNum;
  1200.     LRelId    *relIdPtr;
  1201.     Relation     reln;
  1202.     ObjectId    bufdb, bufrel;
  1203.     int        status;
  1204.  
  1205.     blockSize = BLOCKSZ(bufHdr);
  1206.     blockNum = bufHdr->tag.blockNum;
  1207.  
  1208.     /*
  1209.      * first try to find the reldesc in the cache, if no luck,
  1210.      * don't bother to build the reldesc from scratch, just do
  1211.      * a blind write.
  1212.      */
  1213.  
  1214.     bufdb = bufHdr->tag.relId.dbId;
  1215.     bufrel = bufHdr->tag.relId.relId;
  1216.  
  1217.     if (bufdb == MyDatabaseId || bufdb == (OID) NULL)
  1218.     reln = RelationIdCacheGetRelation(bufrel);
  1219.     else
  1220.     reln = (Relation) NULL;
  1221.  
  1222.     if (reln != (Relation) NULL) {
  1223.     status = smgrflush(bufHdr->bufsmgr, reln, bufHdr->tag.blockNum,
  1224.                (char *) MAKE_PTR(bufHdr->data));
  1225.     } else {
  1226.  
  1227.     /* blind write always flushes */
  1228.     status = smgrblindwrt(bufHdr->bufsmgr, &bufHdr->sb_dbname,
  1229.                   &bufHdr->sb_relname, bufdb, bufrel,
  1230.                   bufHdr->tag.blockNum,
  1231.                   (char *) MAKE_PTR(bufHdr->data));
  1232.     }
  1233.  
  1234.     if (status == SM_FAIL)
  1235.     return (FALSE);
  1236.  
  1237.     return (TRUE);
  1238. }
  1239.  
  1240. /**************************************************
  1241.   BufferIsDirty
  1242.  
  1243.  **************************************************/
  1244.  
  1245. bool
  1246. BufferIsDirty(buffer)
  1247.     Buffer buffer;
  1248. {
  1249.     return (bool)
  1250.         (BufferGetBufferDescriptor(buffer)->flags & BM_DIRTY);
  1251. }
  1252.  
  1253.  
  1254. /**************************************************
  1255.   BufferIsInvalid
  1256.  
  1257.  **************************************************/
  1258. bool
  1259. BufferIsInvalid(buffer)
  1260.         Buffer  buffer;
  1261. {
  1262.     return (bool)
  1263.         (buffer == InvalidBuffer);
  1264. }
  1265.  
  1266.  
  1267. /**************************************************
  1268.   BufferIsUnknown
  1269.  
  1270.  **************************************************/
  1271. bool
  1272. BufferIsUnknown(buffer)
  1273.     Buffer      buffer;
  1274. {
  1275.     return (bool)
  1276.         (buffer == UnknownBuffer);
  1277. }
  1278.  
  1279. /***************************************************
  1280.  * RelationGetNumberOfPages --
  1281.  *      Returns number of pages in an open relation.
  1282.  *
  1283.  * Note:
  1284.  *      XXX may fail for huge relations.
  1285.  *      XXX should be elsewhere.
  1286.  *      XXX maybe should be hidden
  1287.  ***************************************************
  1288.  */
  1289.  
  1290. BlockNumber
  1291. RelationGetNumberOfBlocks(relation)
  1292. Relation        relation;
  1293. {
  1294.      return (smgrnblocks(relation->rd_rel->relsmgr, relation));
  1295. }
  1296.  
  1297. /**************************************************
  1298.   BufferGetBlock
  1299.  
  1300.  **************************************************/
  1301.  
  1302. Block
  1303. BufferGetBlock(buffer)
  1304.         Buffer  buffer;
  1305. {
  1306.     Assert(BufferIsValid(buffer));
  1307.  
  1308.     return((Block)MAKE_PTR(BufferDescriptors[buffer-1].data));
  1309. }
  1310.  
  1311. /* ---------------------------------------------------------------------
  1312.  *      ReleaseTmpRelBuffers
  1313.  *
  1314.  *      this function unmarks all the dirty pages of a temporary
  1315.  *      relation in the buffer pool so that at the end of transaction
  1316.  *      these pages will not be flushed.
  1317.  *      XXX currently it sequentially searches the buffer pool, should be
  1318.  *      changed to more clever ways of searching.
  1319.  * --------------------------------------------------------------------
  1320.  */
  1321. void
  1322. ReleaseTmpRelBuffers(tempreldesc)
  1323. Relation tempreldesc;
  1324. {
  1325.     register int i;
  1326.     BufferDesc *buf;
  1327.  
  1328.     for (i=1; i<=NBuffers; i++) {
  1329.     buf = BufferGetBufferDescriptor(i);
  1330.         if (BufferIsDirty(i) &&
  1331.             (buf->tag.relId.dbId == MyDatabaseId) &&
  1332.             (buf->tag.relId.relId == tempreldesc->rd_id)) {
  1333.             buf->flags &= ~BM_DIRTY;
  1334.             if (!(buf->flags & BM_FREE))
  1335.                ReleaseBuffer(i);
  1336.         }
  1337.      }
  1338. }
  1339.  
  1340. /* ---------------------------------------------------------------------
  1341.  *      DropBuffers
  1342.  *
  1343.  *    This function marks all the buffers in the buffer cache for a
  1344.  *    particular database as clean.  This is used when we destroy a
  1345.  *    database, to avoid trying to flush data to disk when the directory
  1346.  *    tree no longer exists.
  1347.  *
  1348.  *    This is an exceedingly non-public interface.
  1349.  * --------------------------------------------------------------------
  1350.  */
  1351.  
  1352. void
  1353. DropBuffers(dbid)
  1354. ObjectId dbid;
  1355. {
  1356.     register int i;
  1357.     BufferDesc *buf;
  1358.  
  1359.     for (i=1; i<=NBuffers; i++) {
  1360.     buf = BufferGetBufferDescriptor(i);
  1361.         if ((buf->tag.relId.dbId == dbid) && (buf->flags & BM_DIRTY)) {
  1362.             buf->flags &= ~BM_DIRTY;
  1363.         }
  1364.      }
  1365. }
  1366.  
  1367. /* -----------------------------------------------------------------
  1368.  *    PrintBufferDescs
  1369.  *
  1370.  *    this function prints all the buffer descriptors, for debugging
  1371.  *    use only.
  1372.  * -----------------------------------------------------------------
  1373.  */
  1374.  
  1375. void
  1376. PrintBufferDescs()
  1377. {
  1378.     register int i;
  1379.     BufferDesc *buf;
  1380.  
  1381.     for (i=0; i<NBuffers; i++) {
  1382.     buf = &(BufferDescriptors[i]);
  1383.     printf("(freeNext=%d, freePrev=%d, relname=%s, blockNum=%d, flags=0x%x, refcount=%d %d)\n", buf->freeNext, buf->freePrev, &(buf->sb_relname), buf->tag.blockNum, buf->flags, buf->refcount, PrivateRefCount[i]);
  1384.      }
  1385. }
  1386.  
  1387. void
  1388. PrintPinnedBufs()
  1389. {
  1390.     register int i;
  1391.     BufferDesc *buf;
  1392.  
  1393.     for (i=0; i<NBuffers; i++) {
  1394.     buf = &(BufferDescriptors[i]);
  1395.     if (PrivateRefCount[i] > 0)
  1396.         printf("(freeNext=%d, freePrev=%d, relname=%s, blockNum=%d, flags=0x%x, refcount=%d %d)\n", buf->freeNext, buf->freePrev, &(buf->sb_relname), buf->tag.blockNum, buf->flags, buf->refcount, PrivateRefCount[i]);
  1397.      }
  1398. }
  1399.  
  1400. /* -----------------------------------------------------
  1401.  * BufferShmemSize
  1402.  *
  1403.  * compute the size of shared memory for the buffer pool including
  1404.  * data pages, buffer descriptors, hash tables, etc.
  1405.  * ----------------------------------------------------
  1406.  */
  1407.  
  1408. int
  1409. BufferShmemSize()
  1410. {
  1411.     int size;
  1412.     int nbuckets;
  1413.     int nsegs;
  1414.     int tmp;
  1415.  
  1416.     nbuckets = 1 << (int)my_log2((NBuffers - 1) / DEF_FFACTOR + 1);
  1417.     nsegs = 1 << (int)my_log2((nbuckets - 1) / DEF_SEGSIZE + 1);
  1418.     size =  /* size of shmem binding table */
  1419.         my_log2(BTABLE_SIZE) + sizeof(HHDR);
  1420.     size += DEF_SEGSIZE * sizeof(SEGMENT) + BUCKET_ALLOC_INCR * 
  1421.         (sizeof(BUCKET_INDEX) + BTABLE_KEYSIZE + BTABLE_DATASIZE);
  1422.          /* size of buffer descriptors */
  1423.     size += (NBuffers + 1) * sizeof(BufferDesc);
  1424.         /* size of data pages */
  1425.     size += NBuffers * BLOCK_SIZE;
  1426.         /* size of buffer hash table */
  1427.     size += my_log2(NBuffers) + sizeof(HHDR);
  1428.     size += nsegs * DEF_SEGSIZE * sizeof(SEGMENT);
  1429.     tmp = (int)ceil((double)NBuffers/BUCKET_ALLOC_INCR);
  1430.     size += tmp * BUCKET_ALLOC_INCR * 
  1431.         (sizeof(BUCKET_INDEX) + sizeof(BufferTag) + sizeof(Buffer));
  1432.         /* extra space, just to make sure there is enough  */
  1433.     size += NBuffers * 4 + 4096;
  1434.  
  1435. #ifdef BMTRACE
  1436.     size += (BMT_LIMIT * sizeof(bmtrace)) + sizeof(int);
  1437. #endif
  1438.     return size;
  1439. }
  1440.  
  1441. /*
  1442.  * BufferPoolBlowaway
  1443.  *
  1444.  * this routine is solely for the purpose of experiments -- sometimes
  1445.  * you may want to blowaway whatever is left from the past in buffer
  1446.  * pool and start measuring some performance with a clean empty buffer
  1447.  * pool.
  1448.  */
  1449. void
  1450. BufferPoolBlowaway()
  1451. {
  1452.     register int i;
  1453.     
  1454.     BufferSync();
  1455.     for (i=1; i<=NBuffers; i++) {
  1456.         if (BufferIsValid(i)) {
  1457.             while(BufferIsValid(i))
  1458.                 ReleaseBuffer(i);
  1459.         }
  1460.         BufTableDelete(BufferGetBufferDescriptor(i));
  1461.     }
  1462. }
  1463.  
  1464. #undef IncrBufferRefCount
  1465. #undef ReleaseBuffer
  1466.  
  1467. IncrBufferRefCount(buffer)
  1468. Buffer buffer;
  1469. {
  1470.     PrivateRefCount[buffer - 1]++;
  1471. }
  1472.  
  1473. /*
  1474.  * ReleaseBuffer -- remove the pin on a buffer without
  1475.  *     marking it dirty.
  1476.  *
  1477.  */
  1478.  
  1479. ReleaseBuffer(buffer)
  1480. Buffer    buffer;
  1481. {
  1482.   BufferDesc    *bufHdr;
  1483.  
  1484.   if (BAD_BUFFER_ID(buffer)) {
  1485.     return(STATUS_ERROR);
  1486.   }
  1487.   bufHdr = BufferGetBufferDescriptor(buffer);
  1488.  
  1489.   Assert(PrivateRefCount[buffer - 1] > 0);
  1490.   PrivateRefCount[buffer - 1]--;
  1491.   if (PrivateRefCount[buffer - 1] == 0 && LastRefCount[buffer - 1] == 0) {
  1492.       /* only release buffer if it is not pinned in previous ExecMain levels */
  1493.       SpinAcquire(BufMgrLock);
  1494.       bufHdr->refcount--;
  1495.       if (bufHdr->refcount == 0) {
  1496.       AddBufferToFreelist(bufHdr);
  1497.       bufHdr->flags |= BM_FREE;
  1498.       }
  1499.       SpinRelease(BufMgrLock);
  1500.   }
  1501.  
  1502.   return(STATUS_OK);
  1503. }
  1504.  
  1505. int ShowPinTrace = 0;
  1506.  
  1507. IncrBufferRefCount_Debug(file, line, buffer)
  1508. String file;
  1509. int line;
  1510. Buffer buffer;
  1511. {
  1512.     IncrBufferRefCount(buffer);
  1513.     if (ShowPinTrace && is_userbuffer(buffer)) {
  1514.         BufferDesc *buf;
  1515.         buf = BufferGetBufferDescriptor(buffer);
  1516.         fprintf(stderr, "PIN(Incr) %d relname = %s, blockNum = %d, refcount = %d, file: %s, line: %d\n", buffer, &(buf->sb_relname), buf->tag.blockNum, PrivateRefCount[buffer - 1], file, line);
  1517.       }
  1518. }
  1519.  
  1520. ReleaseBuffer_Debug(file, line, buffer)
  1521. String file;
  1522. int line;
  1523. Buffer buffer;
  1524. {
  1525.     ReleaseBuffer(buffer);
  1526.     if (ShowPinTrace && is_userbuffer(buffer)) {
  1527.         BufferDesc *buf;
  1528.     buf = BufferGetBufferDescriptor(buffer);
  1529.         fprintf(stderr, "UNPIN(Rel) %d relname = %s, blockNum = %d, refcount = %d, file: %s, line: %d\n", buffer, &(buf->sb_relname), buf->tag.blockNum, PrivateRefCount[buffer - 1], file, line);
  1530.       }
  1531. }
  1532.  
  1533. ReleaseAndReadBuffer_Debug(file, line, buffer, relation, blockNum)
  1534. String file;
  1535. int line;
  1536. Buffer buffer;
  1537. Relation relation;
  1538. BlockNumber blockNum;
  1539. {
  1540.     bool bufferValid;
  1541.     Buffer b;
  1542.  
  1543.     bufferValid = BufferIsValid(buffer);
  1544.     b = ReleaseAndReadBuffer(buffer, relation, blockNum);
  1545.     if (ShowPinTrace && bufferValid && is_userbuffer(buffer)) {
  1546.     BufferDesc *buf;
  1547.     buf = BufferGetBufferDescriptor(buffer);
  1548.         fprintf(stderr, "UNPIN(Rel&Rd) %d relname = %s, blockNum = %d, refcount = %d, file: %s, line: %d\n", buffer, &(buf->sb_relname), buf->tag.blockNum, PrivateRefCount[buffer - 1], file, line);
  1549.       }
  1550.     if (ShowPinTrace && is_userbuffer(buffer)) {
  1551.     BufferDesc *buf;
  1552.     buf = BufferGetBufferDescriptor(b);
  1553.         fprintf(stderr, "PIN(Rel&Rd) %d relname = %s, blockNum = %d, refcount = %d, file: %s, line: %d\n", b, &(buf->sb_relname), buf->tag.blockNum, PrivateRefCount[b - 1], file, line);
  1554.       }
  1555.     return b;
  1556. }
  1557.  
  1558. #ifdef BMTRACE
  1559.  
  1560. /*
  1561.  *  trace allocations and deallocations in a circular buffer in
  1562.  *  shared memory.  check the buffer before doing the allocation,
  1563.  *  and die if there's anything fishy.
  1564.  */
  1565.  
  1566. _bm_trace(dbId, relId, blkNo, bufNo, allocType)
  1567.     long dbId;
  1568.     long relId;
  1569.     int blkNo;
  1570.     int bufNo;
  1571.     int allocType;
  1572. {
  1573.     static int mypid = 0;
  1574.     int start, cur;
  1575.     bmtrace *tb;
  1576.  
  1577.     if (mypid == 0)
  1578.     mypid = getpid();
  1579.  
  1580.     start = *CurTraceBuf;
  1581.  
  1582.     if (start > 0)
  1583.     cur = start - 1;
  1584.     else
  1585.     cur = BMT_LIMIT - 1;
  1586.  
  1587.     for (;;) {
  1588.     tb = &TraceBuf[cur];
  1589.     if (tb->bmt_op != BMT_NOTUSED) {
  1590.         if (tb->bmt_buf == bufNo) {
  1591.         if ((tb->bmt_op == BMT_DEALLOC)
  1592.             || (tb->bmt_dbid == dbId && tb->bmt_relid == relId
  1593.             && tb->bmt_blkno == blkNo))
  1594.             goto okay;
  1595.  
  1596.         /* die holding the buffer lock */
  1597.         _bm_die(dbId, relId, blkNo, bufNo, allocType, start, cur);
  1598.         }
  1599.     }
  1600.  
  1601.     if (cur == start)
  1602.         goto okay;
  1603.  
  1604.     if (cur == 0)
  1605.         cur = BMT_LIMIT - 1;
  1606.     else
  1607.         cur--;
  1608.     }
  1609.  
  1610. okay:
  1611.     tb = &TraceBuf[start];
  1612.     tb->bmt_pid = mypid;
  1613.     tb->bmt_buf = bufNo;
  1614.     tb->bmt_dbid = dbId;
  1615.     tb->bmt_relid = relId;
  1616.     tb->bmt_blkno = blkNo;
  1617.     tb->bmt_op = allocType;
  1618.  
  1619.     *CurTraceBuf = (start + 1) % BMT_LIMIT;
  1620. }
  1621.  
  1622. _bm_die(dbId, relId, blkNo, bufNo, allocType, start, cur)
  1623.     long dbId;
  1624.     long relId;
  1625.     int blkNo;
  1626.     int bufNo;
  1627.     int allocType;
  1628.     int start;
  1629.     int cur;
  1630. {
  1631.     FILE *fp;
  1632.     bmtrace *tb;
  1633.     int i;
  1634.  
  1635.     tb = &TraceBuf[cur];
  1636.  
  1637.     if ((fp = fopen("/tmp/death_notice", "w")) == (FILE *) NULL)
  1638.     elog(FATAL, "buffer alloc trace error and can't open log file");
  1639.  
  1640.     fprintf(fp, "buffer alloc trace detected the following error:\n\n");
  1641.     fprintf(fp, "    buffer %d being %s inconsistently with a previous %s\n\n",
  1642.         bufNo, (allocType == BMT_DEALLOC ? "deallocated" : "allocated"),
  1643.         (tb->bmt_op == BMT_DEALLOC ? "deallocation" : "allocation"));
  1644.  
  1645.     fprintf(fp, "the trace buffer contains:\n");
  1646.  
  1647.     i = start;
  1648.     for (;;) {
  1649.     tb = &TraceBuf[i];
  1650.     if (tb->bmt_op != BMT_NOTUSED) {
  1651.         fprintf(fp, "     [%3d]%spid %d buf %2d for <%d,%d,%d> ",
  1652.             i, (i == cur ? " ---> " : "\t"),
  1653.             tb->bmt_pid, tb->bmt_buf,
  1654.             tb->bmt_dbid, tb->bmt_relid, tb->bmt_blkno);
  1655.  
  1656.         switch (tb->bmt_op) {
  1657.           case BMT_ALLOCFND:
  1658.         fprintf(fp, "allocate (found)\n");
  1659.         break;
  1660.  
  1661.           case BMT_ALLOCNOTFND:
  1662.         fprintf(fp, "allocate (not found)\n");
  1663.         break;
  1664.  
  1665.           case BMT_DEALLOC:
  1666.         fprintf(fp, "deallocate\n");
  1667.         break;
  1668.  
  1669.           default:
  1670.         fprintf(fp, "unknown op type %d\n", tb->bmt_op);
  1671.         break;
  1672.         }
  1673.     }
  1674.  
  1675.     i = (i + 1) % BMT_LIMIT;
  1676.     if (i == start)
  1677.         break;
  1678.     }
  1679.  
  1680.     fprintf(fp, "\noperation causing error:\n");
  1681.     fprintf(fp, "\tpid %d buf %d for <%d,%d,%d> ",
  1682.         getpid(), bufNo, dbId, relId, blkNo);
  1683.  
  1684.     switch (allocType) {
  1685.       case BMT_ALLOCFND:
  1686.     fprintf(fp, "allocate (found)\n");
  1687.     break;
  1688.  
  1689.       case BMT_ALLOCNOTFND:
  1690.     fprintf(fp, "allocate (not found)\n");
  1691.     break;
  1692.  
  1693.       case BMT_DEALLOC:
  1694.     fprintf(fp, "deallocate\n");
  1695.     break;
  1696.  
  1697.       default:
  1698.     fprintf(fp, "unknown op type %d\n", allocType);
  1699.     break;
  1700.     }
  1701.  
  1702.     (void) fclose(fp);
  1703.  
  1704.     kill(getpid(), SIGILL);
  1705. }
  1706.  
  1707. #endif /* BMTRACE */
  1708.  
  1709. void
  1710. BufferRefCountReset(refcountsave)
  1711. int *refcountsave;
  1712. {
  1713.     int i;
  1714.     for (i=0; i<NBuffers; i++) {
  1715.     refcountsave[i] = PrivateRefCount[i];
  1716.     LastRefCount[i] += PrivateRefCount[i];
  1717.     PrivateRefCount[i] = 0;
  1718.       }
  1719. }
  1720.  
  1721. void
  1722. BufferRefCountRestore(refcountsave)
  1723. int *refcountsave;
  1724. {
  1725.     int i;
  1726.     for (i=0; i<NBuffers; i++) {
  1727.     PrivateRefCount[i] = refcountsave[i];
  1728.     LastRefCount[i] -= PrivateRefCount[i];
  1729.     refcountsave[i] = 0;
  1730.       }
  1731. }
  1732.