Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions doc/src/sgml/config.sgml
Original file line number Diff line number Diff line change
Expand Up @@ -10881,8 +10881,9 @@ LOG: CleanUpLock: deleting: lock(0xb7acd844) id(24688,24696,0,0,0,1)
the supported resource managers are <literal>heap</literal>,
<literal>heap2</literal>, <literal>btree</literal>, <literal>hash</literal>,
<literal>gin</literal>, <literal>gist</literal>, <literal>sequence</literal>,
<literal>spgist</literal>, <literal>brin</literal>, and <literal>generic</literal>. Only
superusers can change this setting.
<literal>spgist</literal>, <literal>brin</literal>, and <literal>generic</literal>.
Extensions may define additional resource managers. Only superusers and users with
the appropriate <literal>SET</literal> privilege can change this setting.
</para>
</listitem>
</varlistentry>
Expand Down
98 changes: 98 additions & 0 deletions doc/src/sgml/custom-rmgr.sgml
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
<!-- 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 resouce 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
Comment thread
my-ship-it marked this conversation as resolved.
<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);
Comment thread
my-ship-it marked this conversation as resolved.
void (*rm_cleanup) (void);
void (*rm_mask) (char *pagedata, BlockNumber blkno);
void (*rm_decode) (struct LogicalDecodingContext *ctx,
struct XLogRecordBuffer *buf);
} RmgrData;
</programlisting>
</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/CustomWALResourceManager 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, 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 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 shared_preload_libraries 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>
1 change: 1 addition & 0 deletions doc/src/sgml/filelist.sgml
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@
<!ENTITY storage SYSTEM "storage.sgml">
<!ENTITY tablesample-method SYSTEM "tablesample-method.sgml">
<!ENTITY generic-wal SYSTEM "generic-wal.sgml">
<!ENTITY custom-rmgr SYSTEM "custom-rmgr.sgml">
<!ENTITY backup-manifest SYSTEM "backup-manifest.sgml">

<!-- contrib information -->
Expand Down
19 changes: 19 additions & 0 deletions doc/src/sgml/func.sgml
Original file line number Diff line number Diff line change
Expand Up @@ -25559,6 +25559,25 @@ postgres=# SELECT * FROM pg_walfile_name_offset(pg_stop_backup());
without recovery, the function returns <literal>NULL</literal>.
</para></entry>
</row>

<row>
<entry role="func_table_entry"><para role="func_signature">
<indexterm>
<primary>pg_get_wal_resource_managers</primary>
</indexterm>
<function>pg_get_wal_resource_managers</function> ()
<returnvalue>setof record</returnvalue>
( <parameter>rm_id</parameter> <type>integer</type>,
<parameter>rm_name</parameter> <type>text</type>,
<parameter>rm_builtin</parameter> <type>boolean</type> )
</para>
<para>
Returns the currently-loaded WAL resource managers in the system. The
column <parameter>rm_builtin</parameter> indicates whether it's a
built-in resource manager, or a custom resource manager loaded by an
extension.
</para></entry>
</row>
</tbody>
</tgroup>
</table>
Expand Down
174 changes: 174 additions & 0 deletions doc/src/sgml/generic-wal.sgml
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
<!-- 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>
1 change: 1 addition & 0 deletions doc/src/sgml/postgres.sgml
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,7 @@ break is not needed in a wider output rendering.
&tableam;
&indexam;
&generic-wal;
&custom-rmgr;
&btree;
&gist;
&spgist;
Expand Down
8 changes: 8 additions & 0 deletions doc/src/sgml/ref/pg_waldump.sgml
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,14 @@ PostgreSQL documentation
If <literal>list</literal> is passed as name, print a list of valid resource manager
names, and exit.
</para>
<para>
Extensions may define custom resource managers, but pg_waldump does
not load the extension module and therefore does not recognize custom
resource managers by name. Instead, you can specify the custom
resource managers as <literal>custom###</literal> where
"<literal>###</literal>" is the three-digit resource manager ID. Names
of this form will always be considered valid.
</para>
</listitem>
</varlistentry>

Expand Down
Loading