+/*
+ * Based on the given oldest MultiXactId, determine what's the oldest member
+ * offset and install the limit info in MultiXactState, where it can be used to
+ * prevent overrun of old data in the members SLRU area.
+ */
+static void
+DetermineSafeOldestOffset(MultiXactId oldestMXact)
+{
+ MultiXactOffset oldestOffset;
+
+ /*
+ * Can't do this while initdb'ing or in the startup process while
+ * replaying WAL: the segment file to read might have not yet been
+ * created, or already been removed.
+ */
+ if (IsBootstrapProcessingMode() || InRecovery)
+ return;
+
+ /*
+ * We determine the safe upper bound for offsets of new xacts by reading
+ * the offset of the oldest multixact, and going back one segment. This
+ * way, the sequence of multixact member segments will always have a
+ * one-segment hole at a minimum. We start spewing warnings a few
+ * complete segments before that.
+ */
+ oldestOffset = read_offset_for_multi(oldestMXact);
+ /* move back to start of the corresponding segment */
+ oldestOffset -= oldestOffset / MULTIXACT_MEMBERS_PER_PAGE * SLRU_PAGES_PER_SEGMENT;
+
+ LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);
+ /* always leave one segment before the wraparound point */
+ MultiXactState->offsetStopLimit = oldestOffset -
+ (MULTIXACT_MEMBERS_PER_PAGE * SLRU_PAGES_PER_SEGMENT);
+ LWLockRelease(MultiXactGenLock);
+}
+
+/*
+ * Return whether adding "distance" to "start" would move past "boundary".
+ *
+ * We use this to determine whether the addition is "wrapping around" the
+ * boundary point, hence the name. The reason we don't want to use the regular
+ * 2^31-modulo arithmetic here is that we want to be able to use the whole of
+ * the 2^32-1 space here, allowing for more multixacts that would fit
+ * otherwise. See also SlruScanDirCbRemoveMembers.
+ */
+static bool
+MultiXactOffsetWouldWrap(MultiXactOffset boundary, MultiXactOffset start,
+ uint32 distance)
+{
+ MultiXactOffset finish;
+
+ Assert(distance >= 0);
+
+ /*
+ * Note that offset number 0 is not used (see GetMultiXactIdMembers), so
+ * if the addition wraps around the UINT_MAX boundary, skip that value.
+ */
+ finish = start + distance;
+ if (finish < start)
+ finish++;
+
+ /*-----------------------------------------------------------------------
+ * When the boundary is numerically greater than the starting point, any
+ * value numerically between the two is not wrapped:
+ *
+ * <----S----B---->
+ * [---) = F wrapped past B (and UINT_MAX)
+ * [---) = F not wrapped
+ * [----] = F wrapped past B
+ *
+ * When the boundary is numerically less than the starting point (i.e. the
+ * UINT_MAX wraparound occurs somewhere in between) then all values in
+ * between are wrapped:
+ *
+ * <----B----S---->
+ * [---) = F not wrapped past B (but wrapped past UINT_MAX)
+ * [---) = F wrapped past B (and UINT_MAX)
+ * [----] = F not wrapped
+ *-----------------------------------------------------------------------
+ */
+ if (start < boundary)
+ {
+ return finish >= boundary || finish < start;
+ }
+ else
+ {
+ return finish >= boundary && finish < start;
+ }
+}
+
+/*
+ * Read the offset of the first member of the given multixact.
+ */
+static MultiXactOffset
+read_offset_for_multi(MultiXactId multi)
+{
+ MultiXactOffset offset;
+ int pageno;
+ int entryno;
+ int slotno;
+ MultiXactOffset *offptr;
+
+ pageno = MultiXactIdToOffsetPage(multi);
+ entryno = MultiXactIdToOffsetEntry(multi);
+
+ /* lock is acquired by SimpleLruReadPage_ReadOnly */
+ slotno = SimpleLruReadPage_ReadOnly(MultiXactOffsetCtl, pageno, multi);
+ offptr = (MultiXactOffset *) MultiXactOffsetCtl->shared->page_buffer[slotno];
+ offptr += entryno;
+ offset = *offptr;
+ LWLockRelease(MultiXactOffsetControlLock);
+
+ return offset;
+}
+