00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040 #include "postgres.h"
00041
00042 #include <fcntl.h>
00043 #include <sys/stat.h>
00044 #include <unistd.h>
00045
00046 #include "access/xact.h"
00047 #include "catalog/catalog.h"
00048 #include "catalog/pg_tablespace.h"
00049 #include "catalog/storage.h"
00050 #include "miscadmin.h"
00051 #include "storage/fd.h"
00052 #include "storage/lwlock.h"
00053 #include "utils/inval.h"
00054 #include "utils/relmapper.h"
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070 #define RELMAPPER_FILENAME "pg_filenode.map"
00071
00072 #define RELMAPPER_FILEMAGIC 0x592717
00073
00074 #define MAX_MAPPINGS 62
00075
00076 typedef struct RelMapping
00077 {
00078 Oid mapoid;
00079 Oid mapfilenode;
00080 } RelMapping;
00081
00082 typedef struct RelMapFile
00083 {
00084 int32 magic;
00085 int32 num_mappings;
00086 RelMapping mappings[MAX_MAPPINGS];
00087 int32 crc;
00088 int32 pad;
00089 } RelMapFile;
00090
00091
00092
00093
00094
00095
00096 static RelMapFile shared_map;
00097 static RelMapFile local_map;
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112 static RelMapFile active_shared_updates;
00113 static RelMapFile active_local_updates;
00114 static RelMapFile pending_shared_updates;
00115 static RelMapFile pending_local_updates;
00116
00117
00118
00119 static void apply_map_update(RelMapFile *map, Oid relationId, Oid fileNode,
00120 bool add_okay);
00121 static void merge_map_updates(RelMapFile *map, const RelMapFile *updates,
00122 bool add_okay);
00123 static void load_relmap_file(bool shared);
00124 static void write_relmap_file(bool shared, RelMapFile *newmap,
00125 bool write_wal, bool send_sinval, bool preserve_files,
00126 Oid dbid, Oid tsid, const char *dbpath);
00127 static void perform_relmap_update(bool shared, const RelMapFile *updates);
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142 Oid
00143 RelationMapOidToFilenode(Oid relationId, bool shared)
00144 {
00145 const RelMapFile *map;
00146 int32 i;
00147
00148
00149 if (shared)
00150 {
00151 map = &active_shared_updates;
00152 for (i = 0; i < map->num_mappings; i++)
00153 {
00154 if (relationId == map->mappings[i].mapoid)
00155 return map->mappings[i].mapfilenode;
00156 }
00157 map = &shared_map;
00158 for (i = 0; i < map->num_mappings; i++)
00159 {
00160 if (relationId == map->mappings[i].mapoid)
00161 return map->mappings[i].mapfilenode;
00162 }
00163 }
00164 else
00165 {
00166 map = &active_local_updates;
00167 for (i = 0; i < map->num_mappings; i++)
00168 {
00169 if (relationId == map->mappings[i].mapoid)
00170 return map->mappings[i].mapfilenode;
00171 }
00172 map = &local_map;
00173 for (i = 0; i < map->num_mappings; i++)
00174 {
00175 if (relationId == map->mappings[i].mapoid)
00176 return map->mappings[i].mapfilenode;
00177 }
00178 }
00179
00180 return InvalidOid;
00181 }
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191 void
00192 RelationMapUpdateMap(Oid relationId, Oid fileNode, bool shared,
00193 bool immediate)
00194 {
00195 RelMapFile *map;
00196
00197 if (IsBootstrapProcessingMode())
00198 {
00199
00200
00201
00202 if (shared)
00203 map = &shared_map;
00204 else
00205 map = &local_map;
00206 }
00207 else
00208 {
00209
00210
00211
00212
00213
00214 if (GetCurrentTransactionNestLevel() > 1)
00215 elog(ERROR, "cannot change relation mapping within subtransaction");
00216
00217 if (immediate)
00218 {
00219
00220 if (shared)
00221 map = &active_shared_updates;
00222 else
00223 map = &active_local_updates;
00224 }
00225 else
00226 {
00227
00228 if (shared)
00229 map = &pending_shared_updates;
00230 else
00231 map = &pending_local_updates;
00232 }
00233 }
00234 apply_map_update(map, relationId, fileNode, true);
00235 }
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246 static void
00247 apply_map_update(RelMapFile *map, Oid relationId, Oid fileNode, bool add_okay)
00248 {
00249 int32 i;
00250
00251
00252 for (i = 0; i < map->num_mappings; i++)
00253 {
00254 if (relationId == map->mappings[i].mapoid)
00255 {
00256 map->mappings[i].mapfilenode = fileNode;
00257 return;
00258 }
00259 }
00260
00261
00262 if (!add_okay)
00263 elog(ERROR, "attempt to apply a mapping to unmapped relation %u",
00264 relationId);
00265 if (map->num_mappings >= MAX_MAPPINGS)
00266 elog(ERROR, "ran out of space in relation map");
00267 map->mappings[map->num_mappings].mapoid = relationId;
00268 map->mappings[map->num_mappings].mapfilenode = fileNode;
00269 map->num_mappings++;
00270 }
00271
00272
00273
00274
00275
00276
00277
00278 static void
00279 merge_map_updates(RelMapFile *map, const RelMapFile *updates, bool add_okay)
00280 {
00281 int32 i;
00282
00283 for (i = 0; i < updates->num_mappings; i++)
00284 {
00285 apply_map_update(map,
00286 updates->mappings[i].mapoid,
00287 updates->mappings[i].mapfilenode,
00288 add_okay);
00289 }
00290 }
00291
00292
00293
00294
00295
00296
00297
00298
00299
00300 void
00301 RelationMapRemoveMapping(Oid relationId)
00302 {
00303 RelMapFile *map = &active_local_updates;
00304 int32 i;
00305
00306 for (i = 0; i < map->num_mappings; i++)
00307 {
00308 if (relationId == map->mappings[i].mapoid)
00309 {
00310
00311 map->mappings[i] = map->mappings[map->num_mappings - 1];
00312 map->num_mappings--;
00313 return;
00314 }
00315 }
00316 elog(ERROR, "could not find temporary mapping for relation %u",
00317 relationId);
00318 }
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330 void
00331 RelationMapInvalidate(bool shared)
00332 {
00333 if (shared)
00334 {
00335 if (shared_map.magic == RELMAPPER_FILEMAGIC)
00336 load_relmap_file(true);
00337 }
00338 else
00339 {
00340 if (local_map.magic == RELMAPPER_FILEMAGIC)
00341 load_relmap_file(false);
00342 }
00343 }
00344
00345
00346
00347
00348
00349
00350
00351
00352 void
00353 RelationMapInvalidateAll(void)
00354 {
00355 if (shared_map.magic == RELMAPPER_FILEMAGIC)
00356 load_relmap_file(true);
00357 if (local_map.magic == RELMAPPER_FILEMAGIC)
00358 load_relmap_file(false);
00359 }
00360
00361
00362
00363
00364
00365
00366 void
00367 AtCCI_RelationMap(void)
00368 {
00369 if (pending_shared_updates.num_mappings != 0)
00370 {
00371 merge_map_updates(&active_shared_updates,
00372 &pending_shared_updates,
00373 true);
00374 pending_shared_updates.num_mappings = 0;
00375 }
00376 if (pending_local_updates.num_mappings != 0)
00377 {
00378 merge_map_updates(&active_local_updates,
00379 &pending_local_updates,
00380 true);
00381 pending_local_updates.num_mappings = 0;
00382 }
00383 }
00384
00385
00386
00387
00388
00389
00390
00391
00392
00393
00394
00395
00396
00397
00398
00399
00400 void
00401 AtEOXact_RelationMap(bool isCommit)
00402 {
00403 if (isCommit)
00404 {
00405
00406
00407
00408
00409
00410 Assert(pending_shared_updates.num_mappings == 0);
00411 Assert(pending_local_updates.num_mappings == 0);
00412
00413
00414
00415
00416 if (active_shared_updates.num_mappings != 0)
00417 {
00418 perform_relmap_update(true, &active_shared_updates);
00419 active_shared_updates.num_mappings = 0;
00420 }
00421 if (active_local_updates.num_mappings != 0)
00422 {
00423 perform_relmap_update(false, &active_local_updates);
00424 active_local_updates.num_mappings = 0;
00425 }
00426 }
00427 else
00428 {
00429
00430 active_shared_updates.num_mappings = 0;
00431 active_local_updates.num_mappings = 0;
00432 pending_shared_updates.num_mappings = 0;
00433 pending_local_updates.num_mappings = 0;
00434 }
00435 }
00436
00437
00438
00439
00440
00441
00442
00443
00444 void
00445 AtPrepare_RelationMap(void)
00446 {
00447 if (active_shared_updates.num_mappings != 0 ||
00448 active_local_updates.num_mappings != 0 ||
00449 pending_shared_updates.num_mappings != 0 ||
00450 pending_local_updates.num_mappings != 0)
00451 ereport(ERROR,
00452 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
00453 errmsg("cannot PREPARE a transaction that modified relation mapping")));
00454 }
00455
00456
00457
00458
00459
00460
00461
00462
00463
00464
00465
00466
00467 void
00468 CheckPointRelationMap(void)
00469 {
00470 LWLockAcquire(RelationMappingLock, LW_SHARED);
00471 LWLockRelease(RelationMappingLock);
00472 }
00473
00474
00475
00476
00477
00478
00479
00480
00481 void
00482 RelationMapFinishBootstrap(void)
00483 {
00484 Assert(IsBootstrapProcessingMode());
00485
00486
00487 Assert(active_shared_updates.num_mappings == 0);
00488 Assert(active_local_updates.num_mappings == 0);
00489 Assert(pending_shared_updates.num_mappings == 0);
00490 Assert(pending_local_updates.num_mappings == 0);
00491
00492
00493 write_relmap_file(true, &shared_map, false, false, false,
00494 InvalidOid, GLOBALTABLESPACE_OID, NULL);
00495 write_relmap_file(false, &local_map, false, false, false,
00496 MyDatabaseId, MyDatabaseTableSpace, DatabasePath);
00497 }
00498
00499
00500
00501
00502
00503
00504
00505 void
00506 RelationMapInitialize(void)
00507 {
00508
00509 shared_map.magic = 0;
00510 local_map.magic = 0;
00511 shared_map.num_mappings = 0;
00512 local_map.num_mappings = 0;
00513 active_shared_updates.num_mappings = 0;
00514 active_local_updates.num_mappings = 0;
00515 pending_shared_updates.num_mappings = 0;
00516 pending_local_updates.num_mappings = 0;
00517 }
00518
00519
00520
00521
00522
00523
00524
00525 void
00526 RelationMapInitializePhase2(void)
00527 {
00528
00529
00530
00531 if (IsBootstrapProcessingMode())
00532 return;
00533
00534
00535
00536
00537 load_relmap_file(true);
00538 }
00539
00540
00541
00542
00543
00544
00545
00546 void
00547 RelationMapInitializePhase3(void)
00548 {
00549
00550
00551
00552 if (IsBootstrapProcessingMode())
00553 return;
00554
00555
00556
00557
00558 load_relmap_file(false);
00559 }
00560
00561
00562
00563
00564
00565
00566
00567
00568
00569 static void
00570 load_relmap_file(bool shared)
00571 {
00572 RelMapFile *map;
00573 char mapfilename[MAXPGPATH];
00574 pg_crc32 crc;
00575 int fd;
00576
00577 if (shared)
00578 {
00579 snprintf(mapfilename, sizeof(mapfilename), "global/%s",
00580 RELMAPPER_FILENAME);
00581 map = &shared_map;
00582 }
00583 else
00584 {
00585 snprintf(mapfilename, sizeof(mapfilename), "%s/%s",
00586 DatabasePath, RELMAPPER_FILENAME);
00587 map = &local_map;
00588 }
00589
00590
00591 fd = OpenTransientFile(mapfilename,
00592 O_RDONLY | PG_BINARY, S_IRUSR | S_IWUSR);
00593 if (fd < 0)
00594 ereport(FATAL,
00595 (errcode_for_file_access(),
00596 errmsg("could not open relation mapping file \"%s\": %m",
00597 mapfilename)));
00598
00599
00600
00601
00602
00603
00604
00605
00606 if (read(fd, map, sizeof(RelMapFile)) != sizeof(RelMapFile))
00607 ereport(FATAL,
00608 (errcode_for_file_access(),
00609 errmsg("could not read relation mapping file \"%s\": %m",
00610 mapfilename)));
00611
00612 CloseTransientFile(fd);
00613
00614
00615 if (map->magic != RELMAPPER_FILEMAGIC ||
00616 map->num_mappings < 0 ||
00617 map->num_mappings > MAX_MAPPINGS)
00618 ereport(FATAL,
00619 (errmsg("relation mapping file \"%s\" contains invalid data",
00620 mapfilename)));
00621
00622
00623 INIT_CRC32(crc);
00624 COMP_CRC32(crc, (char *) map, offsetof(RelMapFile, crc));
00625 FIN_CRC32(crc);
00626
00627 if (!EQ_CRC32(crc, map->crc))
00628 ereport(FATAL,
00629 (errmsg("relation mapping file \"%s\" contains incorrect checksum",
00630 mapfilename)));
00631 }
00632
00633
00634
00635
00636
00637
00638
00639
00640
00641
00642
00643
00644
00645
00646
00647
00648
00649
00650
00651
00652
00653 static void
00654 write_relmap_file(bool shared, RelMapFile *newmap,
00655 bool write_wal, bool send_sinval, bool preserve_files,
00656 Oid dbid, Oid tsid, const char *dbpath)
00657 {
00658 int fd;
00659 RelMapFile *realmap;
00660 char mapfilename[MAXPGPATH];
00661
00662
00663
00664
00665 newmap->magic = RELMAPPER_FILEMAGIC;
00666 if (newmap->num_mappings < 0 || newmap->num_mappings > MAX_MAPPINGS)
00667 elog(ERROR, "attempt to write bogus relation mapping");
00668
00669 INIT_CRC32(newmap->crc);
00670 COMP_CRC32(newmap->crc, (char *) newmap, offsetof(RelMapFile, crc));
00671 FIN_CRC32(newmap->crc);
00672
00673
00674
00675
00676
00677 if (shared)
00678 {
00679 snprintf(mapfilename, sizeof(mapfilename), "global/%s",
00680 RELMAPPER_FILENAME);
00681 realmap = &shared_map;
00682 }
00683 else
00684 {
00685 snprintf(mapfilename, sizeof(mapfilename), "%s/%s",
00686 dbpath, RELMAPPER_FILENAME);
00687 realmap = &local_map;
00688 }
00689
00690 fd = OpenTransientFile(mapfilename,
00691 O_WRONLY | O_CREAT | PG_BINARY,
00692 S_IRUSR | S_IWUSR);
00693 if (fd < 0)
00694 ereport(ERROR,
00695 (errcode_for_file_access(),
00696 errmsg("could not open relation mapping file \"%s\": %m",
00697 mapfilename)));
00698
00699 if (write_wal)
00700 {
00701 xl_relmap_update xlrec;
00702 XLogRecData rdata[2];
00703 XLogRecPtr lsn;
00704
00705
00706 START_CRIT_SECTION();
00707
00708 xlrec.dbid = dbid;
00709 xlrec.tsid = tsid;
00710 xlrec.nbytes = sizeof(RelMapFile);
00711
00712 rdata[0].data = (char *) (&xlrec);
00713 rdata[0].len = MinSizeOfRelmapUpdate;
00714 rdata[0].buffer = InvalidBuffer;
00715 rdata[0].next = &(rdata[1]);
00716 rdata[1].data = (char *) newmap;
00717 rdata[1].len = sizeof(RelMapFile);
00718 rdata[1].buffer = InvalidBuffer;
00719 rdata[1].next = NULL;
00720
00721 lsn = XLogInsert(RM_RELMAP_ID, XLOG_RELMAP_UPDATE, rdata);
00722
00723
00724 XLogFlush(lsn);
00725 }
00726
00727 errno = 0;
00728 if (write(fd, newmap, sizeof(RelMapFile)) != sizeof(RelMapFile))
00729 {
00730
00731 if (errno == 0)
00732 errno = ENOSPC;
00733 ereport(ERROR,
00734 (errcode_for_file_access(),
00735 errmsg("could not write to relation mapping file \"%s\": %m",
00736 mapfilename)));
00737 }
00738
00739
00740
00741
00742
00743
00744
00745 if (pg_fsync(fd) != 0)
00746 ereport(ERROR,
00747 (errcode_for_file_access(),
00748 errmsg("could not fsync relation mapping file \"%s\": %m",
00749 mapfilename)));
00750
00751 if (CloseTransientFile(fd))
00752 ereport(ERROR,
00753 (errcode_for_file_access(),
00754 errmsg("could not close relation mapping file \"%s\": %m",
00755 mapfilename)));
00756
00757
00758
00759
00760
00761
00762
00763
00764
00765 if (send_sinval)
00766 CacheInvalidateRelmap(dbid);
00767
00768
00769
00770
00771
00772
00773
00774
00775
00776
00777
00778 if (preserve_files)
00779 {
00780 int32 i;
00781
00782 for (i = 0; i < newmap->num_mappings; i++)
00783 {
00784 RelFileNode rnode;
00785
00786 rnode.spcNode = tsid;
00787 rnode.dbNode = dbid;
00788 rnode.relNode = newmap->mappings[i].mapfilenode;
00789 RelationPreserveStorage(rnode, false);
00790 }
00791 }
00792
00793
00794 memcpy(realmap, newmap, sizeof(RelMapFile));
00795
00796
00797 if (write_wal)
00798 END_CRIT_SECTION();
00799 }
00800
00801
00802
00803
00804
00805
00806 static void
00807 perform_relmap_update(bool shared, const RelMapFile *updates)
00808 {
00809 RelMapFile newmap;
00810
00811
00812
00813
00814
00815
00816
00817
00818
00819
00820
00821
00822
00823
00824 LWLockAcquire(RelationMappingLock, LW_EXCLUSIVE);
00825
00826
00827 load_relmap_file(shared);
00828
00829
00830 if (shared)
00831 memcpy(&newmap, &shared_map, sizeof(RelMapFile));
00832 else
00833 memcpy(&newmap, &local_map, sizeof(RelMapFile));
00834
00835
00836
00837
00838
00839 merge_map_updates(&newmap, updates, allowSystemTableMods);
00840
00841
00842 write_relmap_file(shared, &newmap, true, true, true,
00843 (shared ? InvalidOid : MyDatabaseId),
00844 (shared ? GLOBALTABLESPACE_OID : MyDatabaseTableSpace),
00845 DatabasePath);
00846
00847
00848 LWLockRelease(RelationMappingLock);
00849 }
00850
00851
00852
00853
00854 void
00855 relmap_redo(XLogRecPtr lsn, XLogRecord *record)
00856 {
00857 uint8 info = record->xl_info & ~XLR_INFO_MASK;
00858
00859
00860 Assert(!(record->xl_info & XLR_BKP_BLOCK_MASK));
00861
00862 if (info == XLOG_RELMAP_UPDATE)
00863 {
00864 xl_relmap_update *xlrec = (xl_relmap_update *) XLogRecGetData(record);
00865 RelMapFile newmap;
00866 char *dbpath;
00867
00868 if (xlrec->nbytes != sizeof(RelMapFile))
00869 elog(PANIC, "relmap_redo: wrong size %u in relmap update record",
00870 xlrec->nbytes);
00871 memcpy(&newmap, xlrec->data, sizeof(newmap));
00872
00873
00874 dbpath = GetDatabasePath(xlrec->dbid, xlrec->tsid);
00875
00876
00877
00878
00879
00880
00881
00882
00883
00884
00885 write_relmap_file((xlrec->dbid == InvalidOid), &newmap,
00886 false, true, false,
00887 xlrec->dbid, xlrec->tsid, dbpath);
00888
00889 pfree(dbpath);
00890 }
00891 else
00892 elog(PANIC, "relmap_redo: unknown op code %u", info);
00893 }