Skip to content

Commit 39f0c4b

Browse files
committed
Refactor code for reading and writing relation map files.
Restructure things so that the functions which update the global variables shared_map and local_map are separate from the functions which just read and write relation map files without touching any global variables. In the new structure of things, write_relmap_file() writes a relmap file but no longer performs global variable updates. A symmetric function read_relmap_file() that just reads a file without changing any global variables is added, and load_relmap_file(), which does change the global variables, uses it as a subroutine. Because write_relmap_file() no longer updates shared_map and local_map, that logic is moved to perform_relmap_update(). However, no similar logic is added to relmap_redo() even though it also calls write_relmap_file(). That's because recovery must not rely on the contents of the relation map, and therefore there is no need to initialize it. In fact, doing so seems like a mistake, because we might then manage to rely on the in-memory map where we shouldn't. Patch by me, based on earlier work by Dilip Kumar. Reviewed by Ashutosh Sharma. Discussion: http://postgr.es/m/CA+TgmobQLgrt4AXsc0ru7aFFkzv=9fS-Q_yO69=k9WY67RCctg@mail.gmail.com
1 parent 5a07966 commit 39f0c4b

File tree

1 file changed

+60
-61
lines changed

1 file changed

+60
-61
lines changed

src/backend/utils/cache/relmapper.c

+60-61
Original file line numberDiff line numberDiff line change
@@ -137,8 +137,10 @@ static void apply_map_update(RelMapFile *map, Oid relationId, Oid fileNode,
137137
static void merge_map_updates(RelMapFile *map, const RelMapFile *updates,
138138
bool add_okay);
139139
static void load_relmap_file(bool shared, bool lock_held);
140-
static void write_relmap_file(bool shared, RelMapFile *newmap,
141-
bool write_wal, bool send_sinval, bool preserve_files,
140+
static void read_relmap_file(RelMapFile *map, char *dbpath, bool lock_held,
141+
int elevel);
142+
static void write_relmap_file(RelMapFile *newmap, bool write_wal,
143+
bool send_sinval, bool preserve_files,
142144
Oid dbid, Oid tsid, const char *dbpath);
143145
static void perform_relmap_update(bool shared, const RelMapFile *updates);
144146

@@ -568,9 +570,9 @@ RelationMapFinishBootstrap(void)
568570
Assert(pending_local_updates.num_mappings == 0);
569571

570572
/* Write the files; no WAL or sinval needed */
571-
write_relmap_file(true, &shared_map, false, false, false,
572-
InvalidOid, GLOBALTABLESPACE_OID, NULL);
573-
write_relmap_file(false, &local_map, false, false, false,
573+
write_relmap_file(&shared_map, false, false, false,
574+
InvalidOid, GLOBALTABLESPACE_OID, "global");
575+
write_relmap_file(&local_map, false, false, false,
574576
MyDatabaseId, MyDatabaseTableSpace, DatabasePath);
575577
}
576578

@@ -687,39 +689,48 @@ RestoreRelationMap(char *startAddress)
687689
}
688690

689691
/*
690-
* load_relmap_file -- load data from the shared or local map file
692+
* load_relmap_file -- load the shared or local map file
691693
*
692-
* Because the map file is essential for access to core system catalogs,
693-
* failure to read it is a fatal error.
694+
* Because these files are essential for access to core system catalogs,
695+
* failure to load either of them is a fatal error.
694696
*
695697
* Note that the local case requires DatabasePath to be set up.
696698
*/
697699
static void
698700
load_relmap_file(bool shared, bool lock_held)
699701
{
700-
RelMapFile *map;
702+
if (shared)
703+
read_relmap_file(&shared_map, "global", lock_held, FATAL);
704+
else
705+
read_relmap_file(&local_map, DatabasePath, lock_held, FATAL);
706+
}
707+
708+
/*
709+
* read_relmap_file -- load data from any relation mapper file
710+
*
711+
* dbpath must be the relevant database path, or "global" for shared relations.
712+
*
713+
* RelationMappingLock will be acquired released unless lock_held = true.
714+
*
715+
* Errors will be reported at the indicated elevel, which should be at least
716+
* ERROR.
717+
*/
718+
static void
719+
read_relmap_file(RelMapFile *map, char *dbpath, bool lock_held, int elevel)
720+
{
701721
char mapfilename[MAXPGPATH];
702722
pg_crc32c crc;
703723
int fd;
704724
int r;
705725

706-
if (shared)
707-
{
708-
snprintf(mapfilename, sizeof(mapfilename), "global/%s",
709-
RELMAPPER_FILENAME);
710-
map = &shared_map;
711-
}
712-
else
713-
{
714-
snprintf(mapfilename, sizeof(mapfilename), "%s/%s",
715-
DatabasePath, RELMAPPER_FILENAME);
716-
map = &local_map;
717-
}
726+
Assert(elevel >= ERROR);
718727

719-
/* Read data ... */
728+
/* Open the target file. */
729+
snprintf(mapfilename, sizeof(mapfilename), "%s/%s", dbpath,
730+
RELMAPPER_FILENAME);
720731
fd = OpenTransientFile(mapfilename, O_RDONLY | PG_BINARY);
721732
if (fd < 0)
722-
ereport(FATAL,
733+
ereport(elevel,
723734
(errcode_for_file_access(),
724735
errmsg("could not open file \"%s\": %m",
725736
mapfilename)));
@@ -734,16 +745,17 @@ load_relmap_file(bool shared, bool lock_held)
734745
if (!lock_held)
735746
LWLockAcquire(RelationMappingLock, LW_SHARED);
736747

748+
/* Now read the data. */
737749
pgstat_report_wait_start(WAIT_EVENT_RELATION_MAP_READ);
738750
r = read(fd, map, sizeof(RelMapFile));
739751
if (r != sizeof(RelMapFile))
740752
{
741753
if (r < 0)
742-
ereport(FATAL,
754+
ereport(elevel,
743755
(errcode_for_file_access(),
744756
errmsg("could not read file \"%s\": %m", mapfilename)));
745757
else
746-
ereport(FATAL,
758+
ereport(elevel,
747759
(errcode(ERRCODE_DATA_CORRUPTED),
748760
errmsg("could not read file \"%s\": read %d of %zu",
749761
mapfilename, r, sizeof(RelMapFile))));
@@ -754,7 +766,7 @@ load_relmap_file(bool shared, bool lock_held)
754766
LWLockRelease(RelationMappingLock);
755767

756768
if (CloseTransientFile(fd) != 0)
757-
ereport(FATAL,
769+
ereport(elevel,
758770
(errcode_for_file_access(),
759771
errmsg("could not close file \"%s\": %m",
760772
mapfilename)));
@@ -763,7 +775,7 @@ load_relmap_file(bool shared, bool lock_held)
763775
if (map->magic != RELMAPPER_FILEMAGIC ||
764776
map->num_mappings < 0 ||
765777
map->num_mappings > MAX_MAPPINGS)
766-
ereport(FATAL,
778+
ereport(elevel,
767779
(errmsg("relation mapping file \"%s\" contains invalid data",
768780
mapfilename)));
769781

@@ -773,7 +785,7 @@ load_relmap_file(bool shared, bool lock_held)
773785
FIN_CRC32C(crc);
774786

775787
if (!EQ_CRC32C(crc, map->crc))
776-
ereport(FATAL,
788+
ereport(elevel,
777789
(errmsg("relation mapping file \"%s\" contains incorrect checksum",
778790
mapfilename)));
779791
}
@@ -795,16 +807,16 @@ load_relmap_file(bool shared, bool lock_held)
795807
*
796808
* Because this may be called during WAL replay when MyDatabaseId,
797809
* DatabasePath, etc aren't valid, we require the caller to pass in suitable
798-
* values. The caller is also responsible for being sure no concurrent
799-
* map update could be happening.
810+
* values. Pass dbpath as "global" for the shared map.
811+
*
812+
* The caller is also responsible for being sure no concurrent map update
813+
* could be happening.
800814
*/
801815
static void
802-
write_relmap_file(bool shared, RelMapFile *newmap,
803-
bool write_wal, bool send_sinval, bool preserve_files,
804-
Oid dbid, Oid tsid, const char *dbpath)
816+
write_relmap_file(RelMapFile *newmap, bool write_wal, bool send_sinval,
817+
bool preserve_files, Oid dbid, Oid tsid, const char *dbpath)
805818
{
806819
int fd;
807-
RelMapFile *realmap;
808820
char mapfilename[MAXPGPATH];
809821

810822
/*
@@ -822,19 +834,8 @@ write_relmap_file(bool shared, RelMapFile *newmap,
822834
* Open the target file. We prefer to do this before entering the
823835
* critical section, so that an open() failure need not force PANIC.
824836
*/
825-
if (shared)
826-
{
827-
snprintf(mapfilename, sizeof(mapfilename), "global/%s",
828-
RELMAPPER_FILENAME);
829-
realmap = &shared_map;
830-
}
831-
else
832-
{
833-
snprintf(mapfilename, sizeof(mapfilename), "%s/%s",
834-
dbpath, RELMAPPER_FILENAME);
835-
realmap = &local_map;
836-
}
837-
837+
snprintf(mapfilename, sizeof(mapfilename), "%s/%s",
838+
dbpath, RELMAPPER_FILENAME);
838839
fd = OpenTransientFile(mapfilename, O_WRONLY | O_CREAT | PG_BINARY);
839840
if (fd < 0)
840841
ereport(ERROR,
@@ -934,16 +935,6 @@ write_relmap_file(bool shared, RelMapFile *newmap,
934935
}
935936
}
936937

937-
/*
938-
* Success, update permanent copy. During bootstrap, we might be working
939-
* on the permanent copy itself, in which case skip the memcpy() to avoid
940-
* invoking nominally-undefined behavior.
941-
*/
942-
if (realmap != newmap)
943-
memcpy(realmap, newmap, sizeof(RelMapFile));
944-
else
945-
Assert(!send_sinval); /* must be bootstrapping */
946-
947938
/* Critical section done */
948939
if (write_wal)
949940
END_CRIT_SECTION();
@@ -990,10 +981,19 @@ perform_relmap_update(bool shared, const RelMapFile *updates)
990981
merge_map_updates(&newmap, updates, allowSystemTableMods);
991982

992983
/* Write out the updated map and do other necessary tasks */
993-
write_relmap_file(shared, &newmap, true, true, true,
984+
write_relmap_file(&newmap, true, true, true,
994985
(shared ? InvalidOid : MyDatabaseId),
995986
(shared ? GLOBALTABLESPACE_OID : MyDatabaseTableSpace),
996-
DatabasePath);
987+
(shared ? "global" : DatabasePath));
988+
989+
/*
990+
* We succesfully wrote the updated file, so it's now safe to rely on the
991+
* new values in this process, too.
992+
*/
993+
if (shared)
994+
memcpy(&shared_map, &newmap, sizeof(RelMapFile));
995+
else
996+
memcpy(&local_map, &newmap, sizeof(RelMapFile));
997997

998998
/* Now we can release the lock */
999999
LWLockRelease(RelationMappingLock);
@@ -1033,8 +1033,7 @@ relmap_redo(XLogReaderState *record)
10331033
* but grab the lock to interlock against load_relmap_file().
10341034
*/
10351035
LWLockAcquire(RelationMappingLock, LW_EXCLUSIVE);
1036-
write_relmap_file((xlrec->dbid == InvalidOid), &newmap,
1037-
false, true, false,
1036+
write_relmap_file(&newmap, false, true, false,
10381037
xlrec->dbid, xlrec->tsid, dbpath);
10391038
LWLockRelease(RelationMappingLock);
10401039

0 commit comments

Comments
 (0)