]> granicus.if.org Git - postgresql/commitdiff
Wrap multixact/members correctly during extension
authorAlvaro Herrera <alvherre@alvh.no-ip.org>
Thu, 2 Jan 2014 21:17:07 +0000 (18:17 -0300)
committerAlvaro Herrera <alvherre@alvh.no-ip.org>
Thu, 2 Jan 2014 21:17:07 +0000 (18:17 -0300)
In the 9.2 code for extending multixact/members, the logic was very
simple because the number of entries in a members page was a proper
divisor of 2^32, and thus at 2^32 wraparound the logic for page switch
was identical than at any other page boundary.  In commit 0ac5ad5134f I
failed to realize this and introduced code that was not able to go over
the 2^32 boundary.  Fix that by ensuring that when we reach the last
page of the last segment we correctly zero the initial page of the
initial segment, using correct uint32-wraparound-safe arithmetic.

Noticed while investigating bug #8673 reported by Serge Negodyuck, as
diagnosed by Andres Freund.

src/backend/access/transam/multixact.c

index 60c3370ece24a059cab1d47dd8145fe93c4c6cd8..e2b31ee441f662deae9220bc7fb75ace12e7b446 100644 (file)
@@ -2259,7 +2259,6 @@ ExtendMultiXactMember(MultiXactOffset offset, int nmembers)
        {
                int                     flagsoff;
                int                     flagsbit;
-               int                     difference;
 
                /*
                 * Only zero when at first entry of a page.
@@ -2280,10 +2279,25 @@ ExtendMultiXactMember(MultiXactOffset offset, int nmembers)
                        LWLockRelease(MultiXactMemberControlLock);
                }
 
-               /* Advance to next page (OK if nmembers goes negative) */
-               difference = MULTIXACT_MEMBERS_PER_PAGE - offset % MULTIXACT_MEMBERS_PER_PAGE;
-               offset += difference;
-               nmembers -= difference;
+               /*
+                * Advance to next page, taking care to properly handle the wraparound
+                * case.  OK if nmembers goes negative.
+                */
+               if ((unsigned int) (offset + nmembers) < offset)
+               {
+                       uint32          difference = offset + MULTIXACT_MEMBERS_PER_PAGE;
+
+                       nmembers -= (unsigned int) (MULTIXACT_MEMBERS_PER_PAGE - difference);
+                       offset = 0;
+               }
+               else
+               {
+                       int                     difference;
+
+                       difference = MULTIXACT_MEMBERS_PER_PAGE - offset % MULTIXACT_MEMBERS_PER_PAGE;
+                       nmembers -= difference;
+                       offset += difference;
+               }
        }
 }