8000 Back-patch fix to grab read lock on a buffer while it is written out. · percona/postgres@956ba75 · GitHub
[go: up one dir, main page]

Skip to content

Commit 956ba75

Browse files
committed
Back-patch fix to grab read lock on a buffer while it is written out.
1 parent 730e2ff commit 956ba75

File tree

1 file changed

+47
-33
lines changed

1 file changed

+47
-33
lines changed

src/backend/storage/buffer/bufmgr.c

Lines changed: 47 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
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);
7575
static void StartBufferIO(BufferDesc *buf, bool forInput);
7676
static void TerminateBufferIO(BufferDesc *buf);
7777
static void ContinueBufferIO(BufferDesc *buf, bool forInput);
78-
extern void InitBufferIO(void);
7978
extern void AbortBufferIO(void);
8079

8180
/*
@@ -430,17 +429,10 @@ BufferAlloc(Relation reln,
430429
inProgress = FALSE;
431430
for (buf = (BufferDesc *) NULL; buf == (BufferDesc *) NULL;)
432431
{
433-
434-
/* GetFreeBuffer will abort if it can't find a free buffer */
435432
buf = 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)
790782
WaitIO(bufHdr, BufMgrLock); /* confirm end of IO */
791783
bufHdr->flags &= ~BM_JUST_DIRTIED;
792784
StartBufferIO(bufHdr, false); /* output IO start */
785+
793786
SpinRelease(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+
795795
status = 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 */
799801
RelationDecrementReferenceCount(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
*/
10351024
static void
10361025
BufferSync()
@@ -1113,15 +1102,28 @@ BufferSync()
11131102
bufHdr->flags &= ~BM_JUST_DIRTIED;
11141103
StartBufferIO(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 */
11251127
if (reln == (Relation) NULL)
11261128
{
11271129
status = smgrblindwrt(DEFAULT_SMGR,
@@ -1138,9 +1140,14 @@ BufferSync()
11381140
bufHdr->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+
11421150
SpinAcquire(BufMgrLock);
1143-
#endif /* OPTIMIZE_SINGLE */
11441151

11451152
UnpinBuffer(bufHdr);
11461153
if (status == SM_FAIL)
@@ -1523,9 +1530,14 @@ BufferReplace(BufferDesc *bufHdr)
15231530
/* To check if block content changed while flushing. - vadim 01/17/97 */
15241531
bufHdr->flags &= ~BM_JUST_DIRTIED;
15251532

1526-
#ifndef OPTIMIZE_SINGLE
15271533
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);
15291541

15301542
if (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+
15451558
SpinAcquire(BufMgrLock);
1546-
#endif /* OPTIMIZE_SINGLE */
15471559

15481560
/* drop relcache refcnt incremented by RelationIdCacheGetRelation */
15491561
if (reln != (Relation) NULL)
@@ -2488,11 +2500,13 @@ ContinueBufferIO(BufferDesc *buf, bool forInput)
24882500
IsForInput = forInput;
24892501
}
24902502

2503+
#ifdef NOT_USED
24912504
void
24922505
InitBufferIO(void)
24932506
{
24942507
InProgressBuf = (BufferDesc *) 0;
24952508
}
2509+
#endif
24962510

24972511
/*
24982512
* This function is called from ProcReleaseSpins().

0 commit comments

Comments
 (0)
0