8
8
*
9
9
*
10
10
* 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 $
12
12
*
13
13
*-------------------------------------------------------------------------
14
14
*/
@@ -75,7 +75,6 @@ static void WaitIO(BufferDesc *buf, SPINLOCK spinlock);
75
75
static void StartBufferIO (BufferDesc * buf ,bool forInput );
76
76
static void TerminateBufferIO (BufferDesc * buf );
77
77
static void ContinueBufferIO (BufferDesc * buf ,bool forInput );
78
- extern void InitBufferIO (void );
79
78
extern void AbortBufferIO (void );
80
79
81
80
/*
@@ -430,17 +429,10 @@ BufferAlloc(Relation reln,
430
429
inProgress = FALSE;
431
430
for (buf = (BufferDesc * )NULL ;buf == (BufferDesc * )NULL ;)
432
431
{
433
-
434
- /* GetFreeBuffer will abort if it can't find a free buffer */
435
432
buf = GetFreeBuffer ();
436
433
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 );
444
436
445
437
/*
446
438
* There should be exactly one pin on the buffer after it is
@@ -790,11 +782,21 @@ FlushBuffer(Buffer buffer, bool release)
790
782
WaitIO (bufHdr ,BufMgrLock );/* confirm end of IO */
791
783
bufHdr -> flags &= ~BM_JUST_DIRTIED ;
792
784
StartBufferIO (bufHdr , false);/* output IO start */
785
+
793
786
SpinRelease (BufMgrLock );
794
787
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
+
795
795
status = smgrflush (DEFAULT_SMGR ,bufrel ,bufHdr -> tag .blockNum ,
796
796
(char * )MAKE_PTR (bufHdr -> data ));
797
797
798
+ LockBuffer (BufferDescriptorGetBuffer (bufHdr ),BUFFER_LOCK_UNLOCK );
799
+
798
800
/* drop relcache refcnt incremented by RelationIdCacheGetRelation */
799
801
RelationDecrementReferenceCount (bufrel );
800
802
@@ -1018,19 +1020,6 @@ ClearBufferDirtiedByMe(Buffer buffer, BufferDesc *bufHdr)
1018
1020
*that have been dirtied by the current xact and flush them to disk.
1019
1021
*We do *not* flush dirty buffers that have been dirtied by other xacts.
1020
1022
*(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.
1034
1023
*/
1035
1024
static void
1036
1025
BufferSync ()
@@ -1113,15 +1102,28 @@ BufferSync()
1113
1102
bufHdr -> flags &= ~BM_JUST_DIRTIED ;
1114
1103
StartBufferIO (bufHdr , false);/* output IO start */
1115
1104
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
+
1116
1121
/*
1117
1122
* If we didn't have the reldesc in our local cache,
1118
1123
* write this page out using the 'blind write' storage
1119
1124
* manager routine. If we did find it, use the
1120
1125
* standard interface.
1121
1126
*/
1122
- #ifndef OPTIMIZE_SINGLE
1123
- SpinRelease (BufMgrLock );
1124
- #endif /* OPTIMIZE_SINGLE */
1125
1127
if (reln == (Relation )NULL )
1126
1128
{
1127
1129
status = smgrblindwrt (DEFAULT_SMGR ,
@@ -1138,9 +1140,14 @@ BufferSync()
1138
1140
bufHdr -> tag .blockNum ,
1139
1141
(char * )MAKE_PTR (bufHdr -> data ));
1140
1142
}
1141
- #ifndef OPTIMIZE_SINGLE
1143
+
1144
+ /*
1145
+ * Release the per-buffer readlock, reacquire BufMgrLock.
1146
+ */
1147
+ LockBuffer (BufferDescriptorGetBuffer (bufHdr ),
1148
+ BUFFER_LOCK_UNLOCK );
1149
+
1142
1150
SpinAcquire (BufMgrLock );
1143
- #endif /* OPTIMIZE_SINGLE */
1144
1151
1145
1152
UnpinBuffer (bufHdr );
1146
1153
if (status == SM_FAIL )
@@ -1523,9 +1530,14 @@ BufferReplace(BufferDesc *bufHdr)
1523
1530
/* To check if block content changed while flushing. - vadim 01/17/97 */
1524
1531
bufHdr -> flags &= ~BM_JUST_DIRTIED ;
1525
1532
1526
- #ifndef OPTIMIZE_SINGLE
1527
1533
SpinRelease (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 );
1529
1541
1530
1542
if (reln != (Relation )NULL )
1531
1543
{
@@ -1541,9 +1553,9 @@ BufferReplace(BufferDesc *bufHdr)
1541
1553
false);/* no fsync */
1542
1554
}
1543
1555
1544
- #ifndef OPTIMIZE_SINGLE
1556
+ LockBuffer (BufferDescriptorGetBuffer (bufHdr ),BUFFER_LOCK_UNLOCK );
1557
+
1545
1558
SpinAcquire (BufMgrLock );
1546
- #endif /* OPTIMIZE_SINGLE */
1547
1559
1548
1560
/* drop relcache refcnt incremented by RelationIdCacheGetRelation */
1549
1561
if (reln != (Relation )NULL )
@@ -2488,11 +2500,13 @@ ContinueBufferIO(BufferDesc *buf, bool forInput)
2488
2500
IsForInput = forInput ;
2489
2501
}
2490
2502
2503
+ #ifdef NOT_USED
2491
2504
void
2492
2505
InitBufferIO (void )
2493
2506
{
2494
2507
InProgressBuf = (BufferDesc * )0 ;
2495
2508
}
2509
+ #endif
2496
2510
2497
2511
/*
2498
2512
*This function is called from ProcReleaseSpins().