summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander Korotkov2018-12-13 03:12:25 +0000
committerAlexander Korotkov2018-12-13 03:18:13 +0000
commit80d4d8d71d57cc336e00e448f14c1b70ad8bc85f (patch)
treef948176afd920d5f42222d448513b14493c2d2f3
parent12cb7ea599fb651bddadcff5d55188cdc4633190 (diff)
Prevent deadlock in ginRedoDeletePage()
On standby ginRedoDeletePage() can work concurrently with read-only queries. Those queries can traverse posting tree in two ways. 1) Using rightlinks by ginStepRight(), which locks the next page before unlocking its left sibling. 2) Using downlinks by ginFindLeafPage(), which locks at most one page at time. Original lock order was: page, parent, left sibling. That lock order can deadlock with ginStepRight(). In order to prevent deadlock this commit changes lock order to: left sibling, page, parent. Note, that position of parent in locking order seems insignificant, because we only lock one page at time while traversing downlinks. Reported-by: Chen Huajun Diagnosed-by: Chen Huajun, Peter Geoghegan, Andrey Borodin Discussion: https://postgr.es/m/31a702a.14dd.166c1366ac1.Coremail.chjischj%40163.com Author: Alexander Korotkov Backpatch-through: 9.4
-rw-r--r--src/backend/access/gin/ginxlog.c22
1 files changed, 13 insertions, 9 deletions
diff --git a/src/backend/access/gin/ginxlog.c b/src/backend/access/gin/ginxlog.c
index 7a217801210..19ab1b61dce 100644
--- a/src/backend/access/gin/ginxlog.c
+++ b/src/backend/access/gin/ginxlog.c
@@ -511,6 +511,19 @@ ginRedoDeletePage(XLogReaderState *record)
Buffer lbuffer;
Page page;
+ /*
+ * Lock left page first in order to prevent possible deadlock with
+ * ginStepRight().
+ */
+ if (XLogReadBufferForRedo(record, 2, &lbuffer) == BLK_NEEDS_REDO)
+ {
+ page = BufferGetPage(lbuffer);
+ Assert(GinPageIsData(page));
+ GinPageGetOpaque(page)->rightlink = data->rightLink;
+ PageSetLSN(page, lsn);
+ MarkBufferDirty(lbuffer);
+ }
+
if (XLogReadBufferForRedo(record, 0, &dbuffer) == BLK_NEEDS_REDO)
{
page = BufferGetPage(dbuffer);
@@ -530,15 +543,6 @@ ginRedoDeletePage(XLogReaderState *record)
MarkBufferDirty(pbuffer);
}
- if (XLogReadBufferForRedo(record, 2, &lbuffer) == BLK_NEEDS_REDO)
- {
- page = BufferGetPage(lbuffer);
- Assert(GinPageIsData(page));
- GinPageGetOpaque(page)->rightlink = data->rightLink;
- PageSetLSN(page, lsn);
- MarkBufferDirty(lbuffer);
- }
-
if (BufferIsValid(lbuffer))
UnlockReleaseBuffer(lbuffer);
if (BufferIsValid(pbuffer))