88 *
99 *
1010 * IDENTIFICATION
11- * $Header: /cvsroot/pgsql/src/backend/storage/buffer/bufmgr.c,v 1.81 2000/05/19 03:22:28 tgl Exp $
11+ * $Header: /cvsroot/pgsql/src/backend/storage/buffer/bufmgr.c,v 1.81.2.1 2000/09/25 04:34:10 tgl Exp $
1212 *
1313 *-------------------------------------------------------------------------
1414 */
@@ -75,7 +75,6 @@ static void WaitIO(BufferDesc *buf, SPINLOCK spinlock);
7575static void StartBufferIO (BufferDesc * buf ,bool forInput );
7676static void TerminateBufferIO (BufferDesc * buf );
7777static void ContinueBufferIO (BufferDesc * buf ,bool forInput );
78- extern void InitBufferIO (void );
7978extern void AbortBufferIO (void );
8079
8180/*
@@ -430,17 +429,10 @@ BufferAlloc(Relation reln,
430429inProgress = FALSE;
431430for (buf = (BufferDesc * )NULL ;buf == (BufferDesc * )NULL ;)
432431{
433-
434- /* GetFreeBuffer will abort if it can't find a free buffer */
435432buf = GetFreeBuffer ();
436433
437- /*
438- * But it can return buf == NULL if we are in aborting transaction
439- * now and so elog(ERROR,...) in GetFreeBuffer will not abort
440- * again.
441- */
442- if (buf == NULL )
443- return NULL ;
434+ /* GetFreeBuffer will abort if it can't find a free buffer */
435+ Assert (buf );
444436
445437/*
446438 * There should be exactly one pin on the buffer after it is
@@ -790,11 +782,21 @@ FlushBuffer(Buffer buffer, bool release)
790782WaitIO (bufHdr ,BufMgrLock );/* confirm end of IO */
791783bufHdr -> flags &= ~BM_JUST_DIRTIED ;
792784StartBufferIO (bufHdr , false);/* output IO start */
785+
793786SpinRelease (BufMgrLock );
794787
788+ /*
789+ * Grab a read lock on the buffer to ensure that no
790+ * other backend changes its contents while we write it;
791+ * see comments in BufferSync().
792+ */
793+ LockBuffer (BufferDescriptorGetBuffer (bufHdr ),BUFFER_LOCK_SHARE );
794+
795795status = smgrflush (DEFAULT_SMGR ,bufrel ,bufHdr -> tag .blockNum ,
796796 (char * )MAKE_PTR (bufHdr -> data ));
797797
798+ LockBuffer (BufferDescriptorGetBuffer (bufHdr ),BUFFER_LOCK_UNLOCK );
799+
798800/* drop relcache refcnt incremented by RelationIdCacheGetRelation */
799801RelationDecrementReferenceCount (bufrel );
800802
@@ -1018,19 +1020,6 @@ ClearBufferDirtiedByMe(Buffer buffer, BufferDesc *bufHdr)
10181020 *that have been dirtied by the current xact and flush them to disk.
10191021 *We do *not* flush dirty buffers that have been dirtied by other xacts.
10201022 *(This is a substantial change from pre-7.0 behavior.)
1021- *
1022- *OLD COMMENTS (do these still apply?)
1023- *
1024- *Also, we need to be sure that no other transaction is
1025- *modifying the page as we flush it.This is only a problem for objects
1026- *that use a non-two-phase locking protocol, like btree indices.For
1027- *those objects, we would like to set a write lock for the duration of
1028- *our IO. Another possibility is to code updates to btree pages
1029- *carefully, so that writing them out out of order cannot cause
1030- *any unrecoverable errors.
1031- *
1032- *I don't want to think hard about this right now, so I will try
1033- *to come back to it later.
10341023 */
10351024static void
10361025BufferSync ()
@@ -1113,15 +1102,28 @@ BufferSync()
11131102bufHdr -> flags &= ~BM_JUST_DIRTIED ;
11141103StartBufferIO (bufHdr , false);/* output IO start */
11151104
1105+ SpinRelease (BufMgrLock );
1106+
1107+ /*
1108+ * Grab a read lock on the buffer to ensure that no
1109+ * other backend changes its contents while we write it;
1110+ * otherwise we could write a non-self-consistent page
1111+ * image to disk, which'd be bad news if the other
1112+ * transaction aborts before writing its changes.
1113+ *
1114+ * Note that we still need the BM_JUST_DIRTIED mechanism
1115+ * in case someone dirties the buffer just before we
1116+ * grab this lock or just after we release it.
1117+ */
1118+ LockBuffer (BufferDescriptorGetBuffer (bufHdr ),
1119+ BUFFER_LOCK_SHARE );
1120+
11161121/*
11171122 * If we didn't have the reldesc in our local cache,
11181123 * write this page out using the 'blind write' storage
11191124 * manager routine. If we did find it, use the
11201125 * standard interface.
11211126 */
1122- #ifndef OPTIMIZE_SINGLE
1123- SpinRelease (BufMgrLock );
1124- #endif /* OPTIMIZE_SINGLE */
11251127if (reln == (Relation )NULL )
11261128{
11271129status = smgrblindwrt (DEFAULT_SMGR ,
@@ -1138,9 +1140,14 @@ BufferSync()
11381140bufHdr -> tag .blockNum ,
11391141(char * )MAKE_PTR (bufHdr -> data ));
11401142}
1141- #ifndef OPTIMIZE_SINGLE
1143+
1144+ /*
1145+ * Release the per-buffer readlock, reacquire BufMgrLock.
1146+ */
1147+ LockBuffer (BufferDescriptorGetBuffer (bufHdr ),
1148+ BUFFER_LOCK_UNLOCK );
1149+
11421150SpinAcquire (BufMgrLock );
1143- #endif /* OPTIMIZE_SINGLE */
11441151
11451152UnpinBuffer (bufHdr );
11461153if (status == SM_FAIL )
@@ -1523,9 +1530,14 @@ BufferReplace(BufferDesc *bufHdr)
15231530/* To check if block content changed while flushing. - vadim 01/17/97 */
15241531bufHdr -> flags &= ~BM_JUST_DIRTIED ;
15251532
1526- #ifndef OPTIMIZE_SINGLE
15271533SpinRelease (BufMgrLock );
1528- #endif /* OPTIMIZE_SINGLE */
1534+
1535+ /*
1536+ * Grab a read lock on the buffer to ensure that no
1537+ * other backend changes its contents while we write it;
1538+ * see comments in BufferSync().
1539+ */
1540+ LockBuffer (BufferDescriptorGetBuffer (bufHdr ),BUFFER_LOCK_SHARE );
15291541
15301542if (reln != (Relation )NULL )
15311543{
@@ -1541,9 +1553,9 @@ BufferReplace(BufferDesc *bufHdr)
15411553 false);/* no fsync */
15421554}
15431555
1544- #ifndef OPTIMIZE_SINGLE
1556+ LockBuffer (BufferDescriptorGetBuffer (bufHdr ),BUFFER_LOCK_UNLOCK );
1557+
15451558SpinAcquire (BufMgrLock );
1546- #endif /* OPTIMIZE_SINGLE */
15471559
15481560/* drop relcache refcnt incremented by RelationIdCacheGetRelation */
15491561if (reln != (Relation )NULL )
@@ -2488,11 +2500,13 @@ ContinueBufferIO(BufferDesc *buf, bool forInput)
24882500IsForInput = forInput ;
24892501}
24902502
2503+ #ifdef NOT_USED
24912504void
24922505InitBufferIO (void )
24932506{
24942507InProgressBuf = (BufferDesc * )0 ;
24952508}
2509+ #endif
24962510
24972511/*
24982512 *This function is called from ProcReleaseSpins().