diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c index 03ca079..25958aa 100644 --- a/src/backend/access/transam/multixact.c +++ b/src/backend/access/transam/multixact.c @@ -908,6 +908,37 @@ RecordNewMultiXact(MultiXactId multi, MultiXactOffset offset, } /* + * Check if we could add "distance" to "start", without moving past + * "boundary", using modulo arithmetic. + */ +static bool +MultiXactOffsetWouldWrap(MultiXactOffset boundary, + MultiXactOffset start, + int distance) +{ + MultiXactOffset finish = start + distance; + Assert(distance >= 0); + if (start < boundary) + /* + * <----S----B----> + * + * [---) = F wrapped past B (and UINT_MAX) + * [---) = F OK + * [----] = F wrapped past B + */ + return finish >= boundary || finish < start; + else + /* + * <----B----S----> + * + * [---) = F OK + * [---) = F wrapped past B (and UINT_MAX) + * [----] = F OK + */ + return finish >= boundary && finish < start; +} + +/* * GetNewMultiXactId * Get the next MultiXactId. * @@ -1063,13 +1094,13 @@ GetNewMultiXactId(int nmembers, MultiXactOffset *offset) * multixact freeze settings would have to be reduced for that to have any * effect, and we can't do that from here. */ - if (MultiXactOffsetPrecedes(MultiXactState->offsetStopLimit, nextOffset + nmembers)) + if (MultiXactOffsetWouldWrap(MultiXactState->offsetStopLimit, nextOffset, nmembers)) ereport(ERROR, (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), errmsg("database is not accepting commands that generate new MultiXactIds to avoid \"members\" wraparound data loss in database with OID %u", MultiXactState->oldestMultiXactDB), errhint("Execute a database-wide VACUUM in that database, with reduced vacuum_multixact_freeze_min_age and vacuum_multixact_freeze_table_age settings."))); - else if (MultiXactOffsetPrecedes(MultiXactState->offsetWarnLimit, nextOffset + nmembers)) + else if (MultiXactOffsetWouldWrap(MultiXactState->offsetWarnLimit, nextOffset, nmembers)) ereport(WARNING, (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), errmsg_plural("database with OID %u must be vacuumed before %d more multixact member is used",