Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit a04b7f5

Browse files
Maxim OrlovCommitfest Bot
Maxim Orlov
authored and
Commitfest Bot
committed
Use 64-bit multixact offsets.
Author: Maxim Orlov <orlovmg@gmail.com>
1 parent 7033acb commit a04b7f5

File tree

5 files changed

+10
-168
lines changed

5 files changed

+10
-168
lines changed

src/backend/access/transam/multixact.c

Lines changed: 6 additions & 164 deletions
Original file line numberDiff line numberDiff line change
@@ -96,14 +96,6 @@
9696
/*
9797
* Defines for MultiXactOffset page sizes. A page is the same BLCKSZ as is
9898
* used everywhere else in Postgres.
99-
*
100-
* Note: because MultiXactOffsets are 32 bits and wrap around at 0xFFFFFFFF,
101-
* MultiXact page numbering also wraps around at
102-
* 0xFFFFFFFF/MULTIXACT_OFFSETS_PER_PAGE, and segment numbering at
103-
* 0xFFFFFFFF/MULTIXACT_OFFSETS_PER_PAGE/SLRU_PAGES_PER_SEGMENT. We need
104-
* take no explicit notice of that fact in this module, except when comparing
105-
* segment and page numbers in TruncateMultiXact (see
106-
* MultiXactOffsetPagePrecedes).
10799
*/
108100

109101
/* We need four bytes per offset */
@@ -272,9 +264,6 @@ typedef struct MultiXactStateData
272264
MultiXactId multiStopLimit;
273265
MultiXactId multiWrapLimit;
274266

275-
/* support for members anti-wraparound measures */
276-
MultiXactOffset offsetStopLimit; /* known if oldestOffsetKnown */
277-
278267
/*
279268
* This is used to sleep until a multixact offset is written when we want
280269
* to create the next one.
@@ -409,8 +398,6 @@ static bool MultiXactOffsetPrecedes(MultiXactOffset offset1,
409398
MultiXactOffset offset2);
410399
static void ExtendMultiXactOffset(MultiXactId multi);
411400
static void ExtendMultiXactMember(MultiXactOffset offset, int nmembers);
412-
static bool MultiXactOffsetWouldWrap(MultiXactOffset boundary,
413-
MultiXactOffset start, uint32 distance);
414401
static bool SetOffsetVacuumLimit(bool is_startup);
415402
static bool find_multixact_start(MultiXactId multi, MultiXactOffset *result);
416403
static void WriteMZeroPageXlogRec(int64 pageno, uint8 info);
@@ -1164,78 +1151,6 @@ GetNewMultiXactId(int nmembers, MultiXactOffset *offset)
11641151
else
11651152
*offset = nextOffset;
11661153

1167-
/*----------
1168-
* Protect against overrun of the members space as well, with the
1169-
* following rules:
1170-
*
1171-
* If we're past offsetStopLimit, refuse to generate more multis.
1172-
* If we're close to offsetStopLimit, emit a warning.
1173-
*
1174-
* Arbitrarily, we start emitting warnings when we're 20 segments or less
1175-
* from offsetStopLimit.
1176-
*
1177-
* Note we haven't updated the shared state yet, so if we fail at this
1178-
* point, the multixact ID we grabbed can still be used by the next guy.
1179-
*
1180-
* Note that there is no point in forcing autovacuum runs here: the
1181-
* multixact freeze settings would have to be reduced for that to have any
1182-
* effect.
1183-
*----------
1184-
*/
1185-
#define OFFSET_WARN_SEGMENTS 20
1186-
if (MultiXactState->oldestOffsetKnown &&
1187-
MultiXactOffsetWouldWrap(MultiXactState->offsetStopLimit, nextOffset,
1188-
nmembers))
1189-
{
1190-
/* see comment in the corresponding offsets wraparound case */
1191-
SendPostmasterSignal(PMSIGNAL_START_AUTOVAC_LAUNCHER);
1192-
1193-
ereport(ERROR,
1194-
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
1195-
errmsg("multixact \"members\" limit exceeded"),
1196-
errdetail_plural("This command would create a multixact with %u members, but the remaining space is only enough for %u member.",
1197-
"This command would create a multixact with %u members, but the remaining space is only enough for %u members.",
1198-
MultiXactState->offsetStopLimit - nextOffset - 1,
1199-
nmembers,
1200-
MultiXactState->offsetStopLimit - nextOffset - 1),
1201-
errhint("Execute a database-wide VACUUM in database with OID %u with reduced \"vacuum_multixact_freeze_min_age\" and \"vacuum_multixact_freeze_table_age\" settings.",
1202-
MultiXactState->oldestMultiXactDB)));
1203-
}
1204-
1205-
/*
1206-
* Check whether we should kick autovacuum into action, to prevent members
1207-
* wraparound. NB we use a much larger window to trigger autovacuum than
1208-
* just the warning limit. The warning is just a measure of last resort -
1209-
* this is in line with GetNewTransactionId's behaviour.
1210-
*/
1211-
if (!MultiXactState->oldestOffsetKnown ||
1212-
(MultiXactState->nextOffset - MultiXactState->oldestOffset
1213-
> MULTIXACT_MEMBER_SAFE_THRESHOLD))
1214-
{
1215-
/*
1216-
* To avoid swamping the postmaster with signals, we issue the autovac
1217-
* request only when crossing a segment boundary. With default
1218-
* compilation settings that's roughly after 50k members. This still
1219-
* gives plenty of chances before we get into real trouble.
1220-
*/
1221-
if ((MXOffsetToMemberPage(nextOffset) / SLRU_PAGES_PER_SEGMENT) !=
1222-
(MXOffsetToMemberPage(nextOffset + nmembers) / SLRU_PAGES_PER_SEGMENT))
1223-
SendPostmasterSignal(PMSIGNAL_START_AUTOVAC_LAUNCHER);
1224-
}
1225-
1226-
if (MultiXactState->oldestOffsetKnown &&
1227-
MultiXactOffsetWouldWrap(MultiXactState->offsetStopLimit,
1228-
nextOffset,
1229-
nmembers + MULTIXACT_MEMBERS_PER_PAGE * SLRU_PAGES_PER_SEGMENT * OFFSET_WARN_SEGMENTS))
1230-
ereport(WARNING,
1231-
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
1232-
errmsg_plural("database with OID %u must be vacuumed before %d more multixact member is used",
1233-
"database with OID %u must be vacuumed before %d more multixact members are used",
1234-
MultiXactState->offsetStopLimit - nextOffset + nmembers,
1235-
MultiXactState->oldestMultiXactDB,
1236-
MultiXactState->offsetStopLimit - nextOffset + nmembers),
1237-
errhint("Execute a database-wide VACUUM in that database with reduced \"vacuum_multixact_freeze_min_age\" and \"vacuum_multixact_freeze_table_age\" settings.")));
1238-
12391154
ExtendMultiXactMember(nextOffset, nmembers);
12401155

12411156
/*
@@ -2720,8 +2635,6 @@ SetOffsetVacuumLimit(bool is_startup)
27202635
MultiXactOffset nextOffset;
27212636
bool oldestOffsetKnown = false;
27222637
bool prevOldestOffsetKnown;
2723-
MultiXactOffset offsetStopLimit = 0;
2724-
MultiXactOffset prevOffsetStopLimit;
27252638

27262639
/*
27272640
* NB: Have to prevent concurrent truncation, we might otherwise try to
@@ -2736,7 +2649,6 @@ SetOffsetVacuumLimit(bool is_startup)
27362649
nextOffset = MultiXactState->nextOffset;
27372650
prevOldestOffsetKnown = MultiXactState->oldestOffsetKnown;
27382651
prevOldestOffset = MultiXactState->oldestOffset;
2739-
prevOffsetStopLimit = MultiXactState->offsetStopLimit;
27402652
Assert(MultiXactState->finishedStartup);
27412653
LWLockRelease(MultiXactGenLock);
27422654

@@ -2767,11 +2679,7 @@ SetOffsetVacuumLimit(bool is_startup)
27672679
oldestOffsetKnown =
27682680
find_multixact_start(oldestMultiXactId, &oldestOffset);
27692681

2770-
if (oldestOffsetKnown)
2771-
ereport(DEBUG1,
2772-
(errmsg_internal("oldest MultiXactId member is at offset %u",
2773-
oldestOffset)));
2774-
else
2682+
if (!oldestOffsetKnown)
27752683
ereport(LOG,
27762684
(errmsg("MultiXact member wraparound protections are disabled because oldest checkpointed MultiXact %u does not exist on disk",
27772685
oldestMultiXactId)));
@@ -2784,24 +2692,7 @@ SetOffsetVacuumLimit(bool is_startup)
27842692
* overrun of old data in the members SLRU area. We can only do so if the
27852693
* oldest offset is known though.
27862694
*/
2787-
if (oldestOffsetKnown)
2788-
{
2789-
/* move back to start of the corresponding segment */
2790-
offsetStopLimit = oldestOffset - (oldestOffset %
2791-
(MULTIXACT_MEMBERS_PER_PAGE * SLRU_PAGES_PER_SEGMENT));
2792-
2793-
/* always leave one segment before the wraparound point */
2794-
offsetStopLimit -= (MULTIXACT_MEMBERS_PER_PAGE * SLRU_PAGES_PER_SEGMENT);
2795-
2796-
if (!prevOldestOffsetKnown && !is_startup)
2797-
ereport(LOG,
2798-
(errmsg("MultiXact member wraparound protections are now enabled")));
2799-
2800-
ereport(DEBUG1,
2801-
(errmsg_internal("MultiXact member stop limit is now %u based on MultiXact %u",
2802-
offsetStopLimit, oldestMultiXactId)));
2803-
}
2804-
else if (prevOldestOffsetKnown)
2695+
if (prevOldestOffsetKnown)
28052696
{
28062697
/*
28072698
* If we failed to get the oldest offset this time, but we have a
@@ -2811,14 +2702,12 @@ SetOffsetVacuumLimit(bool is_startup)
28112702
*/
28122703
oldestOffset = prevOldestOffset;
28132704
oldestOffsetKnown = true;
2814-
offsetStopLimit = prevOffsetStopLimit;
28152705
}
28162706

28172707
/* Install the computed values */
28182708
LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);
28192709
MultiXactState->oldestOffset = oldestOffset;
28202710
MultiXactState->oldestOffsetKnown = oldestOffsetKnown;
2821-
MultiXactState->offsetStopLimit = offsetStopLimit;
28222711
LWLockRelease(MultiXactGenLock);
28232712

28242713
/*
@@ -2828,54 +2717,6 @@ SetOffsetVacuumLimit(bool is_startup)
28282717
(nextOffset - oldestOffset > MULTIXACT_MEMBER_SAFE_THRESHOLD);
28292718
}
28302719

2831-
/*
2832-
* Return whether adding "distance" to "start" would move past "boundary".
2833-
*
2834-
* We use this to determine whether the addition is "wrapping around" the
2835-
* boundary point, hence the name. The reason we don't want to use the regular
2836-
* 2^31-modulo arithmetic here is that we want to be able to use the whole of
2837-
* the 2^32-1 space here, allowing for more multixacts than would fit
2838-
* otherwise.
2839-
*/
2840-
static bool
2841-
MultiXactOffsetWouldWrap(MultiXactOffset boundary, MultiXactOffset start,
2842-
uint32 distance)
2843-
{
2844-
MultiXactOffset finish;
2845-
2846-
/*
2847-
* Note that offset number 0 is not used (see GetMultiXactIdMembers), so
2848-
* if the addition wraps around the UINT_MAX boundary, skip that value.
2849-
*/
2850-
finish = start + distance;
2851-
if (finish < start)
2852-
finish++;
2853-
2854-
/*-----------------------------------------------------------------------
2855-
* When the boundary is numerically greater than the starting point, any
2856-
* value numerically between the two is not wrapped:
2857-
*
2858-
* <----S----B---->
2859-
* [---) = F wrapped past B (and UINT_MAX)
2860-
* [---) = F not wrapped
2861-
* [----] = F wrapped past B
2862-
*
2863-
* When the boundary is numerically less than the starting point (i.e. the
2864-
* UINT_MAX wraparound occurs somewhere in between) then all values in
2865-
* between are wrapped:
2866-
*
2867-
* <----B----S---->
2868-
* [---) = F not wrapped past B (but wrapped past UINT_MAX)
2869-
* [---) = F wrapped past B (and UINT_MAX)
2870-
* [----] = F not wrapped
2871-
*-----------------------------------------------------------------------
2872-
*/
2873-
if (start < boundary)
2874-
return finish >= boundary || finish < start;
2875-
else
2876-
return finish >= boundary && finish < start;
2877-
}
2878-
28792720
/*
28802721
* Find the starting offset of the given MultiXactId.
28812722
*
@@ -2997,8 +2838,9 @@ MultiXactMemberFreezeThreshold(void)
29972838
* we try to eliminate from the system is based on how far we are past
29982839
* MULTIXACT_MEMBER_SAFE_THRESHOLD.
29992840
*/
3000-
fraction = (double) (members - MULTIXACT_MEMBER_SAFE_THRESHOLD) /
3001-
(MULTIXACT_MEMBER_DANGER_THRESHOLD - MULTIXACT_MEMBER_SAFE_THRESHOLD);
2841+
fraction = (double) (members - MULTIXACT_MEMBER_SAFE_THRESHOLD);
2842+
fraction /= (double) (MULTIXACT_MEMBER_DANGER_THRESHOLD - MULTIXACT_MEMBER_SAFE_THRESHOLD);
2843+
30022844
victim_multixacts = multixacts * fraction;
30032845

30042846
/* fraction could be > 1.0, but lowest possible freeze age is zero */
@@ -3343,7 +3185,7 @@ MultiXactIdPrecedesOrEquals(MultiXactId multi1, MultiXactId multi2)
33433185
static bool
33443186
MultiXactOffsetPrecedes(MultiXactOffset offset1, MultiXactOffset offset2)
33453187
{
3346-
int32 diff = (int32) (offset1 - offset2);
3188+
int64 diff = (int64) (offset1 - offset2);
33473189

33483190
return (diff < 0);
33493191
}

src/bin/pg_resetwal/pg_resetwal.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -266,7 +266,7 @@ main(int argc, char *argv[])
266266

267267
case 'O':
268268
errno = 0;
269-
set_mxoff = strtoul(optarg, &endptr, 0);
269+
set_mxoff = strtou64(optarg, &endptr, 0);
270270
if (endptr == optarg || *endptr != '\0' || errno != 0)
271271
{
272272
pg_log_error("invalid argument for option %s", "-O");

src/bin/pg_resetwal/t/001_basic.pl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,7 @@ sub get_slru_files
213213
sprintf("%d,%d", hex($files[0]) == 0 ? 3 : hex($files[0]), hex($files[-1]));
214214

215215
@files = get_slru_files('pg_multixact/offsets');
216-
$mult = 32 * $blcksz / 4;
216+
$mult = 32 * $blcksz / 8;
217217
# --multixact-ids argument is "new,old"
218218
push @cmd,
219219
'--multixact-ids' => sprintf("%d,%d",

src/include/access/multixact.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727

2828
#define MultiXactIdIsValid(multi) ((multi) != InvalidMultiXactId)
2929

30-
#define MaxMultiXactOffset ((MultiXactOffset) 0xFFFFFFFF)
30+
#define MaxMultiXactOffset UINT64CONST(0xFFFFFFFFFFFFFFFF)
3131

3232
/*
3333
* Possible multixact lock modes ("status"). The first four modes are for

src/include/c.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -632,7 +632,7 @@ typedef uint32 SubTransactionId;
632632
/* MultiXactId must be equivalent to TransactionId, to fit in t_xmax */
633633
typedef TransactionId MultiXactId;
634634

635-
typedef uint32 MultiXactOffset;
635+
typedef uint64 MultiXactOffset;
636636

637637
typedef uint32 CommandId;
638638

0 commit comments

Comments
 (0)