aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAlexander Korotkov <akorotkov@postgresql.org>2018-12-13 06:12:25 +0300
committerAlexander Korotkov <akorotkov@postgresql.org>2018-12-13 06:15:23 +0300
commit225b5c9c480fa90d4734ce4a8d1a4b46ac5e826e (patch)
tree9af9bc057fef0e3c31f9b5fda2b0aaee05f5defd /src
parent9aa94d8536f81168b6de3744c1fb4a173af1cefe (diff)
downloadpostgresql-225b5c9c480fa90d4734ce4a8d1a4b46ac5e826e.tar.gz
postgresql-225b5c9c480fa90d4734ce4a8d1a4b46ac5e826e.zip
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
Diffstat (limited to 'src')
-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 7701a2d6bfc..b626a219dec 100644
--- a/src/backend/access/gin/ginxlog.c
+++ b/src/backend/access/gin/ginxlog.c
@@ -513,6 +513,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);
@@ -532,15 +545,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))