hio: Relax rules for calling GetVisibilityMapPins()
authorAndres Freund <[email protected]>
Thu, 6 Apr 2023 17:27:30 +0000 (10:27 -0700)
committerAndres Freund <[email protected]>
Thu, 6 Apr 2023 17:36:30 +0000 (10:36 -0700)
GetVisibilityMapPins() insisted on the buffer1/buffer2 being in a specific
order. This required checks at the callsite. As a subsequent patch will add
another callsite, move related logic into GetVisibilityMapPins().

Discussion: https://postgr.es/m/20230403190030[email protected]

src/backend/access/heap/hio.c

index 7479212d4e02739520d89f83ac6b93447564c9e1..db810ec45ea10ee92bd97544775ea391d8208461 100644 (file)
@@ -131,9 +131,9 @@ ReadBufferBI(Relation relation, BlockNumber targetBlock,
  * For each heap page which is all-visible, acquire a pin on the appropriate
  * 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, block1 must
- * be less than block2.
+ * To avoid complexity in the callers, either buffer1 or buffer2 may be
+ * InvalidBuffer if only one buffer is involved. For the same reason, block2
+ * may be smaller than block1.
  */
 static void
 GetVisibilityMapPins(Relation relation, Buffer buffer1, Buffer buffer2,
@@ -143,6 +143,26 @@ GetVisibilityMapPins(Relation relation, Buffer buffer1, Buffer buffer2,
    bool        need_to_pin_buffer1;
    bool        need_to_pin_buffer2;
 
+   /*
+    * Swap buffers around to handle case of a single block/buffer, and to
+    * handle if lock ordering rules require to lock block2 first.
+    */
+   if (!BufferIsValid(buffer1) ||
+       (BufferIsValid(buffer2) && block1 > block2))
+   {
+       Buffer      tmpbuf = buffer1;
+       Buffer     *tmpvmbuf = vmbuffer1;
+       BlockNumber tmpblock = block1;
+
+       buffer1 = buffer2;
+       vmbuffer1 = vmbuffer2;
+       block1 = block2;
+
+       buffer2 = tmpbuf;
+       vmbuffer2 = tmpvmbuf;
+       block2 = tmpblock;
+   }
+
    Assert(BufferIsValid(buffer1));
    Assert(buffer2 == InvalidBuffer || block1 <= block2);
 
@@ -502,14 +522,9 @@ loop:
         * done a bit of extra work for no gain, but there's no real harm
         * done.
         */
-       if (otherBuffer == InvalidBuffer || targetBlock <= otherBlock)
-           GetVisibilityMapPins(relation, buffer, otherBuffer,
-                                targetBlock, otherBlock, vmbuffer,
-                                vmbuffer_other);
-       else
-           GetVisibilityMapPins(relation, otherBuffer, buffer,
-                                otherBlock, targetBlock, vmbuffer_other,
-                                vmbuffer);
+       GetVisibilityMapPins(relation, buffer, otherBuffer,
+                            targetBlock, otherBlock, vmbuffer,
+                            vmbuffer_other);
 
        /*
         * Now we can check to see if there's enough free space here. If so,