From 5304db1a398bee08e540a6b638de4693a01e5dff Mon Sep 17 00:00:00 2001
From: Robert Haas <rhaas@postgresql.org>
Date: Wed, 20 Mar 2024 12:12:48 -0400
Subject: [PATCH v1 4/4] docs: Consolidate into new "WAL for Extensions"
 chapter.

Previously, we had consecutive, very short chapters called "Generic
WAL" and "Custom WAL Resource Managers," explaining different approaches
to the same problem. Merge them into a single chapter.
---
 doc/src/sgml/custom-rmgr.sgml        | 105 ----------
 doc/src/sgml/filelist.sgml           |   3 +-
 doc/src/sgml/generic-wal.sgml        | 174 ----------------
 doc/src/sgml/postgres.sgml           |   3 +-
 doc/src/sgml/wal-for-extensions.sgml | 283 +++++++++++++++++++++++++++
 5 files changed, 285 insertions(+), 283 deletions(-)
 delete mode 100644 doc/src/sgml/custom-rmgr.sgml
 delete mode 100644 doc/src/sgml/generic-wal.sgml
 create mode 100644 doc/src/sgml/wal-for-extensions.sgml

diff --git a/doc/src/sgml/custom-rmgr.sgml b/doc/src/sgml/custom-rmgr.sgml
deleted file mode 100644
index 0d98229295..0000000000
--- a/doc/src/sgml/custom-rmgr.sgml
+++ /dev/null
@@ -1,105 +0,0 @@
-<!-- doc/src/sgml/custom-rmgr.sgml -->
-
-<chapter id="custom-rmgr">
- <title>Custom WAL Resource Managers</title>
-
- <para>
-  This chapter explains the interface between the core
-  <productname>PostgreSQL</productname> system and custom WAL resource
-  managers, which enable extensions to integrate directly with the <link
-  linkend="wal"><acronym>WAL</acronym></link>.
- </para>
- <para>
-  An extension, especially a <link linkend="tableam">Table Access
-  Method</link> or <link linkend="indexam">Index Access Method</link>, may
-  need to use WAL for recovery, replication, and/or <link
-  linkend="logicaldecoding">Logical Decoding</link>. Custom resource managers
-  are a more flexible alternative to <link linkend="generic-wal">Generic
-  WAL</link> (which does not support logical decoding), but more complex for
-  an extension to implement.
- </para>
- <para>
-  To create a new custom WAL resource manager, first define an
-  <structname>RmgrData</structname> structure with implementations for the
-  resource manager methods. Refer to
-  <filename>src/backend/access/transam/README</filename> and
-  <filename>src/include/access/xlog_internal.h</filename> in the
-  <productname>PostgreSQL</productname> source.
-<programlisting>
-/*
- * Method table for resource managers.
- *
- * This struct must be kept in sync with the PG_RMGR definition in
- * rmgr.c.
- *
- * rm_identify must return a name for the record based on xl_info (without
- * reference to the rmid). For example, XLOG_BTREE_VACUUM would be named
- * "VACUUM". rm_desc can then be called to obtain additional detail for the
- * record, if available (e.g. the last block).
- *
- * rm_mask takes as input a page modified by the resource manager and masks
- * out bits that shouldn't be flagged by wal_consistency_checking.
- *
- * RmgrTable[] is indexed by RmgrId values (see rmgrlist.h). If rm_name is
- * NULL, the corresponding RmgrTable entry is considered invalid.
- */
-typedef struct RmgrData
-{
-    const char *rm_name;
-    void        (*rm_redo) (XLogReaderState *record);
-    void        (*rm_desc) (StringInfo buf, XLogReaderState *record);
-    const char *(*rm_identify) (uint8 info);
-    void        (*rm_startup) (void);
-    void        (*rm_cleanup) (void);
-    void        (*rm_mask) (char *pagedata, BlockNumber blkno);
-    void        (*rm_decode) (struct LogicalDecodingContext *ctx,
-                              struct XLogRecordBuffer *buf);
-} RmgrData;
-</programlisting>
- </para>
-
-  <para>
-   The <filename>src/test/modules/test_custom_rmgrs</filename> module
-   contains a working example, which demonstrates usage of custom WAL
-   resource managers.
-  </para>
-
- <para>
-  Then, register your new resource
-  manager.
-
-<programlisting>
-/*
- * Register a new custom WAL resource manager.
- *
- * Resource manager IDs must be globally unique across all extensions. Refer
- * to https://wiki.postgresql.org/wiki/CustomWALResourceManagers to reserve a
- * unique RmgrId for your extension, to avoid conflicts with other extension
- * developers. During development, use RM_EXPERIMENTAL_ID to avoid needlessly
- * reserving a new ID.
- */
-extern void RegisterCustomRmgr(RmgrId rmid, const RmgrData *rmgr);
-</programlisting>
-  <function>RegisterCustomRmgr</function> must be called from the
-  extension module's <link linkend="xfunc-c-dynload">_PG_init</link> function.
-  While developing a new extension, use <literal>RM_EXPERIMENTAL_ID</literal>
-  for <parameter>rmid</parameter>. When you are ready to release the extension
-  to users, reserve a new resource manager ID at the <ulink
-  url="https://wiki.postgresql.org/wiki/CustomWALResourceManagers">Custom WAL
-  Resource Manager</ulink> page.
- </para>
-
- <para>
-  Place the extension module implementing the custom resource manager in <xref
-  linkend="guc-shared-preload-libraries"/> so that it will be loaded early
-  during <productname>PostgreSQL</productname> startup.
- </para>
- <note>
-   <para>
-    The extension must remain in <varname>shared_preload_libraries</varname>
-    as long as any custom WAL records may exist in the system. Otherwise
-    <productname>PostgreSQL</productname> will not be able to apply or decode
-    the custom WAL records, which may prevent the server from starting.
-   </para>
- </note>
-</chapter>
diff --git a/doc/src/sgml/filelist.sgml b/doc/src/sgml/filelist.sgml
index de683e3400..6e5ff6fa69 100644
--- a/doc/src/sgml/filelist.sgml
+++ b/doc/src/sgml/filelist.sgml
@@ -100,8 +100,7 @@
 <!ENTITY storage    SYSTEM "storage.sgml">
 <!ENTITY transaction     SYSTEM "xact.sgml">
 <!ENTITY tablesample-method SYSTEM "tablesample-method.sgml">
-<!ENTITY generic-wal SYSTEM "generic-wal.sgml">
-<!ENTITY custom-rmgr SYSTEM "custom-rmgr.sgml">
+<!ENTITY wal-for-extensions SYSTEM "wal-for-extensions.sgml">
 <!ENTITY backup-manifest SYSTEM "backup-manifest.sgml">
 
 <!-- contrib information -->
diff --git a/doc/src/sgml/generic-wal.sgml b/doc/src/sgml/generic-wal.sgml
deleted file mode 100644
index a028856d2e..0000000000
--- a/doc/src/sgml/generic-wal.sgml
+++ /dev/null
@@ -1,174 +0,0 @@
-<!-- doc/src/sgml/generic-wal.sgml -->
-
-<chapter id="generic-wal">
- <title>Generic WAL Records</title>
-
-  <para>
-   Although all built-in WAL-logged modules have their own types of WAL
-   records, there is also a generic WAL record type, which describes changes
-   to pages in a generic way. This is useful for extensions that provide
-   custom access methods.
-  </para>
-
-  <para>
-   In comparison with <link linkend="custom-rmgr">Custom WAL Resource
-   Managers</link>, Generic WAL is simpler for an extension to implement and
-   does not require the extension library to be loaded in order to apply the
-   records.
-  </para>
-
-  <note>
-   <para>
-    Generic WAL records are ignored during <link
-    linkend="logicaldecoding">Logical Decoding</link>. If logical decoding is
-    required for your extension, consider a Custom WAL Resource Manager.
-   </para>
-  </note>
-
-  <para>
-   The API for constructing generic WAL records is defined in
-   <filename>access/generic_xlog.h</filename> and implemented
-   in <filename>access/transam/generic_xlog.c</filename>.
-  </para>
-
-  <para>
-   To perform a WAL-logged data update using the generic WAL record
-   facility, follow these steps:
-
-   <orderedlist>
-    <listitem>
-     <para>
-      <function>state = GenericXLogStart(relation)</function> &mdash; start
-      construction of a generic WAL record for the given relation.
-     </para>
-    </listitem>
-
-    <listitem>
-     <para>
-      <function>page = GenericXLogRegisterBuffer(state, buffer, flags)</function>
-      &mdash; register a buffer to be modified within the current generic WAL
-      record.  This function returns a pointer to a temporary copy of the
-      buffer's page, where modifications should be made.  (Do not modify the
-      buffer's contents directly.)  The third argument is a bit mask of flags
-      applicable to the operation.  Currently the only such flag is
-      <literal>GENERIC_XLOG_FULL_IMAGE</literal>, which indicates that a full-page
-      image rather than a delta update should be included in the WAL record.
-      Typically this flag would be set if the page is new or has been
-      rewritten completely.
-      <function>GenericXLogRegisterBuffer</function> can be repeated if the
-      WAL-logged action needs to modify multiple pages.
-     </para>
-    </listitem>
-
-    <listitem>
-     <para>
-      Apply modifications to the page images obtained in the previous step.
-     </para>
-    </listitem>
-
-    <listitem>
-     <para>
-      <function>GenericXLogFinish(state)</function> &mdash; apply the changes to
-      the buffers and emit the generic WAL record.
-     </para>
-    </listitem>
-   </orderedlist>
-  </para>
-
-  <para>
-   WAL record construction can be canceled between any of the above steps by
-   calling <function>GenericXLogAbort(state)</function>.  This will discard all
-   changes to the page image copies.
-  </para>
-
-  <para>
-   Please note the following points when using the generic WAL record
-   facility:
-
-   <itemizedlist>
-    <listitem>
-     <para>
-      No direct modifications of buffers are allowed!  All modifications must
-      be done in copies acquired from <function>GenericXLogRegisterBuffer()</function>.
-      In other words, code that makes generic WAL records should never call
-      <function>BufferGetPage()</function> for itself.  However, it remains the
-      caller's responsibility to pin/unpin and lock/unlock the buffers at
-      appropriate times.  Exclusive lock must be held on each target buffer
-      from before <function>GenericXLogRegisterBuffer()</function> until after
-      <function>GenericXLogFinish()</function>.
-     </para>
-    </listitem>
-
-    <listitem>
-     <para>
-      Registrations of buffers (step 2) and modifications of page images
-      (step 3) can be mixed freely, i.e., both steps may be repeated in any
-      sequence.  Keep in mind that buffers should be registered in the same
-      order in which locks are to be obtained on them during replay.
-     </para>
-    </listitem>
-
-    <listitem>
-     <para>
-      The maximum number of buffers that can be registered for a generic WAL
-      record is <literal>MAX_GENERIC_XLOG_PAGES</literal>.  An error will be thrown
-      if this limit is exceeded.
-     </para>
-    </listitem>
-
-    <listitem>
-     <para>
-      Generic WAL assumes that the pages to be modified have standard
-      layout, and in particular that there is no useful data between
-      <structfield>pd_lower</structfield> and <structfield>pd_upper</structfield>.
-     </para>
-    </listitem>
-
-    <listitem>
-     <para>
-      Since you are modifying copies of buffer
-      pages, <function>GenericXLogStart()</function> does not start a critical
-      section.  Thus, you can safely do memory allocation, error throwing,
-      etc. between <function>GenericXLogStart()</function> and
-      <function>GenericXLogFinish()</function>.  The only actual critical section is
-      present inside <function>GenericXLogFinish()</function>.  There is no need to
-      worry about calling  <function>GenericXLogAbort()</function> during an error
-      exit, either.
-     </para>
-    </listitem>
-
-    <listitem>
-     <para>
-      <function>GenericXLogFinish()</function> takes care of marking buffers dirty
-      and setting their LSNs.  You do not need to do this explicitly.
-     </para>
-    </listitem>
-
-    <listitem>
-     <para>
-      For unlogged relations, everything works the same except that no
-      actual WAL record is emitted.  Thus, you typically do not need to do
-      any explicit checks for unlogged relations.
-     </para>
-    </listitem>
-
-    <listitem>
-     <para>
-      The generic WAL redo function will acquire exclusive locks to buffers
-      in the same order as they were registered.  After redoing all changes,
-      the locks will be released in the same order.
-     </para>
-    </listitem>
-
-    <listitem>
-     <para>
-      If <literal>GENERIC_XLOG_FULL_IMAGE</literal> is not specified for a
-      registered buffer, the generic WAL record contains a delta between
-      the old and the new page images.  This delta is based on byte-by-byte
-      comparison.  This is not very compact for the case of moving data
-      within a page, and might be improved in the future.
-     </para>
-    </listitem>
-   </itemizedlist>
-  </para>
-</chapter>
diff --git a/doc/src/sgml/postgres.sgml b/doc/src/sgml/postgres.sgml
index 0235c0e352..5bc47a9e71 100644
--- a/doc/src/sgml/postgres.sgml
+++ b/doc/src/sgml/postgres.sgml
@@ -255,8 +255,7 @@ break is not needed in a wider output rendering.
   &geqo;
   &tableam;
   &indexam;
-  &generic-wal;
-  &custom-rmgr;
+  &wal-for-extensions;
   &indextypes;
   &storage;
   &transaction;
diff --git a/doc/src/sgml/wal-for-extensions.sgml b/doc/src/sgml/wal-for-extensions.sgml
new file mode 100644
index 0000000000..cc233358dd
--- /dev/null
+++ b/doc/src/sgml/wal-for-extensions.sgml
@@ -0,0 +1,283 @@
+<!-- doc/src/sgml/wal-for-extensions.sgml -->
+
+<chapter id="wal-for-extensions">
+ <title>Write Ahead Logging for Extensions</title>
+
+ <sect1 id="generic-wal">
+  <title>Generic WAL Records</title>
+
+   <para>
+    Although all built-in WAL-logged modules have their own types of WAL
+    records, there is also a generic WAL record type, which describes changes
+    to pages in a generic way. This is useful for extensions that provide
+    custom access methods.
+   </para>
+
+   <para>
+    In comparison with <link linkend="custom-rmgr">Custom WAL Resource
+    Managers</link>, Generic WAL is simpler for an extension to implement and
+    does not require the extension library to be loaded in order to apply the
+    records.
+   </para>
+
+   <note>
+    <para>
+     Generic WAL records are ignored during <link
+     linkend="logicaldecoding">Logical Decoding</link>. If logical decoding is
+     required for your extension, consider a Custom WAL Resource Manager.
+    </para>
+   </note>
+
+   <para>
+    The API for constructing generic WAL records is defined in
+    <filename>access/generic_xlog.h</filename> and implemented
+    in <filename>access/transam/generic_xlog.c</filename>.
+   </para>
+
+   <para>
+    To perform a WAL-logged data update using the generic WAL record
+    facility, follow these steps:
+
+    <orderedlist>
+     <listitem>
+      <para>
+       <function>state = GenericXLogStart(relation)</function> &mdash; start
+       construction of a generic WAL record for the given relation.
+      </para>
+     </listitem>
+
+     <listitem>
+      <para>
+       <function>page = GenericXLogRegisterBuffer(state, buffer, flags)</function>
+       &mdash; register a buffer to be modified within the current generic WAL
+       record.  This function returns a pointer to a temporary copy of the
+       buffer's page, where modifications should be made.  (Do not modify the
+       buffer's contents directly.)  The third argument is a bit mask of flags
+       applicable to the operation.  Currently the only such flag is
+       <literal>GENERIC_XLOG_FULL_IMAGE</literal>, which indicates that a full-page
+       image rather than a delta update should be included in the WAL record.
+       Typically this flag would be set if the page is new or has been
+       rewritten completely.
+       <function>GenericXLogRegisterBuffer</function> can be repeated if the
+       WAL-logged action needs to modify multiple pages.
+      </para>
+     </listitem>
+
+     <listitem>
+      <para>
+       Apply modifications to the page images obtained in the previous step.
+      </para>
+     </listitem>
+
+     <listitem>
+      <para>
+       <function>GenericXLogFinish(state)</function> &mdash; apply the changes to
+       the buffers and emit the generic WAL record.
+      </para>
+     </listitem>
+    </orderedlist>
+   </para>
+
+   <para>
+    WAL record construction can be canceled between any of the above steps by
+    calling <function>GenericXLogAbort(state)</function>.  This will discard all
+    changes to the page image copies.
+   </para>
+
+   <para>
+    Please note the following points when using the generic WAL record
+    facility:
+
+    <itemizedlist>
+     <listitem>
+      <para>
+       No direct modifications of buffers are allowed!  All modifications must
+       be done in copies acquired from <function>GenericXLogRegisterBuffer()</function>.
+       In other words, code that makes generic WAL records should never call
+       <function>BufferGetPage()</function> for itself.  However, it remains the
+       caller's responsibility to pin/unpin and lock/unlock the buffers at
+       appropriate times.  Exclusive lock must be held on each target buffer
+       from before <function>GenericXLogRegisterBuffer()</function> until after
+       <function>GenericXLogFinish()</function>.
+      </para>
+     </listitem>
+
+     <listitem>
+      <para>
+       Registrations of buffers (step 2) and modifications of page images
+       (step 3) can be mixed freely, i.e., both steps may be repeated in any
+       sequence.  Keep in mind that buffers should be registered in the same
+       order in which locks are to be obtained on them during replay.
+      </para>
+     </listitem>
+
+     <listitem>
+      <para>
+       The maximum number of buffers that can be registered for a generic WAL
+       record is <literal>MAX_GENERIC_XLOG_PAGES</literal>.  An error will be thrown
+       if this limit is exceeded.
+      </para>
+     </listitem>
+
+     <listitem>
+      <para>
+       Generic WAL assumes that the pages to be modified have standard
+       layout, and in particular that there is no useful data between
+       <structfield>pd_lower</structfield> and <structfield>pd_upper</structfield>.
+      </para>
+     </listitem>
+
+     <listitem>
+      <para>
+       Since you are modifying copies of buffer
+       pages, <function>GenericXLogStart()</function> does not start a critical
+       section.  Thus, you can safely do memory allocation, error throwing,
+       etc. between <function>GenericXLogStart()</function> and
+       <function>GenericXLogFinish()</function>.  The only actual critical section is
+       present inside <function>GenericXLogFinish()</function>.  There is no need to
+       worry about calling  <function>GenericXLogAbort()</function> during an error
+       exit, either.
+      </para>
+     </listitem>
+
+     <listitem>
+      <para>
+       <function>GenericXLogFinish()</function> takes care of marking buffers dirty
+       and setting their LSNs.  You do not need to do this explicitly.
+      </para>
+     </listitem>
+
+     <listitem>
+      <para>
+       For unlogged relations, everything works the same except that no
+       actual WAL record is emitted.  Thus, you typically do not need to do
+       any explicit checks for unlogged relations.
+      </para>
+     </listitem>
+
+     <listitem>
+      <para>
+       The generic WAL redo function will acquire exclusive locks to buffers
+       in the same order as they were registered.  After redoing all changes,
+       the locks will be released in the same order.
+      </para>
+     </listitem>
+
+     <listitem>
+      <para>
+       If <literal>GENERIC_XLOG_FULL_IMAGE</literal> is not specified for a
+       registered buffer, the generic WAL record contains a delta between
+       the old and the new page images.  This delta is based on byte-by-byte
+       comparison.  This is not very compact for the case of moving data
+       within a page, and might be improved in the future.
+      </para>
+     </listitem>
+    </itemizedlist>
+   </para>
+ </sect1>
+
+ <sect1 id="custom-rmgr">
+  <title>Custom WAL Resource Managers</title>
+
+  <para>
+   This section explains the interface between the core
+   <productname>PostgreSQL</productname> system and custom WAL resource
+   managers, which enable extensions to integrate directly with the <link
+   linkend="wal"><acronym>WAL</acronym></link>.
+  </para>
+  <para>
+   An extension, especially a <link linkend="tableam">Table Access
+   Method</link> or <link linkend="indexam">Index Access Method</link>, may
+   need to use WAL for recovery, replication, and/or <link
+   linkend="logicaldecoding">Logical Decoding</link>. Custom resource managers
+   are a more flexible alternative to <link linkend="generic-wal">Generic
+   WAL</link> (which does not support logical decoding), but more complex for
+   an extension to implement.
+  </para>
+  <para>
+   To create a new custom WAL resource manager, first define an
+   <structname>RmgrData</structname> structure with implementations for the
+   resource manager methods. Refer to
+   <filename>src/backend/access/transam/README</filename> and
+   <filename>src/include/access/xlog_internal.h</filename> in the
+   <productname>PostgreSQL</productname> source.
+<programlisting>
+/*
+ * Method table for resource managers.
+ *
+ * This struct must be kept in sync with the PG_RMGR definition in
+ * rmgr.c.
+ *
+ * rm_identify must return a name for the record based on xl_info (without
+ * reference to the rmid). For example, XLOG_BTREE_VACUUM would be named
+ * "VACUUM". rm_desc can then be called to obtain additional detail for the
+ * record, if available (e.g. the last block).
+ *
+ * rm_mask takes as input a page modified by the resource manager and masks
+ * out bits that shouldn't be flagged by wal_consistency_checking.
+ *
+ * RmgrTable[] is indexed by RmgrId values (see rmgrlist.h). If rm_name is
+ * NULL, the corresponding RmgrTable entry is considered invalid.
+ */
+typedef struct RmgrData
+{
+    const char *rm_name;
+    void        (*rm_redo) (XLogReaderState *record);
+    void        (*rm_desc) (StringInfo buf, XLogReaderState *record);
+    const char *(*rm_identify) (uint8 info);
+    void        (*rm_startup) (void);
+    void        (*rm_cleanup) (void);
+    void        (*rm_mask) (char *pagedata, BlockNumber blkno);
+    void        (*rm_decode) (struct LogicalDecodingContext *ctx,
+                              struct XLogRecordBuffer *buf);
+} RmgrData;
+</programlisting>
+  </para>
+
+   <para>
+    The <filename>src/test/modules/test_custom_rmgrs</filename> module
+    contains a working example, which demonstrates usage of custom WAL
+    resource managers.
+   </para>
+
+  <para>
+   Then, register your new resource
+   manager.
+
+<programlisting>
+/*
+ * Register a new custom WAL resource manager.
+ *
+ * Resource manager IDs must be globally unique across all extensions. Refer
+ * to https://wiki.postgresql.org/wiki/CustomWALResourceManagers to reserve a
+ * unique RmgrId for your extension, to avoid conflicts with other extension
+ * developers. During development, use RM_EXPERIMENTAL_ID to avoid needlessly
+ * reserving a new ID.
+ */
+extern void RegisterCustomRmgr(RmgrId rmid, const RmgrData *rmgr);
+</programlisting>
+   <function>RegisterCustomRmgr</function> must be called from the
+   extension module's <link linkend="xfunc-c-dynload">_PG_init</link> function.
+   While developing a new extension, use <literal>RM_EXPERIMENTAL_ID</literal>
+   for <parameter>rmid</parameter>. When you are ready to release the extension
+   to users, reserve a new resource manager ID at the <ulink
+   url="https://wiki.postgresql.org/wiki/CustomWALResourceManagers">Custom WAL
+   Resource Manager</ulink> page.
+  </para>
+
+  <para>
+   Place the extension module implementing the custom resource manager in <xref
+   linkend="guc-shared-preload-libraries"/> so that it will be loaded early
+   during <productname>PostgreSQL</productname> startup.
+  </para>
+  <note>
+    <para>
+     The extension must remain in <varname>shared_preload_libraries</varname>
+     as long as any custom WAL records may exist in the system. Otherwise
+     <productname>PostgreSQL</productname> will not be able to apply or decode
+     the custom WAL records, which may prevent the server from starting.
+    </para>
+  </note>
+ </sect1>
+
+</chapter>
-- 
2.39.3 (Apple Git-145)

