]> granicus.if.org Git - postgresql/blobdiff - src/backend/utils/cache/relmapper.c
Fix initialization of fake LSN for unlogged relations
[postgresql] / src / backend / utils / cache / relmapper.c
index 2d31f9f912a30c27a96a88e73a52e9705121e69c..42b0c48c2bebaf8bd1fb7d06231f284d9e3dbad5 100644 (file)
@@ -28,7 +28,7 @@
  * all these files commit in a single map file update rather than being tied
  * to transaction commit.
  *
- * Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  *
@@ -91,6 +91,16 @@ typedef struct RelMapFile
        int32           pad;                    /* to make the struct size be 512 exactly */
 } RelMapFile;
 
+/*
+ * State for serializing local and shared relmappings for parallel workers
+ * (active states only).  See notes on active_* and pending_* updates state.
+ */
+typedef struct SerializedActiveRelMaps
+{
+       RelMapFile      active_shared_updates;
+       RelMapFile      active_local_updates;
+} SerializedActiveRelMaps;
+
 /*
  * The currently known contents of the shared map file and our database's
  * local map file are stored here.  These can be reloaded from disk
@@ -111,6 +121,9 @@ static RelMapFile local_map;
  * they will become active at the next CommandCounterIncrement.  This setup
  * lets map updates act similarly to updates of pg_class rows, ie, they
  * become visible only at the next CommandCounterIncrement boundary.
+ *
+ * Active shared and active local updates are serialized by the parallel
+ * infrastructure, and deserialized within parallel workers.
  */
 static RelMapFile active_shared_updates;
 static RelMapFile active_local_updates;
@@ -120,13 +133,13 @@ static RelMapFile pending_local_updates;
 
 /* non-export function prototypes */
 static void apply_map_update(RelMapFile *map, Oid relationId, Oid fileNode,
-                                bool add_okay);
+                                                        bool add_okay);
 static void merge_map_updates(RelMapFile *map, const RelMapFile *updates,
-                                 bool add_okay);
+                                                         bool add_okay);
 static void load_relmap_file(bool shared);
 static void write_relmap_file(bool shared, RelMapFile *newmap,
-                                 bool write_wal, bool send_sinval, bool preserve_files,
-                                 Oid dbid, Oid tsid, const char *dbpath);
+                                                         bool write_wal, bool send_sinval, bool preserve_files,
+                                                         Oid dbid, Oid tsid, const char *dbpath);
 static void perform_relmap_update(bool shared, const RelMapFile *updates);
 
 
@@ -263,13 +276,16 @@ RelationMapUpdateMap(Oid relationId, Oid fileNode, bool shared,
        else
        {
                /*
-                * We don't currently support map changes within subtransactions. This
-                * could be done with more bookkeeping infrastructure, but it doesn't
-                * presently seem worth it.
+                * We don't currently support map changes within subtransactions, or
+                * when in parallel mode.  This could be done with more bookkeeping
+                * infrastructure, but it doesn't presently seem worth it.
                 */
                if (GetCurrentTransactionNestLevel() > 1)
                        elog(ERROR, "cannot change relation mapping within subtransaction");
 
+               if (IsInParallelMode())
+                       elog(ERROR, "cannot change relation mapping in parallel mode");
+
                if (immediate)
                {
                        /* Make it active, but only locally */
@@ -452,11 +468,14 @@ AtCCI_RelationMap(void)
  *
  * During abort, we just have to throw away any pending map changes.
  * Normal post-abort cleanup will take care of fixing relcache entries.
+ * Parallel worker commit/abort is handled by resetting active mappings
+ * that may have been received from the leader process.  (There should be
+ * no pending updates in parallel workers.)
  */
 void
-AtEOXact_RelationMap(bool isCommit)
+AtEOXact_RelationMap(bool isCommit, bool isParallelWorker)
 {
-       if (isCommit)
+       if (isCommit && !isParallelWorker)
        {
                /*
                 * We should not get here with any "pending" updates.  (We could
@@ -482,7 +501,10 @@ AtEOXact_RelationMap(bool isCommit)
        }
        else
        {
-               /* Abort --- drop all local and pending updates */
+               /* Abort or parallel worker --- drop all local and pending updates */
+               Assert(!isParallelWorker || pending_shared_updates.num_mappings == 0);
+               Assert(!isParallelWorker || pending_local_updates.num_mappings == 0);
+
                active_shared_updates.num_mappings = 0;
                active_local_updates.num_mappings = 0;
                pending_shared_updates.num_mappings = 0;
@@ -614,6 +636,56 @@ RelationMapInitializePhase3(void)
        load_relmap_file(false);
 }
 
+/*
+ * EstimateRelationMapSpace
+ *
+ * Estimate space needed to pass active shared and local relmaps to parallel
+ * workers.
+ */
+Size
+EstimateRelationMapSpace(void)
+{
+       return sizeof(SerializedActiveRelMaps);
+}
+
+/*
+ * SerializeRelationMap
+ *
+ * Serialize active shared and local relmap state for parallel workers.
+ */
+void
+SerializeRelationMap(Size maxSize, char *startAddress)
+{
+       SerializedActiveRelMaps *relmaps;
+
+       Assert(maxSize >= EstimateRelationMapSpace());
+
+       relmaps = (SerializedActiveRelMaps *) startAddress;
+       relmaps->active_shared_updates = active_shared_updates;
+       relmaps->active_local_updates = active_local_updates;
+}
+
+/*
+ * RestoreRelationMap
+ *
+ * Restore active shared and local relmap state within a parallel worker.
+ */
+void
+RestoreRelationMap(char *startAddress)
+{
+       SerializedActiveRelMaps *relmaps;
+
+       if (active_shared_updates.num_mappings != 0 ||
+               active_local_updates.num_mappings != 0 ||
+               pending_shared_updates.num_mappings != 0 ||
+               pending_local_updates.num_mappings != 0)
+               elog(ERROR, "parallel worker has existing mappings");
+
+       relmaps = (SerializedActiveRelMaps *) startAddress;
+       active_shared_updates = relmaps->active_shared_updates;
+       active_local_updates = relmaps->active_local_updates;
+}
+
 /*
  * load_relmap_file -- load data from the shared or local map file
  *
@@ -669,12 +741,17 @@ load_relmap_file(bool shared)
                                         errmsg("could not read file \"%s\": %m", mapfilename)));
                else
                        ereport(FATAL,
-                                       (errmsg("could not read file \"%s\": read %d of %zu",
+                                       (errcode(ERRCODE_DATA_CORRUPTED),
+                                        errmsg("could not read file \"%s\": read %d of %zu",
                                                        mapfilename, r, sizeof(RelMapFile))));
        }
        pgstat_report_wait_end();
 
-       CloseTransientFile(fd);
+       if (CloseTransientFile(fd) != 0)
+               ereport(FATAL,
+                               (errcode_for_file_access(),
+                                errmsg("could not close file \"%s\": %m",
+                                               mapfilename)));
 
        /* check for correct magic number, etc */
        if (map->magic != RELMAPPER_FILEMAGIC ||
@@ -803,13 +880,13 @@ write_relmap_file(bool shared, RelMapFile *newmap,
         */
        pgstat_report_wait_start(WAIT_EVENT_RELATION_MAP_SYNC);
        if (pg_fsync(fd) != 0)
-               ereport(ERROR,
+               ereport(data_sync_elevel(ERROR),
                                (errcode_for_file_access(),
                                 errmsg("could not fsync file \"%s\": %m",
                                                mapfilename)));
        pgstat_report_wait_end();
 
-       if (CloseTransientFile(fd))
+       if (CloseTransientFile(fd) != 0)
                ereport(ERROR,
                                (errcode_for_file_access(),
                                 errmsg("could not close file \"%s\": %m",