]> granicus.if.org Git - postgresql/commitdiff
Avoid possible deadlock while locking multiple heap pages.
authorAmit Kapila <akapila@postgresql.org>
Sat, 2 Feb 2019 03:24:33 +0000 (08:54 +0530)
committerAmit Kapila <akapila@postgresql.org>
Sat, 2 Feb 2019 03:24:33 +0000 (08:54 +0530)
To avoid deadlock, backend acquires a lock on heap pages in block
number order.  In certain cases, lock on heap pages is dropped and
reacquired.  In this case, the locks are dropped for reading in
corresponding VM page/s. The issue is we re-acquire locks in bufferId
order whereas the intention was to acquire in blockid order.

This commit ensures that we will always acquire locks on heap pages in
blockid order.

Reported-by: Nishant Fnu
Author: Nishant Fnu
Reviewed-by: Amit Kapila and Robert Haas
Backpatch-through: 9.4
Discussion: https://postgr.es/m/5883C831-2ED1-47C8-BFAC-2D5BAE5A8CAE@amazon.com

src/backend/access/heap/hio.c

index c90fb71965ce19ff3c9241a1085f95f6b0c6e1df..6041508b6974cd9b7a5456556663b9c5d30dfcc6 100644 (file)
@@ -115,8 +115,8 @@ ReadBufferBI(Relation relation, BlockNumber targetBlock,
  * visibility map page, if we haven't already got one.
  *
  * buffer2 may be InvalidBuffer, if only one buffer is involved.  buffer1
- * must not be InvalidBuffer.  If both buffers are specified, buffer1 must
- * be less than buffer2.
+ * must not be InvalidBuffer.  If both buffers are specified, block1 must
+ * be less than block2.
  */
 static void
 GetVisibilityMapPins(Relation relation, Buffer buffer1, Buffer buffer2,
@@ -127,7 +127,7 @@ GetVisibilityMapPins(Relation relation, Buffer buffer1, Buffer buffer2,
        bool            need_to_pin_buffer2;
 
        Assert(BufferIsValid(buffer1));
-       Assert(buffer2 == InvalidBuffer || buffer1 <= buffer2);
+       Assert(buffer2 == InvalidBuffer || block1 <= block2);
 
        while (1)
        {
@@ -449,7 +449,7 @@ loop:
                 * done a bit of extra work for no gain, but there's no real harm
                 * done.
                 */
-               if (otherBuffer == InvalidBuffer || buffer <= otherBuffer)
+               if (otherBuffer == InvalidBuffer || targetBlock <= otherBlock)
                        GetVisibilityMapPins(relation, buffer, otherBuffer,
                                                                 targetBlock, otherBlock, vmbuffer,
                                                                 vmbuffer_other);