From 50761c0caf60b17be99c4ba063369d74e75c77fa Mon Sep 17 00:00:00 2001 From: Dilip Kumar Date: Wed, 1 Sep 2021 14:16:35 +0530 Subject: [PATCH v2 2/3] Extend relmap interfaces Support new interfaces in relmapper, 1) Support copying the relmap file from one database path to the other database path. 2) Like RelationMapOidToFilenode, provide another interface which do the same but instead of getting it for the database we are connected to it will get it for the input database path. These interfaces are required for next patch for supporting the wal logged created database. --- src/backend/utils/cache/relmapper.c | 131 +++++++++++++++++++++++++++++++----- src/include/utils/relmapper.h | 6 +- 2 files changed, 119 insertions(+), 18 deletions(-) diff --git a/src/backend/utils/cache/relmapper.c b/src/backend/utils/cache/relmapper.c index ae62910..182054e 100644 --- a/src/backend/utils/cache/relmapper.c +++ b/src/backend/utils/cache/relmapper.c @@ -141,7 +141,7 @@ static void read_relmap_file(char *mapfilename, RelMapFile *map, static void write_relmap_file_internal(char *mapfilename, RelMapFile *newmap, bool write_wal, bool send_sinval, bool preserve_files, Oid dbid, Oid tsid, - const char *dbpath); + const char *dbpath, bool create); static void load_relmap_file(bool shared, bool lock_held); static void write_relmap_file(bool shared, RelMapFile *newmap, bool write_wal, bool send_sinval, bool preserve_files, @@ -256,6 +256,40 @@ RelationMapFilenodeToOid(Oid filenode, bool shared) } /* + * RelationMapOidToFilenodeForDatabase + * + * Find relfilenode for the given relation id in the dbpath. Returns + * InvalidOid if the relationId is not found in the relmap. + * + * This function is only called during CREATE DATABASE command, so we can pass + * lock_held as true while reading the relmap file since we are already holding + * the exclusive lock on the database. + */ +Oid +RelationMapOidToFilenodeForDatabase(char *dbpath, Oid relationId) +{ + RelMapFile map; + int i; + char mapfilename[MAXPGPATH]; + + /* Relmap file path for the given dbpath. */ + snprintf(mapfilename, sizeof(mapfilename), "%s/%s", + dbpath, RELMAPPER_FILENAME); + + /* Read the relmap file from the source database. */ + read_relmap_file(mapfilename, &map, true); + + /* Iterate over the relmap entries to find the input relation oid. */ + for (i = 0; i < map.num_mappings; i++) + { + if (relationId == map.mappings[i].mapoid) + return map.mappings[i].mapfilenode; + } + + return InvalidOid; +} + +/* * RelationMapUpdateMap * * Install a new relfilenode mapping for the specified relation. @@ -693,10 +727,47 @@ RestoreRelationMap(char *startAddress) } /* - * load_relmap_file -- load data from the shared or local map file + * CopyRelationMap * - * Because the map file is essential for access to core system catalogs, - * failure to read it is a fatal error. + * Copy relmapfile from source db path to the destination db path and WAL log + * the operation. This function is only called during the create database so + * the caller must hold the exclusive lock on the source database. Destination + * database is not yet created so we don't have any issue. + */ +void +CopyRelationMap(Oid dbid, Oid tsid, char *srcdbpath, char *dstdbpath) +{ + RelMapFile map; + char mapfilename[MAXPGPATH]; + + /* Relmap file path of the source database. */ + snprintf(mapfilename, sizeof(mapfilename), "%s/%s", + srcdbpath, RELMAPPER_FILENAME); + + /* + * Read the relmap file from the source database. We are not connected to + * the database so we can not take the relmap lock, but we are already + * holding exclusive lock on the database so pass lock_held as true. + */ + read_relmap_file(mapfilename, &map, true); + + /* Relmap file path of the destination database. */ + snprintf(mapfilename, sizeof(mapfilename), "%s/%s", + dstdbpath, RELMAPPER_FILENAME); + + /* + * Write map contents into the destination database's relmap file. + * write_relmap_file_internal, expects that the CRC should have been + * computed and stored in the input map. But, since we have read this map + * from the source database and directly writing to the destination file + * without updating it so we don't need to recompute it. + */ + write_relmap_file_internal(mapfilename, &map, true, false, true, dbid, + tsid, dstdbpath, true); +} + +/* + * read_relmap_file - read the relmap file data. * * lock_held, pass true if caller already have the relation mapping or higher * level lock. @@ -802,15 +873,18 @@ load_relmap_file(bool shared, bool lock_held) } /* - * Helper function for write_relmap_file, Read comments atop write_relmap_file - * for more details. The CRC should be computed by the caller and stored in - * the newmap. + * Helper function for write_relmap_file and CopyRelationMap, Read comments + * atop write_relmap_file for more details. The CRC should be computed by the + * caller and stored in the newmap. + * + * Pass the create = true, if we are copying the relmap file during CREATE + * DATABASE command. */ static void write_relmap_file_internal(char *mapfilename, RelMapFile *newmap, bool write_wal, bool send_sinval, bool preserve_files, Oid dbid, Oid tsid, - const char *dbpath) + const char *dbpath, bool create) { int fd; @@ -836,6 +910,7 @@ write_relmap_file_internal(char *mapfilename, RelMapFile *newmap, xlrec.dbid = dbid; xlrec.tsid = tsid; xlrec.nbytes = sizeof(RelMapFile); + xlrec.create = create; XLogBeginInsert(); XLogRegisterData((char *) (&xlrec), MinSizeOfRelmapUpdate); @@ -977,7 +1052,7 @@ write_relmap_file(bool shared, RelMapFile *newmap, /* Write the map to the relmap file. */ write_relmap_file_internal(mapfilename, newmap, write_wal, send_sinval, preserve_files, dbid, tsid, - dbpath); + dbpath, false); /* * Success, update permanent copy. During bootstrap, we might be working @@ -1069,15 +1144,37 @@ relmap_redo(XLogReaderState *record) * Write out the new map and send sinval, but of course don't write a * new WAL entry. There's no surrounding transaction to tell to * preserve files, either. - * - * There shouldn't be anyone else updating relmaps during WAL replay, - * but grab the lock to interlock against load_relmap_file(). */ - LWLockAcquire(RelationMappingLock, LW_EXCLUSIVE); - write_relmap_file((xlrec->dbid == InvalidOid), &newmap, - false, true, false, - xlrec->dbid, xlrec->tsid, dbpath); - LWLockRelease(RelationMappingLock); + if (!xlrec->create) + { + /* + * There shouldn't be anyone else updating relmaps during WAL + * replay, but grab the lock to interlock against + * load_relmap_file(). + */ + LWLockAcquire(RelationMappingLock, LW_EXCLUSIVE); + write_relmap_file((xlrec->dbid == InvalidOid), &newmap, + false, true, false, + xlrec->dbid, xlrec->tsid, dbpath); + LWLockRelease(RelationMappingLock); + } + else + { + char mapfilename[MAXPGPATH]; + + /* Construct the mapfilename. */ + snprintf(mapfilename, sizeof(mapfilename), "%s/%s", + dbpath, RELMAPPER_FILENAME); + + /* + * We don't need to take relmap lock because this wal is logged + * while creating a new database, so there could be no one else + * reading/writing the relmap file. + */ + write_relmap_file_internal(mapfilename, &newmap, false, false, + false, xlrec->dbid, xlrec->tsid, dbpath, + true); + } pfree(dbpath); } diff --git a/src/include/utils/relmapper.h b/src/include/utils/relmapper.h index c0d14da..4165f09 100644 --- a/src/include/utils/relmapper.h +++ b/src/include/utils/relmapper.h @@ -29,6 +29,7 @@ typedef struct xl_relmap_update Oid dbid; /* database ID, or 0 for shared map */ Oid tsid; /* database's tablespace, or pg_global */ int32 nbytes; /* size of relmap data */ + bool create; /* true if creating new relmap */ char data[FLEXIBLE_ARRAY_MEMBER]; } xl_relmap_update; @@ -39,6 +40,8 @@ extern Oid RelationMapOidToFilenode(Oid relationId, bool shared); extern Oid RelationMapFilenodeToOid(Oid relationId, bool shared); +extern Oid RelationMapOidToFilenodeForDatabase(char *dbpath, Oid relationId); + extern void RelationMapUpdateMap(Oid relationId, Oid fileNode, bool shared, bool immediate); @@ -62,7 +65,8 @@ extern void RelationMapInitializePhase3(void); extern Size EstimateRelationMapSpace(void); extern void SerializeRelationMap(Size maxSize, char *startAddress); extern void RestoreRelationMap(char *startAddress); - +extern void CopyRelationMap(Oid dbid, Oid tsid, char *srcdbpath, + char *dstdbpath); extern void relmap_redo(XLogReaderState *record); extern void relmap_desc(StringInfo buf, XLogReaderState *record); extern const char *relmap_identify(uint8 info); -- 1.8.3.1