Coverage Report

Created: 2025-08-12 06:43

/src/postgres/src/backend/access/transam/multixact.c
Line
Count
Source (jump to first uncovered line)
1
/*-------------------------------------------------------------------------
2
 *
3
 * multixact.c
4
 *    PostgreSQL multi-transaction-log manager
5
 *
6
 * The pg_multixact manager is a pg_xact-like manager that stores an array of
7
 * MultiXactMember for each MultiXactId.  It is a fundamental part of the
8
 * shared-row-lock implementation.  Each MultiXactMember is comprised of a
9
 * TransactionId and a set of flag bits.  The name is a bit historical:
10
 * originally, a MultiXactId consisted of more than one TransactionId (except
11
 * in rare corner cases), hence "multi".  Nowadays, however, it's perfectly
12
 * legitimate to have MultiXactIds that only include a single Xid.
13
 *
14
 * The meaning of the flag bits is opaque to this module, but they are mostly
15
 * used in heapam.c to identify lock modes that each of the member transactions
16
 * is holding on any given tuple.  This module just contains support to store
17
 * and retrieve the arrays.
18
 *
19
 * We use two SLRU areas, one for storing the offsets at which the data
20
 * starts for each MultiXactId in the other one.  This trick allows us to
21
 * store variable length arrays of TransactionIds.  (We could alternatively
22
 * use one area containing counts and TransactionIds, with valid MultiXactId
23
 * values pointing at slots containing counts; but that way seems less robust
24
 * since it would get completely confused if someone inquired about a bogus
25
 * MultiXactId that pointed to an intermediate slot containing an XID.)
26
 *
27
 * XLOG interactions: this module generates a record whenever a new OFFSETs or
28
 * MEMBERs page is initialized to zeroes, as well as an
29
 * XLOG_MULTIXACT_CREATE_ID record whenever a new MultiXactId is defined.
30
 * This module ignores the WAL rule "write xlog before data," because it
31
 * suffices that actions recording a MultiXactId in a heap xmax do follow that
32
 * rule.  The only way for the MXID to be referenced from any data page is for
33
 * heap_lock_tuple() or heap_update() to have put it there, and each generates
34
 * an XLOG record that must follow ours.  The normal LSN interlock between the
35
 * data page and that XLOG record will ensure that our XLOG record reaches
36
 * disk first.  If the SLRU members/offsets data reaches disk sooner than the
37
 * XLOG records, we do not care; after recovery, no xmax will refer to it.  On
38
 * the flip side, to ensure that all referenced entries _do_ reach disk, this
39
 * module's XLOG records completely rebuild the data entered since the last
40
 * checkpoint.  We flush and sync all dirty OFFSETs and MEMBERs pages to disk
41
 * before each checkpoint is considered complete.
42
 *
43
 * Like clog.c, and unlike subtrans.c, we have to preserve state across
44
 * crashes and ensure that MXID and offset numbering increases monotonically
45
 * across a crash.  We do this in the same way as it's done for transaction
46
 * IDs: the WAL record is guaranteed to contain evidence of every MXID we
47
 * could need to worry about, and we just make sure that at the end of
48
 * replay, the next-MXID and next-offset counters are at least as large as
49
 * anything we saw during replay.
50
 *
51
 * We are able to remove segments no longer necessary by carefully tracking
52
 * each table's used values: during vacuum, any multixact older than a certain
53
 * value is removed; the cutoff value is stored in pg_class.  The minimum value
54
 * across all tables in each database is stored in pg_database, and the global
55
 * minimum across all databases is part of pg_control and is kept in shared
56
 * memory.  Whenever that minimum is advanced, the SLRUs are truncated.
57
 *
58
 * When new multixactid values are to be created, care is taken that the
59
 * counter does not fall within the wraparound horizon considering the global
60
 * minimum value.
61
 *
62
 * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
63
 * Portions Copyright (c) 1994, Regents of the University of California
64
 *
65
 * src/backend/access/transam/multixact.c
66
 *
67
 *-------------------------------------------------------------------------
68
 */
69
#include "postgres.h"
70
71
#include "access/multixact.h"
72
#include "access/slru.h"
73
#include "access/transam.h"
74
#include "access/twophase.h"
75
#include "access/twophase_rmgr.h"
76
#include "access/xact.h"
77
#include "access/xlog.h"
78
#include "access/xloginsert.h"
79
#include "access/xlogutils.h"
80
#include "commands/dbcommands.h"
81
#include "funcapi.h"
82
#include "lib/ilist.h"
83
#include "miscadmin.h"
84
#include "pg_trace.h"
85
#include "pgstat.h"
86
#include "postmaster/autovacuum.h"
87
#include "storage/pmsignal.h"
88
#include "storage/proc.h"
89
#include "storage/procarray.h"
90
#include "utils/fmgrprotos.h"
91
#include "utils/guc_hooks.h"
92
#include "utils/injection_point.h"
93
#include "utils/memutils.h"
94
95
96
/*
97
 * Defines for MultiXactOffset page sizes.  A page is the same BLCKSZ as is
98
 * 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).
107
 */
108
109
/* We need four bytes per offset */
110
0
#define MULTIXACT_OFFSETS_PER_PAGE (BLCKSZ / sizeof(MultiXactOffset))
111
112
static inline int64
113
MultiXactIdToOffsetPage(MultiXactId multi)
114
0
{
115
0
  return multi / MULTIXACT_OFFSETS_PER_PAGE;
116
0
}
117
118
static inline int
119
MultiXactIdToOffsetEntry(MultiXactId multi)
120
0
{
121
0
  return multi % MULTIXACT_OFFSETS_PER_PAGE;
122
0
}
123
124
static inline int64
125
MultiXactIdToOffsetSegment(MultiXactId multi)
126
0
{
127
0
  return MultiXactIdToOffsetPage(multi) / SLRU_PAGES_PER_SEGMENT;
128
0
}
129
130
/*
131
 * The situation for members is a bit more complex: we store one byte of
132
 * additional flag bits for each TransactionId.  To do this without getting
133
 * into alignment issues, we store four bytes of flags, and then the
134
 * corresponding 4 Xids.  Each such 5-word (20-byte) set we call a "group", and
135
 * are stored as a whole in pages.  Thus, with 8kB BLCKSZ, we keep 409 groups
136
 * per page.  This wastes 12 bytes per page, but that's OK -- simplicity (and
137
 * performance) trumps space efficiency here.
138
 *
139
 * Note that the "offset" macros work with byte offset, not array indexes, so
140
 * arithmetic must be done using "char *" pointers.
141
 */
142
/* We need eight bits per xact, so one xact fits in a byte */
143
0
#define MXACT_MEMBER_BITS_PER_XACT      8
144
0
#define MXACT_MEMBER_FLAGS_PER_BYTE     1
145
0
#define MXACT_MEMBER_XACT_BITMASK ((1 << MXACT_MEMBER_BITS_PER_XACT) - 1)
146
147
/* how many full bytes of flags are there in a group? */
148
0
#define MULTIXACT_FLAGBYTES_PER_GROUP   4
149
#define MULTIXACT_MEMBERS_PER_MEMBERGROUP \
150
0
  (MULTIXACT_FLAGBYTES_PER_GROUP * MXACT_MEMBER_FLAGS_PER_BYTE)
151
/* size in bytes of a complete group */
152
#define MULTIXACT_MEMBERGROUP_SIZE \
153
0
  (sizeof(TransactionId) * MULTIXACT_MEMBERS_PER_MEMBERGROUP + MULTIXACT_FLAGBYTES_PER_GROUP)
154
0
#define MULTIXACT_MEMBERGROUPS_PER_PAGE (BLCKSZ / MULTIXACT_MEMBERGROUP_SIZE)
155
#define MULTIXACT_MEMBERS_PER_PAGE  \
156
0
  (MULTIXACT_MEMBERGROUPS_PER_PAGE * MULTIXACT_MEMBERS_PER_MEMBERGROUP)
157
158
/*
159
 * Because the number of items per page is not a divisor of the last item
160
 * number (member 0xFFFFFFFF), the last segment does not use the maximum number
161
 * of pages, and moreover the last used page therein does not use the same
162
 * number of items as previous pages.  (Another way to say it is that the
163
 * 0xFFFFFFFF member is somewhere in the middle of the last page, so the page
164
 * has some empty space after that item.)
165
 *
166
 * This constant is the number of members in the last page of the last segment.
167
 */
168
#define MAX_MEMBERS_IN_LAST_MEMBERS_PAGE \
169
0
    ((uint32) ((0xFFFFFFFF % MULTIXACT_MEMBERS_PER_PAGE) + 1))
170
171
/* page in which a member is to be found */
172
static inline int64
173
MXOffsetToMemberPage(MultiXactOffset offset)
174
0
{
175
0
  return offset / MULTIXACT_MEMBERS_PER_PAGE;
176
0
}
177
178
static inline int64
179
MXOffsetToMemberSegment(MultiXactOffset offset)
180
0
{
181
0
  return MXOffsetToMemberPage(offset) / SLRU_PAGES_PER_SEGMENT;
182
0
}
183
184
/* Location (byte offset within page) of flag word for a given member */
185
static inline int
186
MXOffsetToFlagsOffset(MultiXactOffset offset)
187
0
{
188
0
  MultiXactOffset group = offset / MULTIXACT_MEMBERS_PER_MEMBERGROUP;
189
0
  int     grouponpg = group % MULTIXACT_MEMBERGROUPS_PER_PAGE;
190
0
  int     byteoff = grouponpg * MULTIXACT_MEMBERGROUP_SIZE;
191
192
0
  return byteoff;
193
0
}
194
195
static inline int
196
MXOffsetToFlagsBitShift(MultiXactOffset offset)
197
0
{
198
0
  int     member_in_group = offset % MULTIXACT_MEMBERS_PER_MEMBERGROUP;
199
0
  int     bshift = member_in_group * MXACT_MEMBER_BITS_PER_XACT;
200
201
0
  return bshift;
202
0
}
203
204
/* Location (byte offset within page) of TransactionId of given member */
205
static inline int
206
MXOffsetToMemberOffset(MultiXactOffset offset)
207
0
{
208
0
  int     member_in_group = offset % MULTIXACT_MEMBERS_PER_MEMBERGROUP;
209
210
0
  return MXOffsetToFlagsOffset(offset) +
211
0
    MULTIXACT_FLAGBYTES_PER_GROUP +
212
0
    member_in_group * sizeof(TransactionId);
213
0
}
214
215
/* Multixact members wraparound thresholds. */
216
0
#define MULTIXACT_MEMBER_SAFE_THRESHOLD   (MaxMultiXactOffset / 2)
217
#define MULTIXACT_MEMBER_DANGER_THRESHOLD \
218
0
  (MaxMultiXactOffset - MaxMultiXactOffset / 4)
219
220
static inline MultiXactId
221
PreviousMultiXactId(MultiXactId multi)
222
0
{
223
0
  return multi == FirstMultiXactId ? MaxMultiXactId : multi - 1;
224
0
}
225
226
/*
227
 * Links to shared-memory data structures for MultiXact control
228
 */
229
static SlruCtlData MultiXactOffsetCtlData;
230
static SlruCtlData MultiXactMemberCtlData;
231
232
0
#define MultiXactOffsetCtl  (&MultiXactOffsetCtlData)
233
0
#define MultiXactMemberCtl  (&MultiXactMemberCtlData)
234
235
/*
236
 * MultiXact state shared across all backends.  All this state is protected
237
 * by MultiXactGenLock.  (We also use SLRU bank's lock of MultiXactOffset and
238
 * MultiXactMember to guard accesses to the two sets of SLRU buffers.  For
239
 * concurrency's sake, we avoid holding more than one of these locks at a
240
 * time.)
241
 */
242
typedef struct MultiXactStateData
243
{
244
  /* next-to-be-assigned MultiXactId */
245
  MultiXactId nextMXact;
246
247
  /* next-to-be-assigned offset */
248
  MultiXactOffset nextOffset;
249
250
  /* Have we completed multixact startup? */
251
  bool    finishedStartup;
252
253
  /*
254
   * Oldest multixact that is still potentially referenced by a relation.
255
   * Anything older than this should not be consulted.  These values are
256
   * updated by vacuum.
257
   */
258
  MultiXactId oldestMultiXactId;
259
  Oid     oldestMultiXactDB;
260
261
  /*
262
   * Oldest multixact offset that is potentially referenced by a multixact
263
   * referenced by a relation.  We don't always know this value, so there's
264
   * a flag here to indicate whether or not we currently do.
265
   */
266
  MultiXactOffset oldestOffset;
267
  bool    oldestOffsetKnown;
268
269
  /* support for anti-wraparound measures */
270
  MultiXactId multiVacLimit;
271
  MultiXactId multiWarnLimit;
272
  MultiXactId multiStopLimit;
273
  MultiXactId multiWrapLimit;
274
275
  /* support for members anti-wraparound measures */
276
  MultiXactOffset offsetStopLimit;  /* known if oldestOffsetKnown */
277
278
  /*
279
   * This is used to sleep until a multixact offset is written when we want
280
   * to create the next one.
281
   */
282
  ConditionVariable nextoff_cv;
283
284
  /*
285
   * Per-backend data starts here.  We have two arrays stored in the area
286
   * immediately following the MultiXactStateData struct. Each is indexed by
287
   * ProcNumber.
288
   *
289
   * In both arrays, there's a slot for all normal backends
290
   * (0..MaxBackends-1) followed by a slot for max_prepared_xacts prepared
291
   * transactions.
292
   *
293
   * OldestMemberMXactId[k] is the oldest MultiXactId each backend's current
294
   * transaction(s) could possibly be a member of, or InvalidMultiXactId
295
   * when the backend has no live transaction that could possibly be a
296
   * member of a MultiXact.  Each backend sets its entry to the current
297
   * nextMXact counter just before first acquiring a shared lock in a given
298
   * transaction, and clears it at transaction end. (This works because only
299
   * during or after acquiring a shared lock could an XID possibly become a
300
   * member of a MultiXact, and that MultiXact would have to be created
301
   * during or after the lock acquisition.)
302
   *
303
   * OldestVisibleMXactId[k] is the oldest MultiXactId each backend's
304
   * current transaction(s) think is potentially live, or InvalidMultiXactId
305
   * when not in a transaction or not in a transaction that's paid any
306
   * attention to MultiXacts yet.  This is computed when first needed in a
307
   * given transaction, and cleared at transaction end.  We can compute it
308
   * as the minimum of the valid OldestMemberMXactId[] entries at the time
309
   * we compute it (using nextMXact if none are valid).  Each backend is
310
   * required not to attempt to access any SLRU data for MultiXactIds older
311
   * than its own OldestVisibleMXactId[] setting; this is necessary because
312
   * the relevant SLRU data can be concurrently truncated away.
313
   *
314
   * The oldest valid value among all of the OldestMemberMXactId[] and
315
   * OldestVisibleMXactId[] entries is considered by vacuum as the earliest
316
   * possible value still having any live member transaction -- OldestMxact.
317
   * Any value older than that is typically removed from tuple headers, or
318
   * "frozen" via being replaced with a new xmax.  VACUUM can sometimes even
319
   * remove an individual MultiXact xmax whose value is >= its OldestMxact
320
   * cutoff, though typically only when no individual member XID is still
321
   * running.  See FreezeMultiXactId for full details.
322
   *
323
   * Whenever VACUUM advances relminmxid, then either its OldestMxact cutoff
324
   * or the oldest extant Multi remaining in the table is used as the new
325
   * pg_class.relminmxid value (whichever is earlier).  The minimum of all
326
   * relminmxid values in each database is stored in pg_database.datminmxid.
327
   * In turn, the minimum of all of those values is stored in pg_control.
328
   * This is used as the truncation point for pg_multixact when unneeded
329
   * segments get removed by vac_truncate_clog() during vacuuming.
330
   */
331
  MultiXactId perBackendXactIds[FLEXIBLE_ARRAY_MEMBER];
332
} MultiXactStateData;
333
334
/*
335
 * Size of OldestMemberMXactId and OldestVisibleMXactId arrays.
336
 */
337
0
#define MaxOldestSlot (MaxBackends + max_prepared_xacts)
338
339
/* Pointers to the state data in shared memory */
340
static MultiXactStateData *MultiXactState;
341
static MultiXactId *OldestMemberMXactId;
342
static MultiXactId *OldestVisibleMXactId;
343
344
345
/*
346
 * Definitions for the backend-local MultiXactId cache.
347
 *
348
 * We use this cache to store known MultiXacts, so we don't need to go to
349
 * SLRU areas every time.
350
 *
351
 * The cache lasts for the duration of a single transaction, the rationale
352
 * for this being that most entries will contain our own TransactionId and
353
 * so they will be uninteresting by the time our next transaction starts.
354
 * (XXX not clear that this is correct --- other members of the MultiXact
355
 * could hang around longer than we did.  However, it's not clear what a
356
 * better policy for flushing old cache entries would be.)  FIXME actually
357
 * this is plain wrong now that multixact's may contain update Xids.
358
 *
359
 * We allocate the cache entries in a memory context that is deleted at
360
 * transaction end, so we don't need to do retail freeing of entries.
361
 */
362
typedef struct mXactCacheEnt
363
{
364
  MultiXactId multi;
365
  int     nmembers;
366
  dlist_node  node;
367
  MultiXactMember members[FLEXIBLE_ARRAY_MEMBER];
368
} mXactCacheEnt;
369
370
0
#define MAX_CACHE_ENTRIES 256
371
static dclist_head MXactCache = DCLIST_STATIC_INIT(MXactCache);
372
static MemoryContext MXactContext = NULL;
373
374
#ifdef MULTIXACT_DEBUG
375
#define debug_elog2(a,b) elog(a,b)
376
#define debug_elog3(a,b,c) elog(a,b,c)
377
#define debug_elog4(a,b,c,d) elog(a,b,c,d)
378
#define debug_elog5(a,b,c,d,e) elog(a,b,c,d,e)
379
#define debug_elog6(a,b,c,d,e,f) elog(a,b,c,d,e,f)
380
#else
381
#define debug_elog2(a,b)
382
#define debug_elog3(a,b,c)
383
#define debug_elog4(a,b,c,d)
384
#define debug_elog5(a,b,c,d,e)
385
#define debug_elog6(a,b,c,d,e,f)
386
#endif
387
388
/* internal MultiXactId management */
389
static void MultiXactIdSetOldestVisible(void);
390
static void RecordNewMultiXact(MultiXactId multi, MultiXactOffset offset,
391
                 int nmembers, MultiXactMember *members);
392
static MultiXactId GetNewMultiXactId(int nmembers, MultiXactOffset *offset);
393
394
/* MultiXact cache management */
395
static int  mxactMemberComparator(const void *arg1, const void *arg2);
396
static MultiXactId mXactCacheGetBySet(int nmembers, MultiXactMember *members);
397
static int  mXactCacheGetById(MultiXactId multi, MultiXactMember **members);
398
static void mXactCachePut(MultiXactId multi, int nmembers,
399
              MultiXactMember *members);
400
401
static char *mxstatus_to_string(MultiXactStatus status);
402
403
/* management of SLRU infrastructure */
404
static bool MultiXactOffsetPagePrecedes(int64 page1, int64 page2);
405
static bool MultiXactMemberPagePrecedes(int64 page1, int64 page2);
406
static bool MultiXactOffsetPrecedes(MultiXactOffset offset1,
407
                  MultiXactOffset offset2);
408
static void ExtendMultiXactOffset(MultiXactId multi);
409
static void ExtendMultiXactMember(MultiXactOffset offset, int nmembers);
410
static bool MultiXactOffsetWouldWrap(MultiXactOffset boundary,
411
                   MultiXactOffset start, uint32 distance);
412
static bool SetOffsetVacuumLimit(bool is_startup);
413
static bool find_multixact_start(MultiXactId multi, MultiXactOffset *result);
414
static void WriteMTruncateXlogRec(Oid oldestMultiDB,
415
                  MultiXactId startTruncOff,
416
                  MultiXactId endTruncOff,
417
                  MultiXactOffset startTruncMemb,
418
                  MultiXactOffset endTruncMemb);
419
420
421
/*
422
 * MultiXactIdCreate
423
 *    Construct a MultiXactId representing two TransactionIds.
424
 *
425
 * The two XIDs must be different, or be requesting different statuses.
426
 *
427
 * NB - we don't worry about our local MultiXactId cache here, because that
428
 * is handled by the lower-level routines.
429
 */
430
MultiXactId
431
MultiXactIdCreate(TransactionId xid1, MultiXactStatus status1,
432
          TransactionId xid2, MultiXactStatus status2)
433
0
{
434
0
  MultiXactId newMulti;
435
0
  MultiXactMember members[2];
436
437
0
  Assert(TransactionIdIsValid(xid1));
438
0
  Assert(TransactionIdIsValid(xid2));
439
440
0
  Assert(!TransactionIdEquals(xid1, xid2) || (status1 != status2));
441
442
  /* MultiXactIdSetOldestMember() must have been called already. */
443
0
  Assert(MultiXactIdIsValid(OldestMemberMXactId[MyProcNumber]));
444
445
  /*
446
   * Note: unlike MultiXactIdExpand, we don't bother to check that both XIDs
447
   * are still running.  In typical usage, xid2 will be our own XID and the
448
   * caller just did a check on xid1, so it'd be wasted effort.
449
   */
450
451
0
  members[0].xid = xid1;
452
0
  members[0].status = status1;
453
0
  members[1].xid = xid2;
454
0
  members[1].status = status2;
455
456
0
  newMulti = MultiXactIdCreateFromMembers(2, members);
457
458
0
  debug_elog3(DEBUG2, "Create: %s",
459
0
        mxid_to_string(newMulti, 2, members));
460
461
0
  return newMulti;
462
0
}
463
464
/*
465
 * MultiXactIdExpand
466
 *    Add a TransactionId to a pre-existing MultiXactId.
467
 *
468
 * If the TransactionId is already a member of the passed MultiXactId with the
469
 * same status, just return it as-is.
470
 *
471
 * Note that we do NOT actually modify the membership of a pre-existing
472
 * MultiXactId; instead we create a new one.  This is necessary to avoid
473
 * a race condition against code trying to wait for one MultiXactId to finish;
474
 * see notes in heapam.c.
475
 *
476
 * NB - we don't worry about our local MultiXactId cache here, because that
477
 * is handled by the lower-level routines.
478
 *
479
 * Note: It is critical that MultiXactIds that come from an old cluster (i.e.
480
 * one upgraded by pg_upgrade from a cluster older than this feature) are not
481
 * passed in.
482
 */
483
MultiXactId
484
MultiXactIdExpand(MultiXactId multi, TransactionId xid, MultiXactStatus status)
485
0
{
486
0
  MultiXactId newMulti;
487
0
  MultiXactMember *members;
488
0
  MultiXactMember *newMembers;
489
0
  int     nmembers;
490
0
  int     i;
491
0
  int     j;
492
493
0
  Assert(MultiXactIdIsValid(multi));
494
0
  Assert(TransactionIdIsValid(xid));
495
496
  /* MultiXactIdSetOldestMember() must have been called already. */
497
0
  Assert(MultiXactIdIsValid(OldestMemberMXactId[MyProcNumber]));
498
499
0
  debug_elog5(DEBUG2, "Expand: received multi %u, xid %u status %s",
500
0
        multi, xid, mxstatus_to_string(status));
501
502
  /*
503
   * Note: we don't allow for old multis here.  The reason is that the only
504
   * caller of this function does a check that the multixact is no longer
505
   * running.
506
   */
507
0
  nmembers = GetMultiXactIdMembers(multi, &members, false, false);
508
509
0
  if (nmembers < 0)
510
0
  {
511
0
    MultiXactMember member;
512
513
    /*
514
     * The MultiXactId is obsolete.  This can only happen if all the
515
     * MultiXactId members stop running between the caller checking and
516
     * passing it to us.  It would be better to return that fact to the
517
     * caller, but it would complicate the API and it's unlikely to happen
518
     * too often, so just deal with it by creating a singleton MultiXact.
519
     */
520
0
    member.xid = xid;
521
0
    member.status = status;
522
0
    newMulti = MultiXactIdCreateFromMembers(1, &member);
523
524
0
    debug_elog4(DEBUG2, "Expand: %u has no members, create singleton %u",
525
0
          multi, newMulti);
526
0
    return newMulti;
527
0
  }
528
529
  /*
530
   * If the TransactionId is already a member of the MultiXactId with the
531
   * same status, just return the existing MultiXactId.
532
   */
533
0
  for (i = 0; i < nmembers; i++)
534
0
  {
535
0
    if (TransactionIdEquals(members[i].xid, xid) &&
536
0
      (members[i].status == status))
537
0
    {
538
0
      debug_elog4(DEBUG2, "Expand: %u is already a member of %u",
539
0
            xid, multi);
540
0
      pfree(members);
541
0
      return multi;
542
0
    }
543
0
  }
544
545
  /*
546
   * Determine which of the members of the MultiXactId are still of
547
   * interest. This is any running transaction, and also any transaction
548
   * that grabbed something stronger than just a lock and was committed. (An
549
   * update that aborted is of no interest here; and having more than one
550
   * update Xid in a multixact would cause errors elsewhere.)
551
   *
552
   * Removing dead members is not just an optimization: freezing of tuples
553
   * whose Xmax are multis depends on this behavior.
554
   *
555
   * Note we have the same race condition here as above: j could be 0 at the
556
   * end of the loop.
557
   */
558
0
  newMembers = (MultiXactMember *)
559
0
    palloc(sizeof(MultiXactMember) * (nmembers + 1));
560
561
0
  for (i = 0, j = 0; i < nmembers; i++)
562
0
  {
563
0
    if (TransactionIdIsInProgress(members[i].xid) ||
564
0
      (ISUPDATE_from_mxstatus(members[i].status) &&
565
0
       TransactionIdDidCommit(members[i].xid)))
566
0
    {
567
0
      newMembers[j].xid = members[i].xid;
568
0
      newMembers[j++].status = members[i].status;
569
0
    }
570
0
  }
571
572
0
  newMembers[j].xid = xid;
573
0
  newMembers[j++].status = status;
574
0
  newMulti = MultiXactIdCreateFromMembers(j, newMembers);
575
576
0
  pfree(members);
577
0
  pfree(newMembers);
578
579
0
  debug_elog3(DEBUG2, "Expand: returning new multi %u", newMulti);
580
581
0
  return newMulti;
582
0
}
583
584
/*
585
 * MultiXactIdIsRunning
586
 *    Returns whether a MultiXactId is "running".
587
 *
588
 * We return true if at least one member of the given MultiXactId is still
589
 * running.  Note that a "false" result is certain not to change,
590
 * because it is not legal to add members to an existing MultiXactId.
591
 *
592
 * Caller is expected to have verified that the multixact does not come from
593
 * a pg_upgraded share-locked tuple.
594
 */
595
bool
596
MultiXactIdIsRunning(MultiXactId multi, bool isLockOnly)
597
0
{
598
0
  MultiXactMember *members;
599
0
  int     nmembers;
600
0
  int     i;
601
602
0
  debug_elog3(DEBUG2, "IsRunning %u?", multi);
603
604
  /*
605
   * "false" here means we assume our callers have checked that the given
606
   * multi cannot possibly come from a pg_upgraded database.
607
   */
608
0
  nmembers = GetMultiXactIdMembers(multi, &members, false, isLockOnly);
609
610
0
  if (nmembers <= 0)
611
0
  {
612
0
    debug_elog2(DEBUG2, "IsRunning: no members");
613
0
    return false;
614
0
  }
615
616
  /*
617
   * Checking for myself is cheap compared to looking in shared memory;
618
   * return true if any live subtransaction of the current top-level
619
   * transaction is a member.
620
   *
621
   * This is not needed for correctness, it's just a fast path.
622
   */
623
0
  for (i = 0; i < nmembers; i++)
624
0
  {
625
0
    if (TransactionIdIsCurrentTransactionId(members[i].xid))
626
0
    {
627
0
      debug_elog3(DEBUG2, "IsRunning: I (%d) am running!", i);
628
0
      pfree(members);
629
0
      return true;
630
0
    }
631
0
  }
632
633
  /*
634
   * This could be made faster by having another entry point in procarray.c,
635
   * walking the PGPROC array only once for all the members.  But in most
636
   * cases nmembers should be small enough that it doesn't much matter.
637
   */
638
0
  for (i = 0; i < nmembers; i++)
639
0
  {
640
0
    if (TransactionIdIsInProgress(members[i].xid))
641
0
    {
642
0
      debug_elog4(DEBUG2, "IsRunning: member %d (%u) is running",
643
0
            i, members[i].xid);
644
0
      pfree(members);
645
0
      return true;
646
0
    }
647
0
  }
648
649
0
  pfree(members);
650
651
0
  debug_elog3(DEBUG2, "IsRunning: %u is not running", multi);
652
653
0
  return false;
654
0
}
655
656
/*
657
 * MultiXactIdSetOldestMember
658
 *    Save the oldest MultiXactId this transaction could be a member of.
659
 *
660
 * We set the OldestMemberMXactId for a given transaction the first time it's
661
 * going to do some operation that might require a MultiXactId (tuple lock,
662
 * update or delete).  We need to do this even if we end up using a
663
 * TransactionId instead of a MultiXactId, because there is a chance that
664
 * another transaction would add our XID to a MultiXactId.
665
 *
666
 * The value to set is the next-to-be-assigned MultiXactId, so this is meant to
667
 * be called just before doing any such possibly-MultiXactId-able operation.
668
 */
669
void
670
MultiXactIdSetOldestMember(void)
671
0
{
672
0
  if (!MultiXactIdIsValid(OldestMemberMXactId[MyProcNumber]))
673
0
  {
674
0
    MultiXactId nextMXact;
675
676
    /*
677
     * You might think we don't need to acquire a lock here, since
678
     * fetching and storing of TransactionIds is probably atomic, but in
679
     * fact we do: suppose we pick up nextMXact and then lose the CPU for
680
     * a long time.  Someone else could advance nextMXact, and then
681
     * another someone else could compute an OldestVisibleMXactId that
682
     * would be after the value we are going to store when we get control
683
     * back.  Which would be wrong.
684
     *
685
     * Note that a shared lock is sufficient, because it's enough to stop
686
     * someone from advancing nextMXact; and nobody else could be trying
687
     * to write to our OldestMember entry, only reading (and we assume
688
     * storing it is atomic.)
689
     */
690
0
    LWLockAcquire(MultiXactGenLock, LW_SHARED);
691
692
    /*
693
     * We have to beware of the possibility that nextMXact is in the
694
     * wrapped-around state.  We don't fix the counter itself here, but we
695
     * must be sure to store a valid value in our array entry.
696
     */
697
0
    nextMXact = MultiXactState->nextMXact;
698
0
    if (nextMXact < FirstMultiXactId)
699
0
      nextMXact = FirstMultiXactId;
700
701
0
    OldestMemberMXactId[MyProcNumber] = nextMXact;
702
703
0
    LWLockRelease(MultiXactGenLock);
704
705
0
    debug_elog4(DEBUG2, "MultiXact: setting OldestMember[%d] = %u",
706
0
          MyProcNumber, nextMXact);
707
0
  }
708
0
}
709
710
/*
711
 * MultiXactIdSetOldestVisible
712
 *    Save the oldest MultiXactId this transaction considers possibly live.
713
 *
714
 * We set the OldestVisibleMXactId for a given transaction the first time
715
 * it's going to inspect any MultiXactId.  Once we have set this, we are
716
 * guaranteed that SLRU data for MultiXactIds >= our own OldestVisibleMXactId
717
 * won't be truncated away.
718
 *
719
 * The value to set is the oldest of nextMXact and all the valid per-backend
720
 * OldestMemberMXactId[] entries.  Because of the locking we do, we can be
721
 * certain that no subsequent call to MultiXactIdSetOldestMember can set
722
 * an OldestMemberMXactId[] entry older than what we compute here.  Therefore
723
 * there is no live transaction, now or later, that can be a member of any
724
 * MultiXactId older than the OldestVisibleMXactId we compute here.
725
 */
726
static void
727
MultiXactIdSetOldestVisible(void)
728
0
{
729
0
  if (!MultiXactIdIsValid(OldestVisibleMXactId[MyProcNumber]))
730
0
  {
731
0
    MultiXactId oldestMXact;
732
0
    int     i;
733
734
0
    LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);
735
736
    /*
737
     * We have to beware of the possibility that nextMXact is in the
738
     * wrapped-around state.  We don't fix the counter itself here, but we
739
     * must be sure to store a valid value in our array entry.
740
     */
741
0
    oldestMXact = MultiXactState->nextMXact;
742
0
    if (oldestMXact < FirstMultiXactId)
743
0
      oldestMXact = FirstMultiXactId;
744
745
0
    for (i = 0; i < MaxOldestSlot; i++)
746
0
    {
747
0
      MultiXactId thisoldest = OldestMemberMXactId[i];
748
749
0
      if (MultiXactIdIsValid(thisoldest) &&
750
0
        MultiXactIdPrecedes(thisoldest, oldestMXact))
751
0
        oldestMXact = thisoldest;
752
0
    }
753
754
0
    OldestVisibleMXactId[MyProcNumber] = oldestMXact;
755
756
0
    LWLockRelease(MultiXactGenLock);
757
758
0
    debug_elog4(DEBUG2, "MultiXact: setting OldestVisible[%d] = %u",
759
0
          MyProcNumber, oldestMXact);
760
0
  }
761
0
}
762
763
/*
764
 * ReadNextMultiXactId
765
 *    Return the next MultiXactId to be assigned, but don't allocate it
766
 */
767
MultiXactId
768
ReadNextMultiXactId(void)
769
0
{
770
0
  MultiXactId mxid;
771
772
  /* XXX we could presumably do this without a lock. */
773
0
  LWLockAcquire(MultiXactGenLock, LW_SHARED);
774
0
  mxid = MultiXactState->nextMXact;
775
0
  LWLockRelease(MultiXactGenLock);
776
777
0
  if (mxid < FirstMultiXactId)
778
0
    mxid = FirstMultiXactId;
779
780
0
  return mxid;
781
0
}
782
783
/*
784
 * ReadMultiXactIdRange
785
 *    Get the range of IDs that may still be referenced by a relation.
786
 */
787
void
788
ReadMultiXactIdRange(MultiXactId *oldest, MultiXactId *next)
789
0
{
790
0
  LWLockAcquire(MultiXactGenLock, LW_SHARED);
791
0
  *oldest = MultiXactState->oldestMultiXactId;
792
0
  *next = MultiXactState->nextMXact;
793
0
  LWLockRelease(MultiXactGenLock);
794
795
0
  if (*oldest < FirstMultiXactId)
796
0
    *oldest = FirstMultiXactId;
797
0
  if (*next < FirstMultiXactId)
798
0
    *next = FirstMultiXactId;
799
0
}
800
801
802
/*
803
 * MultiXactIdCreateFromMembers
804
 *    Make a new MultiXactId from the specified set of members
805
 *
806
 * Make XLOG, SLRU and cache entries for a new MultiXactId, recording the
807
 * given TransactionIds as members.  Returns the newly created MultiXactId.
808
 *
809
 * NB: the passed members[] array will be sorted in-place.
810
 */
811
MultiXactId
812
MultiXactIdCreateFromMembers(int nmembers, MultiXactMember *members)
813
0
{
814
0
  MultiXactId multi;
815
0
  MultiXactOffset offset;
816
0
  xl_multixact_create xlrec;
817
818
0
  debug_elog3(DEBUG2, "Create: %s",
819
0
        mxid_to_string(InvalidMultiXactId, nmembers, members));
820
821
  /*
822
   * See if the same set of members already exists in our cache; if so, just
823
   * re-use that MultiXactId.  (Note: it might seem that looking in our
824
   * cache is insufficient, and we ought to search disk to see if a
825
   * duplicate definition already exists.  But since we only ever create
826
   * MultiXacts containing our own XID, in most cases any such MultiXacts
827
   * were in fact created by us, and so will be in our cache.  There are
828
   * corner cases where someone else added us to a MultiXact without our
829
   * knowledge, but it's not worth checking for.)
830
   */
831
0
  multi = mXactCacheGetBySet(nmembers, members);
832
0
  if (MultiXactIdIsValid(multi))
833
0
  {
834
0
    debug_elog2(DEBUG2, "Create: in cache!");
835
0
    return multi;
836
0
  }
837
838
  /* Verify that there is a single update Xid among the given members. */
839
0
  {
840
0
    int     i;
841
0
    bool    has_update = false;
842
843
0
    for (i = 0; i < nmembers; i++)
844
0
    {
845
0
      if (ISUPDATE_from_mxstatus(members[i].status))
846
0
      {
847
0
        if (has_update)
848
0
          elog(ERROR, "new multixact has more than one updating member: %s",
849
0
             mxid_to_string(InvalidMultiXactId, nmembers, members));
850
0
        has_update = true;
851
0
      }
852
0
    }
853
0
  }
854
855
  /* Load the injection point before entering the critical section */
856
0
  INJECTION_POINT_LOAD("multixact-create-from-members");
857
858
  /*
859
   * Assign the MXID and offsets range to use, and make sure there is space
860
   * in the OFFSETs and MEMBERs files.  NB: this routine does
861
   * START_CRIT_SECTION().
862
   *
863
   * Note: unlike MultiXactIdCreate and MultiXactIdExpand, we do not check
864
   * that we've called MultiXactIdSetOldestMember here.  This is because
865
   * this routine is used in some places to create new MultiXactIds of which
866
   * the current backend is not a member, notably during freezing of multis
867
   * in vacuum.  During vacuum, in particular, it would be unacceptable to
868
   * keep OldestMulti set, in case it runs for long.
869
   */
870
0
  multi = GetNewMultiXactId(nmembers, &offset);
871
872
0
  INJECTION_POINT_CACHED("multixact-create-from-members", NULL);
873
874
  /* Make an XLOG entry describing the new MXID. */
875
0
  xlrec.mid = multi;
876
0
  xlrec.moff = offset;
877
0
  xlrec.nmembers = nmembers;
878
879
  /*
880
   * XXX Note: there's a lot of padding space in MultiXactMember.  We could
881
   * find a more compact representation of this Xlog record -- perhaps all
882
   * the status flags in one XLogRecData, then all the xids in another one?
883
   * Not clear that it's worth the trouble though.
884
   */
885
0
  XLogBeginInsert();
886
0
  XLogRegisterData(&xlrec, SizeOfMultiXactCreate);
887
0
  XLogRegisterData(members, nmembers * sizeof(MultiXactMember));
888
889
0
  (void) XLogInsert(RM_MULTIXACT_ID, XLOG_MULTIXACT_CREATE_ID);
890
891
  /* Now enter the information into the OFFSETs and MEMBERs logs */
892
0
  RecordNewMultiXact(multi, offset, nmembers, members);
893
894
  /* Done with critical section */
895
0
  END_CRIT_SECTION();
896
897
  /* Store the new MultiXactId in the local cache, too */
898
0
  mXactCachePut(multi, nmembers, members);
899
900
0
  debug_elog2(DEBUG2, "Create: all done");
901
902
0
  return multi;
903
0
}
904
905
/*
906
 * RecordNewMultiXact
907
 *    Write info about a new multixact into the offsets and members files
908
 *
909
 * This is broken out of MultiXactIdCreateFromMembers so that xlog replay can
910
 * use it.
911
 */
912
static void
913
RecordNewMultiXact(MultiXactId multi, MultiXactOffset offset,
914
           int nmembers, MultiXactMember *members)
915
0
{
916
0
  int64   pageno;
917
0
  int64   prev_pageno;
918
0
  int     entryno;
919
0
  int     slotno;
920
0
  MultiXactOffset *offptr;
921
0
  int     i;
922
0
  LWLock     *lock;
923
0
  LWLock     *prevlock = NULL;
924
925
0
  pageno = MultiXactIdToOffsetPage(multi);
926
0
  entryno = MultiXactIdToOffsetEntry(multi);
927
928
0
  lock = SimpleLruGetBankLock(MultiXactOffsetCtl, pageno);
929
0
  LWLockAcquire(lock, LW_EXCLUSIVE);
930
931
  /*
932
   * Note: we pass the MultiXactId to SimpleLruReadPage as the "transaction"
933
   * to complain about if there's any I/O error.  This is kinda bogus, but
934
   * since the errors will always give the full pathname, it should be clear
935
   * enough that a MultiXactId is really involved.  Perhaps someday we'll
936
   * take the trouble to generalize the slru.c error reporting code.
937
   */
938
0
  slotno = SimpleLruReadPage(MultiXactOffsetCtl, pageno, true, multi);
939
0
  offptr = (MultiXactOffset *) MultiXactOffsetCtl->shared->page_buffer[slotno];
940
0
  offptr += entryno;
941
942
0
  *offptr = offset;
943
944
0
  MultiXactOffsetCtl->shared->page_dirty[slotno] = true;
945
946
  /* Release MultiXactOffset SLRU lock. */
947
0
  LWLockRelease(lock);
948
949
  /*
950
   * If anybody was waiting to know the offset of this multixact ID we just
951
   * wrote, they can read it now, so wake them up.
952
   */
953
0
  ConditionVariableBroadcast(&MultiXactState->nextoff_cv);
954
955
0
  prev_pageno = -1;
956
957
0
  for (i = 0; i < nmembers; i++, offset++)
958
0
  {
959
0
    TransactionId *memberptr;
960
0
    uint32     *flagsptr;
961
0
    uint32    flagsval;
962
0
    int     bshift;
963
0
    int     flagsoff;
964
0
    int     memberoff;
965
966
0
    Assert(members[i].status <= MultiXactStatusUpdate);
967
968
0
    pageno = MXOffsetToMemberPage(offset);
969
0
    memberoff = MXOffsetToMemberOffset(offset);
970
0
    flagsoff = MXOffsetToFlagsOffset(offset);
971
0
    bshift = MXOffsetToFlagsBitShift(offset);
972
973
0
    if (pageno != prev_pageno)
974
0
    {
975
      /*
976
       * MultiXactMember SLRU page is changed so check if this new page
977
       * fall into the different SLRU bank then release the old bank's
978
       * lock and acquire lock on the new bank.
979
       */
980
0
      lock = SimpleLruGetBankLock(MultiXactMemberCtl, pageno);
981
0
      if (lock != prevlock)
982
0
      {
983
0
        if (prevlock != NULL)
984
0
          LWLockRelease(prevlock);
985
986
0
        LWLockAcquire(lock, LW_EXCLUSIVE);
987
0
        prevlock = lock;
988
0
      }
989
0
      slotno = SimpleLruReadPage(MultiXactMemberCtl, pageno, true, multi);
990
0
      prev_pageno = pageno;
991
0
    }
992
993
0
    memberptr = (TransactionId *)
994
0
      (MultiXactMemberCtl->shared->page_buffer[slotno] + memberoff);
995
996
0
    *memberptr = members[i].xid;
997
998
0
    flagsptr = (uint32 *)
999
0
      (MultiXactMemberCtl->shared->page_buffer[slotno] + flagsoff);
1000
1001
0
    flagsval = *flagsptr;
1002
0
    flagsval &= ~(((1 << MXACT_MEMBER_BITS_PER_XACT) - 1) << bshift);
1003
0
    flagsval |= (members[i].status << bshift);
1004
0
    *flagsptr = flagsval;
1005
1006
0
    MultiXactMemberCtl->shared->page_dirty[slotno] = true;
1007
0
  }
1008
1009
0
  if (prevlock != NULL)
1010
0
    LWLockRelease(prevlock);
1011
0
}
1012
1013
/*
1014
 * GetNewMultiXactId
1015
 *    Get the next MultiXactId.
1016
 *
1017
 * Also, reserve the needed amount of space in the "members" area.  The
1018
 * starting offset of the reserved space is returned in *offset.
1019
 *
1020
 * This may generate XLOG records for expansion of the offsets and/or members
1021
 * files.  Unfortunately, we have to do that while holding MultiXactGenLock
1022
 * to avoid race conditions --- the XLOG record for zeroing a page must appear
1023
 * before any backend can possibly try to store data in that page!
1024
 *
1025
 * We start a critical section before advancing the shared counters.  The
1026
 * caller must end the critical section after writing SLRU data.
1027
 */
1028
static MultiXactId
1029
GetNewMultiXactId(int nmembers, MultiXactOffset *offset)
1030
0
{
1031
0
  MultiXactId result;
1032
0
  MultiXactOffset nextOffset;
1033
1034
0
  debug_elog3(DEBUG2, "GetNew: for %d xids", nmembers);
1035
1036
  /* safety check, we should never get this far in a HS standby */
1037
0
  if (RecoveryInProgress())
1038
0
    elog(ERROR, "cannot assign MultiXactIds during recovery");
1039
1040
0
  LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);
1041
1042
  /* Handle wraparound of the nextMXact counter */
1043
0
  if (MultiXactState->nextMXact < FirstMultiXactId)
1044
0
    MultiXactState->nextMXact = FirstMultiXactId;
1045
1046
  /* Assign the MXID */
1047
0
  result = MultiXactState->nextMXact;
1048
1049
  /*----------
1050
   * Check to see if it's safe to assign another MultiXactId.  This protects
1051
   * against catastrophic data loss due to multixact wraparound.  The basic
1052
   * rules are:
1053
   *
1054
   * If we're past multiVacLimit or the safe threshold for member storage
1055
   * space, or we don't know what the safe threshold for member storage is,
1056
   * start trying to force autovacuum cycles.
1057
   * If we're past multiWarnLimit, start issuing warnings.
1058
   * If we're past multiStopLimit, refuse to create new MultiXactIds.
1059
   *
1060
   * Note these are pretty much the same protections in GetNewTransactionId.
1061
   *----------
1062
   */
1063
0
  if (!MultiXactIdPrecedes(result, MultiXactState->multiVacLimit))
1064
0
  {
1065
    /*
1066
     * For safety's sake, we release MultiXactGenLock while sending
1067
     * signals, warnings, etc.  This is not so much because we care about
1068
     * preserving concurrency in this situation, as to avoid any
1069
     * possibility of deadlock while doing get_database_name(). First,
1070
     * copy all the shared values we'll need in this path.
1071
     */
1072
0
    MultiXactId multiWarnLimit = MultiXactState->multiWarnLimit;
1073
0
    MultiXactId multiStopLimit = MultiXactState->multiStopLimit;
1074
0
    MultiXactId multiWrapLimit = MultiXactState->multiWrapLimit;
1075
0
    Oid     oldest_datoid = MultiXactState->oldestMultiXactDB;
1076
1077
0
    LWLockRelease(MultiXactGenLock);
1078
1079
0
    if (IsUnderPostmaster &&
1080
0
      !MultiXactIdPrecedes(result, multiStopLimit))
1081
0
    {
1082
0
      char     *oldest_datname = get_database_name(oldest_datoid);
1083
1084
      /*
1085
       * Immediately kick autovacuum into action as we're already in
1086
       * ERROR territory.
1087
       */
1088
0
      SendPostmasterSignal(PMSIGNAL_START_AUTOVAC_LAUNCHER);
1089
1090
      /* complain even if that DB has disappeared */
1091
0
      if (oldest_datname)
1092
0
        ereport(ERROR,
1093
0
            (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
1094
0
             errmsg("database is not accepting commands that assign new MultiXactIds to avoid wraparound data loss in database \"%s\"",
1095
0
                oldest_datname),
1096
0
             errhint("Execute a database-wide VACUUM in that database.\n"
1097
0
                 "You might also need to commit or roll back old prepared transactions, or drop stale replication slots.")));
1098
0
      else
1099
0
        ereport(ERROR,
1100
0
            (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
1101
0
             errmsg("database is not accepting commands that assign new MultiXactIds to avoid wraparound data loss in database with OID %u",
1102
0
                oldest_datoid),
1103
0
             errhint("Execute a database-wide VACUUM in that database.\n"
1104
0
                 "You might also need to commit or roll back old prepared transactions, or drop stale replication slots.")));
1105
0
    }
1106
1107
    /*
1108
     * To avoid swamping the postmaster with signals, we issue the autovac
1109
     * request only once per 64K multis generated.  This still gives
1110
     * plenty of chances before we get into real trouble.
1111
     */
1112
0
    if (IsUnderPostmaster && (result % 65536) == 0)
1113
0
      SendPostmasterSignal(PMSIGNAL_START_AUTOVAC_LAUNCHER);
1114
1115
0
    if (!MultiXactIdPrecedes(result, multiWarnLimit))
1116
0
    {
1117
0
      char     *oldest_datname = get_database_name(oldest_datoid);
1118
1119
      /* complain even if that DB has disappeared */
1120
0
      if (oldest_datname)
1121
0
        ereport(WARNING,
1122
0
            (errmsg_plural("database \"%s\" must be vacuumed before %u more MultiXactId is used",
1123
0
                     "database \"%s\" must be vacuumed before %u more MultiXactIds are used",
1124
0
                     multiWrapLimit - result,
1125
0
                     oldest_datname,
1126
0
                     multiWrapLimit - result),
1127
0
             errhint("Execute a database-wide VACUUM in that database.\n"
1128
0
                 "You might also need to commit or roll back old prepared transactions, or drop stale replication slots.")));
1129
0
      else
1130
0
        ereport(WARNING,
1131
0
            (errmsg_plural("database with OID %u must be vacuumed before %u more MultiXactId is used",
1132
0
                     "database with OID %u must be vacuumed before %u more MultiXactIds are used",
1133
0
                     multiWrapLimit - result,
1134
0
                     oldest_datoid,
1135
0
                     multiWrapLimit - result),
1136
0
             errhint("Execute a database-wide VACUUM in that database.\n"
1137
0
                 "You might also need to commit or roll back old prepared transactions, or drop stale replication slots.")));
1138
0
    }
1139
1140
    /* Re-acquire lock and start over */
1141
0
    LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);
1142
0
    result = MultiXactState->nextMXact;
1143
0
    if (result < FirstMultiXactId)
1144
0
      result = FirstMultiXactId;
1145
0
  }
1146
1147
  /* Make sure there is room for the MXID in the file.  */
1148
0
  ExtendMultiXactOffset(result);
1149
1150
  /*
1151
   * Reserve the members space, similarly to above.  Also, be careful not to
1152
   * return zero as the starting offset for any multixact. See
1153
   * GetMultiXactIdMembers() for motivation.
1154
   */
1155
0
  nextOffset = MultiXactState->nextOffset;
1156
0
  if (nextOffset == 0)
1157
0
  {
1158
0
    *offset = 1;
1159
0
    nmembers++;       /* allocate member slot 0 too */
1160
0
  }
1161
0
  else
1162
0
    *offset = nextOffset;
1163
1164
  /*----------
1165
   * Protect against overrun of the members space as well, with the
1166
   * following rules:
1167
   *
1168
   * If we're past offsetStopLimit, refuse to generate more multis.
1169
   * If we're close to offsetStopLimit, emit a warning.
1170
   *
1171
   * Arbitrarily, we start emitting warnings when we're 20 segments or less
1172
   * from offsetStopLimit.
1173
   *
1174
   * Note we haven't updated the shared state yet, so if we fail at this
1175
   * point, the multixact ID we grabbed can still be used by the next guy.
1176
   *
1177
   * Note that there is no point in forcing autovacuum runs here: the
1178
   * multixact freeze settings would have to be reduced for that to have any
1179
   * effect.
1180
   *----------
1181
   */
1182
0
#define OFFSET_WARN_SEGMENTS  20
1183
0
  if (MultiXactState->oldestOffsetKnown &&
1184
0
    MultiXactOffsetWouldWrap(MultiXactState->offsetStopLimit, nextOffset,
1185
0
                 nmembers))
1186
0
  {
1187
    /* see comment in the corresponding offsets wraparound case */
1188
0
    SendPostmasterSignal(PMSIGNAL_START_AUTOVAC_LAUNCHER);
1189
1190
0
    ereport(ERROR,
1191
0
        (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
1192
0
         errmsg("multixact \"members\" limit exceeded"),
1193
0
         errdetail_plural("This command would create a multixact with %u members, but the remaining space is only enough for %u member.",
1194
0
                  "This command would create a multixact with %u members, but the remaining space is only enough for %u members.",
1195
0
                  MultiXactState->offsetStopLimit - nextOffset - 1,
1196
0
                  nmembers,
1197
0
                  MultiXactState->offsetStopLimit - nextOffset - 1),
1198
0
         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.",
1199
0
             MultiXactState->oldestMultiXactDB)));
1200
0
  }
1201
1202
  /*
1203
   * Check whether we should kick autovacuum into action, to prevent members
1204
   * wraparound. NB we use a much larger window to trigger autovacuum than
1205
   * just the warning limit. The warning is just a measure of last resort -
1206
   * this is in line with GetNewTransactionId's behaviour.
1207
   */
1208
0
  if (!MultiXactState->oldestOffsetKnown ||
1209
0
    (MultiXactState->nextOffset - MultiXactState->oldestOffset
1210
0
     > MULTIXACT_MEMBER_SAFE_THRESHOLD))
1211
0
  {
1212
    /*
1213
     * To avoid swamping the postmaster with signals, we issue the autovac
1214
     * request only when crossing a segment boundary. With default
1215
     * compilation settings that's roughly after 50k members.  This still
1216
     * gives plenty of chances before we get into real trouble.
1217
     */
1218
0
    if ((MXOffsetToMemberPage(nextOffset) / SLRU_PAGES_PER_SEGMENT) !=
1219
0
      (MXOffsetToMemberPage(nextOffset + nmembers) / SLRU_PAGES_PER_SEGMENT))
1220
0
      SendPostmasterSignal(PMSIGNAL_START_AUTOVAC_LAUNCHER);
1221
0
  }
1222
1223
0
  if (MultiXactState->oldestOffsetKnown &&
1224
0
    MultiXactOffsetWouldWrap(MultiXactState->offsetStopLimit,
1225
0
                 nextOffset,
1226
0
                 nmembers + MULTIXACT_MEMBERS_PER_PAGE * SLRU_PAGES_PER_SEGMENT * OFFSET_WARN_SEGMENTS))
1227
0
    ereport(WARNING,
1228
0
        (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
1229
0
         errmsg_plural("database with OID %u must be vacuumed before %d more multixact member is used",
1230
0
                 "database with OID %u must be vacuumed before %d more multixact members are used",
1231
0
                 MultiXactState->offsetStopLimit - nextOffset + nmembers,
1232
0
                 MultiXactState->oldestMultiXactDB,
1233
0
                 MultiXactState->offsetStopLimit - nextOffset + nmembers),
1234
0
         errhint("Execute a database-wide VACUUM in that database with reduced \"vacuum_multixact_freeze_min_age\" and \"vacuum_multixact_freeze_table_age\" settings.")));
1235
1236
0
  ExtendMultiXactMember(nextOffset, nmembers);
1237
1238
  /*
1239
   * Critical section from here until caller has written the data into the
1240
   * just-reserved SLRU space; we don't want to error out with a partly
1241
   * written MultiXact structure.  (In particular, failing to write our
1242
   * start offset after advancing nextMXact would effectively corrupt the
1243
   * previous MultiXact.)
1244
   */
1245
0
  START_CRIT_SECTION();
1246
1247
  /*
1248
   * Advance counters.  As in GetNewTransactionId(), this must not happen
1249
   * until after file extension has succeeded!
1250
   *
1251
   * We don't care about MultiXactId wraparound here; it will be handled by
1252
   * the next iteration.  But note that nextMXact may be InvalidMultiXactId
1253
   * or the first value on a segment-beginning page after this routine
1254
   * exits, so anyone else looking at the variable must be prepared to deal
1255
   * with either case.  Similarly, nextOffset may be zero, but we won't use
1256
   * that as the actual start offset of the next multixact.
1257
   */
1258
0
  (MultiXactState->nextMXact)++;
1259
1260
0
  MultiXactState->nextOffset += nmembers;
1261
1262
0
  LWLockRelease(MultiXactGenLock);
1263
1264
0
  debug_elog4(DEBUG2, "GetNew: returning %u offset %u", result, *offset);
1265
0
  return result;
1266
0
}
1267
1268
/*
1269
 * GetMultiXactIdMembers
1270
 *    Return the set of MultiXactMembers that make up a MultiXactId
1271
 *
1272
 * Return value is the number of members found, or -1 if there are none,
1273
 * and *members is set to a newly palloc'ed array of members.  It's the
1274
 * caller's responsibility to free it when done with it.
1275
 *
1276
 * from_pgupgrade must be passed as true if and only if only the multixact
1277
 * corresponds to a value from a tuple that was locked in a 9.2-or-older
1278
 * installation and later pg_upgrade'd (that is, the infomask is
1279
 * HEAP_LOCKED_UPGRADED).  In this case, we know for certain that no members
1280
 * can still be running, so we return -1 just like for an empty multixact
1281
 * without any further checking.  It would be wrong to try to resolve such a
1282
 * multixact: either the multixact is within the current valid multixact
1283
 * range, in which case the returned result would be bogus, or outside that
1284
 * range, in which case an error would be raised.
1285
 *
1286
 * In all other cases, the passed multixact must be within the known valid
1287
 * range, that is, greater than or equal to oldestMultiXactId, and less than
1288
 * nextMXact.  Otherwise, an error is raised.
1289
 *
1290
 * isLockOnly must be set to true if caller is certain that the given multi
1291
 * is used only to lock tuples; can be false without loss of correctness,
1292
 * but passing a true means we can return quickly without checking for
1293
 * old updates.
1294
 */
1295
int
1296
GetMultiXactIdMembers(MultiXactId multi, MultiXactMember **members,
1297
            bool from_pgupgrade, bool isLockOnly)
1298
0
{
1299
0
  int64   pageno;
1300
0
  int64   prev_pageno;
1301
0
  int     entryno;
1302
0
  int     slotno;
1303
0
  MultiXactOffset *offptr;
1304
0
  MultiXactOffset offset;
1305
0
  int     length;
1306
0
  int     truelength;
1307
0
  MultiXactId oldestMXact;
1308
0
  MultiXactId nextMXact;
1309
0
  MultiXactId tmpMXact;
1310
0
  MultiXactOffset nextOffset;
1311
0
  MultiXactMember *ptr;
1312
0
  LWLock     *lock;
1313
0
  bool    slept = false;
1314
1315
0
  debug_elog3(DEBUG2, "GetMembers: asked for %u", multi);
1316
1317
0
  if (!MultiXactIdIsValid(multi) || from_pgupgrade)
1318
0
  {
1319
0
    *members = NULL;
1320
0
    return -1;
1321
0
  }
1322
1323
  /* See if the MultiXactId is in the local cache */
1324
0
  length = mXactCacheGetById(multi, members);
1325
0
  if (length >= 0)
1326
0
  {
1327
0
    debug_elog3(DEBUG2, "GetMembers: found %s in the cache",
1328
0
          mxid_to_string(multi, length, *members));
1329
0
    return length;
1330
0
  }
1331
1332
  /* Set our OldestVisibleMXactId[] entry if we didn't already */
1333
0
  MultiXactIdSetOldestVisible();
1334
1335
  /*
1336
   * If we know the multi is used only for locking and not for updates, then
1337
   * we can skip checking if the value is older than our oldest visible
1338
   * multi.  It cannot possibly still be running.
1339
   */
1340
0
  if (isLockOnly &&
1341
0
    MultiXactIdPrecedes(multi, OldestVisibleMXactId[MyProcNumber]))
1342
0
  {
1343
0
    debug_elog2(DEBUG2, "GetMembers: a locker-only multi is too old");
1344
0
    *members = NULL;
1345
0
    return -1;
1346
0
  }
1347
1348
  /*
1349
   * We check known limits on MultiXact before resorting to the SLRU area.
1350
   *
1351
   * An ID older than MultiXactState->oldestMultiXactId cannot possibly be
1352
   * useful; it has already been removed, or will be removed shortly, by
1353
   * truncation.  If one is passed, an error is raised.
1354
   *
1355
   * Also, an ID >= nextMXact shouldn't ever be seen here; if it is seen, it
1356
   * implies undetected ID wraparound has occurred.  This raises a hard
1357
   * error.
1358
   *
1359
   * Shared lock is enough here since we aren't modifying any global state.
1360
   * Acquire it just long enough to grab the current counter values.  We may
1361
   * need both nextMXact and nextOffset; see below.
1362
   */
1363
0
  LWLockAcquire(MultiXactGenLock, LW_SHARED);
1364
1365
0
  oldestMXact = MultiXactState->oldestMultiXactId;
1366
0
  nextMXact = MultiXactState->nextMXact;
1367
0
  nextOffset = MultiXactState->nextOffset;
1368
1369
0
  LWLockRelease(MultiXactGenLock);
1370
1371
0
  if (MultiXactIdPrecedes(multi, oldestMXact))
1372
0
    ereport(ERROR,
1373
0
        (errcode(ERRCODE_INTERNAL_ERROR),
1374
0
         errmsg("MultiXactId %u does no longer exist -- apparent wraparound",
1375
0
            multi)));
1376
1377
0
  if (!MultiXactIdPrecedes(multi, nextMXact))
1378
0
    ereport(ERROR,
1379
0
        (errcode(ERRCODE_INTERNAL_ERROR),
1380
0
         errmsg("MultiXactId %u has not been created yet -- apparent wraparound",
1381
0
            multi)));
1382
1383
  /*
1384
   * Find out the offset at which we need to start reading MultiXactMembers
1385
   * and the number of members in the multixact.  We determine the latter as
1386
   * the difference between this multixact's starting offset and the next
1387
   * one's.  However, there are some corner cases to worry about:
1388
   *
1389
   * 1. This multixact may be the latest one created, in which case there is
1390
   * no next one to look at.  In this case the nextOffset value we just
1391
   * saved is the correct endpoint.
1392
   *
1393
   * 2. The next multixact may still be in process of being filled in: that
1394
   * is, another process may have done GetNewMultiXactId but not yet written
1395
   * the offset entry for that ID.  In that scenario, it is guaranteed that
1396
   * the offset entry for that multixact exists (because GetNewMultiXactId
1397
   * won't release MultiXactGenLock until it does) but contains zero
1398
   * (because we are careful to pre-zero offset pages). Because
1399
   * GetNewMultiXactId will never return zero as the starting offset for a
1400
   * multixact, when we read zero as the next multixact's offset, we know we
1401
   * have this case.  We handle this by sleeping on the condition variable
1402
   * we have just for this; the process in charge will signal the CV as soon
1403
   * as it has finished writing the multixact offset.
1404
   *
1405
   * 3. Because GetNewMultiXactId increments offset zero to offset one to
1406
   * handle case #2, there is an ambiguity near the point of offset
1407
   * wraparound.  If we see next multixact's offset is one, is that our
1408
   * multixact's actual endpoint, or did it end at zero with a subsequent
1409
   * increment?  We handle this using the knowledge that if the zero'th
1410
   * member slot wasn't filled, it'll contain zero, and zero isn't a valid
1411
   * transaction ID so it can't be a multixact member.  Therefore, if we
1412
   * read a zero from the members array, just ignore it.
1413
   *
1414
   * This is all pretty messy, but the mess occurs only in infrequent corner
1415
   * cases, so it seems better than holding the MultiXactGenLock for a long
1416
   * time on every multixact creation.
1417
   */
1418
0
retry:
1419
0
  pageno = MultiXactIdToOffsetPage(multi);
1420
0
  entryno = MultiXactIdToOffsetEntry(multi);
1421
1422
  /* Acquire the bank lock for the page we need. */
1423
0
  lock = SimpleLruGetBankLock(MultiXactOffsetCtl, pageno);
1424
0
  LWLockAcquire(lock, LW_EXCLUSIVE);
1425
1426
0
  slotno = SimpleLruReadPage(MultiXactOffsetCtl, pageno, true, multi);
1427
0
  offptr = (MultiXactOffset *) MultiXactOffsetCtl->shared->page_buffer[slotno];
1428
0
  offptr += entryno;
1429
0
  offset = *offptr;
1430
1431
0
  Assert(offset != 0);
1432
1433
  /*
1434
   * Use the same increment rule as GetNewMultiXactId(), that is, don't
1435
   * handle wraparound explicitly until needed.
1436
   */
1437
0
  tmpMXact = multi + 1;
1438
1439
0
  if (nextMXact == tmpMXact)
1440
0
  {
1441
    /* Corner case 1: there is no next multixact */
1442
0
    length = nextOffset - offset;
1443
0
  }
1444
0
  else
1445
0
  {
1446
0
    MultiXactOffset nextMXOffset;
1447
1448
    /* handle wraparound if needed */
1449
0
    if (tmpMXact < FirstMultiXactId)
1450
0
      tmpMXact = FirstMultiXactId;
1451
1452
0
    prev_pageno = pageno;
1453
1454
0
    pageno = MultiXactIdToOffsetPage(tmpMXact);
1455
0
    entryno = MultiXactIdToOffsetEntry(tmpMXact);
1456
1457
0
    if (pageno != prev_pageno)
1458
0
    {
1459
0
      LWLock     *newlock;
1460
1461
      /*
1462
       * Since we're going to access a different SLRU page, if this page
1463
       * falls under a different bank, release the old bank's lock and
1464
       * acquire the lock of the new bank.
1465
       */
1466
0
      newlock = SimpleLruGetBankLock(MultiXactOffsetCtl, pageno);
1467
0
      if (newlock != lock)
1468
0
      {
1469
0
        LWLockRelease(lock);
1470
0
        LWLockAcquire(newlock, LW_EXCLUSIVE);
1471
0
        lock = newlock;
1472
0
      }
1473
0
      slotno = SimpleLruReadPage(MultiXactOffsetCtl, pageno, true, tmpMXact);
1474
0
    }
1475
1476
0
    offptr = (MultiXactOffset *) MultiXactOffsetCtl->shared->page_buffer[slotno];
1477
0
    offptr += entryno;
1478
0
    nextMXOffset = *offptr;
1479
1480
0
    if (nextMXOffset == 0)
1481
0
    {
1482
      /* Corner case 2: next multixact is still being filled in */
1483
0
      LWLockRelease(lock);
1484
0
      CHECK_FOR_INTERRUPTS();
1485
1486
0
      INJECTION_POINT("multixact-get-members-cv-sleep", NULL);
1487
1488
0
      ConditionVariableSleep(&MultiXactState->nextoff_cv,
1489
0
                   WAIT_EVENT_MULTIXACT_CREATION);
1490
0
      slept = true;
1491
0
      goto retry;
1492
0
    }
1493
1494
0
    length = nextMXOffset - offset;
1495
0
  }
1496
1497
0
  LWLockRelease(lock);
1498
0
  lock = NULL;
1499
1500
  /*
1501
   * If we slept above, clean up state; it's no longer needed.
1502
   */
1503
0
  if (slept)
1504
0
    ConditionVariableCancelSleep();
1505
1506
0
  ptr = (MultiXactMember *) palloc(length * sizeof(MultiXactMember));
1507
1508
0
  truelength = 0;
1509
0
  prev_pageno = -1;
1510
0
  for (int i = 0; i < length; i++, offset++)
1511
0
  {
1512
0
    TransactionId *xactptr;
1513
0
    uint32     *flagsptr;
1514
0
    int     flagsoff;
1515
0
    int     bshift;
1516
0
    int     memberoff;
1517
1518
0
    pageno = MXOffsetToMemberPage(offset);
1519
0
    memberoff = MXOffsetToMemberOffset(offset);
1520
1521
0
    if (pageno != prev_pageno)
1522
0
    {
1523
0
      LWLock     *newlock;
1524
1525
      /*
1526
       * Since we're going to access a different SLRU page, if this page
1527
       * falls under a different bank, release the old bank's lock and
1528
       * acquire the lock of the new bank.
1529
       */
1530
0
      newlock = SimpleLruGetBankLock(MultiXactMemberCtl, pageno);
1531
0
      if (newlock != lock)
1532
0
      {
1533
0
        if (lock)
1534
0
          LWLockRelease(lock);
1535
0
        LWLockAcquire(newlock, LW_EXCLUSIVE);
1536
0
        lock = newlock;
1537
0
      }
1538
1539
0
      slotno = SimpleLruReadPage(MultiXactMemberCtl, pageno, true, multi);
1540
0
      prev_pageno = pageno;
1541
0
    }
1542
1543
0
    xactptr = (TransactionId *)
1544
0
      (MultiXactMemberCtl->shared->page_buffer[slotno] + memberoff);
1545
1546
0
    if (!TransactionIdIsValid(*xactptr))
1547
0
    {
1548
      /* Corner case 3: we must be looking at unused slot zero */
1549
0
      Assert(offset == 0);
1550
0
      continue;
1551
0
    }
1552
1553
0
    flagsoff = MXOffsetToFlagsOffset(offset);
1554
0
    bshift = MXOffsetToFlagsBitShift(offset);
1555
0
    flagsptr = (uint32 *) (MultiXactMemberCtl->shared->page_buffer[slotno] + flagsoff);
1556
1557
0
    ptr[truelength].xid = *xactptr;
1558
0
    ptr[truelength].status = (*flagsptr >> bshift) & MXACT_MEMBER_XACT_BITMASK;
1559
0
    truelength++;
1560
0
  }
1561
1562
0
  LWLockRelease(lock);
1563
1564
  /* A multixid with zero members should not happen */
1565
0
  Assert(truelength > 0);
1566
1567
  /*
1568
   * Copy the result into the local cache.
1569
   */
1570
0
  mXactCachePut(multi, truelength, ptr);
1571
1572
0
  debug_elog3(DEBUG2, "GetMembers: no cache for %s",
1573
0
        mxid_to_string(multi, truelength, ptr));
1574
0
  *members = ptr;
1575
0
  return truelength;
1576
0
}
1577
1578
/*
1579
 * mxactMemberComparator
1580
 *    qsort comparison function for MultiXactMember
1581
 *
1582
 * We can't use wraparound comparison for XIDs because that does not respect
1583
 * the triangle inequality!  Any old sort order will do.
1584
 */
1585
static int
1586
mxactMemberComparator(const void *arg1, const void *arg2)
1587
0
{
1588
0
  MultiXactMember member1 = *(const MultiXactMember *) arg1;
1589
0
  MultiXactMember member2 = *(const MultiXactMember *) arg2;
1590
1591
0
  if (member1.xid > member2.xid)
1592
0
    return 1;
1593
0
  if (member1.xid < member2.xid)
1594
0
    return -1;
1595
0
  if (member1.status > member2.status)
1596
0
    return 1;
1597
0
  if (member1.status < member2.status)
1598
0
    return -1;
1599
0
  return 0;
1600
0
}
1601
1602
/*
1603
 * mXactCacheGetBySet
1604
 *    returns a MultiXactId from the cache based on the set of
1605
 *    TransactionIds that compose it, or InvalidMultiXactId if
1606
 *    none matches.
1607
 *
1608
 * This is helpful, for example, if two transactions want to lock a huge
1609
 * table.  By using the cache, the second will use the same MultiXactId
1610
 * for the majority of tuples, thus keeping MultiXactId usage low (saving
1611
 * both I/O and wraparound issues).
1612
 *
1613
 * NB: the passed members array will be sorted in-place.
1614
 */
1615
static MultiXactId
1616
mXactCacheGetBySet(int nmembers, MultiXactMember *members)
1617
0
{
1618
0
  dlist_iter  iter;
1619
1620
0
  debug_elog3(DEBUG2, "CacheGet: looking for %s",
1621
0
        mxid_to_string(InvalidMultiXactId, nmembers, members));
1622
1623
  /* sort the array so comparison is easy */
1624
0
  qsort(members, nmembers, sizeof(MultiXactMember), mxactMemberComparator);
1625
1626
0
  dclist_foreach(iter, &MXactCache)
1627
0
  {
1628
0
    mXactCacheEnt *entry = dclist_container(mXactCacheEnt, node,
1629
0
                        iter.cur);
1630
1631
0
    if (entry->nmembers != nmembers)
1632
0
      continue;
1633
1634
    /*
1635
     * We assume the cache entries are sorted, and that the unused bits in
1636
     * "status" are zeroed.
1637
     */
1638
0
    if (memcmp(members, entry->members, nmembers * sizeof(MultiXactMember)) == 0)
1639
0
    {
1640
0
      debug_elog3(DEBUG2, "CacheGet: found %u", entry->multi);
1641
0
      dclist_move_head(&MXactCache, iter.cur);
1642
0
      return entry->multi;
1643
0
    }
1644
0
  }
1645
1646
0
  debug_elog2(DEBUG2, "CacheGet: not found :-(");
1647
0
  return InvalidMultiXactId;
1648
0
}
1649
1650
/*
1651
 * mXactCacheGetById
1652
 *    returns the composing MultiXactMember set from the cache for a
1653
 *    given MultiXactId, if present.
1654
 *
1655
 * If successful, *xids is set to the address of a palloc'd copy of the
1656
 * MultiXactMember set.  Return value is number of members, or -1 on failure.
1657
 */
1658
static int
1659
mXactCacheGetById(MultiXactId multi, MultiXactMember **members)
1660
0
{
1661
0
  dlist_iter  iter;
1662
1663
0
  debug_elog3(DEBUG2, "CacheGet: looking for %u", multi);
1664
1665
0
  dclist_foreach(iter, &MXactCache)
1666
0
  {
1667
0
    mXactCacheEnt *entry = dclist_container(mXactCacheEnt, node,
1668
0
                        iter.cur);
1669
1670
0
    if (entry->multi == multi)
1671
0
    {
1672
0
      MultiXactMember *ptr;
1673
0
      Size    size;
1674
1675
0
      size = sizeof(MultiXactMember) * entry->nmembers;
1676
0
      ptr = (MultiXactMember *) palloc(size);
1677
1678
0
      memcpy(ptr, entry->members, size);
1679
1680
0
      debug_elog3(DEBUG2, "CacheGet: found %s",
1681
0
            mxid_to_string(multi,
1682
0
                     entry->nmembers,
1683
0
                     entry->members));
1684
1685
      /*
1686
       * Note we modify the list while not using a modifiable iterator.
1687
       * This is acceptable only because we exit the iteration
1688
       * immediately afterwards.
1689
       */
1690
0
      dclist_move_head(&MXactCache, iter.cur);
1691
1692
0
      *members = ptr;
1693
0
      return entry->nmembers;
1694
0
    }
1695
0
  }
1696
1697
0
  debug_elog2(DEBUG2, "CacheGet: not found");
1698
0
  return -1;
1699
0
}
1700
1701
/*
1702
 * mXactCachePut
1703
 *    Add a new MultiXactId and its composing set into the local cache.
1704
 */
1705
static void
1706
mXactCachePut(MultiXactId multi, int nmembers, MultiXactMember *members)
1707
0
{
1708
0
  mXactCacheEnt *entry;
1709
1710
0
  debug_elog3(DEBUG2, "CachePut: storing %s",
1711
0
        mxid_to_string(multi, nmembers, members));
1712
1713
0
  if (MXactContext == NULL)
1714
0
  {
1715
    /* The cache only lives as long as the current transaction */
1716
0
    debug_elog2(DEBUG2, "CachePut: initializing memory context");
1717
0
    MXactContext = AllocSetContextCreate(TopTransactionContext,
1718
0
                       "MultiXact cache context",
1719
0
                       ALLOCSET_SMALL_SIZES);
1720
0
  }
1721
1722
0
  entry = (mXactCacheEnt *)
1723
0
    MemoryContextAlloc(MXactContext,
1724
0
               offsetof(mXactCacheEnt, members) +
1725
0
               nmembers * sizeof(MultiXactMember));
1726
1727
0
  entry->multi = multi;
1728
0
  entry->nmembers = nmembers;
1729
0
  memcpy(entry->members, members, nmembers * sizeof(MultiXactMember));
1730
1731
  /* mXactCacheGetBySet assumes the entries are sorted, so sort them */
1732
0
  qsort(entry->members, nmembers, sizeof(MultiXactMember), mxactMemberComparator);
1733
1734
0
  dclist_push_head(&MXactCache, &entry->node);
1735
0
  if (dclist_count(&MXactCache) > MAX_CACHE_ENTRIES)
1736
0
  {
1737
0
    dlist_node *node;
1738
1739
0
    node = dclist_tail_node(&MXactCache);
1740
0
    dclist_delete_from(&MXactCache, node);
1741
1742
0
    entry = dclist_container(mXactCacheEnt, node, node);
1743
0
    debug_elog3(DEBUG2, "CachePut: pruning cached multi %u",
1744
0
          entry->multi);
1745
1746
0
    pfree(entry);
1747
0
  }
1748
0
}
1749
1750
static char *
1751
mxstatus_to_string(MultiXactStatus status)
1752
0
{
1753
0
  switch (status)
1754
0
  {
1755
0
    case MultiXactStatusForKeyShare:
1756
0
      return "keysh";
1757
0
    case MultiXactStatusForShare:
1758
0
      return "sh";
1759
0
    case MultiXactStatusForNoKeyUpdate:
1760
0
      return "fornokeyupd";
1761
0
    case MultiXactStatusForUpdate:
1762
0
      return "forupd";
1763
0
    case MultiXactStatusNoKeyUpdate:
1764
0
      return "nokeyupd";
1765
0
    case MultiXactStatusUpdate:
1766
0
      return "upd";
1767
0
    default:
1768
0
      elog(ERROR, "unrecognized multixact status %d", status);
1769
0
      return "";
1770
0
  }
1771
0
}
1772
1773
char *
1774
mxid_to_string(MultiXactId multi, int nmembers, MultiXactMember *members)
1775
0
{
1776
0
  static char *str = NULL;
1777
0
  StringInfoData buf;
1778
0
  int     i;
1779
1780
0
  if (str != NULL)
1781
0
    pfree(str);
1782
1783
0
  initStringInfo(&buf);
1784
1785
0
  appendStringInfo(&buf, "%u %d[%u (%s)", multi, nmembers, members[0].xid,
1786
0
           mxstatus_to_string(members[0].status));
1787
1788
0
  for (i = 1; i < nmembers; i++)
1789
0
    appendStringInfo(&buf, ", %u (%s)", members[i].xid,
1790
0
             mxstatus_to_string(members[i].status));
1791
1792
0
  appendStringInfoChar(&buf, ']');
1793
0
  str = MemoryContextStrdup(TopMemoryContext, buf.data);
1794
0
  pfree(buf.data);
1795
0
  return str;
1796
0
}
1797
1798
/*
1799
 * AtEOXact_MultiXact
1800
 *    Handle transaction end for MultiXact
1801
 *
1802
 * This is called at top transaction commit or abort (we don't care which).
1803
 */
1804
void
1805
AtEOXact_MultiXact(void)
1806
0
{
1807
  /*
1808
   * Reset our OldestMemberMXactId and OldestVisibleMXactId values, both of
1809
   * which should only be valid while within a transaction.
1810
   *
1811
   * We assume that storing a MultiXactId is atomic and so we need not take
1812
   * MultiXactGenLock to do this.
1813
   */
1814
0
  OldestMemberMXactId[MyProcNumber] = InvalidMultiXactId;
1815
0
  OldestVisibleMXactId[MyProcNumber] = InvalidMultiXactId;
1816
1817
  /*
1818
   * Discard the local MultiXactId cache.  Since MXactContext was created as
1819
   * a child of TopTransactionContext, we needn't delete it explicitly.
1820
   */
1821
0
  MXactContext = NULL;
1822
0
  dclist_init(&MXactCache);
1823
0
}
1824
1825
/*
1826
 * AtPrepare_MultiXact
1827
 *    Save multixact state at 2PC transaction prepare
1828
 *
1829
 * In this phase, we only store our OldestMemberMXactId value in the two-phase
1830
 * state file.
1831
 */
1832
void
1833
AtPrepare_MultiXact(void)
1834
0
{
1835
0
  MultiXactId myOldestMember = OldestMemberMXactId[MyProcNumber];
1836
1837
0
  if (MultiXactIdIsValid(myOldestMember))
1838
0
    RegisterTwoPhaseRecord(TWOPHASE_RM_MULTIXACT_ID, 0,
1839
0
                 &myOldestMember, sizeof(MultiXactId));
1840
0
}
1841
1842
/*
1843
 * PostPrepare_MultiXact
1844
 *    Clean up after successful PREPARE TRANSACTION
1845
 */
1846
void
1847
PostPrepare_MultiXact(FullTransactionId fxid)
1848
0
{
1849
0
  MultiXactId myOldestMember;
1850
1851
  /*
1852
   * Transfer our OldestMemberMXactId value to the slot reserved for the
1853
   * prepared transaction.
1854
   */
1855
0
  myOldestMember = OldestMemberMXactId[MyProcNumber];
1856
0
  if (MultiXactIdIsValid(myOldestMember))
1857
0
  {
1858
0
    ProcNumber  dummyProcNumber = TwoPhaseGetDummyProcNumber(fxid, false);
1859
1860
    /*
1861
     * Even though storing MultiXactId is atomic, acquire lock to make
1862
     * sure others see both changes, not just the reset of the slot of the
1863
     * current backend. Using a volatile pointer might suffice, but this
1864
     * isn't a hot spot.
1865
     */
1866
0
    LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);
1867
1868
0
    OldestMemberMXactId[dummyProcNumber] = myOldestMember;
1869
0
    OldestMemberMXactId[MyProcNumber] = InvalidMultiXactId;
1870
1871
0
    LWLockRelease(MultiXactGenLock);
1872
0
  }
1873
1874
  /*
1875
   * We don't need to transfer OldestVisibleMXactId value, because the
1876
   * transaction is not going to be looking at any more multixacts once it's
1877
   * prepared.
1878
   *
1879
   * We assume that storing a MultiXactId is atomic and so we need not take
1880
   * MultiXactGenLock to do this.
1881
   */
1882
0
  OldestVisibleMXactId[MyProcNumber] = InvalidMultiXactId;
1883
1884
  /*
1885
   * Discard the local MultiXactId cache like in AtEOXact_MultiXact.
1886
   */
1887
0
  MXactContext = NULL;
1888
0
  dclist_init(&MXactCache);
1889
0
}
1890
1891
/*
1892
 * multixact_twophase_recover
1893
 *    Recover the state of a prepared transaction at startup
1894
 */
1895
void
1896
multixact_twophase_recover(FullTransactionId fxid, uint16 info,
1897
               void *recdata, uint32 len)
1898
0
{
1899
0
  ProcNumber  dummyProcNumber = TwoPhaseGetDummyProcNumber(fxid, false);
1900
0
  MultiXactId oldestMember;
1901
1902
  /*
1903
   * Get the oldest member XID from the state file record, and set it in the
1904
   * OldestMemberMXactId slot reserved for this prepared transaction.
1905
   */
1906
0
  Assert(len == sizeof(MultiXactId));
1907
0
  oldestMember = *((MultiXactId *) recdata);
1908
1909
0
  OldestMemberMXactId[dummyProcNumber] = oldestMember;
1910
0
}
1911
1912
/*
1913
 * multixact_twophase_postcommit
1914
 *    Similar to AtEOXact_MultiXact but for COMMIT PREPARED
1915
 */
1916
void
1917
multixact_twophase_postcommit(FullTransactionId fxid, uint16 info,
1918
                void *recdata, uint32 len)
1919
0
{
1920
0
  ProcNumber  dummyProcNumber = TwoPhaseGetDummyProcNumber(fxid, true);
1921
1922
0
  Assert(len == sizeof(MultiXactId));
1923
1924
0
  OldestMemberMXactId[dummyProcNumber] = InvalidMultiXactId;
1925
0
}
1926
1927
/*
1928
 * multixact_twophase_postabort
1929
 *    This is actually just the same as the COMMIT case.
1930
 */
1931
void
1932
multixact_twophase_postabort(FullTransactionId fxid, uint16 info,
1933
               void *recdata, uint32 len)
1934
0
{
1935
0
  multixact_twophase_postcommit(fxid, info, recdata, len);
1936
0
}
1937
1938
/*
1939
 * Initialization of shared memory for MultiXact.  We use two SLRU areas,
1940
 * thus double memory.  Also, reserve space for the shared MultiXactState
1941
 * struct and the per-backend MultiXactId arrays (two of those, too).
1942
 */
1943
Size
1944
MultiXactShmemSize(void)
1945
0
{
1946
0
  Size    size;
1947
1948
  /* We need 2*MaxOldestSlot perBackendXactIds[] entries */
1949
0
#define SHARED_MULTIXACT_STATE_SIZE \
1950
0
  add_size(offsetof(MultiXactStateData, perBackendXactIds), \
1951
0
       mul_size(sizeof(MultiXactId) * 2, MaxOldestSlot))
1952
1953
0
  size = SHARED_MULTIXACT_STATE_SIZE;
1954
0
  size = add_size(size, SimpleLruShmemSize(multixact_offset_buffers, 0));
1955
0
  size = add_size(size, SimpleLruShmemSize(multixact_member_buffers, 0));
1956
1957
0
  return size;
1958
0
}
1959
1960
void
1961
MultiXactShmemInit(void)
1962
0
{
1963
0
  bool    found;
1964
1965
0
  debug_elog2(DEBUG2, "Shared Memory Init for MultiXact");
1966
1967
0
  MultiXactOffsetCtl->PagePrecedes = MultiXactOffsetPagePrecedes;
1968
0
  MultiXactMemberCtl->PagePrecedes = MultiXactMemberPagePrecedes;
1969
1970
0
  SimpleLruInit(MultiXactOffsetCtl,
1971
0
          "multixact_offset", multixact_offset_buffers, 0,
1972
0
          "pg_multixact/offsets", LWTRANCHE_MULTIXACTOFFSET_BUFFER,
1973
0
          LWTRANCHE_MULTIXACTOFFSET_SLRU,
1974
0
          SYNC_HANDLER_MULTIXACT_OFFSET,
1975
0
          false);
1976
0
  SlruPagePrecedesUnitTests(MultiXactOffsetCtl, MULTIXACT_OFFSETS_PER_PAGE);
1977
0
  SimpleLruInit(MultiXactMemberCtl,
1978
0
          "multixact_member", multixact_member_buffers, 0,
1979
0
          "pg_multixact/members", LWTRANCHE_MULTIXACTMEMBER_BUFFER,
1980
0
          LWTRANCHE_MULTIXACTMEMBER_SLRU,
1981
0
          SYNC_HANDLER_MULTIXACT_MEMBER,
1982
0
          false);
1983
  /* doesn't call SimpleLruTruncate() or meet criteria for unit tests */
1984
1985
  /* Initialize our shared state struct */
1986
0
  MultiXactState = ShmemInitStruct("Shared MultiXact State",
1987
0
                   SHARED_MULTIXACT_STATE_SIZE,
1988
0
                   &found);
1989
0
  if (!IsUnderPostmaster)
1990
0
  {
1991
0
    Assert(!found);
1992
1993
    /* Make sure we zero out the per-backend state */
1994
0
    MemSet(MultiXactState, 0, SHARED_MULTIXACT_STATE_SIZE);
1995
0
    ConditionVariableInit(&MultiXactState->nextoff_cv);
1996
0
  }
1997
0
  else
1998
0
    Assert(found);
1999
2000
  /*
2001
   * Set up array pointers.
2002
   */
2003
0
  OldestMemberMXactId = MultiXactState->perBackendXactIds;
2004
0
  OldestVisibleMXactId = OldestMemberMXactId + MaxOldestSlot;
2005
0
}
2006
2007
/*
2008
 * GUC check_hook for multixact_offset_buffers
2009
 */
2010
bool
2011
check_multixact_offset_buffers(int *newval, void **extra, GucSource source)
2012
2
{
2013
2
  return check_slru_buffers("multixact_offset_buffers", newval);
2014
2
}
2015
2016
/*
2017
 * GUC check_hook for multixact_member_buffers
2018
 */
2019
bool
2020
check_multixact_member_buffers(int *newval, void **extra, GucSource source)
2021
2
{
2022
2
  return check_slru_buffers("multixact_member_buffers", newval);
2023
2
}
2024
2025
/*
2026
 * This func must be called ONCE on system install.  It creates the initial
2027
 * MultiXact segments.  (The MultiXacts directories are assumed to have been
2028
 * created by initdb, and MultiXactShmemInit must have been called already.)
2029
 */
2030
void
2031
BootStrapMultiXact(void)
2032
0
{
2033
  /* Zero the initial pages and flush them to disk */
2034
0
  SimpleLruZeroAndWritePage(MultiXactOffsetCtl, 0);
2035
0
  SimpleLruZeroAndWritePage(MultiXactMemberCtl, 0);
2036
0
}
2037
2038
/*
2039
 * MaybeExtendOffsetSlru
2040
 *    Extend the offsets SLRU area, if necessary
2041
 *
2042
 * After a binary upgrade from <= 9.2, the pg_multixact/offsets SLRU area might
2043
 * contain files that are shorter than necessary; this would occur if the old
2044
 * installation had used multixacts beyond the first page (files cannot be
2045
 * copied, because the on-disk representation is different).  pg_upgrade would
2046
 * update pg_control to set the next offset value to be at that position, so
2047
 * that tuples marked as locked by such MultiXacts would be seen as visible
2048
 * without having to consult multixact.  However, trying to create and use a
2049
 * new MultiXactId would result in an error because the page on which the new
2050
 * value would reside does not exist.  This routine is in charge of creating
2051
 * such pages.
2052
 */
2053
static void
2054
MaybeExtendOffsetSlru(void)
2055
0
{
2056
0
  int64   pageno;
2057
0
  LWLock     *lock;
2058
2059
0
  pageno = MultiXactIdToOffsetPage(MultiXactState->nextMXact);
2060
0
  lock = SimpleLruGetBankLock(MultiXactOffsetCtl, pageno);
2061
2062
0
  LWLockAcquire(lock, LW_EXCLUSIVE);
2063
2064
0
  if (!SimpleLruDoesPhysicalPageExist(MultiXactOffsetCtl, pageno))
2065
0
  {
2066
0
    int     slotno;
2067
2068
    /*
2069
     * Fortunately for us, SimpleLruWritePage is already prepared to deal
2070
     * with creating a new segment file even if the page we're writing is
2071
     * not the first in it, so this is enough.
2072
     */
2073
0
    slotno = SimpleLruZeroPage(MultiXactOffsetCtl, pageno);
2074
0
    SimpleLruWritePage(MultiXactOffsetCtl, slotno);
2075
0
  }
2076
2077
0
  LWLockRelease(lock);
2078
0
}
2079
2080
/*
2081
 * This must be called ONCE during postmaster or standalone-backend startup.
2082
 *
2083
 * StartupXLOG has already established nextMXact/nextOffset by calling
2084
 * MultiXactSetNextMXact and/or MultiXactAdvanceNextMXact, and the oldestMulti
2085
 * info from pg_control and/or MultiXactAdvanceOldest, but we haven't yet
2086
 * replayed WAL.
2087
 */
2088
void
2089
StartupMultiXact(void)
2090
0
{
2091
0
  MultiXactId multi = MultiXactState->nextMXact;
2092
0
  MultiXactOffset offset = MultiXactState->nextOffset;
2093
0
  int64   pageno;
2094
2095
  /*
2096
   * Initialize offset's idea of the latest page number.
2097
   */
2098
0
  pageno = MultiXactIdToOffsetPage(multi);
2099
0
  pg_atomic_write_u64(&MultiXactOffsetCtl->shared->latest_page_number,
2100
0
            pageno);
2101
2102
  /*
2103
   * Initialize member's idea of the latest page number.
2104
   */
2105
0
  pageno = MXOffsetToMemberPage(offset);
2106
0
  pg_atomic_write_u64(&MultiXactMemberCtl->shared->latest_page_number,
2107
0
            pageno);
2108
0
}
2109
2110
/*
2111
 * This must be called ONCE at the end of startup/recovery.
2112
 */
2113
void
2114
TrimMultiXact(void)
2115
0
{
2116
0
  MultiXactId nextMXact;
2117
0
  MultiXactOffset offset;
2118
0
  MultiXactId oldestMXact;
2119
0
  Oid     oldestMXactDB;
2120
0
  int64   pageno;
2121
0
  int     entryno;
2122
0
  int     flagsoff;
2123
2124
0
  LWLockAcquire(MultiXactGenLock, LW_SHARED);
2125
0
  nextMXact = MultiXactState->nextMXact;
2126
0
  offset = MultiXactState->nextOffset;
2127
0
  oldestMXact = MultiXactState->oldestMultiXactId;
2128
0
  oldestMXactDB = MultiXactState->oldestMultiXactDB;
2129
0
  LWLockRelease(MultiXactGenLock);
2130
2131
  /* Clean up offsets state */
2132
2133
  /*
2134
   * (Re-)Initialize our idea of the latest page number for offsets.
2135
   */
2136
0
  pageno = MultiXactIdToOffsetPage(nextMXact);
2137
0
  pg_atomic_write_u64(&MultiXactOffsetCtl->shared->latest_page_number,
2138
0
            pageno);
2139
2140
  /*
2141
   * Zero out the remainder of the current offsets page.  See notes in
2142
   * TrimCLOG() for background.  Unlike CLOG, some WAL record covers every
2143
   * pg_multixact SLRU mutation.  Since, also unlike CLOG, we ignore the WAL
2144
   * rule "write xlog before data," nextMXact successors may carry obsolete,
2145
   * nonzero offset values.  Zero those so case 2 of GetMultiXactIdMembers()
2146
   * operates normally.
2147
   */
2148
0
  entryno = MultiXactIdToOffsetEntry(nextMXact);
2149
0
  if (entryno != 0)
2150
0
  {
2151
0
    int     slotno;
2152
0
    MultiXactOffset *offptr;
2153
0
    LWLock     *lock = SimpleLruGetBankLock(MultiXactOffsetCtl, pageno);
2154
2155
0
    LWLockAcquire(lock, LW_EXCLUSIVE);
2156
0
    slotno = SimpleLruReadPage(MultiXactOffsetCtl, pageno, true, nextMXact);
2157
0
    offptr = (MultiXactOffset *) MultiXactOffsetCtl->shared->page_buffer[slotno];
2158
0
    offptr += entryno;
2159
2160
0
    MemSet(offptr, 0, BLCKSZ - (entryno * sizeof(MultiXactOffset)));
2161
2162
0
    MultiXactOffsetCtl->shared->page_dirty[slotno] = true;
2163
0
    LWLockRelease(lock);
2164
0
  }
2165
2166
  /*
2167
   * And the same for members.
2168
   *
2169
   * (Re-)Initialize our idea of the latest page number for members.
2170
   */
2171
0
  pageno = MXOffsetToMemberPage(offset);
2172
0
  pg_atomic_write_u64(&MultiXactMemberCtl->shared->latest_page_number,
2173
0
            pageno);
2174
2175
  /*
2176
   * Zero out the remainder of the current members page.  See notes in
2177
   * TrimCLOG() for motivation.
2178
   */
2179
0
  flagsoff = MXOffsetToFlagsOffset(offset);
2180
0
  if (flagsoff != 0)
2181
0
  {
2182
0
    int     slotno;
2183
0
    TransactionId *xidptr;
2184
0
    int     memberoff;
2185
0
    LWLock     *lock = SimpleLruGetBankLock(MultiXactMemberCtl, pageno);
2186
2187
0
    LWLockAcquire(lock, LW_EXCLUSIVE);
2188
0
    memberoff = MXOffsetToMemberOffset(offset);
2189
0
    slotno = SimpleLruReadPage(MultiXactMemberCtl, pageno, true, offset);
2190
0
    xidptr = (TransactionId *)
2191
0
      (MultiXactMemberCtl->shared->page_buffer[slotno] + memberoff);
2192
2193
0
    MemSet(xidptr, 0, BLCKSZ - memberoff);
2194
2195
    /*
2196
     * Note: we don't need to zero out the flag bits in the remaining
2197
     * members of the current group, because they are always reset before
2198
     * writing.
2199
     */
2200
2201
0
    MultiXactMemberCtl->shared->page_dirty[slotno] = true;
2202
0
    LWLockRelease(lock);
2203
0
  }
2204
2205
  /* signal that we're officially up */
2206
0
  LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);
2207
0
  MultiXactState->finishedStartup = true;
2208
0
  LWLockRelease(MultiXactGenLock);
2209
2210
  /* Now compute how far away the next members wraparound is. */
2211
0
  SetMultiXactIdLimit(oldestMXact, oldestMXactDB, true);
2212
0
}
2213
2214
/*
2215
 * Get the MultiXact data to save in a checkpoint record
2216
 */
2217
void
2218
MultiXactGetCheckptMulti(bool is_shutdown,
2219
             MultiXactId *nextMulti,
2220
             MultiXactOffset *nextMultiOffset,
2221
             MultiXactId *oldestMulti,
2222
             Oid *oldestMultiDB)
2223
0
{
2224
0
  LWLockAcquire(MultiXactGenLock, LW_SHARED);
2225
0
  *nextMulti = MultiXactState->nextMXact;
2226
0
  *nextMultiOffset = MultiXactState->nextOffset;
2227
0
  *oldestMulti = MultiXactState->oldestMultiXactId;
2228
0
  *oldestMultiDB = MultiXactState->oldestMultiXactDB;
2229
0
  LWLockRelease(MultiXactGenLock);
2230
2231
0
  debug_elog6(DEBUG2,
2232
0
        "MultiXact: checkpoint is nextMulti %u, nextOffset %u, oldestMulti %u in DB %u",
2233
0
        *nextMulti, *nextMultiOffset, *oldestMulti, *oldestMultiDB);
2234
0
}
2235
2236
/*
2237
 * Perform a checkpoint --- either during shutdown, or on-the-fly
2238
 */
2239
void
2240
CheckPointMultiXact(void)
2241
0
{
2242
0
  TRACE_POSTGRESQL_MULTIXACT_CHECKPOINT_START(true);
2243
2244
  /*
2245
   * Write dirty MultiXact pages to disk.  This may result in sync requests
2246
   * queued for later handling by ProcessSyncRequests(), as part of the
2247
   * checkpoint.
2248
   */
2249
0
  SimpleLruWriteAll(MultiXactOffsetCtl, true);
2250
0
  SimpleLruWriteAll(MultiXactMemberCtl, true);
2251
2252
0
  TRACE_POSTGRESQL_MULTIXACT_CHECKPOINT_DONE(true);
2253
0
}
2254
2255
/*
2256
 * Set the next-to-be-assigned MultiXactId and offset
2257
 *
2258
 * This is used when we can determine the correct next ID/offset exactly
2259
 * from a checkpoint record.  Although this is only called during bootstrap
2260
 * and XLog replay, we take the lock in case any hot-standby backends are
2261
 * examining the values.
2262
 */
2263
void
2264
MultiXactSetNextMXact(MultiXactId nextMulti,
2265
            MultiXactOffset nextMultiOffset)
2266
0
{
2267
0
  debug_elog4(DEBUG2, "MultiXact: setting next multi to %u offset %u",
2268
0
        nextMulti, nextMultiOffset);
2269
0
  LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);
2270
0
  MultiXactState->nextMXact = nextMulti;
2271
0
  MultiXactState->nextOffset = nextMultiOffset;
2272
0
  LWLockRelease(MultiXactGenLock);
2273
2274
  /*
2275
   * During a binary upgrade, make sure that the offsets SLRU is large
2276
   * enough to contain the next value that would be created.
2277
   *
2278
   * We need to do this pretty early during the first startup in binary
2279
   * upgrade mode: before StartupMultiXact() in fact, because this routine
2280
   * is called even before that by StartupXLOG().  And we can't do it
2281
   * earlier than at this point, because during that first call of this
2282
   * routine we determine the MultiXactState->nextMXact value that
2283
   * MaybeExtendOffsetSlru needs.
2284
   */
2285
0
  if (IsBinaryUpgrade)
2286
0
    MaybeExtendOffsetSlru();
2287
0
}
2288
2289
/*
2290
 * Determine the last safe MultiXactId to allocate given the currently oldest
2291
 * datminmxid (ie, the oldest MultiXactId that might exist in any database
2292
 * of our cluster), and the OID of the (or a) database with that value.
2293
 *
2294
 * is_startup is true when we are just starting the cluster, false when we
2295
 * are updating state in a running cluster.  This only affects log messages.
2296
 */
2297
void
2298
SetMultiXactIdLimit(MultiXactId oldest_datminmxid, Oid oldest_datoid,
2299
          bool is_startup)
2300
0
{
2301
0
  MultiXactId multiVacLimit;
2302
0
  MultiXactId multiWarnLimit;
2303
0
  MultiXactId multiStopLimit;
2304
0
  MultiXactId multiWrapLimit;
2305
0
  MultiXactId curMulti;
2306
0
  bool    needs_offset_vacuum;
2307
2308
0
  Assert(MultiXactIdIsValid(oldest_datminmxid));
2309
2310
  /*
2311
   * We pretend that a wrap will happen halfway through the multixact ID
2312
   * space, but that's not really true, because multixacts wrap differently
2313
   * from transaction IDs.  Note that, separately from any concern about
2314
   * multixact IDs wrapping, we must ensure that multixact members do not
2315
   * wrap.  Limits for that are set in SetOffsetVacuumLimit, not here.
2316
   */
2317
0
  multiWrapLimit = oldest_datminmxid + (MaxMultiXactId >> 1);
2318
0
  if (multiWrapLimit < FirstMultiXactId)
2319
0
    multiWrapLimit += FirstMultiXactId;
2320
2321
  /*
2322
   * We'll refuse to continue assigning MultiXactIds once we get within 3M
2323
   * multi of data loss.  See SetTransactionIdLimit.
2324
   */
2325
0
  multiStopLimit = multiWrapLimit - 3000000;
2326
0
  if (multiStopLimit < FirstMultiXactId)
2327
0
    multiStopLimit -= FirstMultiXactId;
2328
2329
  /*
2330
   * We'll start complaining loudly when we get within 40M multis of data
2331
   * loss.  This is kind of arbitrary, but if you let your gas gauge get
2332
   * down to 2% of full, would you be looking for the next gas station?  We
2333
   * need to be fairly liberal about this number because there are lots of
2334
   * scenarios where most transactions are done by automatic clients that
2335
   * won't pay attention to warnings.  (No, we're not gonna make this
2336
   * configurable.  If you know enough to configure it, you know enough to
2337
   * not get in this kind of trouble in the first place.)
2338
   */
2339
0
  multiWarnLimit = multiWrapLimit - 40000000;
2340
0
  if (multiWarnLimit < FirstMultiXactId)
2341
0
    multiWarnLimit -= FirstMultiXactId;
2342
2343
  /*
2344
   * We'll start trying to force autovacuums when oldest_datminmxid gets to
2345
   * be more than autovacuum_multixact_freeze_max_age mxids old.
2346
   *
2347
   * Note: autovacuum_multixact_freeze_max_age is a PGC_POSTMASTER parameter
2348
   * so that we don't have to worry about dealing with on-the-fly changes in
2349
   * its value.  See SetTransactionIdLimit.
2350
   */
2351
0
  multiVacLimit = oldest_datminmxid + autovacuum_multixact_freeze_max_age;
2352
0
  if (multiVacLimit < FirstMultiXactId)
2353
0
    multiVacLimit += FirstMultiXactId;
2354
2355
  /* Grab lock for just long enough to set the new limit values */
2356
0
  LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);
2357
0
  MultiXactState->oldestMultiXactId = oldest_datminmxid;
2358
0
  MultiXactState->oldestMultiXactDB = oldest_datoid;
2359
0
  MultiXactState->multiVacLimit = multiVacLimit;
2360
0
  MultiXactState->multiWarnLimit = multiWarnLimit;
2361
0
  MultiXactState->multiStopLimit = multiStopLimit;
2362
0
  MultiXactState->multiWrapLimit = multiWrapLimit;
2363
0
  curMulti = MultiXactState->nextMXact;
2364
0
  LWLockRelease(MultiXactGenLock);
2365
2366
  /* Log the info */
2367
0
  ereport(DEBUG1,
2368
0
      (errmsg_internal("MultiXactId wrap limit is %u, limited by database with OID %u",
2369
0
               multiWrapLimit, oldest_datoid)));
2370
2371
  /*
2372
   * Computing the actual limits is only possible once the data directory is
2373
   * in a consistent state. There's no need to compute the limits while
2374
   * still replaying WAL - no decisions about new multis are made even
2375
   * though multixact creations might be replayed. So we'll only do further
2376
   * checks after TrimMultiXact() has been called.
2377
   */
2378
0
  if (!MultiXactState->finishedStartup)
2379
0
    return;
2380
2381
0
  Assert(!InRecovery);
2382
2383
  /* Set limits for offset vacuum. */
2384
0
  needs_offset_vacuum = SetOffsetVacuumLimit(is_startup);
2385
2386
  /*
2387
   * If past the autovacuum force point, immediately signal an autovac
2388
   * request.  The reason for this is that autovac only processes one
2389
   * database per invocation.  Once it's finished cleaning up the oldest
2390
   * database, it'll call here, and we'll signal the postmaster to start
2391
   * another iteration immediately if there are still any old databases.
2392
   */
2393
0
  if ((MultiXactIdPrecedes(multiVacLimit, curMulti) ||
2394
0
     needs_offset_vacuum) && IsUnderPostmaster)
2395
0
    SendPostmasterSignal(PMSIGNAL_START_AUTOVAC_LAUNCHER);
2396
2397
  /* Give an immediate warning if past the wrap warn point */
2398
0
  if (MultiXactIdPrecedes(multiWarnLimit, curMulti))
2399
0
  {
2400
0
    char     *oldest_datname;
2401
2402
    /*
2403
     * We can be called when not inside a transaction, for example during
2404
     * StartupXLOG().  In such a case we cannot do database access, so we
2405
     * must just report the oldest DB's OID.
2406
     *
2407
     * Note: it's also possible that get_database_name fails and returns
2408
     * NULL, for example because the database just got dropped.  We'll
2409
     * still warn, even though the warning might now be unnecessary.
2410
     */
2411
0
    if (IsTransactionState())
2412
0
      oldest_datname = get_database_name(oldest_datoid);
2413
0
    else
2414
0
      oldest_datname = NULL;
2415
2416
0
    if (oldest_datname)
2417
0
      ereport(WARNING,
2418
0
          (errmsg_plural("database \"%s\" must be vacuumed before %u more MultiXactId is used",
2419
0
                   "database \"%s\" must be vacuumed before %u more MultiXactIds are used",
2420
0
                   multiWrapLimit - curMulti,
2421
0
                   oldest_datname,
2422
0
                   multiWrapLimit - curMulti),
2423
0
           errhint("To avoid MultiXactId assignment failures, execute a database-wide VACUUM in that database.\n"
2424
0
               "You might also need to commit or roll back old prepared transactions, or drop stale replication slots.")));
2425
0
    else
2426
0
      ereport(WARNING,
2427
0
          (errmsg_plural("database with OID %u must be vacuumed before %u more MultiXactId is used",
2428
0
                   "database with OID %u must be vacuumed before %u more MultiXactIds are used",
2429
0
                   multiWrapLimit - curMulti,
2430
0
                   oldest_datoid,
2431
0
                   multiWrapLimit - curMulti),
2432
0
           errhint("To avoid MultiXactId assignment failures, execute a database-wide VACUUM in that database.\n"
2433
0
               "You might also need to commit or roll back old prepared transactions, or drop stale replication slots.")));
2434
0
  }
2435
0
}
2436
2437
/*
2438
 * Ensure the next-to-be-assigned MultiXactId is at least minMulti,
2439
 * and similarly nextOffset is at least minMultiOffset.
2440
 *
2441
 * This is used when we can determine minimum safe values from an XLog
2442
 * record (either an on-line checkpoint or an mxact creation log entry).
2443
 * Although this is only called during XLog replay, we take the lock in case
2444
 * any hot-standby backends are examining the values.
2445
 */
2446
void
2447
MultiXactAdvanceNextMXact(MultiXactId minMulti,
2448
              MultiXactOffset minMultiOffset)
2449
0
{
2450
0
  LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);
2451
0
  if (MultiXactIdPrecedes(MultiXactState->nextMXact, minMulti))
2452
0
  {
2453
0
    debug_elog3(DEBUG2, "MultiXact: setting next multi to %u", minMulti);
2454
0
    MultiXactState->nextMXact = minMulti;
2455
0
  }
2456
0
  if (MultiXactOffsetPrecedes(MultiXactState->nextOffset, minMultiOffset))
2457
0
  {
2458
0
    debug_elog3(DEBUG2, "MultiXact: setting next offset to %u",
2459
0
          minMultiOffset);
2460
0
    MultiXactState->nextOffset = minMultiOffset;
2461
0
  }
2462
0
  LWLockRelease(MultiXactGenLock);
2463
0
}
2464
2465
/*
2466
 * Update our oldestMultiXactId value, but only if it's more recent than what
2467
 * we had.
2468
 *
2469
 * This may only be called during WAL replay.
2470
 */
2471
void
2472
MultiXactAdvanceOldest(MultiXactId oldestMulti, Oid oldestMultiDB)
2473
0
{
2474
0
  Assert(InRecovery);
2475
2476
0
  if (MultiXactIdPrecedes(MultiXactState->oldestMultiXactId, oldestMulti))
2477
0
    SetMultiXactIdLimit(oldestMulti, oldestMultiDB, false);
2478
0
}
2479
2480
/*
2481
 * Make sure that MultiXactOffset has room for a newly-allocated MultiXactId.
2482
 *
2483
 * NB: this is called while holding MultiXactGenLock.  We want it to be very
2484
 * fast most of the time; even when it's not so fast, no actual I/O need
2485
 * happen unless we're forced to write out a dirty log or xlog page to make
2486
 * room in shared memory.
2487
 */
2488
static void
2489
ExtendMultiXactOffset(MultiXactId multi)
2490
0
{
2491
0
  int64   pageno;
2492
0
  LWLock     *lock;
2493
2494
  /*
2495
   * No work except at first MultiXactId of a page.  But beware: just after
2496
   * wraparound, the first MultiXactId of page zero is FirstMultiXactId.
2497
   */
2498
0
  if (MultiXactIdToOffsetEntry(multi) != 0 &&
2499
0
    multi != FirstMultiXactId)
2500
0
    return;
2501
2502
0
  pageno = MultiXactIdToOffsetPage(multi);
2503
0
  lock = SimpleLruGetBankLock(MultiXactOffsetCtl, pageno);
2504
2505
0
  LWLockAcquire(lock, LW_EXCLUSIVE);
2506
2507
  /* Zero the page and make a WAL entry about it */
2508
0
  SimpleLruZeroPage(MultiXactOffsetCtl, pageno);
2509
0
  XLogSimpleInsertInt64(RM_MULTIXACT_ID, XLOG_MULTIXACT_ZERO_OFF_PAGE,
2510
0
              pageno);
2511
2512
0
  LWLockRelease(lock);
2513
0
}
2514
2515
/*
2516
 * Make sure that MultiXactMember has room for the members of a newly-
2517
 * allocated MultiXactId.
2518
 *
2519
 * Like the above routine, this is called while holding MultiXactGenLock;
2520
 * same comments apply.
2521
 */
2522
static void
2523
ExtendMultiXactMember(MultiXactOffset offset, int nmembers)
2524
0
{
2525
  /*
2526
   * It's possible that the members span more than one page of the members
2527
   * file, so we loop to ensure we consider each page.  The coding is not
2528
   * optimal if the members span several pages, but that seems unusual
2529
   * enough to not worry much about.
2530
   */
2531
0
  while (nmembers > 0)
2532
0
  {
2533
0
    int     flagsoff;
2534
0
    int     flagsbit;
2535
0
    uint32    difference;
2536
2537
    /*
2538
     * Only zero when at first entry of a page.
2539
     */
2540
0
    flagsoff = MXOffsetToFlagsOffset(offset);
2541
0
    flagsbit = MXOffsetToFlagsBitShift(offset);
2542
0
    if (flagsoff == 0 && flagsbit == 0)
2543
0
    {
2544
0
      int64   pageno;
2545
0
      LWLock     *lock;
2546
2547
0
      pageno = MXOffsetToMemberPage(offset);
2548
0
      lock = SimpleLruGetBankLock(MultiXactMemberCtl, pageno);
2549
2550
0
      LWLockAcquire(lock, LW_EXCLUSIVE);
2551
2552
      /* Zero the page and make a WAL entry about it */
2553
0
      SimpleLruZeroPage(MultiXactMemberCtl, pageno);
2554
0
      XLogSimpleInsertInt64(RM_MULTIXACT_ID,
2555
0
                  XLOG_MULTIXACT_ZERO_MEM_PAGE, pageno);
2556
2557
0
      LWLockRelease(lock);
2558
0
    }
2559
2560
    /*
2561
     * Compute the number of items till end of current page.  Careful: if
2562
     * addition of unsigned ints wraps around, we're at the last page of
2563
     * the last segment; since that page holds a different number of items
2564
     * than other pages, we need to do it differently.
2565
     */
2566
0
    if (offset + MAX_MEMBERS_IN_LAST_MEMBERS_PAGE < offset)
2567
0
    {
2568
      /*
2569
       * This is the last page of the last segment; we can compute the
2570
       * number of items left to allocate in it without modulo
2571
       * arithmetic.
2572
       */
2573
0
      difference = MaxMultiXactOffset - offset + 1;
2574
0
    }
2575
0
    else
2576
0
      difference = MULTIXACT_MEMBERS_PER_PAGE - offset % MULTIXACT_MEMBERS_PER_PAGE;
2577
2578
    /*
2579
     * Advance to next page, taking care to properly handle the wraparound
2580
     * case.  OK if nmembers goes negative.
2581
     */
2582
0
    nmembers -= difference;
2583
0
    offset += difference;
2584
0
  }
2585
0
}
2586
2587
/*
2588
 * GetOldestMultiXactId
2589
 *
2590
 * Return the oldest MultiXactId that's still possibly still seen as live by
2591
 * any running transaction.  Older ones might still exist on disk, but they no
2592
 * longer have any running member transaction.
2593
 *
2594
 * It's not safe to truncate MultiXact SLRU segments on the value returned by
2595
 * this function; however, it can be set as the new relminmxid for any table
2596
 * that VACUUM knows has no remaining MXIDs < the same value.  It is only safe
2597
 * to truncate SLRUs when no table can possibly still have a referencing MXID.
2598
 */
2599
MultiXactId
2600
GetOldestMultiXactId(void)
2601
0
{
2602
0
  MultiXactId oldestMXact;
2603
0
  MultiXactId nextMXact;
2604
0
  int     i;
2605
2606
  /*
2607
   * This is the oldest valid value among all the OldestMemberMXactId[] and
2608
   * OldestVisibleMXactId[] entries, or nextMXact if none are valid.
2609
   */
2610
0
  LWLockAcquire(MultiXactGenLock, LW_SHARED);
2611
2612
  /*
2613
   * We have to beware of the possibility that nextMXact is in the
2614
   * wrapped-around state.  We don't fix the counter itself here, but we
2615
   * must be sure to use a valid value in our calculation.
2616
   */
2617
0
  nextMXact = MultiXactState->nextMXact;
2618
0
  if (nextMXact < FirstMultiXactId)
2619
0
    nextMXact = FirstMultiXactId;
2620
2621
0
  oldestMXact = nextMXact;
2622
0
  for (i = 0; i < MaxOldestSlot; i++)
2623
0
  {
2624
0
    MultiXactId thisoldest;
2625
2626
0
    thisoldest = OldestMemberMXactId[i];
2627
0
    if (MultiXactIdIsValid(thisoldest) &&
2628
0
      MultiXactIdPrecedes(thisoldest, oldestMXact))
2629
0
      oldestMXact = thisoldest;
2630
0
    thisoldest = OldestVisibleMXactId[i];
2631
0
    if (MultiXactIdIsValid(thisoldest) &&
2632
0
      MultiXactIdPrecedes(thisoldest, oldestMXact))
2633
0
      oldestMXact = thisoldest;
2634
0
  }
2635
2636
0
  LWLockRelease(MultiXactGenLock);
2637
2638
0
  return oldestMXact;
2639
0
}
2640
2641
/*
2642
 * Determine how aggressively we need to vacuum in order to prevent member
2643
 * wraparound.
2644
 *
2645
 * To do so determine what's the oldest member offset and install the limit
2646
 * info in MultiXactState, where it can be used to prevent overrun of old data
2647
 * in the members SLRU area.
2648
 *
2649
 * The return value is true if emergency autovacuum is required and false
2650
 * otherwise.
2651
 */
2652
static bool
2653
SetOffsetVacuumLimit(bool is_startup)
2654
0
{
2655
0
  MultiXactId oldestMultiXactId;
2656
0
  MultiXactId nextMXact;
2657
0
  MultiXactOffset oldestOffset = 0; /* placate compiler */
2658
0
  MultiXactOffset prevOldestOffset;
2659
0
  MultiXactOffset nextOffset;
2660
0
  bool    oldestOffsetKnown = false;
2661
0
  bool    prevOldestOffsetKnown;
2662
0
  MultiXactOffset offsetStopLimit = 0;
2663
0
  MultiXactOffset prevOffsetStopLimit;
2664
2665
  /*
2666
   * NB: Have to prevent concurrent truncation, we might otherwise try to
2667
   * lookup an oldestMulti that's concurrently getting truncated away.
2668
   */
2669
0
  LWLockAcquire(MultiXactTruncationLock, LW_SHARED);
2670
2671
  /* Read relevant fields from shared memory. */
2672
0
  LWLockAcquire(MultiXactGenLock, LW_SHARED);
2673
0
  oldestMultiXactId = MultiXactState->oldestMultiXactId;
2674
0
  nextMXact = MultiXactState->nextMXact;
2675
0
  nextOffset = MultiXactState->nextOffset;
2676
0
  prevOldestOffsetKnown = MultiXactState->oldestOffsetKnown;
2677
0
  prevOldestOffset = MultiXactState->oldestOffset;
2678
0
  prevOffsetStopLimit = MultiXactState->offsetStopLimit;
2679
0
  Assert(MultiXactState->finishedStartup);
2680
0
  LWLockRelease(MultiXactGenLock);
2681
2682
  /*
2683
   * Determine the offset of the oldest multixact.  Normally, we can read
2684
   * the offset from the multixact itself, but there's an important special
2685
   * case: if there are no multixacts in existence at all, oldestMXact
2686
   * obviously can't point to one.  It will instead point to the multixact
2687
   * ID that will be assigned the next time one is needed.
2688
   */
2689
0
  if (oldestMultiXactId == nextMXact)
2690
0
  {
2691
    /*
2692
     * When the next multixact gets created, it will be stored at the next
2693
     * offset.
2694
     */
2695
0
    oldestOffset = nextOffset;
2696
0
    oldestOffsetKnown = true;
2697
0
  }
2698
0
  else
2699
0
  {
2700
    /*
2701
     * Figure out where the oldest existing multixact's offsets are
2702
     * stored. Due to bugs in early release of PostgreSQL 9.3.X and 9.4.X,
2703
     * the supposedly-earliest multixact might not really exist.  We are
2704
     * careful not to fail in that case.
2705
     */
2706
0
    oldestOffsetKnown =
2707
0
      find_multixact_start(oldestMultiXactId, &oldestOffset);
2708
2709
0
    if (oldestOffsetKnown)
2710
0
      ereport(DEBUG1,
2711
0
          (errmsg_internal("oldest MultiXactId member is at offset %u",
2712
0
                   oldestOffset)));
2713
0
    else
2714
0
      ereport(LOG,
2715
0
          (errmsg("MultiXact member wraparound protections are disabled because oldest checkpointed MultiXact %u does not exist on disk",
2716
0
              oldestMultiXactId)));
2717
0
  }
2718
2719
0
  LWLockRelease(MultiXactTruncationLock);
2720
2721
  /*
2722
   * If we can, compute limits (and install them MultiXactState) to prevent
2723
   * overrun of old data in the members SLRU area. We can only do so if the
2724
   * oldest offset is known though.
2725
   */
2726
0
  if (oldestOffsetKnown)
2727
0
  {
2728
    /* move back to start of the corresponding segment */
2729
0
    offsetStopLimit = oldestOffset - (oldestOffset %
2730
0
                      (MULTIXACT_MEMBERS_PER_PAGE * SLRU_PAGES_PER_SEGMENT));
2731
2732
    /* always leave one segment before the wraparound point */
2733
0
    offsetStopLimit -= (MULTIXACT_MEMBERS_PER_PAGE * SLRU_PAGES_PER_SEGMENT);
2734
2735
0
    if (!prevOldestOffsetKnown && !is_startup)
2736
0
      ereport(LOG,
2737
0
          (errmsg("MultiXact member wraparound protections are now enabled")));
2738
2739
0
    ereport(DEBUG1,
2740
0
        (errmsg_internal("MultiXact member stop limit is now %u based on MultiXact %u",
2741
0
                 offsetStopLimit, oldestMultiXactId)));
2742
0
  }
2743
0
  else if (prevOldestOffsetKnown)
2744
0
  {
2745
    /*
2746
     * If we failed to get the oldest offset this time, but we have a
2747
     * value from a previous pass through this function, use the old
2748
     * values rather than automatically forcing an emergency autovacuum
2749
     * cycle again.
2750
     */
2751
0
    oldestOffset = prevOldestOffset;
2752
0
    oldestOffsetKnown = true;
2753
0
    offsetStopLimit = prevOffsetStopLimit;
2754
0
  }
2755
2756
  /* Install the computed values */
2757
0
  LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);
2758
0
  MultiXactState->oldestOffset = oldestOffset;
2759
0
  MultiXactState->oldestOffsetKnown = oldestOffsetKnown;
2760
0
  MultiXactState->offsetStopLimit = offsetStopLimit;
2761
0
  LWLockRelease(MultiXactGenLock);
2762
2763
  /*
2764
   * Do we need an emergency autovacuum?  If we're not sure, assume yes.
2765
   */
2766
0
  return !oldestOffsetKnown ||
2767
0
    (nextOffset - oldestOffset > MULTIXACT_MEMBER_SAFE_THRESHOLD);
2768
0
}
2769
2770
/*
2771
 * Return whether adding "distance" to "start" would move past "boundary".
2772
 *
2773
 * We use this to determine whether the addition is "wrapping around" the
2774
 * boundary point, hence the name.  The reason we don't want to use the regular
2775
 * 2^31-modulo arithmetic here is that we want to be able to use the whole of
2776
 * the 2^32-1 space here, allowing for more multixacts than would fit
2777
 * otherwise.
2778
 */
2779
static bool
2780
MultiXactOffsetWouldWrap(MultiXactOffset boundary, MultiXactOffset start,
2781
             uint32 distance)
2782
0
{
2783
0
  MultiXactOffset finish;
2784
2785
  /*
2786
   * Note that offset number 0 is not used (see GetMultiXactIdMembers), so
2787
   * if the addition wraps around the UINT_MAX boundary, skip that value.
2788
   */
2789
0
  finish = start + distance;
2790
0
  if (finish < start)
2791
0
    finish++;
2792
2793
  /*-----------------------------------------------------------------------
2794
   * When the boundary is numerically greater than the starting point, any
2795
   * value numerically between the two is not wrapped:
2796
   *
2797
   *  <----S----B---->
2798
   *  [---)      = F wrapped past B (and UINT_MAX)
2799
   *     [---)     = F not wrapped
2800
   *        [----] = F wrapped past B
2801
   *
2802
   * When the boundary is numerically less than the starting point (i.e. the
2803
   * UINT_MAX wraparound occurs somewhere in between) then all values in
2804
   * between are wrapped:
2805
   *
2806
   *  <----B----S---->
2807
   *  [---)      = F not wrapped past B (but wrapped past UINT_MAX)
2808
   *     [---)     = F wrapped past B (and UINT_MAX)
2809
   *        [----] = F not wrapped
2810
   *-----------------------------------------------------------------------
2811
   */
2812
0
  if (start < boundary)
2813
0
    return finish >= boundary || finish < start;
2814
0
  else
2815
0
    return finish >= boundary && finish < start;
2816
0
}
2817
2818
/*
2819
 * Find the starting offset of the given MultiXactId.
2820
 *
2821
 * Returns false if the file containing the multi does not exist on disk.
2822
 * Otherwise, returns true and sets *result to the starting member offset.
2823
 *
2824
 * This function does not prevent concurrent truncation, so if that's
2825
 * required, the caller has to protect against that.
2826
 */
2827
static bool
2828
find_multixact_start(MultiXactId multi, MultiXactOffset *result)
2829
0
{
2830
0
  MultiXactOffset offset;
2831
0
  int64   pageno;
2832
0
  int     entryno;
2833
0
  int     slotno;
2834
0
  MultiXactOffset *offptr;
2835
2836
0
  Assert(MultiXactState->finishedStartup);
2837
2838
0
  pageno = MultiXactIdToOffsetPage(multi);
2839
0
  entryno = MultiXactIdToOffsetEntry(multi);
2840
2841
  /*
2842
   * Write out dirty data, so PhysicalPageExists can work correctly.
2843
   */
2844
0
  SimpleLruWriteAll(MultiXactOffsetCtl, true);
2845
0
  SimpleLruWriteAll(MultiXactMemberCtl, true);
2846
2847
0
  if (!SimpleLruDoesPhysicalPageExist(MultiXactOffsetCtl, pageno))
2848
0
    return false;
2849
2850
  /* lock is acquired by SimpleLruReadPage_ReadOnly */
2851
0
  slotno = SimpleLruReadPage_ReadOnly(MultiXactOffsetCtl, pageno, multi);
2852
0
  offptr = (MultiXactOffset *) MultiXactOffsetCtl->shared->page_buffer[slotno];
2853
0
  offptr += entryno;
2854
0
  offset = *offptr;
2855
0
  LWLockRelease(SimpleLruGetBankLock(MultiXactOffsetCtl, pageno));
2856
2857
0
  *result = offset;
2858
0
  return true;
2859
0
}
2860
2861
/*
2862
 * Determine how many multixacts, and how many multixact members, currently
2863
 * exist.  Return false if unable to determine.
2864
 */
2865
static bool
2866
ReadMultiXactCounts(uint32 *multixacts, MultiXactOffset *members)
2867
0
{
2868
0
  MultiXactOffset nextOffset;
2869
0
  MultiXactOffset oldestOffset;
2870
0
  MultiXactId oldestMultiXactId;
2871
0
  MultiXactId nextMultiXactId;
2872
0
  bool    oldestOffsetKnown;
2873
2874
0
  LWLockAcquire(MultiXactGenLock, LW_SHARED);
2875
0
  nextOffset = MultiXactState->nextOffset;
2876
0
  oldestMultiXactId = MultiXactState->oldestMultiXactId;
2877
0
  nextMultiXactId = MultiXactState->nextMXact;
2878
0
  oldestOffset = MultiXactState->oldestOffset;
2879
0
  oldestOffsetKnown = MultiXactState->oldestOffsetKnown;
2880
0
  LWLockRelease(MultiXactGenLock);
2881
2882
0
  if (!oldestOffsetKnown)
2883
0
    return false;
2884
2885
0
  *members = nextOffset - oldestOffset;
2886
0
  *multixacts = nextMultiXactId - oldestMultiXactId;
2887
0
  return true;
2888
0
}
2889
2890
/*
2891
 * Multixact members can be removed once the multixacts that refer to them
2892
 * are older than every datminmxid.  autovacuum_multixact_freeze_max_age and
2893
 * vacuum_multixact_freeze_table_age work together to make sure we never have
2894
 * too many multixacts; we hope that, at least under normal circumstances,
2895
 * this will also be sufficient to keep us from using too many offsets.
2896
 * However, if the average multixact has many members, we might exhaust the
2897
 * members space while still using few enough members that these limits fail
2898
 * to trigger relminmxid advancement by VACUUM.  At that point, we'd have no
2899
 * choice but to start failing multixact-creating operations with an error.
2900
 *
2901
 * To prevent that, if more than a threshold portion of the members space is
2902
 * used, we effectively reduce autovacuum_multixact_freeze_max_age and
2903
 * to a value just less than the number of multixacts in use.  We hope that
2904
 * this will quickly trigger autovacuuming on the table or tables with the
2905
 * oldest relminmxid, thus allowing datminmxid values to advance and removing
2906
 * some members.
2907
 *
2908
 * As the fraction of the member space currently in use grows, we become
2909
 * more aggressive in clamping this value.  That not only causes autovacuum
2910
 * to ramp up, but also makes any manual vacuums the user issues more
2911
 * aggressive.  This happens because vacuum_get_cutoffs() will clamp the
2912
 * freeze table and the minimum freeze age cutoffs based on the effective
2913
 * autovacuum_multixact_freeze_max_age this function returns.  In the worst
2914
 * case, we'll claim the freeze_max_age to zero, and every vacuum of any
2915
 * table will freeze every multixact.
2916
 */
2917
int
2918
MultiXactMemberFreezeThreshold(void)
2919
0
{
2920
0
  MultiXactOffset members;
2921
0
  uint32    multixacts;
2922
0
  uint32    victim_multixacts;
2923
0
  double    fraction;
2924
0
  int     result;
2925
2926
  /* If we can't determine member space utilization, assume the worst. */
2927
0
  if (!ReadMultiXactCounts(&multixacts, &members))
2928
0
    return 0;
2929
2930
  /* If member space utilization is low, no special action is required. */
2931
0
  if (members <= MULTIXACT_MEMBER_SAFE_THRESHOLD)
2932
0
    return autovacuum_multixact_freeze_max_age;
2933
2934
  /*
2935
   * Compute a target for relminmxid advancement.  The number of multixacts
2936
   * we try to eliminate from the system is based on how far we are past
2937
   * MULTIXACT_MEMBER_SAFE_THRESHOLD.
2938
   */
2939
0
  fraction = (double) (members - MULTIXACT_MEMBER_SAFE_THRESHOLD) /
2940
0
    (MULTIXACT_MEMBER_DANGER_THRESHOLD - MULTIXACT_MEMBER_SAFE_THRESHOLD);
2941
0
  victim_multixacts = multixacts * fraction;
2942
2943
  /* fraction could be > 1.0, but lowest possible freeze age is zero */
2944
0
  if (victim_multixacts > multixacts)
2945
0
    return 0;
2946
0
  result = multixacts - victim_multixacts;
2947
2948
  /*
2949
   * Clamp to autovacuum_multixact_freeze_max_age, so that we never make
2950
   * autovacuum less aggressive than it would otherwise be.
2951
   */
2952
0
  return Min(result, autovacuum_multixact_freeze_max_age);
2953
0
}
2954
2955
typedef struct mxtruncinfo
2956
{
2957
  int64   earliestExistingPage;
2958
} mxtruncinfo;
2959
2960
/*
2961
 * SlruScanDirectory callback
2962
 *    This callback determines the earliest existing page number.
2963
 */
2964
static bool
2965
SlruScanDirCbFindEarliest(SlruCtl ctl, char *filename, int64 segpage, void *data)
2966
0
{
2967
0
  mxtruncinfo *trunc = (mxtruncinfo *) data;
2968
2969
0
  if (trunc->earliestExistingPage == -1 ||
2970
0
    ctl->PagePrecedes(segpage, trunc->earliestExistingPage))
2971
0
  {
2972
0
    trunc->earliestExistingPage = segpage;
2973
0
  }
2974
2975
0
  return false;       /* keep going */
2976
0
}
2977
2978
2979
/*
2980
 * Delete members segments [oldest, newOldest)
2981
 *
2982
 * The members SLRU can, in contrast to the offsets one, be filled to almost
2983
 * the full range at once. This means SimpleLruTruncate() can't trivially be
2984
 * used - instead the to-be-deleted range is computed using the offsets
2985
 * SLRU. C.f. TruncateMultiXact().
2986
 */
2987
static void
2988
PerformMembersTruncation(MultiXactOffset oldestOffset, MultiXactOffset newOldestOffset)
2989
0
{
2990
0
  const int64 maxsegment = MXOffsetToMemberSegment(MaxMultiXactOffset);
2991
0
  int64   startsegment = MXOffsetToMemberSegment(oldestOffset);
2992
0
  int64   endsegment = MXOffsetToMemberSegment(newOldestOffset);
2993
0
  int64   segment = startsegment;
2994
2995
  /*
2996
   * Delete all the segments but the last one. The last segment can still
2997
   * contain, possibly partially, valid data.
2998
   */
2999
0
  while (segment != endsegment)
3000
0
  {
3001
0
    elog(DEBUG2, "truncating multixact members segment %" PRIx64,
3002
0
       segment);
3003
0
    SlruDeleteSegment(MultiXactMemberCtl, segment);
3004
3005
    /* move to next segment, handling wraparound correctly */
3006
0
    if (segment == maxsegment)
3007
0
      segment = 0;
3008
0
    else
3009
0
      segment += 1;
3010
0
  }
3011
0
}
3012
3013
/*
3014
 * Delete offsets segments [oldest, newOldest)
3015
 */
3016
static void
3017
PerformOffsetsTruncation(MultiXactId oldestMulti, MultiXactId newOldestMulti)
3018
0
{
3019
  /*
3020
   * We step back one multixact to avoid passing a cutoff page that hasn't
3021
   * been created yet in the rare case that oldestMulti would be the first
3022
   * item on a page and oldestMulti == nextMulti.  In that case, if we
3023
   * didn't subtract one, we'd trigger SimpleLruTruncate's wraparound
3024
   * detection.
3025
   */
3026
0
  SimpleLruTruncate(MultiXactOffsetCtl,
3027
0
            MultiXactIdToOffsetPage(PreviousMultiXactId(newOldestMulti)));
3028
0
}
3029
3030
/*
3031
 * Remove all MultiXactOffset and MultiXactMember segments before the oldest
3032
 * ones still of interest.
3033
 *
3034
 * This is only called on a primary as part of vacuum (via
3035
 * vac_truncate_clog()). During recovery truncation is done by replaying
3036
 * truncation WAL records logged here.
3037
 *
3038
 * newOldestMulti is the oldest currently required multixact, newOldestMultiDB
3039
 * is one of the databases preventing newOldestMulti from increasing.
3040
 */
3041
void
3042
TruncateMultiXact(MultiXactId newOldestMulti, Oid newOldestMultiDB)
3043
0
{
3044
0
  MultiXactId oldestMulti;
3045
0
  MultiXactId nextMulti;
3046
0
  MultiXactOffset newOldestOffset;
3047
0
  MultiXactOffset oldestOffset;
3048
0
  MultiXactOffset nextOffset;
3049
0
  mxtruncinfo trunc;
3050
0
  MultiXactId earliest;
3051
3052
0
  Assert(!RecoveryInProgress());
3053
0
  Assert(MultiXactState->finishedStartup);
3054
3055
  /*
3056
   * We can only allow one truncation to happen at once. Otherwise parts of
3057
   * members might vanish while we're doing lookups or similar. There's no
3058
   * need to have an interlock with creating new multis or such, since those
3059
   * are constrained by the limits (which only grow, never shrink).
3060
   */
3061
0
  LWLockAcquire(MultiXactTruncationLock, LW_EXCLUSIVE);
3062
3063
0
  LWLockAcquire(MultiXactGenLock, LW_SHARED);
3064
0
  nextMulti = MultiXactState->nextMXact;
3065
0
  nextOffset = MultiXactState->nextOffset;
3066
0
  oldestMulti = MultiXactState->oldestMultiXactId;
3067
0
  LWLockRelease(MultiXactGenLock);
3068
0
  Assert(MultiXactIdIsValid(oldestMulti));
3069
3070
  /*
3071
   * Make sure to only attempt truncation if there's values to truncate
3072
   * away. In normal processing values shouldn't go backwards, but there's
3073
   * some corner cases (due to bugs) where that's possible.
3074
   */
3075
0
  if (MultiXactIdPrecedesOrEquals(newOldestMulti, oldestMulti))
3076
0
  {
3077
0
    LWLockRelease(MultiXactTruncationLock);
3078
0
    return;
3079
0
  }
3080
3081
  /*
3082
   * Note we can't just plow ahead with the truncation; it's possible that
3083
   * there are no segments to truncate, which is a problem because we are
3084
   * going to attempt to read the offsets page to determine where to
3085
   * truncate the members SLRU.  So we first scan the directory to determine
3086
   * the earliest offsets page number that we can read without error.
3087
   *
3088
   * When nextMXact is less than one segment away from multiWrapLimit,
3089
   * SlruScanDirCbFindEarliest can find some early segment other than the
3090
   * actual earliest.  (MultiXactOffsetPagePrecedes(EARLIEST, LATEST)
3091
   * returns false, because not all pairs of entries have the same answer.)
3092
   * That can also arise when an earlier truncation attempt failed unlink()
3093
   * or returned early from this function.  The only consequence is
3094
   * returning early, which wastes space that we could have liberated.
3095
   *
3096
   * NB: It's also possible that the page that oldestMulti is on has already
3097
   * been truncated away, and we crashed before updating oldestMulti.
3098
   */
3099
0
  trunc.earliestExistingPage = -1;
3100
0
  SlruScanDirectory(MultiXactOffsetCtl, SlruScanDirCbFindEarliest, &trunc);
3101
0
  earliest = trunc.earliestExistingPage * MULTIXACT_OFFSETS_PER_PAGE;
3102
0
  if (earliest < FirstMultiXactId)
3103
0
    earliest = FirstMultiXactId;
3104
3105
  /* If there's nothing to remove, we can bail out early. */
3106
0
  if (MultiXactIdPrecedes(oldestMulti, earliest))
3107
0
  {
3108
0
    LWLockRelease(MultiXactTruncationLock);
3109
0
    return;
3110
0
  }
3111
3112
  /*
3113
   * First, compute the safe truncation point for MultiXactMember. This is
3114
   * the starting offset of the oldest multixact.
3115
   *
3116
   * Hopefully, find_multixact_start will always work here, because we've
3117
   * already checked that it doesn't precede the earliest MultiXact on disk.
3118
   * But if it fails, don't truncate anything, and log a message.
3119
   */
3120
0
  if (oldestMulti == nextMulti)
3121
0
  {
3122
    /* there are NO MultiXacts */
3123
0
    oldestOffset = nextOffset;
3124
0
  }
3125
0
  else if (!find_multixact_start(oldestMulti, &oldestOffset))
3126
0
  {
3127
0
    ereport(LOG,
3128
0
        (errmsg("oldest MultiXact %u not found, earliest MultiXact %u, skipping truncation",
3129
0
            oldestMulti, earliest)));
3130
0
    LWLockRelease(MultiXactTruncationLock);
3131
0
    return;
3132
0
  }
3133
3134
  /*
3135
   * Secondly compute up to where to truncate. Lookup the corresponding
3136
   * member offset for newOldestMulti for that.
3137
   */
3138
0
  if (newOldestMulti == nextMulti)
3139
0
  {
3140
    /* there are NO MultiXacts */
3141
0
    newOldestOffset = nextOffset;
3142
0
  }
3143
0
  else if (!find_multixact_start(newOldestMulti, &newOldestOffset))
3144
0
  {
3145
0
    ereport(LOG,
3146
0
        (errmsg("cannot truncate up to MultiXact %u because it does not exist on disk, skipping truncation",
3147
0
            newOldestMulti)));
3148
0
    LWLockRelease(MultiXactTruncationLock);
3149
0
    return;
3150
0
  }
3151
3152
0
  elog(DEBUG1, "performing multixact truncation: "
3153
0
     "offsets [%u, %u), offsets segments [%" PRIx64 ", %" PRIx64 "), "
3154
0
     "members [%u, %u), members segments [%" PRIx64 ", %" PRIx64 ")",
3155
0
     oldestMulti, newOldestMulti,
3156
0
     MultiXactIdToOffsetSegment(oldestMulti),
3157
0
     MultiXactIdToOffsetSegment(newOldestMulti),
3158
0
     oldestOffset, newOldestOffset,
3159
0
     MXOffsetToMemberSegment(oldestOffset),
3160
0
     MXOffsetToMemberSegment(newOldestOffset));
3161
3162
  /*
3163
   * Do truncation, and the WAL logging of the truncation, in a critical
3164
   * section. That way offsets/members cannot get out of sync anymore, i.e.
3165
   * once consistent the newOldestMulti will always exist in members, even
3166
   * if we crashed in the wrong moment.
3167
   */
3168
0
  START_CRIT_SECTION();
3169
3170
  /*
3171
   * Prevent checkpoints from being scheduled concurrently. This is critical
3172
   * because otherwise a truncation record might not be replayed after a
3173
   * crash/basebackup, even though the state of the data directory would
3174
   * require it.
3175
   */
3176
0
  Assert((MyProc->delayChkptFlags & DELAY_CHKPT_START) == 0);
3177
0
  MyProc->delayChkptFlags |= DELAY_CHKPT_START;
3178
3179
  /* WAL log truncation */
3180
0
  WriteMTruncateXlogRec(newOldestMultiDB,
3181
0
              oldestMulti, newOldestMulti,
3182
0
              oldestOffset, newOldestOffset);
3183
3184
  /*
3185
   * Update in-memory limits before performing the truncation, while inside
3186
   * the critical section: Have to do it before truncation, to prevent
3187
   * concurrent lookups of those values. Has to be inside the critical
3188
   * section as otherwise a future call to this function would error out,
3189
   * while looking up the oldest member in offsets, if our caller crashes
3190
   * before updating the limits.
3191
   */
3192
0
  LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);
3193
0
  MultiXactState->oldestMultiXactId = newOldestMulti;
3194
0
  MultiXactState->oldestMultiXactDB = newOldestMultiDB;
3195
0
  LWLockRelease(MultiXactGenLock);
3196
3197
  /* First truncate members */
3198
0
  PerformMembersTruncation(oldestOffset, newOldestOffset);
3199
3200
  /* Then offsets */
3201
0
  PerformOffsetsTruncation(oldestMulti, newOldestMulti);
3202
3203
0
  MyProc->delayChkptFlags &= ~DELAY_CHKPT_START;
3204
3205
0
  END_CRIT_SECTION();
3206
0
  LWLockRelease(MultiXactTruncationLock);
3207
0
}
3208
3209
/*
3210
 * Decide whether a MultiXactOffset page number is "older" for truncation
3211
 * purposes.  Analogous to CLOGPagePrecedes().
3212
 *
3213
 * Offsetting the values is optional, because MultiXactIdPrecedes() has
3214
 * translational symmetry.
3215
 */
3216
static bool
3217
MultiXactOffsetPagePrecedes(int64 page1, int64 page2)
3218
0
{
3219
0
  MultiXactId multi1;
3220
0
  MultiXactId multi2;
3221
3222
0
  multi1 = ((MultiXactId) page1) * MULTIXACT_OFFSETS_PER_PAGE;
3223
0
  multi1 += FirstMultiXactId + 1;
3224
0
  multi2 = ((MultiXactId) page2) * MULTIXACT_OFFSETS_PER_PAGE;
3225
0
  multi2 += FirstMultiXactId + 1;
3226
3227
0
  return (MultiXactIdPrecedes(multi1, multi2) &&
3228
0
      MultiXactIdPrecedes(multi1,
3229
0
                multi2 + MULTIXACT_OFFSETS_PER_PAGE - 1));
3230
0
}
3231
3232
/*
3233
 * Decide whether a MultiXactMember page number is "older" for truncation
3234
 * purposes.  There is no "invalid offset number" so use the numbers verbatim.
3235
 */
3236
static bool
3237
MultiXactMemberPagePrecedes(int64 page1, int64 page2)
3238
0
{
3239
0
  MultiXactOffset offset1;
3240
0
  MultiXactOffset offset2;
3241
3242
0
  offset1 = ((MultiXactOffset) page1) * MULTIXACT_MEMBERS_PER_PAGE;
3243
0
  offset2 = ((MultiXactOffset) page2) * MULTIXACT_MEMBERS_PER_PAGE;
3244
3245
0
  return (MultiXactOffsetPrecedes(offset1, offset2) &&
3246
0
      MultiXactOffsetPrecedes(offset1,
3247
0
                  offset2 + MULTIXACT_MEMBERS_PER_PAGE - 1));
3248
0
}
3249
3250
/*
3251
 * Decide which of two MultiXactIds is earlier.
3252
 *
3253
 * XXX do we need to do something special for InvalidMultiXactId?
3254
 * (Doesn't look like it.)
3255
 */
3256
bool
3257
MultiXactIdPrecedes(MultiXactId multi1, MultiXactId multi2)
3258
0
{
3259
0
  int32   diff = (int32) (multi1 - multi2);
3260
3261
0
  return (diff < 0);
3262
0
}
3263
3264
/*
3265
 * MultiXactIdPrecedesOrEquals -- is multi1 logically <= multi2?
3266
 *
3267
 * XXX do we need to do something special for InvalidMultiXactId?
3268
 * (Doesn't look like it.)
3269
 */
3270
bool
3271
MultiXactIdPrecedesOrEquals(MultiXactId multi1, MultiXactId multi2)
3272
0
{
3273
0
  int32   diff = (int32) (multi1 - multi2);
3274
3275
0
  return (diff <= 0);
3276
0
}
3277
3278
3279
/*
3280
 * Decide which of two offsets is earlier.
3281
 */
3282
static bool
3283
MultiXactOffsetPrecedes(MultiXactOffset offset1, MultiXactOffset offset2)
3284
0
{
3285
0
  int32   diff = (int32) (offset1 - offset2);
3286
3287
0
  return (diff < 0);
3288
0
}
3289
3290
/*
3291
 * Write a TRUNCATE xlog record
3292
 *
3293
 * We must flush the xlog record to disk before returning --- see notes in
3294
 * TruncateCLOG().
3295
 */
3296
static void
3297
WriteMTruncateXlogRec(Oid oldestMultiDB,
3298
            MultiXactId startTruncOff, MultiXactId endTruncOff,
3299
            MultiXactOffset startTruncMemb, MultiXactOffset endTruncMemb)
3300
0
{
3301
0
  XLogRecPtr  recptr;
3302
0
  xl_multixact_truncate xlrec;
3303
3304
0
  xlrec.oldestMultiDB = oldestMultiDB;
3305
3306
0
  xlrec.startTruncOff = startTruncOff;
3307
0
  xlrec.endTruncOff = endTruncOff;
3308
3309
0
  xlrec.startTruncMemb = startTruncMemb;
3310
0
  xlrec.endTruncMemb = endTruncMemb;
3311
3312
0
  XLogBeginInsert();
3313
0
  XLogRegisterData(&xlrec, SizeOfMultiXactTruncate);
3314
0
  recptr = XLogInsert(RM_MULTIXACT_ID, XLOG_MULTIXACT_TRUNCATE_ID);
3315
0
  XLogFlush(recptr);
3316
0
}
3317
3318
/*
3319
 * MULTIXACT resource manager's routines
3320
 */
3321
void
3322
multixact_redo(XLogReaderState *record)
3323
0
{
3324
0
  uint8   info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
3325
3326
  /* Backup blocks are not used in multixact records */
3327
0
  Assert(!XLogRecHasAnyBlockRefs(record));
3328
3329
0
  if (info == XLOG_MULTIXACT_ZERO_OFF_PAGE)
3330
0
  {
3331
0
    int64   pageno;
3332
3333
0
    memcpy(&pageno, XLogRecGetData(record), sizeof(pageno));
3334
0
    SimpleLruZeroAndWritePage(MultiXactOffsetCtl, pageno);
3335
0
  }
3336
0
  else if (info == XLOG_MULTIXACT_ZERO_MEM_PAGE)
3337
0
  {
3338
0
    int64   pageno;
3339
3340
0
    memcpy(&pageno, XLogRecGetData(record), sizeof(pageno));
3341
0
    SimpleLruZeroAndWritePage(MultiXactMemberCtl, pageno);
3342
0
  }
3343
0
  else if (info == XLOG_MULTIXACT_CREATE_ID)
3344
0
  {
3345
0
    xl_multixact_create *xlrec =
3346
0
      (xl_multixact_create *) XLogRecGetData(record);
3347
0
    TransactionId max_xid;
3348
0
    int     i;
3349
3350
    /* Store the data back into the SLRU files */
3351
0
    RecordNewMultiXact(xlrec->mid, xlrec->moff, xlrec->nmembers,
3352
0
               xlrec->members);
3353
3354
    /* Make sure nextMXact/nextOffset are beyond what this record has */
3355
0
    MultiXactAdvanceNextMXact(xlrec->mid + 1,
3356
0
                  xlrec->moff + xlrec->nmembers);
3357
3358
    /*
3359
     * Make sure nextXid is beyond any XID mentioned in the record. This
3360
     * should be unnecessary, since any XID found here ought to have other
3361
     * evidence in the XLOG, but let's be safe.
3362
     */
3363
0
    max_xid = XLogRecGetXid(record);
3364
0
    for (i = 0; i < xlrec->nmembers; i++)
3365
0
    {
3366
0
      if (TransactionIdPrecedes(max_xid, xlrec->members[i].xid))
3367
0
        max_xid = xlrec->members[i].xid;
3368
0
    }
3369
3370
0
    AdvanceNextFullTransactionIdPastXid(max_xid);
3371
0
  }
3372
0
  else if (info == XLOG_MULTIXACT_TRUNCATE_ID)
3373
0
  {
3374
0
    xl_multixact_truncate xlrec;
3375
0
    int64   pageno;
3376
3377
0
    memcpy(&xlrec, XLogRecGetData(record),
3378
0
         SizeOfMultiXactTruncate);
3379
3380
0
    elog(DEBUG1, "replaying multixact truncation: "
3381
0
       "offsets [%u, %u), offsets segments [%" PRIx64 ", %" PRIx64 "), "
3382
0
       "members [%u, %u), members segments [%" PRIx64 ", %" PRIx64 ")",
3383
0
       xlrec.startTruncOff, xlrec.endTruncOff,
3384
0
       MultiXactIdToOffsetSegment(xlrec.startTruncOff),
3385
0
       MultiXactIdToOffsetSegment(xlrec.endTruncOff),
3386
0
       xlrec.startTruncMemb, xlrec.endTruncMemb,
3387
0
       MXOffsetToMemberSegment(xlrec.startTruncMemb),
3388
0
       MXOffsetToMemberSegment(xlrec.endTruncMemb));
3389
3390
    /* should not be required, but more than cheap enough */
3391
0
    LWLockAcquire(MultiXactTruncationLock, LW_EXCLUSIVE);
3392
3393
    /*
3394
     * Advance the horizon values, so they're current at the end of
3395
     * recovery.
3396
     */
3397
0
    SetMultiXactIdLimit(xlrec.endTruncOff, xlrec.oldestMultiDB, false);
3398
3399
0
    PerformMembersTruncation(xlrec.startTruncMemb, xlrec.endTruncMemb);
3400
3401
    /*
3402
     * During XLOG replay, latest_page_number isn't necessarily set up
3403
     * yet; insert a suitable value to bypass the sanity test in
3404
     * SimpleLruTruncate.
3405
     */
3406
0
    pageno = MultiXactIdToOffsetPage(xlrec.endTruncOff);
3407
0
    pg_atomic_write_u64(&MultiXactOffsetCtl->shared->latest_page_number,
3408
0
              pageno);
3409
0
    PerformOffsetsTruncation(xlrec.startTruncOff, xlrec.endTruncOff);
3410
3411
0
    LWLockRelease(MultiXactTruncationLock);
3412
0
  }
3413
0
  else
3414
0
    elog(PANIC, "multixact_redo: unknown op code %u", info);
3415
0
}
3416
3417
Datum
3418
pg_get_multixact_members(PG_FUNCTION_ARGS)
3419
0
{
3420
0
  typedef struct
3421
0
  {
3422
0
    MultiXactMember *members;
3423
0
    int     nmembers;
3424
0
    int     iter;
3425
0
  } mxact;
3426
0
  MultiXactId mxid = PG_GETARG_TRANSACTIONID(0);
3427
0
  mxact    *multi;
3428
0
  FuncCallContext *funccxt;
3429
3430
0
  if (mxid < FirstMultiXactId)
3431
0
    ereport(ERROR,
3432
0
        (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
3433
0
         errmsg("invalid MultiXactId: %u", mxid)));
3434
3435
0
  if (SRF_IS_FIRSTCALL())
3436
0
  {
3437
0
    MemoryContext oldcxt;
3438
0
    TupleDesc tupdesc;
3439
3440
0
    funccxt = SRF_FIRSTCALL_INIT();
3441
0
    oldcxt = MemoryContextSwitchTo(funccxt->multi_call_memory_ctx);
3442
3443
0
    multi = palloc(sizeof(mxact));
3444
    /* no need to allow for old values here */
3445
0
    multi->nmembers = GetMultiXactIdMembers(mxid, &multi->members, false,
3446
0
                        false);
3447
0
    multi->iter = 0;
3448
3449
0
    if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
3450
0
      elog(ERROR, "return type must be a row type");
3451
0
    funccxt->tuple_desc = tupdesc;
3452
0
    funccxt->attinmeta = TupleDescGetAttInMetadata(tupdesc);
3453
0
    funccxt->user_fctx = multi;
3454
3455
0
    MemoryContextSwitchTo(oldcxt);
3456
0
  }
3457
3458
0
  funccxt = SRF_PERCALL_SETUP();
3459
0
  multi = (mxact *) funccxt->user_fctx;
3460
3461
0
  while (multi->iter < multi->nmembers)
3462
0
  {
3463
0
    HeapTuple tuple;
3464
0
    char     *values[2];
3465
3466
0
    values[0] = psprintf("%u", multi->members[multi->iter].xid);
3467
0
    values[1] = mxstatus_to_string(multi->members[multi->iter].status);
3468
3469
0
    tuple = BuildTupleFromCStrings(funccxt->attinmeta, values);
3470
3471
0
    multi->iter++;
3472
0
    pfree(values[0]);
3473
0
    SRF_RETURN_NEXT(funccxt, HeapTupleGetDatum(tuple));
3474
0
  }
3475
3476
0
  SRF_RETURN_DONE(funccxt);
3477
0
}
3478
3479
/*
3480
 * Entrypoint for sync.c to sync offsets files.
3481
 */
3482
int
3483
multixactoffsetssyncfiletag(const FileTag *ftag, char *path)
3484
0
{
3485
0
  return SlruSyncFileTag(MultiXactOffsetCtl, ftag, path);
3486
0
}
3487
3488
/*
3489
 * Entrypoint for sync.c to sync members files.
3490
 */
3491
int
3492
multixactmemberssyncfiletag(const FileTag *ftag, char *path)
3493
0
{
3494
0
  return SlruSyncFileTag(MultiXactMemberCtl, ftag, path);
3495
0
}