~ubuntu-branches/ubuntu/oneiric/postgresql-9.1/oneiric-security

« back to all changes in this revision

Viewing changes to src/backend/access/transam/multixact.c

  • Committer: Bazaar Package Importer
  • Author(s): Martin Pitt
  • Date: 2011-05-11 10:41:53 UTC
  • Revision ID: james.westby@ubuntu.com-20110511104153-psbh2o58553fv1m0
Tags: upstream-9.1~beta1
ImportĀ upstreamĀ versionĀ 9.1~beta1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*-------------------------------------------------------------------------
 
2
 *
 
3
 * multixact.c
 
4
 *              PostgreSQL multi-transaction-log manager
 
5
 *
 
6
 * The pg_multixact manager is a pg_clog-like manager that stores an array
 
7
 * of TransactionIds for each MultiXactId.      It is a fundamental part of the
 
8
 * shared-row-lock implementation.      A share-locked tuple stores a
 
9
 * MultiXactId in its Xmax, and a transaction that needs to wait for the
 
10
 * tuple to be unlocked can sleep on the potentially-several TransactionIds
 
11
 * that compose the MultiXactId.
 
12
 *
 
13
 * We use two SLRU areas, one for storing the offsets at which the data
 
14
 * starts for each MultiXactId in the other one.  This trick allows us to
 
15
 * store variable length arrays of TransactionIds.      (We could alternatively
 
16
 * use one area containing counts and TransactionIds, with valid MultiXactId
 
17
 * values pointing at slots containing counts; but that way seems less robust
 
18
 * since it would get completely confused if someone inquired about a bogus
 
19
 * MultiXactId that pointed to an intermediate slot containing an XID.)
 
20
 *
 
21
 * XLOG interactions: this module generates an XLOG record whenever a new
 
22
 * OFFSETs or MEMBERs page is initialized to zeroes, as well as an XLOG record
 
23
 * whenever a new MultiXactId is defined.  This allows us to completely
 
24
 * rebuild the data entered since the last checkpoint during XLOG replay.
 
25
 * Because this is possible, we need not follow the normal rule of
 
26
 * "write WAL before data"; the only correctness guarantee needed is that
 
27
 * we flush and sync all dirty OFFSETs and MEMBERs pages to disk before a
 
28
 * checkpoint is considered complete.  If a page does make it to disk ahead
 
29
 * of corresponding WAL records, it will be forcibly zeroed before use anyway.
 
30
 * Therefore, we don't need to mark our pages with LSN information; we have
 
31
 * enough synchronization already.
 
32
 *
 
33
 * Like clog.c, and unlike subtrans.c, we have to preserve state across
 
34
 * crashes and ensure that MXID and offset numbering increases monotonically
 
35
 * across a crash.      We do this in the same way as it's done for transaction
 
36
 * IDs: the WAL record is guaranteed to contain evidence of every MXID we
 
37
 * could need to worry about, and we just make sure that at the end of
 
38
 * replay, the next-MXID and next-offset counters are at least as large as
 
39
 * anything we saw during replay.
 
40
 *
 
41
 *
 
42
 * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group
 
43
 * Portions Copyright (c) 1994, Regents of the University of California
 
44
 *
 
45
 * src/backend/access/transam/multixact.c
 
46
 *
 
47
 *-------------------------------------------------------------------------
 
48
 */
 
49
#include "postgres.h"
 
50
 
 
51
#include "access/multixact.h"
 
52
#include "access/slru.h"
 
53
#include "access/transam.h"
 
54
#include "access/twophase.h"
 
55
#include "access/twophase_rmgr.h"
 
56
#include "access/xact.h"
 
57
#include "miscadmin.h"
 
58
#include "pg_trace.h"
 
59
#include "storage/backendid.h"
 
60
#include "storage/lmgr.h"
 
61
#include "storage/procarray.h"
 
62
#include "utils/builtins.h"
 
63
#include "utils/memutils.h"
 
64
 
 
65
 
 
66
/*
 
67
 * Defines for MultiXactOffset page sizes.      A page is the same BLCKSZ as is
 
68
 * used everywhere else in Postgres.
 
69
 *
 
70
 * Note: because both MultiXactOffsets and TransactionIds are 32 bits and
 
71
 * wrap around at 0xFFFFFFFF, MultiXact page numbering also wraps around at
 
72
 * 0xFFFFFFFF/MULTIXACT_*_PER_PAGE, and segment numbering at
 
73
 * 0xFFFFFFFF/MULTIXACT_*_PER_PAGE/SLRU_SEGMENTS_PER_PAGE.      We need take no
 
74
 * explicit notice of that fact in this module, except when comparing segment
 
75
 * and page numbers in TruncateMultiXact
 
76
 * (see MultiXact{Offset,Member}PagePrecedes).
 
77
 */
 
78
 
 
79
/* We need four bytes per offset and also four bytes per member */
 
80
#define MULTIXACT_OFFSETS_PER_PAGE (BLCKSZ / sizeof(MultiXactOffset))
 
81
#define MULTIXACT_MEMBERS_PER_PAGE (BLCKSZ / sizeof(TransactionId))
 
82
 
 
83
#define MultiXactIdToOffsetPage(xid) \
 
84
        ((xid) / (MultiXactOffset) MULTIXACT_OFFSETS_PER_PAGE)
 
85
#define MultiXactIdToOffsetEntry(xid) \
 
86
        ((xid) % (MultiXactOffset) MULTIXACT_OFFSETS_PER_PAGE)
 
87
 
 
88
#define MXOffsetToMemberPage(xid) \
 
89
        ((xid) / (TransactionId) MULTIXACT_MEMBERS_PER_PAGE)
 
90
#define MXOffsetToMemberEntry(xid) \
 
91
        ((xid) % (TransactionId) MULTIXACT_MEMBERS_PER_PAGE)
 
92
 
 
93
 
 
94
/*
 
95
 * Links to shared-memory data structures for MultiXact control
 
96
 */
 
97
static SlruCtlData MultiXactOffsetCtlData;
 
98
static SlruCtlData MultiXactMemberCtlData;
 
99
 
 
100
#define MultiXactOffsetCtl      (&MultiXactOffsetCtlData)
 
101
#define MultiXactMemberCtl      (&MultiXactMemberCtlData)
 
102
 
 
103
/*
 
104
 * MultiXact state shared across all backends.  All this state is protected
 
105
 * by MultiXactGenLock.  (We also use MultiXactOffsetControlLock and
 
106
 * MultiXactMemberControlLock to guard accesses to the two sets of SLRU
 
107
 * buffers.  For concurrency's sake, we avoid holding more than one of these
 
108
 * locks at a time.)
 
109
 */
 
110
typedef struct MultiXactStateData
 
111
{
 
112
        /* next-to-be-assigned MultiXactId */
 
113
        MultiXactId nextMXact;
 
114
 
 
115
        /* next-to-be-assigned offset */
 
116
        MultiXactOffset nextOffset;
 
117
 
 
118
        /* the Offset SLRU area was last truncated at this MultiXactId */
 
119
        MultiXactId lastTruncationPoint;
 
120
 
 
121
        /*
 
122
         * Per-backend data starts here.  We have two arrays stored in the area
 
123
         * immediately following the MultiXactStateData struct. Each is indexed by
 
124
         * BackendId.
 
125
         *
 
126
         * In both arrays, there's a slot for all normal backends (1..MaxBackends)
 
127
         * followed by a slot for max_prepared_xacts prepared transactions. Valid
 
128
         * BackendIds start from 1; element zero of each array is never used.
 
129
         *
 
130
         * OldestMemberMXactId[k] is the oldest MultiXactId each backend's current
 
131
         * transaction(s) could possibly be a member of, or InvalidMultiXactId
 
132
         * when the backend has no live transaction that could possibly be a
 
133
         * member of a MultiXact.  Each backend sets its entry to the current
 
134
         * nextMXact counter just before first acquiring a shared lock in a given
 
135
         * transaction, and clears it at transaction end. (This works because only
 
136
         * during or after acquiring a shared lock could an XID possibly become a
 
137
         * member of a MultiXact, and that MultiXact would have to be created
 
138
         * during or after the lock acquisition.)
 
139
         *
 
140
         * OldestVisibleMXactId[k] is the oldest MultiXactId each backend's
 
141
         * current transaction(s) think is potentially live, or InvalidMultiXactId
 
142
         * when not in a transaction or not in a transaction that's paid any
 
143
         * attention to MultiXacts yet.  This is computed when first needed in a
 
144
         * given transaction, and cleared at transaction end.  We can compute it
 
145
         * as the minimum of the valid OldestMemberMXactId[] entries at the time
 
146
         * we compute it (using nextMXact if none are valid).  Each backend is
 
147
         * required not to attempt to access any SLRU data for MultiXactIds older
 
148
         * than its own OldestVisibleMXactId[] setting; this is necessary because
 
149
         * the checkpointer could truncate away such data at any instant.
 
150
         *
 
151
         * The checkpointer can compute the safe truncation point as the oldest
 
152
         * valid value among all the OldestMemberMXactId[] and
 
153
         * OldestVisibleMXactId[] entries, or nextMXact if none are valid.
 
154
         * Clearly, it is not possible for any later-computed OldestVisibleMXactId
 
155
         * value to be older than this, and so there is no risk of truncating data
 
156
         * that is still needed.
 
157
         */
 
158
        MultiXactId perBackendXactIds[1];       /* VARIABLE LENGTH ARRAY */
 
159
} MultiXactStateData;
 
160
 
 
161
/*
 
162
 * Last element of OldestMemberMXactID and OldestVisibleMXactId arrays.
 
163
 * Valid elements are (1..MaxOldestSlot); element 0 is never used.
 
164
 */
 
165
#define MaxOldestSlot   (MaxBackends + max_prepared_xacts)
 
166
 
 
167
/* Pointers to the state data in shared memory */
 
168
static MultiXactStateData *MultiXactState;
 
169
static MultiXactId *OldestMemberMXactId;
 
170
static MultiXactId *OldestVisibleMXactId;
 
171
 
 
172
 
 
173
/*
 
174
 * Definitions for the backend-local MultiXactId cache.
 
175
 *
 
176
 * We use this cache to store known MultiXacts, so we don't need to go to
 
177
 * SLRU areas everytime.
 
178
 *
 
179
 * The cache lasts for the duration of a single transaction, the rationale
 
180
 * for this being that most entries will contain our own TransactionId and
 
181
 * so they will be uninteresting by the time our next transaction starts.
 
182
 * (XXX not clear that this is correct --- other members of the MultiXact
 
183
 * could hang around longer than we did.  However, it's not clear what a
 
184
 * better policy for flushing old cache entries would be.)
 
185
 *
 
186
 * We allocate the cache entries in a memory context that is deleted at
 
187
 * transaction end, so we don't need to do retail freeing of entries.
 
188
 */
 
189
typedef struct mXactCacheEnt
 
190
{
 
191
        struct mXactCacheEnt *next;
 
192
        MultiXactId multi;
 
193
        int                     nxids;
 
194
        TransactionId xids[1];          /* VARIABLE LENGTH ARRAY */
 
195
} mXactCacheEnt;
 
196
 
 
197
static mXactCacheEnt *MXactCache = NULL;
 
198
static MemoryContext MXactContext = NULL;
 
199
 
 
200
 
 
201
#ifdef MULTIXACT_DEBUG
 
202
#define debug_elog2(a,b) elog(a,b)
 
203
#define debug_elog3(a,b,c) elog(a,b,c)
 
204
#define debug_elog4(a,b,c,d) elog(a,b,c,d)
 
205
#define debug_elog5(a,b,c,d,e) elog(a,b,c,d,e)
 
206
#else
 
207
#define debug_elog2(a,b)
 
208
#define debug_elog3(a,b,c)
 
209
#define debug_elog4(a,b,c,d)
 
210
#define debug_elog5(a,b,c,d,e)
 
211
#endif
 
212
 
 
213
/* internal MultiXactId management */
 
214
static void MultiXactIdSetOldestVisible(void);
 
215
static MultiXactId CreateMultiXactId(int nxids, TransactionId *xids);
 
216
static void RecordNewMultiXact(MultiXactId multi, MultiXactOffset offset,
 
217
                                   int nxids, TransactionId *xids);
 
218
static MultiXactId GetNewMultiXactId(int nxids, MultiXactOffset *offset);
 
219
 
 
220
/* MultiXact cache management */
 
221
static MultiXactId mXactCacheGetBySet(int nxids, TransactionId *xids);
 
222
static int      mXactCacheGetById(MultiXactId multi, TransactionId **xids);
 
223
static void mXactCachePut(MultiXactId multi, int nxids, TransactionId *xids);
 
224
 
 
225
#ifdef MULTIXACT_DEBUG
 
226
static char *mxid_to_string(MultiXactId multi, int nxids, TransactionId *xids);
 
227
#endif
 
228
 
 
229
/* management of SLRU infrastructure */
 
230
static int      ZeroMultiXactOffsetPage(int pageno, bool writeXlog);
 
231
static int      ZeroMultiXactMemberPage(int pageno, bool writeXlog);
 
232
static bool MultiXactOffsetPagePrecedes(int page1, int page2);
 
233
static bool MultiXactMemberPagePrecedes(int page1, int page2);
 
234
static bool MultiXactIdPrecedes(MultiXactId multi1, MultiXactId multi2);
 
235
static bool MultiXactOffsetPrecedes(MultiXactOffset offset1,
 
236
                                                MultiXactOffset offset2);
 
237
static void ExtendMultiXactOffset(MultiXactId multi);
 
238
static void ExtendMultiXactMember(MultiXactOffset offset, int nmembers);
 
239
static void TruncateMultiXact(void);
 
240
static void WriteMZeroPageXlogRec(int pageno, uint8 info);
 
241
 
 
242
 
 
243
/*
 
244
 * MultiXactIdCreate
 
245
 *              Construct a MultiXactId representing two TransactionIds.
 
246
 *
 
247
 * The two XIDs must be different.
 
248
 *
 
249
 * NB - we don't worry about our local MultiXactId cache here, because that
 
250
 * is handled by the lower-level routines.
 
251
 */
 
252
MultiXactId
 
253
MultiXactIdCreate(TransactionId xid1, TransactionId xid2)
 
254
{
 
255
        MultiXactId newMulti;
 
256
        TransactionId xids[2];
 
257
 
 
258
        AssertArg(TransactionIdIsValid(xid1));
 
259
        AssertArg(TransactionIdIsValid(xid2));
 
260
 
 
261
        Assert(!TransactionIdEquals(xid1, xid2));
 
262
 
 
263
        /*
 
264
         * Note: unlike MultiXactIdExpand, we don't bother to check that both XIDs
 
265
         * are still running.  In typical usage, xid2 will be our own XID and the
 
266
         * caller just did a check on xid1, so it'd be wasted effort.
 
267
         */
 
268
 
 
269
        xids[0] = xid1;
 
270
        xids[1] = xid2;
 
271
 
 
272
        newMulti = CreateMultiXactId(2, xids);
 
273
 
 
274
        debug_elog5(DEBUG2, "Create: returning %u for %u, %u",
 
275
                                newMulti, xid1, xid2);
 
276
 
 
277
        return newMulti;
 
278
}
 
279
 
 
280
/*
 
281
 * MultiXactIdExpand
 
282
 *              Add a TransactionId to a pre-existing MultiXactId.
 
283
 *
 
284
 * If the TransactionId is already a member of the passed MultiXactId,
 
285
 * just return it as-is.
 
286
 *
 
287
 * Note that we do NOT actually modify the membership of a pre-existing
 
288
 * MultiXactId; instead we create a new one.  This is necessary to avoid
 
289
 * a race condition against MultiXactIdWait (see notes there).
 
290
 *
 
291
 * NB - we don't worry about our local MultiXactId cache here, because that
 
292
 * is handled by the lower-level routines.
 
293
 */
 
294
MultiXactId
 
295
MultiXactIdExpand(MultiXactId multi, TransactionId xid)
 
296
{
 
297
        MultiXactId newMulti;
 
298
        TransactionId *members;
 
299
        TransactionId *newMembers;
 
300
        int                     nmembers;
 
301
        int                     i;
 
302
        int                     j;
 
303
 
 
304
        AssertArg(MultiXactIdIsValid(multi));
 
305
        AssertArg(TransactionIdIsValid(xid));
 
306
 
 
307
        debug_elog4(DEBUG2, "Expand: received multi %u, xid %u",
 
308
                                multi, xid);
 
309
 
 
310
        nmembers = GetMultiXactIdMembers(multi, &members);
 
311
 
 
312
        if (nmembers < 0)
 
313
        {
 
314
                /*
 
315
                 * The MultiXactId is obsolete.  This can only happen if all the
 
316
                 * MultiXactId members stop running between the caller checking and
 
317
                 * passing it to us.  It would be better to return that fact to the
 
318
                 * caller, but it would complicate the API and it's unlikely to happen
 
319
                 * too often, so just deal with it by creating a singleton MultiXact.
 
320
                 */
 
321
                newMulti = CreateMultiXactId(1, &xid);
 
322
 
 
323
                debug_elog4(DEBUG2, "Expand: %u has no members, create singleton %u",
 
324
                                        multi, newMulti);
 
325
                return newMulti;
 
326
        }
 
327
 
 
328
        /*
 
329
         * If the TransactionId is already a member of the MultiXactId, just
 
330
         * return the existing MultiXactId.
 
331
         */
 
332
        for (i = 0; i < nmembers; i++)
 
333
        {
 
334
                if (TransactionIdEquals(members[i], xid))
 
335
                {
 
336
                        debug_elog4(DEBUG2, "Expand: %u is already a member of %u",
 
337
                                                xid, multi);
 
338
                        pfree(members);
 
339
                        return multi;
 
340
                }
 
341
        }
 
342
 
 
343
        /*
 
344
         * Determine which of the members of the MultiXactId are still running,
 
345
         * and use them to create a new one.  (Removing dead members is just an
 
346
         * optimization, but a useful one.      Note we have the same race condition
 
347
         * here as above: j could be 0 at the end of the loop.)
 
348
         */
 
349
        newMembers = (TransactionId *)
 
350
                palloc(sizeof(TransactionId) * (nmembers + 1));
 
351
 
 
352
        for (i = 0, j = 0; i < nmembers; i++)
 
353
        {
 
354
                if (TransactionIdIsInProgress(members[i]))
 
355
                        newMembers[j++] = members[i];
 
356
        }
 
357
 
 
358
        newMembers[j++] = xid;
 
359
        newMulti = CreateMultiXactId(j, newMembers);
 
360
 
 
361
        pfree(members);
 
362
        pfree(newMembers);
 
363
 
 
364
        debug_elog3(DEBUG2, "Expand: returning new multi %u", newMulti);
 
365
 
 
366
        return newMulti;
 
367
}
 
368
 
 
369
/*
 
370
 * MultiXactIdIsRunning
 
371
 *              Returns whether a MultiXactId is "running".
 
372
 *
 
373
 * We return true if at least one member of the given MultiXactId is still
 
374
 * running.  Note that a "false" result is certain not to change,
 
375
 * because it is not legal to add members to an existing MultiXactId.
 
376
 */
 
377
bool
 
378
MultiXactIdIsRunning(MultiXactId multi)
 
379
{
 
380
        TransactionId *members;
 
381
        int                     nmembers;
 
382
        int                     i;
 
383
 
 
384
        debug_elog3(DEBUG2, "IsRunning %u?", multi);
 
385
 
 
386
        nmembers = GetMultiXactIdMembers(multi, &members);
 
387
 
 
388
        if (nmembers < 0)
 
389
        {
 
390
                debug_elog2(DEBUG2, "IsRunning: no members");
 
391
                return false;
 
392
        }
 
393
 
 
394
        /*
 
395
         * Checking for myself is cheap compared to looking in shared memory, so
 
396
         * first do the equivalent of MultiXactIdIsCurrent().  This is not needed
 
397
         * for correctness, it's just a fast path.
 
398
         */
 
399
        for (i = 0; i < nmembers; i++)
 
400
        {
 
401
                if (TransactionIdIsCurrentTransactionId(members[i]))
 
402
                {
 
403
                        debug_elog3(DEBUG2, "IsRunning: I (%d) am running!", i);
 
404
                        pfree(members);
 
405
                        return true;
 
406
                }
 
407
        }
 
408
 
 
409
        /*
 
410
         * This could be made faster by having another entry point in procarray.c,
 
411
         * walking the PGPROC array only once for all the members.      But in most
 
412
         * cases nmembers should be small enough that it doesn't much matter.
 
413
         */
 
414
        for (i = 0; i < nmembers; i++)
 
415
        {
 
416
                if (TransactionIdIsInProgress(members[i]))
 
417
                {
 
418
                        debug_elog4(DEBUG2, "IsRunning: member %d (%u) is running",
 
419
                                                i, members[i]);
 
420
                        pfree(members);
 
421
                        return true;
 
422
                }
 
423
        }
 
424
 
 
425
        pfree(members);
 
426
 
 
427
        debug_elog3(DEBUG2, "IsRunning: %u is not running", multi);
 
428
 
 
429
        return false;
 
430
}
 
431
 
 
432
/*
 
433
 * MultiXactIdIsCurrent
 
434
 *              Returns true if the current transaction is a member of the MultiXactId.
 
435
 *
 
436
 * We return true if any live subtransaction of the current top-level
 
437
 * transaction is a member.  This is appropriate for the same reason that a
 
438
 * lock held by any such subtransaction is globally equivalent to a lock
 
439
 * held by the current subtransaction: no such lock could be released without
 
440
 * aborting this subtransaction, and hence releasing its locks.  So it's not
 
441
 * necessary to add the current subxact to the MultiXact separately.
 
442
 */
 
443
bool
 
444
MultiXactIdIsCurrent(MultiXactId multi)
 
445
{
 
446
        bool            result = false;
 
447
        TransactionId *members;
 
448
        int                     nmembers;
 
449
        int                     i;
 
450
 
 
451
        nmembers = GetMultiXactIdMembers(multi, &members);
 
452
 
 
453
        if (nmembers < 0)
 
454
                return false;
 
455
 
 
456
        for (i = 0; i < nmembers; i++)
 
457
        {
 
458
                if (TransactionIdIsCurrentTransactionId(members[i]))
 
459
                {
 
460
                        result = true;
 
461
                        break;
 
462
                }
 
463
        }
 
464
 
 
465
        pfree(members);
 
466
 
 
467
        return result;
 
468
}
 
469
 
 
470
/*
 
471
 * MultiXactIdSetOldestMember
 
472
 *              Save the oldest MultiXactId this transaction could be a member of.
 
473
 *
 
474
 * We set the OldestMemberMXactId for a given transaction the first time
 
475
 * it's going to acquire a shared lock.  We need to do this even if we end
 
476
 * up using a TransactionId instead of a MultiXactId, because there is a
 
477
 * chance that another transaction would add our XID to a MultiXactId.
 
478
 *
 
479
 * The value to set is the next-to-be-assigned MultiXactId, so this is meant
 
480
 * to be called just before acquiring a shared lock.
 
481
 */
 
482
void
 
483
MultiXactIdSetOldestMember(void)
 
484
{
 
485
        if (!MultiXactIdIsValid(OldestMemberMXactId[MyBackendId]))
 
486
        {
 
487
                MultiXactId nextMXact;
 
488
 
 
489
                /*
 
490
                 * You might think we don't need to acquire a lock here, since
 
491
                 * fetching and storing of TransactionIds is probably atomic, but in
 
492
                 * fact we do: suppose we pick up nextMXact and then lose the CPU for
 
493
                 * a long time.  Someone else could advance nextMXact, and then
 
494
                 * another someone else could compute an OldestVisibleMXactId that
 
495
                 * would be after the value we are going to store when we get control
 
496
                 * back.  Which would be wrong.
 
497
                 */
 
498
                LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);
 
499
 
 
500
                /*
 
501
                 * We have to beware of the possibility that nextMXact is in the
 
502
                 * wrapped-around state.  We don't fix the counter itself here, but we
 
503
                 * must be sure to store a valid value in our array entry.
 
504
                 */
 
505
                nextMXact = MultiXactState->nextMXact;
 
506
                if (nextMXact < FirstMultiXactId)
 
507
                        nextMXact = FirstMultiXactId;
 
508
 
 
509
                OldestMemberMXactId[MyBackendId] = nextMXact;
 
510
 
 
511
                LWLockRelease(MultiXactGenLock);
 
512
 
 
513
                debug_elog4(DEBUG2, "MultiXact: setting OldestMember[%d] = %u",
 
514
                                        MyBackendId, nextMXact);
 
515
        }
 
516
}
 
517
 
 
518
/*
 
519
 * MultiXactIdSetOldestVisible
 
520
 *              Save the oldest MultiXactId this transaction considers possibly live.
 
521
 *
 
522
 * We set the OldestVisibleMXactId for a given transaction the first time
 
523
 * it's going to inspect any MultiXactId.  Once we have set this, we are
 
524
 * guaranteed that the checkpointer won't truncate off SLRU data for
 
525
 * MultiXactIds at or after our OldestVisibleMXactId.
 
526
 *
 
527
 * The value to set is the oldest of nextMXact and all the valid per-backend
 
528
 * OldestMemberMXactId[] entries.  Because of the locking we do, we can be
 
529
 * certain that no subsequent call to MultiXactIdSetOldestMember can set
 
530
 * an OldestMemberMXactId[] entry older than what we compute here.      Therefore
 
531
 * there is no live transaction, now or later, that can be a member of any
 
532
 * MultiXactId older than the OldestVisibleMXactId we compute here.
 
533
 */
 
534
static void
 
535
MultiXactIdSetOldestVisible(void)
 
536
{
 
537
        if (!MultiXactIdIsValid(OldestVisibleMXactId[MyBackendId]))
 
538
        {
 
539
                MultiXactId oldestMXact;
 
540
                int                     i;
 
541
 
 
542
                LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);
 
543
 
 
544
                /*
 
545
                 * We have to beware of the possibility that nextMXact is in the
 
546
                 * wrapped-around state.  We don't fix the counter itself here, but we
 
547
                 * must be sure to store a valid value in our array entry.
 
548
                 */
 
549
                oldestMXact = MultiXactState->nextMXact;
 
550
                if (oldestMXact < FirstMultiXactId)
 
551
                        oldestMXact = FirstMultiXactId;
 
552
 
 
553
                for (i = 1; i <= MaxOldestSlot; i++)
 
554
                {
 
555
                        MultiXactId thisoldest = OldestMemberMXactId[i];
 
556
 
 
557
                        if (MultiXactIdIsValid(thisoldest) &&
 
558
                                MultiXactIdPrecedes(thisoldest, oldestMXact))
 
559
                                oldestMXact = thisoldest;
 
560
                }
 
561
 
 
562
                OldestVisibleMXactId[MyBackendId] = oldestMXact;
 
563
 
 
564
                LWLockRelease(MultiXactGenLock);
 
565
 
 
566
                debug_elog4(DEBUG2, "MultiXact: setting OldestVisible[%d] = %u",
 
567
                                        MyBackendId, oldestMXact);
 
568
        }
 
569
}
 
570
 
 
571
/*
 
572
 * MultiXactIdWait
 
573
 *              Sleep on a MultiXactId.
 
574
 *
 
575
 * We do this by sleeping on each member using XactLockTableWait.  Any
 
576
 * members that belong to the current backend are *not* waited for, however;
 
577
 * this would not merely be useless but would lead to Assert failure inside
 
578
 * XactLockTableWait.  By the time this returns, it is certain that all
 
579
 * transactions *of other backends* that were members of the MultiXactId
 
580
 * are dead (and no new ones can have been added, since it is not legal
 
581
 * to add members to an existing MultiXactId).
 
582
 *
 
583
 * But by the time we finish sleeping, someone else may have changed the Xmax
 
584
 * of the containing tuple, so the caller needs to iterate on us somehow.
 
585
 */
 
586
void
 
587
MultiXactIdWait(MultiXactId multi)
 
588
{
 
589
        TransactionId *members;
 
590
        int                     nmembers;
 
591
 
 
592
        nmembers = GetMultiXactIdMembers(multi, &members);
 
593
 
 
594
        if (nmembers >= 0)
 
595
        {
 
596
                int                     i;
 
597
 
 
598
                for (i = 0; i < nmembers; i++)
 
599
                {
 
600
                        TransactionId member = members[i];
 
601
 
 
602
                        debug_elog4(DEBUG2, "MultiXactIdWait: waiting for %d (%u)",
 
603
                                                i, member);
 
604
                        if (!TransactionIdIsCurrentTransactionId(member))
 
605
                                XactLockTableWait(member);
 
606
                }
 
607
 
 
608
                pfree(members);
 
609
        }
 
610
}
 
611
 
 
612
/*
 
613
 * ConditionalMultiXactIdWait
 
614
 *              As above, but only lock if we can get the lock without blocking.
 
615
 */
 
616
bool
 
617
ConditionalMultiXactIdWait(MultiXactId multi)
 
618
{
 
619
        bool            result = true;
 
620
        TransactionId *members;
 
621
        int                     nmembers;
 
622
 
 
623
        nmembers = GetMultiXactIdMembers(multi, &members);
 
624
 
 
625
        if (nmembers >= 0)
 
626
        {
 
627
                int                     i;
 
628
 
 
629
                for (i = 0; i < nmembers; i++)
 
630
                {
 
631
                        TransactionId member = members[i];
 
632
 
 
633
                        debug_elog4(DEBUG2, "ConditionalMultiXactIdWait: trying %d (%u)",
 
634
                                                i, member);
 
635
                        if (!TransactionIdIsCurrentTransactionId(member))
 
636
                        {
 
637
                                result = ConditionalXactLockTableWait(member);
 
638
                                if (!result)
 
639
                                        break;
 
640
                        }
 
641
                }
 
642
 
 
643
                pfree(members);
 
644
        }
 
645
 
 
646
        return result;
 
647
}
 
648
 
 
649
/*
 
650
 * CreateMultiXactId
 
651
 *              Make a new MultiXactId
 
652
 *
 
653
 * Make XLOG, SLRU and cache entries for a new MultiXactId, recording the
 
654
 * given TransactionIds as members.  Returns the newly created MultiXactId.
 
655
 *
 
656
 * NB: the passed xids[] array will be sorted in-place.
 
657
 */
 
658
static MultiXactId
 
659
CreateMultiXactId(int nxids, TransactionId *xids)
 
660
{
 
661
        MultiXactId multi;
 
662
        MultiXactOffset offset;
 
663
        XLogRecData rdata[2];
 
664
        xl_multixact_create xlrec;
 
665
 
 
666
        debug_elog3(DEBUG2, "Create: %s",
 
667
                                mxid_to_string(InvalidMultiXactId, nxids, xids));
 
668
 
 
669
        /*
 
670
         * See if the same set of XIDs already exists in our cache; if so, just
 
671
         * re-use that MultiXactId.  (Note: it might seem that looking in our
 
672
         * cache is insufficient, and we ought to search disk to see if a
 
673
         * duplicate definition already exists.  But since we only ever create
 
674
         * MultiXacts containing our own XID, in most cases any such MultiXacts
 
675
         * were in fact created by us, and so will be in our cache.  There are
 
676
         * corner cases where someone else added us to a MultiXact without our
 
677
         * knowledge, but it's not worth checking for.)
 
678
         */
 
679
        multi = mXactCacheGetBySet(nxids, xids);
 
680
        if (MultiXactIdIsValid(multi))
 
681
        {
 
682
                debug_elog2(DEBUG2, "Create: in cache!");
 
683
                return multi;
 
684
        }
 
685
 
 
686
        /*
 
687
         * Assign the MXID and offsets range to use, and make sure there is space
 
688
         * in the OFFSETs and MEMBERs files.  NB: this routine does
 
689
         * START_CRIT_SECTION().
 
690
         */
 
691
        multi = GetNewMultiXactId(nxids, &offset);
 
692
 
 
693
        /*
 
694
         * Make an XLOG entry describing the new MXID.
 
695
         *
 
696
         * Note: we need not flush this XLOG entry to disk before proceeding. The
 
697
         * only way for the MXID to be referenced from any data page is for
 
698
         * heap_lock_tuple() to have put it there, and heap_lock_tuple() generates
 
699
         * an XLOG record that must follow ours.  The normal LSN interlock between
 
700
         * the data page and that XLOG record will ensure that our XLOG record
 
701
         * reaches disk first.  If the SLRU members/offsets data reaches disk
 
702
         * sooner than the XLOG record, we do not care because we'll overwrite it
 
703
         * with zeroes unless the XLOG record is there too; see notes at top of
 
704
         * this file.
 
705
         */
 
706
        xlrec.mid = multi;
 
707
        xlrec.moff = offset;
 
708
        xlrec.nxids = nxids;
 
709
 
 
710
        rdata[0].data = (char *) (&xlrec);
 
711
        rdata[0].len = MinSizeOfMultiXactCreate;
 
712
        rdata[0].buffer = InvalidBuffer;
 
713
        rdata[0].next = &(rdata[1]);
 
714
        rdata[1].data = (char *) xids;
 
715
        rdata[1].len = nxids * sizeof(TransactionId);
 
716
        rdata[1].buffer = InvalidBuffer;
 
717
        rdata[1].next = NULL;
 
718
 
 
719
        (void) XLogInsert(RM_MULTIXACT_ID, XLOG_MULTIXACT_CREATE_ID, rdata);
 
720
 
 
721
        /* Now enter the information into the OFFSETs and MEMBERs logs */
 
722
        RecordNewMultiXact(multi, offset, nxids, xids);
 
723
 
 
724
        /* Done with critical section */
 
725
        END_CRIT_SECTION();
 
726
 
 
727
        /* Store the new MultiXactId in the local cache, too */
 
728
        mXactCachePut(multi, nxids, xids);
 
729
 
 
730
        debug_elog2(DEBUG2, "Create: all done");
 
731
 
 
732
        return multi;
 
733
}
 
734
 
 
735
/*
 
736
 * RecordNewMultiXact
 
737
 *              Write info about a new multixact into the offsets and members files
 
738
 *
 
739
 * This is broken out of CreateMultiXactId so that xlog replay can use it.
 
740
 */
 
741
static void
 
742
RecordNewMultiXact(MultiXactId multi, MultiXactOffset offset,
 
743
                                   int nxids, TransactionId *xids)
 
744
{
 
745
        int                     pageno;
 
746
        int                     prev_pageno;
 
747
        int                     entryno;
 
748
        int                     slotno;
 
749
        MultiXactOffset *offptr;
 
750
        int                     i;
 
751
 
 
752
        LWLockAcquire(MultiXactOffsetControlLock, LW_EXCLUSIVE);
 
753
 
 
754
        pageno = MultiXactIdToOffsetPage(multi);
 
755
        entryno = MultiXactIdToOffsetEntry(multi);
 
756
 
 
757
        /*
 
758
         * Note: we pass the MultiXactId to SimpleLruReadPage as the "transaction"
 
759
         * to complain about if there's any I/O error.  This is kinda bogus, but
 
760
         * since the errors will always give the full pathname, it should be clear
 
761
         * enough that a MultiXactId is really involved.  Perhaps someday we'll
 
762
         * take the trouble to generalize the slru.c error reporting code.
 
763
         */
 
764
        slotno = SimpleLruReadPage(MultiXactOffsetCtl, pageno, true, multi);
 
765
        offptr = (MultiXactOffset *) MultiXactOffsetCtl->shared->page_buffer[slotno];
 
766
        offptr += entryno;
 
767
 
 
768
        *offptr = offset;
 
769
 
 
770
        MultiXactOffsetCtl->shared->page_dirty[slotno] = true;
 
771
 
 
772
        /* Exchange our lock */
 
773
        LWLockRelease(MultiXactOffsetControlLock);
 
774
 
 
775
        LWLockAcquire(MultiXactMemberControlLock, LW_EXCLUSIVE);
 
776
 
 
777
        prev_pageno = -1;
 
778
 
 
779
        for (i = 0; i < nxids; i++, offset++)
 
780
        {
 
781
                TransactionId *memberptr;
 
782
 
 
783
                pageno = MXOffsetToMemberPage(offset);
 
784
                entryno = MXOffsetToMemberEntry(offset);
 
785
 
 
786
                if (pageno != prev_pageno)
 
787
                {
 
788
                        slotno = SimpleLruReadPage(MultiXactMemberCtl, pageno, true, multi);
 
789
                        prev_pageno = pageno;
 
790
                }
 
791
 
 
792
                memberptr = (TransactionId *)
 
793
                        MultiXactMemberCtl->shared->page_buffer[slotno];
 
794
                memberptr += entryno;
 
795
 
 
796
                *memberptr = xids[i];
 
797
 
 
798
                MultiXactMemberCtl->shared->page_dirty[slotno] = true;
 
799
        }
 
800
 
 
801
        LWLockRelease(MultiXactMemberControlLock);
 
802
}
 
803
 
 
804
/*
 
805
 * GetNewMultiXactId
 
806
 *              Get the next MultiXactId.
 
807
 *
 
808
 * Also, reserve the needed amount of space in the "members" area.      The
 
809
 * starting offset of the reserved space is returned in *offset.
 
810
 *
 
811
 * This may generate XLOG records for expansion of the offsets and/or members
 
812
 * files.  Unfortunately, we have to do that while holding MultiXactGenLock
 
813
 * to avoid race conditions --- the XLOG record for zeroing a page must appear
 
814
 * before any backend can possibly try to store data in that page!
 
815
 *
 
816
 * We start a critical section before advancing the shared counters.  The
 
817
 * caller must end the critical section after writing SLRU data.
 
818
 */
 
819
static MultiXactId
 
820
GetNewMultiXactId(int nxids, MultiXactOffset *offset)
 
821
{
 
822
        MultiXactId result;
 
823
        MultiXactOffset nextOffset;
 
824
 
 
825
        debug_elog3(DEBUG2, "GetNew: for %d xids", nxids);
 
826
 
 
827
        /* MultiXactIdSetOldestMember() must have been called already */
 
828
        Assert(MultiXactIdIsValid(OldestMemberMXactId[MyBackendId]));
 
829
 
 
830
        LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);
 
831
 
 
832
        /* Handle wraparound of the nextMXact counter */
 
833
        if (MultiXactState->nextMXact < FirstMultiXactId)
 
834
                MultiXactState->nextMXact = FirstMultiXactId;
 
835
 
 
836
        /*
 
837
         * Assign the MXID, and make sure there is room for it in the file.
 
838
         */
 
839
        result = MultiXactState->nextMXact;
 
840
 
 
841
        ExtendMultiXactOffset(result);
 
842
 
 
843
        /*
 
844
         * Reserve the members space, similarly to above.  Also, be careful not to
 
845
         * return zero as the starting offset for any multixact. See
 
846
         * GetMultiXactIdMembers() for motivation.
 
847
         */
 
848
        nextOffset = MultiXactState->nextOffset;
 
849
        if (nextOffset == 0)
 
850
        {
 
851
                *offset = 1;
 
852
                nxids++;                                /* allocate member slot 0 too */
 
853
        }
 
854
        else
 
855
                *offset = nextOffset;
 
856
 
 
857
        ExtendMultiXactMember(nextOffset, nxids);
 
858
 
 
859
        /*
 
860
         * Critical section from here until caller has written the data into the
 
861
         * just-reserved SLRU space; we don't want to error out with a partly
 
862
         * written MultiXact structure.  (In particular, failing to write our
 
863
         * start offset after advancing nextMXact would effectively corrupt the
 
864
         * previous MultiXact.)
 
865
         */
 
866
        START_CRIT_SECTION();
 
867
 
 
868
        /*
 
869
         * Advance counters.  As in GetNewTransactionId(), this must not happen
 
870
         * until after file extension has succeeded!
 
871
         *
 
872
         * We don't care about MultiXactId wraparound here; it will be handled by
 
873
         * the next iteration.  But note that nextMXact may be InvalidMultiXactId
 
874
         * after this routine exits, so anyone else looking at the variable must
 
875
         * be prepared to deal with that.  Similarly, nextOffset may be zero, but
 
876
         * we won't use that as the actual start offset of the next multixact.
 
877
         */
 
878
        (MultiXactState->nextMXact)++;
 
879
 
 
880
        MultiXactState->nextOffset += nxids;
 
881
 
 
882
        LWLockRelease(MultiXactGenLock);
 
883
 
 
884
        debug_elog4(DEBUG2, "GetNew: returning %u offset %u", result, *offset);
 
885
        return result;
 
886
}
 
887
 
 
888
/*
 
889
 * GetMultiXactIdMembers
 
890
 *              Returns the set of TransactionIds that make up a MultiXactId
 
891
 *
 
892
 * We return -1 if the MultiXactId is too old to possibly have any members
 
893
 * still running; in that case we have not actually looked them up, and
 
894
 * *xids is not set.
 
895
 */
 
896
int
 
897
GetMultiXactIdMembers(MultiXactId multi, TransactionId **xids)
 
898
{
 
899
        int                     pageno;
 
900
        int                     prev_pageno;
 
901
        int                     entryno;
 
902
        int                     slotno;
 
903
        MultiXactOffset *offptr;
 
904
        MultiXactOffset offset;
 
905
        int                     length;
 
906
        int                     truelength;
 
907
        int                     i;
 
908
        MultiXactId nextMXact;
 
909
        MultiXactId tmpMXact;
 
910
        MultiXactOffset nextOffset;
 
911
        TransactionId *ptr;
 
912
 
 
913
        debug_elog3(DEBUG2, "GetMembers: asked for %u", multi);
 
914
 
 
915
        Assert(MultiXactIdIsValid(multi));
 
916
 
 
917
        /* See if the MultiXactId is in the local cache */
 
918
        length = mXactCacheGetById(multi, xids);
 
919
        if (length >= 0)
 
920
        {
 
921
                debug_elog3(DEBUG2, "GetMembers: found %s in the cache",
 
922
                                        mxid_to_string(multi, length, *xids));
 
923
                return length;
 
924
        }
 
925
 
 
926
        /* Set our OldestVisibleMXactId[] entry if we didn't already */
 
927
        MultiXactIdSetOldestVisible();
 
928
 
 
929
        /*
 
930
         * We check known limits on MultiXact before resorting to the SLRU area.
 
931
         *
 
932
         * An ID older than our OldestVisibleMXactId[] entry can't possibly still
 
933
         * be running, and we'd run the risk of trying to read already-truncated
 
934
         * SLRU data if we did try to examine it.
 
935
         *
 
936
         * Conversely, an ID >= nextMXact shouldn't ever be seen here; if it is
 
937
         * seen, it implies undetected ID wraparound has occurred.      We just
 
938
         * silently assume that such an ID is no longer running.
 
939
         *
 
940
         * Shared lock is enough here since we aren't modifying any global state.
 
941
         * Also, we can examine our own OldestVisibleMXactId without the lock,
 
942
         * since no one else is allowed to change it.
 
943
         */
 
944
        if (MultiXactIdPrecedes(multi, OldestVisibleMXactId[MyBackendId]))
 
945
        {
 
946
                debug_elog2(DEBUG2, "GetMembers: it's too old");
 
947
                *xids = NULL;
 
948
                return -1;
 
949
        }
 
950
 
 
951
        /*
 
952
         * Acquire the shared lock just long enough to grab the current counter
 
953
         * values.      We may need both nextMXact and nextOffset; see below.
 
954
         */
 
955
        LWLockAcquire(MultiXactGenLock, LW_SHARED);
 
956
 
 
957
        nextMXact = MultiXactState->nextMXact;
 
958
        nextOffset = MultiXactState->nextOffset;
 
959
 
 
960
        LWLockRelease(MultiXactGenLock);
 
961
 
 
962
        if (!MultiXactIdPrecedes(multi, nextMXact))
 
963
        {
 
964
                debug_elog2(DEBUG2, "GetMembers: it's too new!");
 
965
                *xids = NULL;
 
966
                return -1;
 
967
        }
 
968
 
 
969
        /*
 
970
         * Find out the offset at which we need to start reading MultiXactMembers
 
971
         * and the number of members in the multixact.  We determine the latter as
 
972
         * the difference between this multixact's starting offset and the next
 
973
         * one's.  However, there are some corner cases to worry about:
 
974
         *
 
975
         * 1. This multixact may be the latest one created, in which case there is
 
976
         * no next one to look at.      In this case the nextOffset value we just
 
977
         * saved is the correct endpoint.
 
978
         *
 
979
         * 2. The next multixact may still be in process of being filled in: that
 
980
         * is, another process may have done GetNewMultiXactId but not yet written
 
981
         * the offset entry for that ID.  In that scenario, it is guaranteed that
 
982
         * the offset entry for that multixact exists (because GetNewMultiXactId
 
983
         * won't release MultiXactGenLock until it does) but contains zero
 
984
         * (because we are careful to pre-zero offset pages). Because
 
985
         * GetNewMultiXactId will never return zero as the starting offset for a
 
986
         * multixact, when we read zero as the next multixact's offset, we know we
 
987
         * have this case.      We sleep for a bit and try again.
 
988
         *
 
989
         * 3. Because GetNewMultiXactId increments offset zero to offset one to
 
990
         * handle case #2, there is an ambiguity near the point of offset
 
991
         * wraparound.  If we see next multixact's offset is one, is that our
 
992
         * multixact's actual endpoint, or did it end at zero with a subsequent
 
993
         * increment?  We handle this using the knowledge that if the zero'th
 
994
         * member slot wasn't filled, it'll contain zero, and zero isn't a valid
 
995
         * transaction ID so it can't be a multixact member.  Therefore, if we
 
996
         * read a zero from the members array, just ignore it.
 
997
         *
 
998
         * This is all pretty messy, but the mess occurs only in infrequent corner
 
999
         * cases, so it seems better than holding the MultiXactGenLock for a long
 
1000
         * time on every multixact creation.
 
1001
         */
 
1002
retry:
 
1003
        LWLockAcquire(MultiXactOffsetControlLock, LW_EXCLUSIVE);
 
1004
 
 
1005
        pageno = MultiXactIdToOffsetPage(multi);
 
1006
        entryno = MultiXactIdToOffsetEntry(multi);
 
1007
 
 
1008
        slotno = SimpleLruReadPage(MultiXactOffsetCtl, pageno, true, multi);
 
1009
        offptr = (MultiXactOffset *) MultiXactOffsetCtl->shared->page_buffer[slotno];
 
1010
        offptr += entryno;
 
1011
        offset = *offptr;
 
1012
 
 
1013
        Assert(offset != 0);
 
1014
 
 
1015
        /*
 
1016
         * Use the same increment rule as GetNewMultiXactId(), that is, don't
 
1017
         * handle wraparound explicitly until needed.
 
1018
         */
 
1019
        tmpMXact = multi + 1;
 
1020
 
 
1021
        if (nextMXact == tmpMXact)
 
1022
        {
 
1023
                /* Corner case 1: there is no next multixact */
 
1024
                length = nextOffset - offset;
 
1025
        }
 
1026
        else
 
1027
        {
 
1028
                MultiXactOffset nextMXOffset;
 
1029
 
 
1030
                /* handle wraparound if needed */
 
1031
                if (tmpMXact < FirstMultiXactId)
 
1032
                        tmpMXact = FirstMultiXactId;
 
1033
 
 
1034
                prev_pageno = pageno;
 
1035
 
 
1036
                pageno = MultiXactIdToOffsetPage(tmpMXact);
 
1037
                entryno = MultiXactIdToOffsetEntry(tmpMXact);
 
1038
 
 
1039
                if (pageno != prev_pageno)
 
1040
                        slotno = SimpleLruReadPage(MultiXactOffsetCtl, pageno, true, tmpMXact);
 
1041
 
 
1042
                offptr = (MultiXactOffset *) MultiXactOffsetCtl->shared->page_buffer[slotno];
 
1043
                offptr += entryno;
 
1044
                nextMXOffset = *offptr;
 
1045
 
 
1046
                if (nextMXOffset == 0)
 
1047
                {
 
1048
                        /* Corner case 2: next multixact is still being filled in */
 
1049
                        LWLockRelease(MultiXactOffsetControlLock);
 
1050
                        pg_usleep(1000L);
 
1051
                        goto retry;
 
1052
                }
 
1053
 
 
1054
                length = nextMXOffset - offset;
 
1055
        }
 
1056
 
 
1057
        LWLockRelease(MultiXactOffsetControlLock);
 
1058
 
 
1059
        ptr = (TransactionId *) palloc(length * sizeof(TransactionId));
 
1060
        *xids = ptr;
 
1061
 
 
1062
        /* Now get the members themselves. */
 
1063
        LWLockAcquire(MultiXactMemberControlLock, LW_EXCLUSIVE);
 
1064
 
 
1065
        truelength = 0;
 
1066
        prev_pageno = -1;
 
1067
        for (i = 0; i < length; i++, offset++)
 
1068
        {
 
1069
                TransactionId *xactptr;
 
1070
 
 
1071
                pageno = MXOffsetToMemberPage(offset);
 
1072
                entryno = MXOffsetToMemberEntry(offset);
 
1073
 
 
1074
                if (pageno != prev_pageno)
 
1075
                {
 
1076
                        slotno = SimpleLruReadPage(MultiXactMemberCtl, pageno, true, multi);
 
1077
                        prev_pageno = pageno;
 
1078
                }
 
1079
 
 
1080
                xactptr = (TransactionId *)
 
1081
                        MultiXactMemberCtl->shared->page_buffer[slotno];
 
1082
                xactptr += entryno;
 
1083
 
 
1084
                if (!TransactionIdIsValid(*xactptr))
 
1085
                {
 
1086
                        /* Corner case 3: we must be looking at unused slot zero */
 
1087
                        Assert(offset == 0);
 
1088
                        continue;
 
1089
                }
 
1090
 
 
1091
                ptr[truelength++] = *xactptr;
 
1092
        }
 
1093
 
 
1094
        LWLockRelease(MultiXactMemberControlLock);
 
1095
 
 
1096
        /*
 
1097
         * Copy the result into the local cache.
 
1098
         */
 
1099
        mXactCachePut(multi, truelength, ptr);
 
1100
 
 
1101
        debug_elog3(DEBUG2, "GetMembers: no cache for %s",
 
1102
                                mxid_to_string(multi, truelength, ptr));
 
1103
        return truelength;
 
1104
}
 
1105
 
 
1106
/*
 
1107
 * mXactCacheGetBySet
 
1108
 *              returns a MultiXactId from the cache based on the set of
 
1109
 *              TransactionIds that compose it, or InvalidMultiXactId if
 
1110
 *              none matches.
 
1111
 *
 
1112
 * This is helpful, for example, if two transactions want to lock a huge
 
1113
 * table.  By using the cache, the second will use the same MultiXactId
 
1114
 * for the majority of tuples, thus keeping MultiXactId usage low (saving
 
1115
 * both I/O and wraparound issues).
 
1116
 *
 
1117
 * NB: the passed xids[] array will be sorted in-place.
 
1118
 */
 
1119
static MultiXactId
 
1120
mXactCacheGetBySet(int nxids, TransactionId *xids)
 
1121
{
 
1122
        mXactCacheEnt *entry;
 
1123
 
 
1124
        debug_elog3(DEBUG2, "CacheGet: looking for %s",
 
1125
                                mxid_to_string(InvalidMultiXactId, nxids, xids));
 
1126
 
 
1127
        /* sort the array so comparison is easy */
 
1128
        qsort(xids, nxids, sizeof(TransactionId), xidComparator);
 
1129
 
 
1130
        for (entry = MXactCache; entry != NULL; entry = entry->next)
 
1131
        {
 
1132
                if (entry->nxids != nxids)
 
1133
                        continue;
 
1134
 
 
1135
                /* We assume the cache entries are sorted */
 
1136
                if (memcmp(xids, entry->xids, nxids * sizeof(TransactionId)) == 0)
 
1137
                {
 
1138
                        debug_elog3(DEBUG2, "CacheGet: found %u", entry->multi);
 
1139
                        return entry->multi;
 
1140
                }
 
1141
        }
 
1142
 
 
1143
        debug_elog2(DEBUG2, "CacheGet: not found :-(");
 
1144
        return InvalidMultiXactId;
 
1145
}
 
1146
 
 
1147
/*
 
1148
 * mXactCacheGetById
 
1149
 *              returns the composing TransactionId set from the cache for a
 
1150
 *              given MultiXactId, if present.
 
1151
 *
 
1152
 * If successful, *xids is set to the address of a palloc'd copy of the
 
1153
 * TransactionId set.  Return value is number of members, or -1 on failure.
 
1154
 */
 
1155
static int
 
1156
mXactCacheGetById(MultiXactId multi, TransactionId **xids)
 
1157
{
 
1158
        mXactCacheEnt *entry;
 
1159
 
 
1160
        debug_elog3(DEBUG2, "CacheGet: looking for %u", multi);
 
1161
 
 
1162
        for (entry = MXactCache; entry != NULL; entry = entry->next)
 
1163
        {
 
1164
                if (entry->multi == multi)
 
1165
                {
 
1166
                        TransactionId *ptr;
 
1167
                        Size            size;
 
1168
 
 
1169
                        size = sizeof(TransactionId) * entry->nxids;
 
1170
                        ptr = (TransactionId *) palloc(size);
 
1171
                        *xids = ptr;
 
1172
 
 
1173
                        memcpy(ptr, entry->xids, size);
 
1174
 
 
1175
                        debug_elog3(DEBUG2, "CacheGet: found %s",
 
1176
                                                mxid_to_string(multi, entry->nxids, entry->xids));
 
1177
                        return entry->nxids;
 
1178
                }
 
1179
        }
 
1180
 
 
1181
        debug_elog2(DEBUG2, "CacheGet: not found");
 
1182
        return -1;
 
1183
}
 
1184
 
 
1185
/*
 
1186
 * mXactCachePut
 
1187
 *              Add a new MultiXactId and its composing set into the local cache.
 
1188
 */
 
1189
static void
 
1190
mXactCachePut(MultiXactId multi, int nxids, TransactionId *xids)
 
1191
{
 
1192
        mXactCacheEnt *entry;
 
1193
 
 
1194
        debug_elog3(DEBUG2, "CachePut: storing %s",
 
1195
                                mxid_to_string(multi, nxids, xids));
 
1196
 
 
1197
        if (MXactContext == NULL)
 
1198
        {
 
1199
                /* The cache only lives as long as the current transaction */
 
1200
                debug_elog2(DEBUG2, "CachePut: initializing memory context");
 
1201
                MXactContext = AllocSetContextCreate(TopTransactionContext,
 
1202
                                                                                         "MultiXact Cache Context",
 
1203
                                                                                         ALLOCSET_SMALL_MINSIZE,
 
1204
                                                                                         ALLOCSET_SMALL_INITSIZE,
 
1205
                                                                                         ALLOCSET_SMALL_MAXSIZE);
 
1206
        }
 
1207
 
 
1208
        entry = (mXactCacheEnt *)
 
1209
                MemoryContextAlloc(MXactContext,
 
1210
                                                   offsetof(mXactCacheEnt, xids) +
 
1211
                                                   nxids * sizeof(TransactionId));
 
1212
 
 
1213
        entry->multi = multi;
 
1214
        entry->nxids = nxids;
 
1215
        memcpy(entry->xids, xids, nxids * sizeof(TransactionId));
 
1216
 
 
1217
        /* mXactCacheGetBySet assumes the entries are sorted, so sort them */
 
1218
        qsort(entry->xids, nxids, sizeof(TransactionId), xidComparator);
 
1219
 
 
1220
        entry->next = MXactCache;
 
1221
        MXactCache = entry;
 
1222
}
 
1223
 
 
1224
#ifdef MULTIXACT_DEBUG
 
1225
static char *
 
1226
mxid_to_string(MultiXactId multi, int nxids, TransactionId *xids)
 
1227
{
 
1228
        char       *str = palloc(15 * (nxids + 1) + 4);
 
1229
        int                     i;
 
1230
 
 
1231
        snprintf(str, 47, "%u %d[%u", multi, nxids, xids[0]);
 
1232
 
 
1233
        for (i = 1; i < nxids; i++)
 
1234
                snprintf(str + strlen(str), 17, ", %u", xids[i]);
 
1235
 
 
1236
        strcat(str, "]");
 
1237
        return str;
 
1238
}
 
1239
#endif
 
1240
 
 
1241
/*
 
1242
 * AtEOXact_MultiXact
 
1243
 *              Handle transaction end for MultiXact
 
1244
 *
 
1245
 * This is called at top transaction commit or abort (we don't care which).
 
1246
 */
 
1247
void
 
1248
AtEOXact_MultiXact(void)
 
1249
{
 
1250
        /*
 
1251
         * Reset our OldestMemberMXactId and OldestVisibleMXactId values, both of
 
1252
         * which should only be valid while within a transaction.
 
1253
         *
 
1254
         * We assume that storing a MultiXactId is atomic and so we need not take
 
1255
         * MultiXactGenLock to do this.
 
1256
         */
 
1257
        OldestMemberMXactId[MyBackendId] = InvalidMultiXactId;
 
1258
        OldestVisibleMXactId[MyBackendId] = InvalidMultiXactId;
 
1259
 
 
1260
        /*
 
1261
         * Discard the local MultiXactId cache.  Since MXactContext was created as
 
1262
         * a child of TopTransactionContext, we needn't delete it explicitly.
 
1263
         */
 
1264
        MXactContext = NULL;
 
1265
        MXactCache = NULL;
 
1266
}
 
1267
 
 
1268
/*
 
1269
 * AtPrepare_MultiXact
 
1270
 *              Save multixact state at 2PC tranasction prepare
 
1271
 *
 
1272
 * In this phase, we only store our OldestMemberMXactId value in the two-phase
 
1273
 * state file.
 
1274
 */
 
1275
void
 
1276
AtPrepare_MultiXact(void)
 
1277
{
 
1278
        MultiXactId myOldestMember = OldestMemberMXactId[MyBackendId];
 
1279
 
 
1280
        if (MultiXactIdIsValid(myOldestMember))
 
1281
                RegisterTwoPhaseRecord(TWOPHASE_RM_MULTIXACT_ID, 0,
 
1282
                                                           &myOldestMember, sizeof(MultiXactId));
 
1283
}
 
1284
 
 
1285
/*
 
1286
 * PostPrepare_MultiXact
 
1287
 *              Clean up after successful PREPARE TRANSACTION
 
1288
 */
 
1289
void
 
1290
PostPrepare_MultiXact(TransactionId xid)
 
1291
{
 
1292
        MultiXactId myOldestMember;
 
1293
 
 
1294
        /*
 
1295
         * Transfer our OldestMemberMXactId value to the slot reserved for the
 
1296
         * prepared transaction.
 
1297
         */
 
1298
        myOldestMember = OldestMemberMXactId[MyBackendId];
 
1299
        if (MultiXactIdIsValid(myOldestMember))
 
1300
        {
 
1301
                BackendId       dummyBackendId = TwoPhaseGetDummyBackendId(xid);
 
1302
 
 
1303
                /*
 
1304
                 * Even though storing MultiXactId is atomic, acquire lock to make
 
1305
                 * sure others see both changes, not just the reset of the slot of the
 
1306
                 * current backend. Using a volatile pointer might suffice, but this
 
1307
                 * isn't a hot spot.
 
1308
                 */
 
1309
                LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);
 
1310
 
 
1311
                OldestMemberMXactId[dummyBackendId] = myOldestMember;
 
1312
                OldestMemberMXactId[MyBackendId] = InvalidMultiXactId;
 
1313
 
 
1314
                LWLockRelease(MultiXactGenLock);
 
1315
        }
 
1316
 
 
1317
        /*
 
1318
         * We don't need to transfer OldestVisibleMXactId value, because the
 
1319
         * transaction is not going to be looking at any more multixacts once it's
 
1320
         * prepared.
 
1321
         *
 
1322
         * We assume that storing a MultiXactId is atomic and so we need not take
 
1323
         * MultiXactGenLock to do this.
 
1324
         */
 
1325
        OldestVisibleMXactId[MyBackendId] = InvalidMultiXactId;
 
1326
 
 
1327
        /*
 
1328
         * Discard the local MultiXactId cache like in AtEOX_MultiXact
 
1329
         */
 
1330
        MXactContext = NULL;
 
1331
        MXactCache = NULL;
 
1332
}
 
1333
 
 
1334
/*
 
1335
 * multixact_twophase_recover
 
1336
 *              Recover the state of a prepared transaction at startup
 
1337
 */
 
1338
void
 
1339
multixact_twophase_recover(TransactionId xid, uint16 info,
 
1340
                                                   void *recdata, uint32 len)
 
1341
{
 
1342
        BackendId       dummyBackendId = TwoPhaseGetDummyBackendId(xid);
 
1343
        MultiXactId oldestMember;
 
1344
 
 
1345
        /*
 
1346
         * Get the oldest member XID from the state file record, and set it in the
 
1347
         * OldestMemberMXactId slot reserved for this prepared transaction.
 
1348
         */
 
1349
        Assert(len == sizeof(MultiXactId));
 
1350
        oldestMember = *((MultiXactId *) recdata);
 
1351
 
 
1352
        OldestMemberMXactId[dummyBackendId] = oldestMember;
 
1353
}
 
1354
 
 
1355
/*
 
1356
 * multixact_twophase_postcommit
 
1357
 *              Similar to AtEOX_MultiXact but for COMMIT PREPARED
 
1358
 */
 
1359
void
 
1360
multixact_twophase_postcommit(TransactionId xid, uint16 info,
 
1361
                                                          void *recdata, uint32 len)
 
1362
{
 
1363
        BackendId       dummyBackendId = TwoPhaseGetDummyBackendId(xid);
 
1364
 
 
1365
        Assert(len == sizeof(MultiXactId));
 
1366
 
 
1367
        OldestMemberMXactId[dummyBackendId] = InvalidMultiXactId;
 
1368
}
 
1369
 
 
1370
/*
 
1371
 * multixact_twophase_postabort
 
1372
 *              This is actually just the same as the COMMIT case.
 
1373
 */
 
1374
void
 
1375
multixact_twophase_postabort(TransactionId xid, uint16 info,
 
1376
                                                         void *recdata, uint32 len)
 
1377
{
 
1378
        multixact_twophase_postcommit(xid, info, recdata, len);
 
1379
}
 
1380
 
 
1381
/*
 
1382
 * Initialization of shared memory for MultiXact.  We use two SLRU areas,
 
1383
 * thus double memory.  Also, reserve space for the shared MultiXactState
 
1384
 * struct and the per-backend MultiXactId arrays (two of those, too).
 
1385
 */
 
1386
Size
 
1387
MultiXactShmemSize(void)
 
1388
{
 
1389
        Size            size;
 
1390
 
 
1391
#define SHARED_MULTIXACT_STATE_SIZE \
 
1392
        add_size(sizeof(MultiXactStateData), \
 
1393
                         mul_size(sizeof(MultiXactId) * 2, MaxOldestSlot))
 
1394
 
 
1395
        size = SHARED_MULTIXACT_STATE_SIZE;
 
1396
        size = add_size(size, SimpleLruShmemSize(NUM_MXACTOFFSET_BUFFERS, 0));
 
1397
        size = add_size(size, SimpleLruShmemSize(NUM_MXACTMEMBER_BUFFERS, 0));
 
1398
 
 
1399
        return size;
 
1400
}
 
1401
 
 
1402
void
 
1403
MultiXactShmemInit(void)
 
1404
{
 
1405
        bool            found;
 
1406
 
 
1407
        debug_elog2(DEBUG2, "Shared Memory Init for MultiXact");
 
1408
 
 
1409
        MultiXactOffsetCtl->PagePrecedes = MultiXactOffsetPagePrecedes;
 
1410
        MultiXactMemberCtl->PagePrecedes = MultiXactMemberPagePrecedes;
 
1411
 
 
1412
        SimpleLruInit(MultiXactOffsetCtl,
 
1413
                                  "MultiXactOffset Ctl", NUM_MXACTOFFSET_BUFFERS, 0,
 
1414
                                  MultiXactOffsetControlLock, "pg_multixact/offsets");
 
1415
        SimpleLruInit(MultiXactMemberCtl,
 
1416
                                  "MultiXactMember Ctl", NUM_MXACTMEMBER_BUFFERS, 0,
 
1417
                                  MultiXactMemberControlLock, "pg_multixact/members");
 
1418
 
 
1419
        /* Initialize our shared state struct */
 
1420
        MultiXactState = ShmemInitStruct("Shared MultiXact State",
 
1421
                                                                         SHARED_MULTIXACT_STATE_SIZE,
 
1422
                                                                         &found);
 
1423
        if (!IsUnderPostmaster)
 
1424
        {
 
1425
                Assert(!found);
 
1426
 
 
1427
                /* Make sure we zero out the per-backend state */
 
1428
                MemSet(MultiXactState, 0, SHARED_MULTIXACT_STATE_SIZE);
 
1429
        }
 
1430
        else
 
1431
                Assert(found);
 
1432
 
 
1433
        /*
 
1434
         * Set up array pointers.  Note that perBackendXactIds[0] is wasted space
 
1435
         * since we only use indexes 1..MaxOldestSlot in each array.
 
1436
         */
 
1437
        OldestMemberMXactId = MultiXactState->perBackendXactIds;
 
1438
        OldestVisibleMXactId = OldestMemberMXactId + MaxOldestSlot;
 
1439
}
 
1440
 
 
1441
/*
 
1442
 * This func must be called ONCE on system install.  It creates the initial
 
1443
 * MultiXact segments.  (The MultiXacts directories are assumed to have been
 
1444
 * created by initdb, and MultiXactShmemInit must have been called already.)
 
1445
 */
 
1446
void
 
1447
BootStrapMultiXact(void)
 
1448
{
 
1449
        int                     slotno;
 
1450
 
 
1451
        LWLockAcquire(MultiXactOffsetControlLock, LW_EXCLUSIVE);
 
1452
 
 
1453
        /* Create and zero the first page of the offsets log */
 
1454
        slotno = ZeroMultiXactOffsetPage(0, false);
 
1455
 
 
1456
        /* Make sure it's written out */
 
1457
        SimpleLruWritePage(MultiXactOffsetCtl, slotno);
 
1458
        Assert(!MultiXactOffsetCtl->shared->page_dirty[slotno]);
 
1459
 
 
1460
        LWLockRelease(MultiXactOffsetControlLock);
 
1461
 
 
1462
        LWLockAcquire(MultiXactMemberControlLock, LW_EXCLUSIVE);
 
1463
 
 
1464
        /* Create and zero the first page of the members log */
 
1465
        slotno = ZeroMultiXactMemberPage(0, false);
 
1466
 
 
1467
        /* Make sure it's written out */
 
1468
        SimpleLruWritePage(MultiXactMemberCtl, slotno);
 
1469
        Assert(!MultiXactMemberCtl->shared->page_dirty[slotno]);
 
1470
 
 
1471
        LWLockRelease(MultiXactMemberControlLock);
 
1472
}
 
1473
 
 
1474
/*
 
1475
 * Initialize (or reinitialize) a page of MultiXactOffset to zeroes.
 
1476
 * If writeXlog is TRUE, also emit an XLOG record saying we did this.
 
1477
 *
 
1478
 * The page is not actually written, just set up in shared memory.
 
1479
 * The slot number of the new page is returned.
 
1480
 *
 
1481
 * Control lock must be held at entry, and will be held at exit.
 
1482
 */
 
1483
static int
 
1484
ZeroMultiXactOffsetPage(int pageno, bool writeXlog)
 
1485
{
 
1486
        int                     slotno;
 
1487
 
 
1488
        slotno = SimpleLruZeroPage(MultiXactOffsetCtl, pageno);
 
1489
 
 
1490
        if (writeXlog)
 
1491
                WriteMZeroPageXlogRec(pageno, XLOG_MULTIXACT_ZERO_OFF_PAGE);
 
1492
 
 
1493
        return slotno;
 
1494
}
 
1495
 
 
1496
/*
 
1497
 * Ditto, for MultiXactMember
 
1498
 */
 
1499
static int
 
1500
ZeroMultiXactMemberPage(int pageno, bool writeXlog)
 
1501
{
 
1502
        int                     slotno;
 
1503
 
 
1504
        slotno = SimpleLruZeroPage(MultiXactMemberCtl, pageno);
 
1505
 
 
1506
        if (writeXlog)
 
1507
                WriteMZeroPageXlogRec(pageno, XLOG_MULTIXACT_ZERO_MEM_PAGE);
 
1508
 
 
1509
        return slotno;
 
1510
}
 
1511
 
 
1512
/*
 
1513
 * This must be called ONCE during postmaster or standalone-backend startup.
 
1514
 *
 
1515
 * StartupXLOG has already established nextMXact/nextOffset by calling
 
1516
 * MultiXactSetNextMXact and/or MultiXactAdvanceNextMXact.      Note that we
 
1517
 * may already have replayed WAL data into the SLRU files.
 
1518
 *
 
1519
 * We don't need any locks here, really; the SLRU locks are taken
 
1520
 * only because slru.c expects to be called with locks held.
 
1521
 */
 
1522
void
 
1523
StartupMultiXact(void)
 
1524
{
 
1525
        MultiXactId multi = MultiXactState->nextMXact;
 
1526
        MultiXactOffset offset = MultiXactState->nextOffset;
 
1527
        int                     pageno;
 
1528
        int                     entryno;
 
1529
 
 
1530
        /* Clean up offsets state */
 
1531
        LWLockAcquire(MultiXactOffsetControlLock, LW_EXCLUSIVE);
 
1532
 
 
1533
        /*
 
1534
         * Initialize our idea of the latest page number.
 
1535
         */
 
1536
        pageno = MultiXactIdToOffsetPage(multi);
 
1537
        MultiXactOffsetCtl->shared->latest_page_number = pageno;
 
1538
 
 
1539
        /*
 
1540
         * Zero out the remainder of the current offsets page.  See notes in
 
1541
         * StartupCLOG() for motivation.
 
1542
         */
 
1543
        entryno = MultiXactIdToOffsetEntry(multi);
 
1544
        if (entryno != 0)
 
1545
        {
 
1546
                int                     slotno;
 
1547
                MultiXactOffset *offptr;
 
1548
 
 
1549
                slotno = SimpleLruReadPage(MultiXactOffsetCtl, pageno, true, multi);
 
1550
                offptr = (MultiXactOffset *) MultiXactOffsetCtl->shared->page_buffer[slotno];
 
1551
                offptr += entryno;
 
1552
 
 
1553
                MemSet(offptr, 0, BLCKSZ - (entryno * sizeof(MultiXactOffset)));
 
1554
 
 
1555
                MultiXactOffsetCtl->shared->page_dirty[slotno] = true;
 
1556
        }
 
1557
 
 
1558
        LWLockRelease(MultiXactOffsetControlLock);
 
1559
 
 
1560
        /* And the same for members */
 
1561
        LWLockAcquire(MultiXactMemberControlLock, LW_EXCLUSIVE);
 
1562
 
 
1563
        /*
 
1564
         * Initialize our idea of the latest page number.
 
1565
         */
 
1566
        pageno = MXOffsetToMemberPage(offset);
 
1567
        MultiXactMemberCtl->shared->latest_page_number = pageno;
 
1568
 
 
1569
        /*
 
1570
         * Zero out the remainder of the current members page.  See notes in
 
1571
         * StartupCLOG() for motivation.
 
1572
         */
 
1573
        entryno = MXOffsetToMemberEntry(offset);
 
1574
        if (entryno != 0)
 
1575
        {
 
1576
                int                     slotno;
 
1577
                TransactionId *xidptr;
 
1578
 
 
1579
                slotno = SimpleLruReadPage(MultiXactMemberCtl, pageno, true, offset);
 
1580
                xidptr = (TransactionId *) MultiXactMemberCtl->shared->page_buffer[slotno];
 
1581
                xidptr += entryno;
 
1582
 
 
1583
                MemSet(xidptr, 0, BLCKSZ - (entryno * sizeof(TransactionId)));
 
1584
 
 
1585
                MultiXactMemberCtl->shared->page_dirty[slotno] = true;
 
1586
        }
 
1587
 
 
1588
        LWLockRelease(MultiXactMemberControlLock);
 
1589
 
 
1590
        /*
 
1591
         * Initialize lastTruncationPoint to invalid, ensuring that the first
 
1592
         * checkpoint will try to do truncation.
 
1593
         */
 
1594
        MultiXactState->lastTruncationPoint = InvalidMultiXactId;
 
1595
}
 
1596
 
 
1597
/*
 
1598
 * This must be called ONCE during postmaster or standalone-backend shutdown
 
1599
 */
 
1600
void
 
1601
ShutdownMultiXact(void)
 
1602
{
 
1603
        /* Flush dirty MultiXact pages to disk */
 
1604
        TRACE_POSTGRESQL_MULTIXACT_CHECKPOINT_START(false);
 
1605
        SimpleLruFlush(MultiXactOffsetCtl, false);
 
1606
        SimpleLruFlush(MultiXactMemberCtl, false);
 
1607
        TRACE_POSTGRESQL_MULTIXACT_CHECKPOINT_DONE(false);
 
1608
}
 
1609
 
 
1610
/*
 
1611
 * Get the next MultiXactId and offset to save in a checkpoint record
 
1612
 */
 
1613
void
 
1614
MultiXactGetCheckptMulti(bool is_shutdown,
 
1615
                                                 MultiXactId *nextMulti,
 
1616
                                                 MultiXactOffset *nextMultiOffset)
 
1617
{
 
1618
        LWLockAcquire(MultiXactGenLock, LW_SHARED);
 
1619
 
 
1620
        *nextMulti = MultiXactState->nextMXact;
 
1621
        *nextMultiOffset = MultiXactState->nextOffset;
 
1622
 
 
1623
        LWLockRelease(MultiXactGenLock);
 
1624
 
 
1625
        debug_elog4(DEBUG2, "MultiXact: checkpoint is nextMulti %u, nextOffset %u",
 
1626
                                *nextMulti, *nextMultiOffset);
 
1627
}
 
1628
 
 
1629
/*
 
1630
 * Perform a checkpoint --- either during shutdown, or on-the-fly
 
1631
 */
 
1632
void
 
1633
CheckPointMultiXact(void)
 
1634
{
 
1635
        TRACE_POSTGRESQL_MULTIXACT_CHECKPOINT_START(true);
 
1636
 
 
1637
        /* Flush dirty MultiXact pages to disk */
 
1638
        SimpleLruFlush(MultiXactOffsetCtl, true);
 
1639
        SimpleLruFlush(MultiXactMemberCtl, true);
 
1640
 
 
1641
        /*
 
1642
         * Truncate the SLRU files.  This could be done at any time, but
 
1643
         * checkpoint seems a reasonable place for it.  There is one exception: if
 
1644
         * we are called during xlog recovery, then shared->latest_page_number
 
1645
         * isn't valid (because StartupMultiXact hasn't been called yet) and so
 
1646
         * SimpleLruTruncate would get confused.  It seems best not to risk
 
1647
         * removing any data during recovery anyway, so don't truncate.
 
1648
         */
 
1649
        if (!RecoveryInProgress())
 
1650
                TruncateMultiXact();
 
1651
 
 
1652
        TRACE_POSTGRESQL_MULTIXACT_CHECKPOINT_DONE(true);
 
1653
}
 
1654
 
 
1655
/*
 
1656
 * Set the next-to-be-assigned MultiXactId and offset
 
1657
 *
 
1658
 * This is used when we can determine the correct next ID/offset exactly
 
1659
 * from a checkpoint record.  We need no locking since it is only called
 
1660
 * during bootstrap and XLog replay.
 
1661
 */
 
1662
void
 
1663
MultiXactSetNextMXact(MultiXactId nextMulti,
 
1664
                                          MultiXactOffset nextMultiOffset)
 
1665
{
 
1666
        debug_elog4(DEBUG2, "MultiXact: setting next multi to %u offset %u",
 
1667
                                nextMulti, nextMultiOffset);
 
1668
        MultiXactState->nextMXact = nextMulti;
 
1669
        MultiXactState->nextOffset = nextMultiOffset;
 
1670
}
 
1671
 
 
1672
/*
 
1673
 * Ensure the next-to-be-assigned MultiXactId is at least minMulti,
 
1674
 * and similarly nextOffset is at least minMultiOffset
 
1675
 *
 
1676
 * This is used when we can determine minimum safe values from an XLog
 
1677
 * record (either an on-line checkpoint or an mxact creation log entry).
 
1678
 * We need no locking since it is only called during XLog replay.
 
1679
 */
 
1680
void
 
1681
MultiXactAdvanceNextMXact(MultiXactId minMulti,
 
1682
                                                  MultiXactOffset minMultiOffset)
 
1683
{
 
1684
        if (MultiXactIdPrecedes(MultiXactState->nextMXact, minMulti))
 
1685
        {
 
1686
                debug_elog3(DEBUG2, "MultiXact: setting next multi to %u", minMulti);
 
1687
                MultiXactState->nextMXact = minMulti;
 
1688
        }
 
1689
        if (MultiXactOffsetPrecedes(MultiXactState->nextOffset, minMultiOffset))
 
1690
        {
 
1691
                debug_elog3(DEBUG2, "MultiXact: setting next offset to %u",
 
1692
                                        minMultiOffset);
 
1693
                MultiXactState->nextOffset = minMultiOffset;
 
1694
        }
 
1695
}
 
1696
 
 
1697
/*
 
1698
 * Make sure that MultiXactOffset has room for a newly-allocated MultiXactId.
 
1699
 *
 
1700
 * NB: this is called while holding MultiXactGenLock.  We want it to be very
 
1701
 * fast most of the time; even when it's not so fast, no actual I/O need
 
1702
 * happen unless we're forced to write out a dirty log or xlog page to make
 
1703
 * room in shared memory.
 
1704
 */
 
1705
static void
 
1706
ExtendMultiXactOffset(MultiXactId multi)
 
1707
{
 
1708
        int                     pageno;
 
1709
 
 
1710
        /*
 
1711
         * No work except at first MultiXactId of a page.  But beware: just after
 
1712
         * wraparound, the first MultiXactId of page zero is FirstMultiXactId.
 
1713
         */
 
1714
        if (MultiXactIdToOffsetEntry(multi) != 0 &&
 
1715
                multi != FirstMultiXactId)
 
1716
                return;
 
1717
 
 
1718
        pageno = MultiXactIdToOffsetPage(multi);
 
1719
 
 
1720
        LWLockAcquire(MultiXactOffsetControlLock, LW_EXCLUSIVE);
 
1721
 
 
1722
        /* Zero the page and make an XLOG entry about it */
 
1723
        ZeroMultiXactOffsetPage(pageno, true);
 
1724
 
 
1725
        LWLockRelease(MultiXactOffsetControlLock);
 
1726
}
 
1727
 
 
1728
/*
 
1729
 * Make sure that MultiXactMember has room for the members of a newly-
 
1730
 * allocated MultiXactId.
 
1731
 *
 
1732
 * Like the above routine, this is called while holding MultiXactGenLock;
 
1733
 * same comments apply.
 
1734
 */
 
1735
static void
 
1736
ExtendMultiXactMember(MultiXactOffset offset, int nmembers)
 
1737
{
 
1738
        /*
 
1739
         * It's possible that the members span more than one page of the members
 
1740
         * file, so we loop to ensure we consider each page.  The coding is not
 
1741
         * optimal if the members span several pages, but that seems unusual
 
1742
         * enough to not worry much about.
 
1743
         */
 
1744
        while (nmembers > 0)
 
1745
        {
 
1746
                int                     entryno;
 
1747
 
 
1748
                /*
 
1749
                 * Only zero when at first entry of a page.
 
1750
                 */
 
1751
                entryno = MXOffsetToMemberEntry(offset);
 
1752
                if (entryno == 0)
 
1753
                {
 
1754
                        int                     pageno;
 
1755
 
 
1756
                        pageno = MXOffsetToMemberPage(offset);
 
1757
 
 
1758
                        LWLockAcquire(MultiXactMemberControlLock, LW_EXCLUSIVE);
 
1759
 
 
1760
                        /* Zero the page and make an XLOG entry about it */
 
1761
                        ZeroMultiXactMemberPage(pageno, true);
 
1762
 
 
1763
                        LWLockRelease(MultiXactMemberControlLock);
 
1764
                }
 
1765
 
 
1766
                /* Advance to next page (OK if nmembers goes negative) */
 
1767
                offset += (MULTIXACT_MEMBERS_PER_PAGE - entryno);
 
1768
                nmembers -= (MULTIXACT_MEMBERS_PER_PAGE - entryno);
 
1769
        }
 
1770
}
 
1771
 
 
1772
/*
 
1773
 * Remove all MultiXactOffset and MultiXactMember segments before the oldest
 
1774
 * ones still of interest.
 
1775
 *
 
1776
 * This is called only during checkpoints.      We assume no more than one
 
1777
 * backend does this at a time.
 
1778
 *
 
1779
 * XXX do we have any issues with needing to checkpoint here?
 
1780
 */
 
1781
static void
 
1782
TruncateMultiXact(void)
 
1783
{
 
1784
        MultiXactId nextMXact;
 
1785
        MultiXactOffset nextOffset;
 
1786
        MultiXactId oldestMXact;
 
1787
        MultiXactOffset oldestOffset;
 
1788
        int                     cutoffPage;
 
1789
        int                     i;
 
1790
 
 
1791
        /*
 
1792
         * First, compute where we can safely truncate.  Per notes above, this is
 
1793
         * the oldest valid value among all the OldestMemberMXactId[] and
 
1794
         * OldestVisibleMXactId[] entries, or nextMXact if none are valid.
 
1795
         */
 
1796
        LWLockAcquire(MultiXactGenLock, LW_SHARED);
 
1797
 
 
1798
        /*
 
1799
         * We have to beware of the possibility that nextMXact is in the
 
1800
         * wrapped-around state.  We don't fix the counter itself here, but we
 
1801
         * must be sure to use a valid value in our calculation.
 
1802
         */
 
1803
        nextMXact = MultiXactState->nextMXact;
 
1804
        if (nextMXact < FirstMultiXactId)
 
1805
                nextMXact = FirstMultiXactId;
 
1806
 
 
1807
        oldestMXact = nextMXact;
 
1808
        for (i = 1; i <= MaxOldestSlot; i++)
 
1809
        {
 
1810
                MultiXactId thisoldest;
 
1811
 
 
1812
                thisoldest = OldestMemberMXactId[i];
 
1813
                if (MultiXactIdIsValid(thisoldest) &&
 
1814
                        MultiXactIdPrecedes(thisoldest, oldestMXact))
 
1815
                        oldestMXact = thisoldest;
 
1816
                thisoldest = OldestVisibleMXactId[i];
 
1817
                if (MultiXactIdIsValid(thisoldest) &&
 
1818
                        MultiXactIdPrecedes(thisoldest, oldestMXact))
 
1819
                        oldestMXact = thisoldest;
 
1820
        }
 
1821
 
 
1822
        /* Save the current nextOffset too */
 
1823
        nextOffset = MultiXactState->nextOffset;
 
1824
 
 
1825
        LWLockRelease(MultiXactGenLock);
 
1826
 
 
1827
        debug_elog3(DEBUG2, "MultiXact: truncation point = %u", oldestMXact);
 
1828
 
 
1829
        /*
 
1830
         * If we already truncated at this point, do nothing.  This saves time
 
1831
         * when no MultiXacts are getting used, which is probably not uncommon.
 
1832
         */
 
1833
        if (MultiXactState->lastTruncationPoint == oldestMXact)
 
1834
                return;
 
1835
 
 
1836
        /*
 
1837
         * We need to determine where to truncate MultiXactMember.      If we found a
 
1838
         * valid oldest MultiXactId, read its starting offset; otherwise we use
 
1839
         * the nextOffset value we saved above.
 
1840
         */
 
1841
        if (oldestMXact == nextMXact)
 
1842
                oldestOffset = nextOffset;
 
1843
        else
 
1844
        {
 
1845
                int                     pageno;
 
1846
                int                     slotno;
 
1847
                int                     entryno;
 
1848
                MultiXactOffset *offptr;
 
1849
 
 
1850
                /* lock is acquired by SimpleLruReadPage_ReadOnly */
 
1851
 
 
1852
                pageno = MultiXactIdToOffsetPage(oldestMXact);
 
1853
                entryno = MultiXactIdToOffsetEntry(oldestMXact);
 
1854
 
 
1855
                slotno = SimpleLruReadPage_ReadOnly(MultiXactOffsetCtl, pageno, oldestMXact);
 
1856
                offptr = (MultiXactOffset *) MultiXactOffsetCtl->shared->page_buffer[slotno];
 
1857
                offptr += entryno;
 
1858
                oldestOffset = *offptr;
 
1859
 
 
1860
                LWLockRelease(MultiXactOffsetControlLock);
 
1861
        }
 
1862
 
 
1863
        /*
 
1864
         * The cutoff point is the start of the segment containing oldestMXact. We
 
1865
         * pass the *page* containing oldestMXact to SimpleLruTruncate.
 
1866
         */
 
1867
        cutoffPage = MultiXactIdToOffsetPage(oldestMXact);
 
1868
 
 
1869
        SimpleLruTruncate(MultiXactOffsetCtl, cutoffPage);
 
1870
 
 
1871
        /*
 
1872
         * Also truncate MultiXactMember at the previously determined offset.
 
1873
         */
 
1874
        cutoffPage = MXOffsetToMemberPage(oldestOffset);
 
1875
 
 
1876
        SimpleLruTruncate(MultiXactMemberCtl, cutoffPage);
 
1877
 
 
1878
        /*
 
1879
         * Set the last known truncation point.  We don't need a lock for this
 
1880
         * since only one backend does checkpoints at a time.
 
1881
         */
 
1882
        MultiXactState->lastTruncationPoint = oldestMXact;
 
1883
}
 
1884
 
 
1885
/*
 
1886
 * Decide which of two MultiXactOffset page numbers is "older" for truncation
 
1887
 * purposes.
 
1888
 *
 
1889
 * We need to use comparison of MultiXactId here in order to do the right
 
1890
 * thing with wraparound.  However, if we are asked about page number zero, we
 
1891
 * don't want to hand InvalidMultiXactId to MultiXactIdPrecedes: it'll get
 
1892
 * weird.  So, offset both multis by FirstMultiXactId to avoid that.
 
1893
 * (Actually, the current implementation doesn't do anything weird with
 
1894
 * InvalidMultiXactId, but there's no harm in leaving this code like this.)
 
1895
 */
 
1896
static bool
 
1897
MultiXactOffsetPagePrecedes(int page1, int page2)
 
1898
{
 
1899
        MultiXactId multi1;
 
1900
        MultiXactId multi2;
 
1901
 
 
1902
        multi1 = ((MultiXactId) page1) * MULTIXACT_OFFSETS_PER_PAGE;
 
1903
        multi1 += FirstMultiXactId;
 
1904
        multi2 = ((MultiXactId) page2) * MULTIXACT_OFFSETS_PER_PAGE;
 
1905
        multi2 += FirstMultiXactId;
 
1906
 
 
1907
        return MultiXactIdPrecedes(multi1, multi2);
 
1908
}
 
1909
 
 
1910
/*
 
1911
 * Decide which of two MultiXactMember page numbers is "older" for truncation
 
1912
 * purposes.  There is no "invalid offset number" so use the numbers verbatim.
 
1913
 */
 
1914
static bool
 
1915
MultiXactMemberPagePrecedes(int page1, int page2)
 
1916
{
 
1917
        MultiXactOffset offset1;
 
1918
        MultiXactOffset offset2;
 
1919
 
 
1920
        offset1 = ((MultiXactOffset) page1) * MULTIXACT_MEMBERS_PER_PAGE;
 
1921
        offset2 = ((MultiXactOffset) page2) * MULTIXACT_MEMBERS_PER_PAGE;
 
1922
 
 
1923
        return MultiXactOffsetPrecedes(offset1, offset2);
 
1924
}
 
1925
 
 
1926
/*
 
1927
 * Decide which of two MultiXactIds is earlier.
 
1928
 *
 
1929
 * XXX do we need to do something special for InvalidMultiXactId?
 
1930
 * (Doesn't look like it.)
 
1931
 */
 
1932
static bool
 
1933
MultiXactIdPrecedes(MultiXactId multi1, MultiXactId multi2)
 
1934
{
 
1935
        int32           diff = (int32) (multi1 - multi2);
 
1936
 
 
1937
        return (diff < 0);
 
1938
}
 
1939
 
 
1940
/*
 
1941
 * Decide which of two offsets is earlier.
 
1942
 */
 
1943
static bool
 
1944
MultiXactOffsetPrecedes(MultiXactOffset offset1, MultiXactOffset offset2)
 
1945
{
 
1946
        int32           diff = (int32) (offset1 - offset2);
 
1947
 
 
1948
        return (diff < 0);
 
1949
}
 
1950
 
 
1951
 
 
1952
/*
 
1953
 * Write an xlog record reflecting the zeroing of either a MEMBERs or
 
1954
 * OFFSETs page (info shows which)
 
1955
 */
 
1956
static void
 
1957
WriteMZeroPageXlogRec(int pageno, uint8 info)
 
1958
{
 
1959
        XLogRecData rdata;
 
1960
 
 
1961
        rdata.data = (char *) (&pageno);
 
1962
        rdata.len = sizeof(int);
 
1963
        rdata.buffer = InvalidBuffer;
 
1964
        rdata.next = NULL;
 
1965
        (void) XLogInsert(RM_MULTIXACT_ID, info, &rdata);
 
1966
}
 
1967
 
 
1968
/*
 
1969
 * MULTIXACT resource manager's routines
 
1970
 */
 
1971
void
 
1972
multixact_redo(XLogRecPtr lsn, XLogRecord *record)
 
1973
{
 
1974
        uint8           info = record->xl_info & ~XLR_INFO_MASK;
 
1975
 
 
1976
        /* Backup blocks are not used in multixact records */
 
1977
        Assert(!(record->xl_info & XLR_BKP_BLOCK_MASK));
 
1978
 
 
1979
        if (info == XLOG_MULTIXACT_ZERO_OFF_PAGE)
 
1980
        {
 
1981
                int                     pageno;
 
1982
                int                     slotno;
 
1983
 
 
1984
                memcpy(&pageno, XLogRecGetData(record), sizeof(int));
 
1985
 
 
1986
                LWLockAcquire(MultiXactOffsetControlLock, LW_EXCLUSIVE);
 
1987
 
 
1988
                slotno = ZeroMultiXactOffsetPage(pageno, false);
 
1989
                SimpleLruWritePage(MultiXactOffsetCtl, slotno);
 
1990
                Assert(!MultiXactOffsetCtl->shared->page_dirty[slotno]);
 
1991
 
 
1992
                LWLockRelease(MultiXactOffsetControlLock);
 
1993
        }
 
1994
        else if (info == XLOG_MULTIXACT_ZERO_MEM_PAGE)
 
1995
        {
 
1996
                int                     pageno;
 
1997
                int                     slotno;
 
1998
 
 
1999
                memcpy(&pageno, XLogRecGetData(record), sizeof(int));
 
2000
 
 
2001
                LWLockAcquire(MultiXactMemberControlLock, LW_EXCLUSIVE);
 
2002
 
 
2003
                slotno = ZeroMultiXactMemberPage(pageno, false);
 
2004
                SimpleLruWritePage(MultiXactMemberCtl, slotno);
 
2005
                Assert(!MultiXactMemberCtl->shared->page_dirty[slotno]);
 
2006
 
 
2007
                LWLockRelease(MultiXactMemberControlLock);
 
2008
        }
 
2009
        else if (info == XLOG_MULTIXACT_CREATE_ID)
 
2010
        {
 
2011
                xl_multixact_create *xlrec = (xl_multixact_create *) XLogRecGetData(record);
 
2012
                TransactionId *xids = xlrec->xids;
 
2013
                TransactionId max_xid;
 
2014
                int                     i;
 
2015
 
 
2016
                /* Store the data back into the SLRU files */
 
2017
                RecordNewMultiXact(xlrec->mid, xlrec->moff, xlrec->nxids, xids);
 
2018
 
 
2019
                /* Make sure nextMXact/nextOffset are beyond what this record has */
 
2020
                MultiXactAdvanceNextMXact(xlrec->mid + 1, xlrec->moff + xlrec->nxids);
 
2021
 
 
2022
                /*
 
2023
                 * Make sure nextXid is beyond any XID mentioned in the record. This
 
2024
                 * should be unnecessary, since any XID found here ought to have other
 
2025
                 * evidence in the XLOG, but let's be safe.
 
2026
                 */
 
2027
                max_xid = record->xl_xid;
 
2028
                for (i = 0; i < xlrec->nxids; i++)
 
2029
                {
 
2030
                        if (TransactionIdPrecedes(max_xid, xids[i]))
 
2031
                                max_xid = xids[i];
 
2032
                }
 
2033
 
 
2034
                /*
 
2035
                 * We don't expect anyone else to modify nextXid, hence startup
 
2036
                 * process doesn't need to hold a lock while checking this. We still
 
2037
                 * acquire the lock to modify it, though.
 
2038
                 */
 
2039
                if (TransactionIdFollowsOrEquals(max_xid,
 
2040
                                                                                 ShmemVariableCache->nextXid))
 
2041
                {
 
2042
                        LWLockAcquire(XidGenLock, LW_EXCLUSIVE);
 
2043
                        ShmemVariableCache->nextXid = max_xid;
 
2044
                        TransactionIdAdvance(ShmemVariableCache->nextXid);
 
2045
                        LWLockRelease(XidGenLock);
 
2046
                }
 
2047
        }
 
2048
        else
 
2049
                elog(PANIC, "multixact_redo: unknown op code %u", info);
 
2050
}
 
2051
 
 
2052
void
 
2053
multixact_desc(StringInfo buf, uint8 xl_info, char *rec)
 
2054
{
 
2055
        uint8           info = xl_info & ~XLR_INFO_MASK;
 
2056
 
 
2057
        if (info == XLOG_MULTIXACT_ZERO_OFF_PAGE)
 
2058
        {
 
2059
                int                     pageno;
 
2060
 
 
2061
                memcpy(&pageno, rec, sizeof(int));
 
2062
                appendStringInfo(buf, "zero offsets page: %d", pageno);
 
2063
        }
 
2064
        else if (info == XLOG_MULTIXACT_ZERO_MEM_PAGE)
 
2065
        {
 
2066
                int                     pageno;
 
2067
 
 
2068
                memcpy(&pageno, rec, sizeof(int));
 
2069
                appendStringInfo(buf, "zero members page: %d", pageno);
 
2070
        }
 
2071
        else if (info == XLOG_MULTIXACT_CREATE_ID)
 
2072
        {
 
2073
                xl_multixact_create *xlrec = (xl_multixact_create *) rec;
 
2074
                int                     i;
 
2075
 
 
2076
                appendStringInfo(buf, "create multixact %u offset %u:",
 
2077
                                                 xlrec->mid, xlrec->moff);
 
2078
                for (i = 0; i < xlrec->nxids; i++)
 
2079
                        appendStringInfo(buf, " %u", xlrec->xids[i]);
 
2080
        }
 
2081
        else
 
2082
                appendStringInfo(buf, "UNKNOWN");
 
2083
}