|
| 1 | +/* |
| 2 | + * multixact_internal.h |
| 3 | + * |
| 4 | + * PostgreSQL multi-transaction-log manager internal declarations |
| 5 | + * |
| 6 | + * These functions and definitions are for dealing with pg_multixact SLRU |
| 7 | + * pages. They are internal to multixact.c, but they are exported here to |
| 8 | + * allow pg_upgrade to write pg_multixact files directly. |
| 9 | + * |
| 10 | + * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group |
| 11 | + * Portions Copyright (c) 1994, Regents of the University of California |
| 12 | + * |
| 13 | + * src/include/access/multixact_internal.h |
| 14 | + */ |
| 15 | +#ifndef MULTIXACT_INTERNAL_H |
| 16 | +#define MULTIXACT_INTERNAL_H |
| 17 | + |
| 18 | +#include "access/multixact.h" |
| 19 | + |
| 20 | + |
| 21 | +/* |
| 22 | + * Defines for MultiXactOffset page sizes. A page is the same BLCKSZ as is |
| 23 | + * used everywhere else in Postgres. |
| 24 | + * |
| 25 | + * Note: because MultiXactOffsets are 32 bits and wrap around at 0xFFFFFFFF, |
| 26 | + * MultiXact page numbering also wraps around at |
| 27 | + * 0xFFFFFFFF/MULTIXACT_OFFSETS_PER_PAGE, and segment numbering at |
| 28 | + * 0xFFFFFFFF/MULTIXACT_OFFSETS_PER_PAGE/SLRU_PAGES_PER_SEGMENT. We need |
| 29 | + * take no explicit notice of that fact in this module, except when comparing |
| 30 | + * segment and page numbers in TruncateMultiXact (see |
| 31 | + * MultiXactOffsetPagePrecedes). |
| 32 | + */ |
| 33 | + |
| 34 | +/* We need four bytes per offset */ |
| 35 | +#define MULTIXACT_OFFSETS_PER_PAGE (BLCKSZ / sizeof(MultiXactOffset)) |
| 36 | + |
| 37 | +static inline int64 |
| 38 | +MultiXactIdToOffsetPage(MultiXactId multi) |
| 39 | +{ |
| 40 | + return multi / MULTIXACT_OFFSETS_PER_PAGE; |
| 41 | +} |
| 42 | + |
| 43 | +static inline int |
| 44 | +MultiXactIdToOffsetEntry(MultiXactId multi) |
| 45 | +{ |
| 46 | + return multi % MULTIXACT_OFFSETS_PER_PAGE; |
| 47 | +} |
| 48 | + |
| 49 | +static inline int64 |
| 50 | +MultiXactIdToOffsetSegment(MultiXactId multi) |
| 51 | +{ |
| 52 | + return MultiXactIdToOffsetPage(multi) / SLRU_PAGES_PER_SEGMENT; |
| 53 | +} |
| 54 | + |
| 55 | +/* |
| 56 | + * The situation for members is a bit more complex: we store one byte of |
| 57 | + * additional flag bits for each TransactionId. To do this without getting |
| 58 | + * into alignment issues, we store four bytes of flags, and then the |
| 59 | + * corresponding 4 Xids. Each such 5-word (20-byte) set we call a "group", and |
| 60 | + * are stored as a whole in pages. Thus, with 8kB BLCKSZ, we keep 409 groups |
| 61 | + * per page. This wastes 12 bytes per page, but that's OK -- simplicity (and |
| 62 | + * performance) trumps space efficiency here. |
| 63 | + * |
| 64 | + * Note that the "offset" macros work with byte offset, not array indexes, so |
| 65 | + * arithmetic must be done using "char *" pointers. |
| 66 | + */ |
| 67 | +/* We need eight bits per xact, so one xact fits in a byte */ |
| 68 | +#define MXACT_MEMBER_BITS_PER_XACT 8 |
| 69 | +#define MXACT_MEMBER_FLAGS_PER_BYTE 1 |
| 70 | +#define MXACT_MEMBER_XACT_BITMASK ((1 << MXACT_MEMBER_BITS_PER_XACT) - 1) |
| 71 | + |
| 72 | +/* how many full bytes of flags are there in a group? */ |
| 73 | +#define MULTIXACT_FLAGBYTES_PER_GROUP 4 |
| 74 | +#define MULTIXACT_MEMBERS_PER_MEMBERGROUP \ |
| 75 | + (MULTIXACT_FLAGBYTES_PER_GROUP * MXACT_MEMBER_FLAGS_PER_BYTE) |
| 76 | +/* size in bytes of a complete group */ |
| 77 | +#define MULTIXACT_MEMBERGROUP_SIZE \ |
| 78 | + (sizeof(TransactionId) * MULTIXACT_MEMBERS_PER_MEMBERGROUP + MULTIXACT_FLAGBYTES_PER_GROUP) |
| 79 | +#define MULTIXACT_MEMBERGROUPS_PER_PAGE (BLCKSZ / MULTIXACT_MEMBERGROUP_SIZE) |
| 80 | +#define MULTIXACT_MEMBERS_PER_PAGE \ |
| 81 | + (MULTIXACT_MEMBERGROUPS_PER_PAGE * MULTIXACT_MEMBERS_PER_MEMBERGROUP) |
| 82 | + |
| 83 | +/* |
| 84 | + * Because the number of items per page is not a divisor of the last item |
| 85 | + * number (member 0xFFFFFFFF), the last segment does not use the maximum number |
| 86 | + * of pages, and moreover the last used page therein does not use the same |
| 87 | + * number of items as previous pages. (Another way to say it is that the |
| 88 | + * 0xFFFFFFFF member is somewhere in the middle of the last page, so the page |
| 89 | + * has some empty space after that item.) |
| 90 | + * |
| 91 | + * This constant is the number of members in the last page of the last segment. |
| 92 | + */ |
| 93 | +#define MAX_MEMBERS_IN_LAST_MEMBERS_PAGE \ |
| 94 | + ((uint32) ((0xFFFFFFFF % MULTIXACT_MEMBERS_PER_PAGE) + 1)) |
| 95 | + |
| 96 | +/* page in which a member is to be found */ |
| 97 | +static inline int64 |
| 98 | +MXOffsetToMemberPage(MultiXactOffset offset) |
| 99 | +{ |
| 100 | + return offset / MULTIXACT_MEMBERS_PER_PAGE; |
| 101 | +} |
| 102 | + |
| 103 | +static inline int64 |
| 104 | +MXOffsetToMemberSegment(MultiXactOffset offset) |
| 105 | +{ |
| 106 | + return MXOffsetToMemberPage(offset) / SLRU_PAGES_PER_SEGMENT; |
| 107 | +} |
| 108 | + |
| 109 | +/* Location (byte offset within page) of flag word for a given member */ |
| 110 | +static inline int |
| 111 | +MXOffsetToFlagsOffset(MultiXactOffset offset) |
| 112 | +{ |
| 113 | + MultiXactOffset group = offset / MULTIXACT_MEMBERS_PER_MEMBERGROUP; |
| 114 | + int grouponpg = group % MULTIXACT_MEMBERGROUPS_PER_PAGE; |
| 115 | + int byteoff = grouponpg * MULTIXACT_MEMBERGROUP_SIZE; |
| 116 | + |
| 117 | + return byteoff; |
| 118 | +} |
| 119 | + |
| 120 | +static inline int |
| 121 | +MXOffsetToFlagsBitShift(MultiXactOffset offset) |
| 122 | +{ |
| 123 | + int member_in_group = offset % MULTIXACT_MEMBERS_PER_MEMBERGROUP; |
| 124 | + int bshift = member_in_group * MXACT_MEMBER_BITS_PER_XACT; |
| 125 | + |
| 126 | + return bshift; |
| 127 | +} |
| 128 | + |
| 129 | +/* Location (byte offset within page) of TransactionId of given member */ |
| 130 | +static inline int |
| 131 | +MXOffsetToMemberOffset(MultiXactOffset offset) |
| 132 | +{ |
| 133 | + int member_in_group = offset % MULTIXACT_MEMBERS_PER_MEMBERGROUP; |
| 134 | + |
| 135 | + return MXOffsetToFlagsOffset(offset) + |
| 136 | + MULTIXACT_FLAGBYTES_PER_GROUP + |
| 137 | + member_in_group * sizeof(TransactionId); |
| 138 | +} |
| 139 | + |
| 140 | +#endif /* MULTIXACT_INTERNAL_H */ |
0 commit comments