aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlvaro Herrera <alvherre@alvh.no-ip.org>2014-01-02 18:17:07 -0300
committerAlvaro Herrera <alvherre@alvh.no-ip.org>2014-01-02 18:17:07 -0300
commita50d97625497b76e3dc7c4aa22cd2c70317ec54d (patch)
tree6f3672ebb689adecef3a00cec1701e35fba2a4cb
parent722acf51a0d074d19782ad7e97ebe3fdb63fbb87 (diff)
downloadpostgresql-a50d97625497b76e3dc7c4aa22cd2c70317ec54d.tar.gz
postgresql-a50d97625497b76e3dc7c4aa22cd2c70317ec54d.zip
Wrap multixact/members correctly during extension
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.
-rw-r--r--src/backend/access/transam/multixact.c24
1 files changed, 19 insertions, 5 deletions
diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c
index 60c3370ece2..e2b31ee441f 100644
--- a/src/backend/access/transam/multixact.c
+++ b/src/backend/access/transam/multixact.c
@@ -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;
+ }
}
}