Age Owner TLA Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * relmapper.c
4 : * Catalog-to-filenumber mapping
5 : *
6 : * For most tables, the physical file underlying the table is specified by
7 : * pg_class.relfilenode. However, that obviously won't work for pg_class
8 : * itself, nor for the other "nailed" catalogs for which we have to be able
9 : * to set up working Relation entries without access to pg_class. It also
10 : * does not work for shared catalogs, since there is no practical way to
11 : * update other databases' pg_class entries when relocating a shared catalog.
12 : * Therefore, for these special catalogs (henceforth referred to as "mapped
13 : * catalogs") we rely on a separately maintained file that shows the mapping
14 : * from catalog OIDs to filenumbers. Each database has a map file for
15 : * its local mapped catalogs, and there is a separate map file for shared
16 : * catalogs. Mapped catalogs have zero in their pg_class.relfilenode entries.
17 : *
18 : * Relocation of a normal table is committed (ie, the new physical file becomes
19 : * authoritative) when the pg_class row update commits. For mapped catalogs,
20 : * the act of updating the map file is effectively commit of the relocation.
21 : * We postpone the file update till just before commit of the transaction
22 : * doing the rewrite, but there is necessarily a window between. Therefore
23 : * mapped catalogs can only be relocated by operations such as VACUUM FULL
24 : * and CLUSTER, which make no transactionally-significant changes: it must be
25 : * safe for the new file to replace the old, even if the transaction itself
26 : * aborts. An important factor here is that the indexes and toast table of
27 : * a mapped catalog must also be mapped, so that the rewrites/relocations of
28 : * all these files commit in a single map file update rather than being tied
29 : * to transaction commit.
30 : *
31 : * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
32 : * Portions Copyright (c) 1994, Regents of the University of California
33 : *
34 : *
35 : * IDENTIFICATION
36 : * src/backend/utils/cache/relmapper.c
37 : *
38 : *-------------------------------------------------------------------------
39 : */
40 : #include "postgres.h"
41 :
42 : #include <fcntl.h>
43 : #include <sys/stat.h>
44 : #include <unistd.h>
45 :
46 : #include "access/xact.h"
47 : #include "access/xlog.h"
48 : #include "access/xloginsert.h"
49 : #include "catalog/catalog.h"
50 : #include "catalog/pg_tablespace.h"
51 : #include "catalog/storage.h"
52 : #include "miscadmin.h"
53 : #include "pgstat.h"
54 : #include "storage/fd.h"
55 : #include "storage/lwlock.h"
56 : #include "utils/inval.h"
57 : #include "utils/relmapper.h"
58 :
59 :
60 : /*
61 : * The map file is critical data: we have no automatic method for recovering
62 : * from loss or corruption of it. We use a CRC so that we can detect
63 : * corruption. Since the file might be more than one standard-size disk
64 : * sector in size, we cannot rely on overwrite-in-place. Instead, we generate
65 : * a new file and rename it into place, atomically replacing the original file.
66 : *
67 : * Entries in the mappings[] array are in no particular order. We could
68 : * speed searching by insisting on OID order, but it really shouldn't be
69 : * worth the trouble given the intended size of the mapping sets.
70 : */
71 : #define RELMAPPER_FILENAME "pg_filenode.map"
72 : #define RELMAPPER_TEMP_FILENAME "pg_filenode.map.tmp"
73 :
74 : #define RELMAPPER_FILEMAGIC 0x592717 /* version ID value */
75 :
76 : /*
77 : * There's no need for this constant to have any particular value, and we
78 : * can raise it as necessary if we end up with more mapped relations. For
79 : * now, we just pick a round number that is modestly larger than the expected
80 : * number of mappings.
81 : */
82 : #define MAX_MAPPINGS 64
83 :
84 : typedef struct RelMapping
85 : {
86 : Oid mapoid; /* OID of a catalog */
87 : RelFileNumber mapfilenumber; /* its rel file number */
88 : } RelMapping;
89 :
90 : typedef struct RelMapFile
91 : {
92 : int32 magic; /* always RELMAPPER_FILEMAGIC */
93 : int32 num_mappings; /* number of valid RelMapping entries */
94 : RelMapping mappings[MAX_MAPPINGS];
95 : pg_crc32c crc; /* CRC of all above */
96 : } RelMapFile;
97 :
98 : /*
99 : * State for serializing local and shared relmappings for parallel workers
100 : * (active states only). See notes on active_* and pending_* updates state.
101 : */
102 : typedef struct SerializedActiveRelMaps
103 : {
104 : RelMapFile active_shared_updates;
105 : RelMapFile active_local_updates;
106 : } SerializedActiveRelMaps;
107 :
108 : /*
109 : * The currently known contents of the shared map file and our database's
110 : * local map file are stored here. These can be reloaded from disk
111 : * immediately whenever we receive an update sinval message.
112 : */
113 : static RelMapFile shared_map;
114 : static RelMapFile local_map;
115 :
116 : /*
117 : * We use the same RelMapFile data structure to track uncommitted local
118 : * changes in the mappings (but note the magic and crc fields are not made
119 : * valid in these variables). Currently, map updates are not allowed within
120 : * subtransactions, so one set of transaction-level changes is sufficient.
121 : *
122 : * The active_xxx variables contain updates that are valid in our transaction
123 : * and should be honored by RelationMapOidToFilenumber. The pending_xxx
124 : * variables contain updates we have been told about that aren't active yet;
125 : * they will become active at the next CommandCounterIncrement. This setup
126 : * lets map updates act similarly to updates of pg_class rows, ie, they
127 : * become visible only at the next CommandCounterIncrement boundary.
128 : *
129 : * Active shared and active local updates are serialized by the parallel
130 : * infrastructure, and deserialized within parallel workers.
131 : */
132 : static RelMapFile active_shared_updates;
133 : static RelMapFile active_local_updates;
134 : static RelMapFile pending_shared_updates;
135 : static RelMapFile pending_local_updates;
136 :
137 :
138 : /* non-export function prototypes */
139 : static void apply_map_update(RelMapFile *map, Oid relationId,
140 : RelFileNumber fileNumber, bool add_okay);
141 : static void merge_map_updates(RelMapFile *map, const RelMapFile *updates,
142 : bool add_okay);
143 : static void load_relmap_file(bool shared, bool lock_held);
144 : static void read_relmap_file(RelMapFile *map, char *dbpath, bool lock_held,
145 : int elevel);
146 : static void write_relmap_file(RelMapFile *newmap, bool write_wal,
147 : bool send_sinval, bool preserve_files,
148 : Oid dbid, Oid tsid, const char *dbpath);
149 : static void perform_relmap_update(bool shared, const RelMapFile *updates);
150 :
151 :
152 : /*
153 : * RelationMapOidToFilenumber
154 : *
155 : * The raison d' etre ... given a relation OID, look up its filenumber.
156 : *
157 : * Although shared and local relation OIDs should never overlap, the caller
158 : * always knows which we need --- so pass that information to avoid useless
159 : * searching.
160 : *
161 : * Returns InvalidRelFileNumber if the OID is not known (which should never
162 : * happen, but the caller is in a better position to report a meaningful
163 : * error).
164 : */
165 : RelFileNumber
277 rhaas 166 GNC 934206 : RelationMapOidToFilenumber(Oid relationId, bool shared)
167 : {
168 : const RelMapFile *map;
169 : int32 i;
170 :
4809 tgl 171 ECB : /* If there are active updates, believe those over the main maps */
4809 tgl 172 GIC 934206 : if (shared)
173 : {
174 378195 : map = &active_shared_updates;
175 379044 : for (i = 0; i < map->num_mappings; i++)
176 : {
4809 tgl 177 CBC 1243 : if (relationId == map->mappings[i].mapoid)
277 rhaas 178 GNC 394 : return map->mappings[i].mapfilenumber;
4809 tgl 179 ECB : }
4809 tgl 180 CBC 377801 : map = &shared_map;
4809 tgl 181 GIC 9232957 : for (i = 0; i < map->num_mappings; i++)
4809 tgl 182 ECB : {
4809 tgl 183 CBC 9232957 : if (relationId == map->mappings[i].mapoid)
277 rhaas 184 GNC 377801 : return map->mappings[i].mapfilenumber;
4809 tgl 185 ECB : }
186 : }
187 : else
188 : {
4809 tgl 189 CBC 556011 : map = &active_local_updates;
4809 tgl 190 GIC 557340 : for (i = 0; i < map->num_mappings; i++)
191 : {
192 2096 : if (relationId == map->mappings[i].mapoid)
277 rhaas 193 GNC 767 : return map->mappings[i].mapfilenumber;
4809 tgl 194 ECB : }
4809 tgl 195 CBC 555244 : map = &local_map;
4809 tgl 196 GIC 2134199 : for (i = 0; i < map->num_mappings; i++)
4809 tgl 197 ECB : {
4809 tgl 198 CBC 2134199 : if (relationId == map->mappings[i].mapoid)
277 rhaas 199 GNC 555244 : return map->mappings[i].mapfilenumber;
4809 tgl 200 ECB : }
201 : }
202 :
277 rhaas 203 UNC 0 : return InvalidRelFileNumber;
4809 tgl 204 ECB : }
205 :
206 : /*
207 : * RelationMapFilenumberToOid
3548 rhaas 208 EUB : *
209 : * Do the reverse of the normal direction of mapping done in
210 : * RelationMapOidToFilenumber.
211 : *
212 : * This is not supposed to be used during normal running but rather for
213 : * information purposes when looking at the filesystem or xlog.
214 : *
215 : * Returns InvalidOid if the OID is not known; this can easily happen if the
216 : * relfilenumber doesn't pertain to a mapped relation.
217 : */
218 : Oid
277 rhaas 219 GNC 513 : RelationMapFilenumberToOid(RelFileNumber filenumber, bool shared)
220 : {
221 : const RelMapFile *map;
222 : int32 i;
223 :
3548 rhaas 224 ECB : /* If there are active updates, believe those over the main maps */
3548 rhaas 225 GIC 513 : if (shared)
226 : {
227 157 : map = &active_shared_updates;
228 157 : for (i = 0; i < map->num_mappings; i++)
229 : {
277 rhaas 230 UNC 0 : if (filenumber == map->mappings[i].mapfilenumber)
3548 rhaas 231 UIC 0 : return map->mappings[i].mapoid;
3548 rhaas 232 ECB : }
3548 rhaas 233 CBC 157 : map = &shared_map;
3548 rhaas 234 GIC 3994 : for (i = 0; i < map->num_mappings; i++)
3548 rhaas 235 EUB : {
277 rhaas 236 GNC 3994 : if (filenumber == map->mappings[i].mapfilenumber)
3548 rhaas 237 GIC 157 : return map->mappings[i].mapoid;
3548 rhaas 238 ECB : }
239 : }
240 : else
241 : {
3548 rhaas 242 CBC 356 : map = &active_local_updates;
3548 rhaas 243 GIC 356 : for (i = 0; i < map->num_mappings; i++)
244 : {
277 rhaas 245 UNC 0 : if (filenumber == map->mappings[i].mapfilenumber)
3548 rhaas 246 UIC 0 : return map->mappings[i].mapoid;
3548 rhaas 247 ECB : }
3548 rhaas 248 CBC 356 : map = &local_map;
3548 rhaas 249 GIC 2002 : for (i = 0; i < map->num_mappings; i++)
3548 rhaas 250 EUB : {
277 rhaas 251 GNC 1949 : if (filenumber == map->mappings[i].mapfilenumber)
3548 rhaas 252 GIC 303 : return map->mappings[i].mapoid;
3548 rhaas 253 ECB : }
254 : }
255 :
3548 rhaas 256 CBC 53 : return InvalidOid;
3548 rhaas 257 ECB : }
258 :
259 : /*
260 : * RelationMapOidToFilenumberForDatabase
376 261 : *
262 : * Like RelationMapOidToFilenumber, but reads the mapping from the indicated
263 : * path instead of using the one for the current database.
264 : */
265 : RelFileNumber
277 rhaas 266 GNC 3312 : RelationMapOidToFilenumberForDatabase(char *dbpath, Oid relationId)
267 : {
268 : RelMapFile map;
269 : int i;
270 :
376 rhaas 271 ECB : /* Read the relmap file from the source database. */
376 rhaas 272 GIC 3312 : read_relmap_file(&map, dbpath, false, ERROR);
273 :
274 : /* Iterate over the relmap entries to find the input relation OID. */
275 28336 : for (i = 0; i < map.num_mappings; i++)
276 : {
376 rhaas 277 CBC 28336 : if (relationId == map.mappings[i].mapoid)
277 rhaas 278 GNC 3312 : return map.mappings[i].mapfilenumber;
279 : }
376 rhaas 280 ECB :
277 rhaas 281 UNC 0 : return InvalidRelFileNumber;
376 rhaas 282 ECB : }
283 :
284 : /*
285 : * RelationMapCopy
376 rhaas 286 EUB : *
287 : * Copy relmapfile from source db path to the destination db path and WAL log
288 : * the operation. This is intended for use in creating a new relmap file
289 : * for a database that doesn't have one yet, not for replacing an existing
290 : * relmap file.
291 : */
292 : void
376 rhaas 293 GIC 184 : RelationMapCopy(Oid dbid, Oid tsid, char *srcdbpath, char *dstdbpath)
294 : {
295 : RelMapFile map;
296 :
297 : /*
376 rhaas 298 ECB : * Read the relmap file from the source database.
299 : */
376 rhaas 300 GIC 184 : read_relmap_file(&map, srcdbpath, false, ERROR);
301 :
302 : /*
303 : * Write the same data into the destination database's relmap file.
304 : *
376 rhaas 305 ECB : * No sinval is needed because no one can be connected to the destination
306 : * database yet. For the same reason, there is no need to acquire
307 : * RelationMappingLock.
308 : *
309 : * There's no point in trying to preserve files here. The new database
310 : * isn't usable yet anyway, and won't ever be if we can't install a relmap
311 : * file.
312 : */
376 rhaas 313 GIC 184 : write_relmap_file(&map, true, false, false, dbid, tsid, dstdbpath);
314 184 : }
315 :
316 : /*
317 : * RelationMapUpdateMap
4809 tgl 318 ECB : *
319 : * Install a new relfilenumber mapping for the specified relation.
320 : *
321 : * If immediate is true (or we're bootstrapping), the mapping is activated
322 : * immediately. Otherwise it is made pending until CommandCounterIncrement.
323 : */
324 : void
277 rhaas 325 GNC 22101 : RelationMapUpdateMap(Oid relationId, RelFileNumber fileNumber, bool shared,
326 : bool immediate)
327 : {
328 : RelMapFile *map;
329 :
4809 tgl 330 CBC 22101 : if (IsBootstrapProcessingMode())
331 : {
332 : /*
333 : * In bootstrap mode, the mapping gets installed in permanent map.
334 : */
335 21655 : if (shared)
4809 tgl 336 GIC 15250 : map = &shared_map;
337 : else
338 6405 : map = &local_map;
339 : }
4809 tgl 340 ECB : else
341 : {
342 : /*
1703 pg 343 : * We don't currently support map changes within subtransactions, or
344 : * when in parallel mode. This could be done with more bookkeeping
345 : * infrastructure, but it doesn't presently seem worth it.
346 : */
4809 tgl 347 GIC 446 : if (GetCurrentTransactionNestLevel() > 1)
4809 tgl 348 UIC 0 : elog(ERROR, "cannot change relation mapping within subtransaction");
349 :
1703 pg 350 GIC 446 : if (IsInParallelMode())
1703 pg 351 UIC 0 : elog(ERROR, "cannot change relation mapping in parallel mode");
1703 pg 352 ECB :
4809 tgl 353 GBC 446 : if (immediate)
354 : {
4809 tgl 355 ECB : /* Make it active, but only locally */
4809 tgl 356 GBC 78 : if (shared)
4809 tgl 357 UIC 0 : map = &active_shared_updates;
4809 tgl 358 ECB : else
4809 tgl 359 GIC 78 : map = &active_local_updates;
360 : }
4809 tgl 361 ECB : else
4809 tgl 362 EUB : {
363 : /* Make it pending */
4809 tgl 364 CBC 368 : if (shared)
4809 tgl 365 GIC 171 : map = &pending_shared_updates;
366 : else
367 197 : map = &pending_local_updates;
368 : }
4809 tgl 369 ECB : }
277 rhaas 370 GNC 22101 : apply_map_update(map, relationId, fileNumber, true);
4809 tgl 371 GIC 22101 : }
4809 tgl 372 ECB :
373 : /*
374 : * apply_map_update
375 : *
376 : * Insert a new mapping into the given map variable, replacing any existing
377 : * mapping for the same relation.
378 : *
379 : * In some cases the caller knows there must be an existing mapping; pass
380 : * add_okay = false to draw an error if not.
381 : */
382 : static void
277 rhaas 383 GNC 22743 : apply_map_update(RelMapFile *map, Oid relationId, RelFileNumber fileNumber,
384 : bool add_okay)
385 : {
386 : int32 i;
387 :
388 : /* Replace any existing mapping */
4809 tgl 389 CBC 446350 : for (i = 0; i < map->num_mappings; i++)
390 : {
4809 tgl 391 GIC 425191 : if (relationId == map->mappings[i].mapoid)
392 : {
277 rhaas 393 GNC 1584 : map->mappings[i].mapfilenumber = fileNumber;
4809 tgl 394 GIC 1584 : return;
4809 tgl 395 ECB : }
396 : }
397 :
398 : /* Nope, need to add a new mapping */
4809 tgl 399 CBC 21159 : if (!add_okay)
4809 tgl 400 LBC 0 : elog(ERROR, "attempt to apply a mapping to unmapped relation %u",
401 : relationId);
4809 tgl 402 GIC 21159 : if (map->num_mappings >= MAX_MAPPINGS)
4809 tgl 403 UIC 0 : elog(ERROR, "ran out of space in relation map");
4809 tgl 404 GIC 21159 : map->mappings[map->num_mappings].mapoid = relationId;
277 rhaas 405 GNC 21159 : map->mappings[map->num_mappings].mapfilenumber = fileNumber;
4809 tgl 406 GBC 21159 : map->num_mappings++;
407 : }
4809 tgl 408 ECB :
4809 tgl 409 EUB : /*
4809 tgl 410 ECB : * merge_map_updates
411 : *
412 : * Merge all the updates in the given pending-update map into the target map.
413 : * This is just a bulk form of apply_map_update.
414 : */
415 : static void
4809 tgl 416 GIC 346 : merge_map_updates(RelMapFile *map, const RelMapFile *updates, bool add_okay)
417 : {
418 : int32 i;
419 :
420 988 : for (i = 0; i < updates->num_mappings; i++)
421 : {
4809 tgl 422 CBC 642 : apply_map_update(map,
4809 tgl 423 GIC 642 : updates->mappings[i].mapoid,
277 rhaas 424 GNC 642 : updates->mappings[i].mapfilenumber,
425 : add_okay);
4809 tgl 426 ECB : }
4809 tgl 427 GIC 346 : }
4809 tgl 428 ECB :
429 : /*
430 : * RelationMapRemoveMapping
431 : *
432 : * Remove a relation's entry in the map. This is only allowed for "active"
3260 bruce 433 : * (but not committed) local mappings. We need it so we can back out the
434 : * entry for the transient target file when doing VACUUM FULL/CLUSTER on
435 : * a mapped relation.
436 : */
437 : void
4809 tgl 438 GIC 78 : RelationMapRemoveMapping(Oid relationId)
439 : {
440 78 : RelMapFile *map = &active_local_updates;
441 : int32 i;
442 :
443 123 : for (i = 0; i < map->num_mappings; i++)
4809 tgl 444 ECB : {
4809 tgl 445 GIC 123 : if (relationId == map->mappings[i].mapoid)
4809 tgl 446 ECB : {
447 : /* Found it, collapse it out */
4809 tgl 448 GIC 78 : map->mappings[i] = map->mappings[map->num_mappings - 1];
4809 tgl 449 CBC 78 : map->num_mappings--;
4809 tgl 450 GIC 78 : return;
4809 tgl 451 ECB : }
452 : }
4809 tgl 453 UIC 0 : elog(ERROR, "could not find temporary mapping for relation %u",
4809 tgl 454 ECB : relationId);
455 : }
456 :
457 : /*
458 : * RelationMapInvalidate
4809 tgl 459 EUB : *
460 : * This routine is invoked for SI cache flush messages. We must re-read
461 : * the indicated map file. However, we might receive a SI message in a
462 : * process that hasn't yet, and might never, load the mapping files;
463 : * for example the autovacuum launcher, which *must not* try to read
464 : * a local map since it is attached to no particular database.
465 : * So, re-read only if the map is valid now.
466 : */
467 : void
4809 tgl 468 GIC 131 : RelationMapInvalidate(bool shared)
469 : {
470 131 : if (shared)
471 : {
472 81 : if (shared_map.magic == RELMAPPER_FILEMAGIC)
654 heikki.linnakangas 473 81 : load_relmap_file(true, false);
4809 tgl 474 ECB : }
475 : else
476 : {
4809 tgl 477 GIC 50 : if (local_map.magic == RELMAPPER_FILEMAGIC)
654 heikki.linnakangas 478 CBC 50 : load_relmap_file(false, false);
4809 tgl 479 ECB : }
4809 tgl 480 GIC 131 : }
481 :
482 : /*
4809 tgl 483 ECB : * RelationMapInvalidateAll
484 : *
485 : * Reload all map files. This is used to recover from SI message buffer
486 : * overflow: we can't be sure if we missed an inval message.
487 : * Again, reload only currently-valid maps.
488 : */
489 : void
4809 tgl 490 GIC 2003 : RelationMapInvalidateAll(void)
491 : {
492 2003 : if (shared_map.magic == RELMAPPER_FILEMAGIC)
654 heikki.linnakangas 493 2003 : load_relmap_file(true, false);
4809 tgl 494 2003 : if (local_map.magic == RELMAPPER_FILEMAGIC)
654 heikki.linnakangas 495 1967 : load_relmap_file(false, false);
4809 tgl 496 CBC 2003 : }
497 :
4809 tgl 498 ECB : /*
499 : * AtCCI_RelationMap
500 : *
501 : * Activate any "pending" relation map updates at CommandCounterIncrement time.
502 : */
503 : void
4809 tgl 504 GIC 1206599 : AtCCI_RelationMap(void)
505 : {
506 1206599 : if (pending_shared_updates.num_mappings != 0)
507 : {
508 141 : merge_map_updates(&active_shared_updates,
509 : &pending_shared_updates,
4809 tgl 510 ECB : true);
4809 tgl 511 GIC 141 : pending_shared_updates.num_mappings = 0;
4809 tgl 512 ECB : }
4809 tgl 513 GIC 1206599 : if (pending_local_updates.num_mappings != 0)
4809 tgl 514 ECB : {
4809 tgl 515 GIC 124 : merge_map_updates(&active_local_updates,
516 : &pending_local_updates,
4809 tgl 517 ECB : true);
4809 tgl 518 GIC 124 : pending_local_updates.num_mappings = 0;
4809 tgl 519 ECB : }
4809 tgl 520 GIC 1206599 : }
4809 tgl 521 ECB :
522 : /*
523 : * AtEOXact_RelationMap
524 : *
525 : * Handle relation mapping at main-transaction commit or abort.
526 : *
527 : * During commit, this must be called as late as possible before the actual
528 : * transaction commit, so as to minimize the window where the transaction
529 : * could still roll back after committing map changes. Although nothing
530 : * critically bad happens in such a case, we still would prefer that it
531 : * not happen, since we'd possibly be losing useful updates to the relations'
532 : * pg_class row(s).
533 : *
534 : * During abort, we just have to throw away any pending map changes.
535 : * Normal post-abort cleanup will take care of fixing relcache entries.
536 : * Parallel worker commit/abort is handled by resetting active mappings
537 : * that may have been received from the leader process. (There should be
538 : * no pending updates in parallel workers.)
539 : */
540 : void
1703 pg 541 GIC 486257 : AtEOXact_RelationMap(bool isCommit, bool isParallelWorker)
542 : {
543 486257 : if (isCommit && !isParallelWorker)
544 : {
545 : /*
546 : * We should not get here with any "pending" updates. (We could
4809 tgl 547 ECB : * logically choose to treat such as committed, but in the current
548 : * code this should never happen.)
549 : */
4809 tgl 550 GIC 464803 : Assert(pending_shared_updates.num_mappings == 0);
551 464803 : Assert(pending_local_updates.num_mappings == 0);
552 :
553 : /*
554 : * Write any active updates to the actual map files, then reset them.
555 : */
4809 tgl 556 CBC 464803 : if (active_shared_updates.num_mappings != 0)
4809 tgl 557 ECB : {
4809 tgl 558 GIC 51 : perform_relmap_update(true, &active_shared_updates);
559 51 : active_shared_updates.num_mappings = 0;
560 : }
561 464803 : if (active_local_updates.num_mappings != 0)
4809 tgl 562 ECB : {
4809 tgl 563 GIC 30 : perform_relmap_update(false, &active_local_updates);
4809 tgl 564 CBC 30 : active_local_updates.num_mappings = 0;
4809 tgl 565 ECB : }
566 : }
567 : else
568 : {
1703 pg 569 : /* Abort or parallel worker --- drop all local and pending updates */
1703 pg 570 CBC 21454 : Assert(!isParallelWorker || pending_shared_updates.num_mappings == 0);
1703 pg 571 GIC 21454 : Assert(!isParallelWorker || pending_local_updates.num_mappings == 0);
572 :
4809 tgl 573 21454 : active_shared_updates.num_mappings = 0;
574 21454 : active_local_updates.num_mappings = 0;
575 21454 : pending_shared_updates.num_mappings = 0;
4809 tgl 576 CBC 21454 : pending_local_updates.num_mappings = 0;
4809 tgl 577 ECB : }
4809 tgl 578 GIC 486257 : }
4809 tgl 579 ECB :
580 : /*
581 : * AtPrepare_RelationMap
582 : *
583 : * Handle relation mapping at PREPARE.
584 : *
585 : * Currently, we don't support preparing any transaction that changes the map.
586 : */
587 : void
4809 tgl 588 GIC 365 : AtPrepare_RelationMap(void)
589 : {
590 365 : if (active_shared_updates.num_mappings != 0 ||
591 365 : active_local_updates.num_mappings != 0 ||
592 365 : pending_shared_updates.num_mappings != 0 ||
593 365 : pending_local_updates.num_mappings != 0)
4809 tgl 594 LBC 0 : ereport(ERROR,
595 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4809 tgl 596 ECB : errmsg("cannot PREPARE a transaction that modified relation mapping")));
4809 tgl 597 CBC 365 : }
4809 tgl 598 ECB :
599 : /*
4809 tgl 600 EUB : * CheckPointRelationMap
601 : *
602 : * This is called during a checkpoint. It must ensure that any relation map
4809 tgl 603 ECB : * updates that were WAL-logged before the start of the checkpoint are
604 : * securely flushed to disk and will not need to be replayed later. This
605 : * seems unlikely to be a performance-critical issue, so we use a simple
606 : * method: we just take and release the RelationMappingLock. This ensures
607 : * that any already-logged map update is complete, because write_relmap_file
608 : * will fsync the map file before the lock is released.
609 : */
610 : void
4809 tgl 611 GIC 2363 : CheckPointRelationMap(void)
612 : {
613 2363 : LWLockAcquire(RelationMappingLock, LW_SHARED);
614 2363 : LWLockRelease(RelationMappingLock);
615 2363 : }
616 :
4809 tgl 617 ECB : /*
618 : * RelationMapFinishBootstrap
619 : *
620 : * Write out the initial relation mapping files at the completion of
621 : * bootstrap. All the mapped files should have been made known to us
622 : * via RelationMapUpdateMap calls.
623 : */
624 : void
4809 tgl 625 GIC 305 : RelationMapFinishBootstrap(void)
626 : {
627 305 : Assert(IsBootstrapProcessingMode());
628 :
629 : /* Shouldn't be anything "pending" ... */
630 305 : Assert(active_shared_updates.num_mappings == 0);
4809 tgl 631 CBC 305 : Assert(active_local_updates.num_mappings == 0);
4809 tgl 632 GIC 305 : Assert(pending_shared_updates.num_mappings == 0);
4809 tgl 633 CBC 305 : Assert(pending_local_updates.num_mappings == 0);
634 :
635 : /* Write the files; no WAL or sinval needed */
388 rhaas 636 305 : write_relmap_file(&shared_map, false, false, false,
388 rhaas 637 ECB : InvalidOid, GLOBALTABLESPACE_OID, "global");
388 rhaas 638 CBC 305 : write_relmap_file(&local_map, false, false, false,
4809 tgl 639 ECB : MyDatabaseId, MyDatabaseTableSpace, DatabasePath);
4809 tgl 640 GIC 305 : }
641 :
4809 tgl 642 ECB : /*
643 : * RelationMapInitialize
644 : *
645 : * This initializes the mapper module at process startup. We can't access the
646 : * database yet, so just make sure the maps are empty.
647 : */
648 : void
4809 tgl 649 GIC 11568 : RelationMapInitialize(void)
650 : {
651 : /* The static variables should initialize to zeroes, but let's be sure */
652 11568 : shared_map.magic = 0; /* mark it not loaded */
653 11568 : local_map.magic = 0;
654 11568 : shared_map.num_mappings = 0;
4809 tgl 655 CBC 11568 : local_map.num_mappings = 0;
4809 tgl 656 GIC 11568 : active_shared_updates.num_mappings = 0;
657 11568 : active_local_updates.num_mappings = 0;
4809 tgl 658 CBC 11568 : pending_shared_updates.num_mappings = 0;
659 11568 : pending_local_updates.num_mappings = 0;
660 11568 : }
4809 tgl 661 ECB :
662 : /*
663 : * RelationMapInitializePhase2
664 : *
665 : * This is called to prepare for access to pg_database during startup.
666 : * We should be able to read the shared map file now.
667 : */
668 : void
4809 tgl 669 GIC 11568 : RelationMapInitializePhase2(void)
670 : {
671 : /*
672 : * In bootstrap mode, the map file isn't there yet, so do nothing.
673 : */
674 11568 : if (IsBootstrapProcessingMode())
4809 tgl 675 CBC 305 : return;
676 :
677 : /*
678 : * Load the shared map file, die on error.
679 : */
654 heikki.linnakangas 680 11263 : load_relmap_file(true, false);
4809 tgl 681 ECB : }
682 :
683 : /*
684 : * RelationMapInitializePhase3
685 : *
686 : * This is called as soon as we have determined MyDatabaseId and set up
687 : * DatabasePath. At this point we should be able to read the local map file.
688 : */
689 : void
4809 tgl 690 GIC 10511 : RelationMapInitializePhase3(void)
691 : {
692 : /*
693 : * In bootstrap mode, the map file isn't there yet, so do nothing.
694 : */
695 10511 : if (IsBootstrapProcessingMode())
4809 tgl 696 CBC 305 : return;
697 :
698 : /*
699 : * Load the local map file, die on error.
700 : */
654 heikki.linnakangas 701 10206 : load_relmap_file(false, false);
4809 tgl 702 ECB : }
703 :
704 : /*
705 : * EstimateRelationMapSpace
706 : *
1703 pg 707 : * Estimate space needed to pass active shared and local relmaps to parallel
708 : * workers.
709 : */
710 : Size
1703 pg 711 GIC 806 : EstimateRelationMapSpace(void)
712 : {
713 806 : return sizeof(SerializedActiveRelMaps);
714 : }
715 :
716 : /*
1703 pg 717 ECB : * SerializeRelationMap
718 : *
719 : * Serialize active shared and local relmap state for parallel workers.
720 : */
721 : void
1703 pg 722 GIC 403 : SerializeRelationMap(Size maxSize, char *startAddress)
723 : {
724 : SerializedActiveRelMaps *relmaps;
725 :
726 403 : Assert(maxSize >= EstimateRelationMapSpace());
727 :
1703 pg 728 CBC 403 : relmaps = (SerializedActiveRelMaps *) startAddress;
1703 pg 729 GIC 403 : relmaps->active_shared_updates = active_shared_updates;
730 403 : relmaps->active_local_updates = active_local_updates;
731 403 : }
1703 pg 732 ECB :
733 : /*
734 : * RestoreRelationMap
735 : *
736 : * Restore active shared and local relmap state within a parallel worker.
737 : */
738 : void
1703 pg 739 GIC 1298 : RestoreRelationMap(char *startAddress)
740 : {
741 : SerializedActiveRelMaps *relmaps;
742 :
743 1298 : if (active_shared_updates.num_mappings != 0 ||
744 1298 : active_local_updates.num_mappings != 0 ||
1703 pg 745 CBC 1298 : pending_shared_updates.num_mappings != 0 ||
1703 pg 746 GIC 1298 : pending_local_updates.num_mappings != 0)
1703 pg 747 UIC 0 : elog(ERROR, "parallel worker has existing mappings");
748 :
1703 pg 749 CBC 1298 : relmaps = (SerializedActiveRelMaps *) startAddress;
750 1298 : active_shared_updates = relmaps->active_shared_updates;
751 1298 : active_local_updates = relmaps->active_local_updates;
752 1298 : }
1703 pg 753 EUB :
754 : /*
388 rhaas 755 ECB : * load_relmap_file -- load the shared or local map file
4809 tgl 756 : *
388 rhaas 757 : * Because these files are essential for access to core system catalogs,
758 : * failure to load either of them is a fatal error.
759 : *
760 : * Note that the local case requires DatabasePath to be set up.
761 : */
762 : static void
654 heikki.linnakangas 763 GIC 25651 : load_relmap_file(bool shared, bool lock_held)
764 : {
388 rhaas 765 25651 : if (shared)
766 13398 : read_relmap_file(&shared_map, "global", lock_held, FATAL);
767 : else
768 12253 : read_relmap_file(&local_map, DatabasePath, lock_held, FATAL);
388 rhaas 769 CBC 25651 : }
770 :
388 rhaas 771 ECB : /*
772 : * read_relmap_file -- load data from any relation mapper file
773 : *
774 : * dbpath must be the relevant database path, or "global" for shared relations.
775 : *
776 : * RelationMappingLock will be acquired released unless lock_held = true.
777 : *
778 : * Errors will be reported at the indicated elevel, which should be at least
779 : * ERROR.
780 : */
781 : static void
388 rhaas 782 GIC 29147 : read_relmap_file(RelMapFile *map, char *dbpath, bool lock_held, int elevel)
783 : {
784 : char mapfilename[MAXPGPATH];
785 : pg_crc32c crc;
786 : int fd;
787 : int r;
4809 tgl 788 ECB :
388 rhaas 789 GIC 29147 : Assert(elevel >= ERROR);
790 :
791 : /*
792 : * Grab the lock to prevent the file from being updated while we read it,
793 : * unless the caller is already holding the lock. If the file is updated
654 heikki.linnakangas 794 ECB : * shortly after we look, the sinval signaling mechanism will make us
795 : * re-read it before we are able to access any relation that's affected by
796 : * the change.
797 : */
654 heikki.linnakangas 798 GIC 29147 : if (!lock_held)
799 29066 : LWLockAcquire(RelationMappingLock, LW_SHARED);
800 :
801 : /*
802 : * Open the target file.
803 : *
804 : * Because Windows isn't happy about the idea of renaming over a file
805 : * that someone has open, we only open this file after acquiring the lock,
806 : * and for the same reason, we close it before releasing the lock. That
807 : * way, by the time write_relmap_file() acquires an exclusive lock, no
808 : * one else will have it open.
809 : */
256 rhaas 810 GNC 29147 : snprintf(mapfilename, sizeof(mapfilename), "%s/%s", dbpath,
811 : RELMAPPER_FILENAME);
812 29147 : fd = OpenTransientFile(mapfilename, O_RDONLY | PG_BINARY);
813 29147 : if (fd < 0)
256 rhaas 814 UNC 0 : ereport(elevel,
815 : (errcode_for_file_access(),
816 : errmsg("could not open file \"%s\": %m",
817 : mapfilename)));
818 :
819 : /* Now read the data. */
2213 rhaas 820 GIC 29147 : pgstat_report_wait_start(WAIT_EVENT_RELATION_MAP_READ);
1726 michael 821 29147 : r = read(fd, map, sizeof(RelMapFile));
822 29147 : if (r != sizeof(RelMapFile))
823 : {
1726 michael 824 LBC 0 : if (r < 0)
388 rhaas 825 UIC 0 : ereport(elevel,
1726 michael 826 ECB : (errcode_for_file_access(),
827 : errmsg("could not read file \"%s\": %m", mapfilename)));
1726 michael 828 EUB : else
388 rhaas 829 UIC 0 : ereport(elevel,
830 : (errcode(ERRCODE_DATA_CORRUPTED),
831 : errmsg("could not read file \"%s\": read %d of %zu",
832 : mapfilename, r, sizeof(RelMapFile))));
833 : }
2213 rhaas 834 CBC 29147 : pgstat_report_wait_end();
4809 tgl 835 ECB :
1373 peter 836 GBC 29147 : if (CloseTransientFile(fd) != 0)
388 rhaas 837 UIC 0 : ereport(elevel,
838 : (errcode_for_file_access(),
839 : errmsg("could not close file \"%s\": %m",
1492 michael 840 EUB : mapfilename)));
841 :
256 rhaas 842 GNC 29147 : if (!lock_held)
843 29066 : LWLockRelease(RelationMappingLock);
844 :
845 : /* check for correct magic number, etc */
4809 tgl 846 GIC 29147 : if (map->magic != RELMAPPER_FILEMAGIC ||
847 29147 : map->num_mappings < 0 ||
4809 tgl 848 CBC 29147 : map->num_mappings > MAX_MAPPINGS)
388 rhaas 849 UIC 0 : ereport(elevel,
4809 tgl 850 ECB : (errmsg("relation mapping file \"%s\" contains invalid data",
4809 tgl 851 EUB : mapfilename)));
852 :
853 : /* verify the CRC */
3078 heikki.linnakangas 854 GIC 29147 : INIT_CRC32C(crc);
855 29147 : COMP_CRC32C(crc, (char *) map, offsetof(RelMapFile, crc));
3078 heikki.linnakangas 856 CBC 29147 : FIN_CRC32C(crc);
4809 tgl 857 ECB :
3078 heikki.linnakangas 858 GIC 29147 : if (!EQ_CRC32C(crc, map->crc))
388 rhaas 859 UIC 0 : ereport(elevel,
2118 tgl 860 ECB : (errmsg("relation mapping file \"%s\" contains incorrect checksum",
861 : mapfilename)));
4809 tgl 862 CBC 29147 : }
4809 tgl 863 EUB :
864 : /*
865 : * Write out a new shared or local map file with the given contents.
866 : *
867 : * The magic number and CRC are automatically updated in *newmap. On
4809 tgl 868 ECB : * success, we copy the data to the appropriate permanent static variable.
869 : *
2062 peter_e 870 : * If write_wal is true then an appropriate WAL message is emitted.
871 : * (It will be false for bootstrap and WAL replay cases.)
4809 tgl 872 : *
2062 peter_e 873 EUB : * If send_sinval is true then a SI invalidation message is sent.
874 : * (This should be true except in bootstrap case.)
875 : *
2062 peter_e 876 ECB : * If preserve_files is true then the storage manager is warned not to
877 : * delete the files listed in the map.
878 : *
879 : * Because this may be called during WAL replay when MyDatabaseId,
880 : * DatabasePath, etc aren't valid, we require the caller to pass in suitable
881 : * values. Pass dbpath as "global" for the shared map.
882 : *
883 : * The caller is also responsible for being sure no concurrent map update
884 : * could be happening.
885 : */
886 : static void
388 rhaas 887 GIC 899 : write_relmap_file(RelMapFile *newmap, bool write_wal, bool send_sinval,
888 : bool preserve_files, Oid dbid, Oid tsid, const char *dbpath)
889 : {
890 : int fd;
891 : char mapfilename[MAXPGPATH];
892 : char maptempfilename[MAXPGPATH];
893 :
894 : /*
895 : * Fill in the overhead fields and update CRC.
896 : */
4809 tgl 897 899 : newmap->magic = RELMAPPER_FILEMAGIC;
898 899 : if (newmap->num_mappings < 0 || newmap->num_mappings > MAX_MAPPINGS)
4809 tgl 899 UIC 0 : elog(ERROR, "attempt to write bogus relation mapping");
900 :
3078 heikki.linnakangas 901 GIC 899 : INIT_CRC32C(newmap->crc);
3078 heikki.linnakangas 902 CBC 899 : COMP_CRC32C(newmap->crc, (char *) newmap, offsetof(RelMapFile, crc));
3078 heikki.linnakangas 903 GIC 899 : FIN_CRC32C(newmap->crc);
904 :
905 : /*
906 : * Construct filenames -- a temporary file that we'll create to write the
907 : * data initially, and then the permanent name to which we will rename it.
908 : */
388 rhaas 909 899 : snprintf(mapfilename, sizeof(mapfilename), "%s/%s",
910 : dbpath, RELMAPPER_FILENAME);
257 rhaas 911 GNC 899 : snprintf(maptempfilename, sizeof(maptempfilename), "%s/%s",
912 : dbpath, RELMAPPER_TEMP_FILENAME);
913 :
914 : /*
915 : * Open a temporary file. If a file already exists with this name, it must
916 : * be left over from a previous crash, so we can overwrite it. Concurrent
917 : * calls to this function are not allowed.
918 : */
919 899 : fd = OpenTransientFile(maptempfilename,
920 : O_WRONLY | O_CREAT | O_TRUNC | PG_BINARY);
4809 tgl 921 CBC 899 : if (fd < 0)
4809 tgl 922 LBC 0 : ereport(ERROR,
4809 tgl 923 EUB : (errcode_for_file_access(),
924 : errmsg("could not open file \"%s\": %m",
925 : maptempfilename)));
926 :
927 : /* Write new data to the file. */
257 rhaas 928 GNC 899 : pgstat_report_wait_start(WAIT_EVENT_RELATION_MAP_WRITE);
929 899 : if (write(fd, newmap, sizeof(RelMapFile)) != sizeof(RelMapFile))
930 : {
931 : /* if write didn't set errno, assume problem is no disk space */
257 rhaas 932 UNC 0 : if (errno == 0)
933 0 : errno = ENOSPC;
934 0 : ereport(ERROR,
935 : (errcode_for_file_access(),
936 : errmsg("could not write file \"%s\": %m",
937 : maptempfilename)));
938 : }
257 rhaas 939 GNC 899 : pgstat_report_wait_end();
940 :
941 : /* And close the file. */
942 899 : if (CloseTransientFile(fd) != 0)
257 rhaas 943 UNC 0 : ereport(ERROR,
944 : (errcode_for_file_access(),
945 : errmsg("could not close file \"%s\": %m",
946 : maptempfilename)));
4809 tgl 947 ECB :
4809 tgl 948 CBC 899 : if (write_wal)
949 : {
950 : xl_relmap_update xlrec;
951 : XLogRecPtr lsn;
952 :
953 : /* now errors are fatal ... */
954 265 : START_CRIT_SECTION();
955 :
956 265 : xlrec.dbid = dbid;
4809 tgl 957 GIC 265 : xlrec.tsid = tsid;
958 265 : xlrec.nbytes = sizeof(RelMapFile);
959 :
3062 heikki.linnakangas 960 265 : XLogBeginInsert();
961 265 : XLogRegisterData((char *) (&xlrec), MinSizeOfRelmapUpdate);
962 265 : XLogRegisterData((char *) newmap, sizeof(RelMapFile));
963 :
3062 heikki.linnakangas 964 CBC 265 : lsn = XLogInsert(RM_RELMAP_ID, XLOG_RELMAP_UPDATE);
965 :
4809 tgl 966 ECB : /* As always, WAL must hit the disk before the data update does */
4809 tgl 967 GBC 265 : XLogFlush(lsn);
968 : }
969 :
4809 tgl 970 ECB : /*
971 : * durable_rename() does all the hard work of making sure that we rename
972 : * the temporary file into place in a crash-safe manner.
973 : *
974 : * NB: Although we instruct durable_rename() to use ERROR, we will often
975 : * be in a critical section at this point; if so, ERROR will become PANIC.
976 : */
257 rhaas 977 GNC 899 : pgstat_report_wait_start(WAIT_EVENT_RELATION_MAP_REPLACE);
978 899 : durable_rename(maptempfilename, mapfilename, ERROR);
2213 rhaas 979 GIC 899 : pgstat_report_wait_end();
980 :
981 : /*
4809 tgl 982 ECB : * Now that the file is safely on disk, send sinval message to let other
983 : * backends know to re-read it. We must do this inside the critical
984 : * section: if for some reason we fail to send the message, we have to
985 : * force a database-wide PANIC. Otherwise other backends might continue
986 : * execution with stale mapping information, which would be catastrophic
987 : * as soon as others began to use the now-committed data.
988 : */
4809 tgl 989 CBC 899 : if (send_sinval)
4809 tgl 990 GIC 105 : CacheInvalidateRelmap(dbid);
991 :
992 : /*
993 : * Make sure that the files listed in the map are not deleted if the outer
994 : * transaction aborts. This had better be within the critical section
995 : * too: it's not likely to fail, but if it did, we'd arrive at transaction
996 : * abort with the files still vulnerable. PANICing will leave things in a
997 : * good state on-disk.
998 : *
4809 tgl 999 ECB : * Note: we're cheating a little bit here by assuming that mapped files
1000 : * are either in pg_global or the database's default tablespace.
1001 : */
4809 tgl 1002 GIC 899 : if (preserve_files)
1003 : {
1004 : int32 i;
1005 :
1006 3141 : for (i = 0; i < newmap->num_mappings; i++)
1007 : {
1008 : RelFileLocator rlocator;
1009 :
277 rhaas 1010 GNC 3060 : rlocator.spcOid = tsid;
1011 3060 : rlocator.dbOid = dbid;
1012 3060 : rlocator.relNumber = newmap->mappings[i].mapfilenumber;
1013 3060 : RelationPreserveStorage(rlocator, false);
1014 : }
1015 : }
1016 :
1017 : /* Critical section done */
4809 tgl 1018 GIC 899 : if (write_wal)
1019 265 : END_CRIT_SECTION();
1020 899 : }
1021 :
1022 : /*
1023 : * Merge the specified updates into the appropriate "real" map,
4809 tgl 1024 ECB : * and write out the changes. This function must be used for committing
1025 : * updates during normal multiuser operation.
1026 : */
1027 : static void
4809 tgl 1028 CBC 81 : perform_relmap_update(bool shared, const RelMapFile *updates)
1029 : {
1030 : RelMapFile newmap;
1031 :
4809 tgl 1032 ECB : /*
4790 bruce 1033 : * Anyone updating a relation's mapping info should take exclusive lock on
1034 : * that rel and hold it until commit. This ensures that there will not be
1035 : * concurrent updates on the same mapping value; but there could easily be
1036 : * concurrent updates on different values in the same file. We cover that
1037 : * by acquiring the RelationMappingLock, re-reading the target file to
1038 : * ensure it's up to date, applying the updates, and writing the data
1039 : * before releasing RelationMappingLock.
4809 tgl 1040 : *
1041 : * There is only one RelationMappingLock. In principle we could try to
1042 : * have one per mapping file, but it seems unlikely to be worth the
1043 : * trouble.
1044 : */
4809 tgl 1045 GIC 81 : LWLockAcquire(RelationMappingLock, LW_EXCLUSIVE);
1046 :
1047 : /* Be certain we see any other updates just made */
654 heikki.linnakangas 1048 81 : load_relmap_file(shared, true);
1049 :
4809 tgl 1050 ECB : /* Prepare updated data in a local variable */
4809 tgl 1051 GIC 81 : if (shared)
1052 51 : memcpy(&newmap, &shared_map, sizeof(RelMapFile));
1053 : else
1054 30 : memcpy(&newmap, &local_map, sizeof(RelMapFile));
1055 :
1056 : /*
1057 : * Apply the updates to newmap. No new mappings should appear, unless
1058 : * somebody is adding indexes to system catalogs.
1059 : */
4036 1060 81 : merge_map_updates(&newmap, updates, allowSystemTableMods);
1061 :
1062 : /* Write out the updated map and do other necessary tasks */
388 rhaas 1063 81 : write_relmap_file(&newmap, true, true, true,
1064 : (shared ? InvalidOid : MyDatabaseId),
1065 : (shared ? GLOBALTABLESPACE_OID : MyDatabaseTableSpace),
1066 : (shared ? "global" : DatabasePath));
388 rhaas 1067 ECB :
1068 : /*
1069 : * We successfully wrote the updated file, so it's now safe to rely on the
1070 : * new values in this process, too.
1071 : */
388 rhaas 1072 GIC 81 : if (shared)
388 rhaas 1073 CBC 51 : memcpy(&shared_map, &newmap, sizeof(RelMapFile));
388 rhaas 1074 ECB : else
388 rhaas 1075 GIC 30 : memcpy(&local_map, &newmap, sizeof(RelMapFile));
4809 tgl 1076 ECB :
1077 : /* Now we can release the lock */
4809 tgl 1078 GIC 81 : LWLockRelease(RelationMappingLock);
1079 81 : }
1080 :
1081 : /*
4809 tgl 1082 ECB : * RELMAP resource manager's routines
1083 : */
1084 : void
3062 heikki.linnakangas 1085 CBC 24 : relmap_redo(XLogReaderState *record)
1086 : {
3062 heikki.linnakangas 1087 GIC 24 : uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
1088 :
1089 : /* Backup blocks are not used in relmap records */
1090 24 : Assert(!XLogRecHasAnyBlockRefs(record));
1091 :
4809 tgl 1092 24 : if (info == XLOG_RELMAP_UPDATE)
1093 : {
4809 tgl 1094 CBC 24 : xl_relmap_update *xlrec = (xl_relmap_update *) XLogRecGetData(record);
4790 bruce 1095 ECB : RelMapFile newmap;
1096 : char *dbpath;
4809 tgl 1097 :
4809 tgl 1098 GIC 24 : if (xlrec->nbytes != sizeof(RelMapFile))
4809 tgl 1099 UIC 0 : elog(PANIC, "relmap_redo: wrong size %u in relmap update record",
4809 tgl 1100 ECB : xlrec->nbytes);
4809 tgl 1101 CBC 24 : memcpy(&newmap, xlrec->data, sizeof(newmap));
1102 :
1103 : /* We need to construct the pathname for this database */
4809 tgl 1104 GIC 24 : dbpath = GetDatabasePath(xlrec->dbid, xlrec->tsid);
1105 :
1106 : /*
4790 bruce 1107 ECB : * Write out the new map and send sinval, but of course don't write a
1108 : * new WAL entry. There's no surrounding transaction to tell to
1109 : * preserve files, either.
1110 : *
1111 : * There shouldn't be anyone else updating relmaps during WAL replay,
654 heikki.linnakangas 1112 : * but grab the lock to interlock against load_relmap_file().
1113 : *
332 tgl 1114 : * Note that we use the same WAL record for updating the relmap of an
1115 : * existing database as we do for creating a new database. In the
1116 : * latter case, taking the relmap log and sending sinval messages is
1117 : * unnecessary, but harmless. If we wanted to avoid it, we could add a
1118 : * flag to the WAL record to indicate which operation is being
1119 : * performed.
4809 1120 : */
654 heikki.linnakangas 1121 GBC 24 : LWLockAcquire(RelationMappingLock, LW_EXCLUSIVE);
388 rhaas 1122 GIC 24 : write_relmap_file(&newmap, false, true, false,
4809 tgl 1123 ECB : xlrec->dbid, xlrec->tsid, dbpath);
654 heikki.linnakangas 1124 GIC 24 : LWLockRelease(RelationMappingLock);
1125 :
4809 tgl 1126 CBC 24 : pfree(dbpath);
1127 : }
1128 : else
4809 tgl 1129 UIC 0 : elog(PANIC, "relmap_redo: unknown op code %u", info);
4809 tgl 1130 GIC 24 : }
|