summaryrefslogtreecommitdiffstats
path: root/doc/src/sgml/html/fdw-row-locking.html
diff options
context:
space:
mode:
Diffstat (limited to 'doc/src/sgml/html/fdw-row-locking.html')
-rw-r--r--doc/src/sgml/html/fdw-row-locking.html93
1 files changed, 93 insertions, 0 deletions
diff --git a/doc/src/sgml/html/fdw-row-locking.html b/doc/src/sgml/html/fdw-row-locking.html
new file mode 100644
index 0000000..98cd9f5
--- /dev/null
+++ b/doc/src/sgml/html/fdw-row-locking.html
@@ -0,0 +1,93 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>59.5. Row Locking in Foreign Data Wrappers</title><link rel="stylesheet" type="text/css" href="stylesheet.css" /><link rev="made" href="pgsql-docs@lists.postgresql.org" /><meta name="generator" content="DocBook XSL Stylesheets Vsnapshot" /><link rel="prev" href="fdw-planning.html" title="59.4. Foreign Data Wrapper Query Planning" /><link rel="next" href="tablesample-method.html" title="Chapter 60. Writing a Table Sampling Method" /></head><body id="docContent" class="container-fluid col-10"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="5" align="center">59.5. Row Locking in Foreign Data Wrappers</th></tr><tr><td width="10%" align="left"><a accesskey="p" href="fdw-planning.html" title="59.4. Foreign Data Wrapper Query Planning">Prev</a> </td><td width="10%" align="left"><a accesskey="u" href="fdwhandler.html" title="Chapter 59. Writing a Foreign Data Wrapper">Up</a></td><th width="60%" align="center">Chapter 59. Writing a Foreign Data Wrapper</th><td width="10%" align="right"><a accesskey="h" href="index.html" title="PostgreSQL 15.4 Documentation">Home</a></td><td width="10%" align="right"> <a accesskey="n" href="tablesample-method.html" title="Chapter 60. Writing a Table Sampling Method">Next</a></td></tr></table><hr /></div><div class="sect1" id="FDW-ROW-LOCKING"><div class="titlepage"><div><div><h2 class="title" style="clear: both">59.5. Row Locking in Foreign Data Wrappers</h2></div></div></div><p>
+ If an FDW's underlying storage mechanism has a concept of locking
+ individual rows to prevent concurrent updates of those rows, it is
+ usually worthwhile for the FDW to perform row-level locking with as
+ close an approximation as practical to the semantics used in
+ ordinary <span class="productname">PostgreSQL</span> tables. There are multiple
+ considerations involved in this.
+ </p><p>
+ One key decision to be made is whether to perform <em class="firstterm">early
+ locking</em> or <em class="firstterm">late locking</em>. In early locking, a row is
+ locked when it is first retrieved from the underlying store, while in
+ late locking, the row is locked only when it is known that it needs to
+ be locked. (The difference arises because some rows may be discarded by
+ locally-checked restriction or join conditions.) Early locking is much
+ simpler and avoids extra round trips to a remote store, but it can cause
+ locking of rows that need not have been locked, resulting in reduced
+ concurrency or even unexpected deadlocks. Also, late locking is only
+ possible if the row to be locked can be uniquely re-identified later.
+ Preferably the row identifier should identify a specific version of the
+ row, as <span class="productname">PostgreSQL</span> TIDs do.
+ </p><p>
+ By default, <span class="productname">PostgreSQL</span> ignores locking considerations
+ when interfacing to FDWs, but an FDW can perform early locking without
+ any explicit support from the core code. The API functions described
+ in <a class="xref" href="fdw-callbacks.html#FDW-CALLBACKS-ROW-LOCKING" title="59.2.6. FDW Routines for Row Locking">Section 59.2.6</a>, which were added
+ in <span class="productname">PostgreSQL</span> 9.5, allow an FDW to use late locking if
+ it wishes.
+ </p><p>
+ An additional consideration is that in <code class="literal">READ COMMITTED</code>
+ isolation mode, <span class="productname">PostgreSQL</span> may need to re-check
+ restriction and join conditions against an updated version of some
+ target tuple. Rechecking join conditions requires re-obtaining copies
+ of the non-target rows that were previously joined to the target tuple.
+ When working with standard <span class="productname">PostgreSQL</span> tables, this is
+ done by including the TIDs of the non-target tables in the column list
+ projected through the join, and then re-fetching non-target rows when
+ required. This approach keeps the join data set compact, but it
+ requires inexpensive re-fetch capability, as well as a TID that can
+ uniquely identify the row version to be re-fetched. By default,
+ therefore, the approach used with foreign tables is to include a copy of
+ the entire row fetched from a foreign table in the column list projected
+ through the join. This puts no special demands on the FDW but can
+ result in reduced performance of merge and hash joins. An FDW that is
+ capable of meeting the re-fetch requirements can choose to do it the
+ first way.
+ </p><p>
+ For an <code class="command">UPDATE</code> or <code class="command">DELETE</code> on a foreign table, it
+ is recommended that the <code class="literal">ForeignScan</code> operation on the target
+ table perform early locking on the rows that it fetches, perhaps via the
+ equivalent of <code class="command">SELECT FOR UPDATE</code>. An FDW can detect whether
+ a table is an <code class="command">UPDATE</code>/<code class="command">DELETE</code> target at plan time
+ by comparing its relid to <code class="literal">root-&gt;parse-&gt;resultRelation</code>,
+ or at execution time by using <code class="function">ExecRelationIsTargetRelation()</code>.
+ An alternative possibility is to perform late locking within the
+ <code class="function">ExecForeignUpdate</code> or <code class="function">ExecForeignDelete</code>
+ callback, but no special support is provided for this.
+ </p><p>
+ For foreign tables that are specified to be locked by a <code class="command">SELECT
+ FOR UPDATE/SHARE</code> command, the <code class="literal">ForeignScan</code> operation can
+ again perform early locking by fetching tuples with the equivalent
+ of <code class="command">SELECT FOR UPDATE/SHARE</code>. To perform late locking
+ instead, provide the callback functions defined
+ in <a class="xref" href="fdw-callbacks.html#FDW-CALLBACKS-ROW-LOCKING" title="59.2.6. FDW Routines for Row Locking">Section 59.2.6</a>.
+ In <code class="function">GetForeignRowMarkType</code>, select rowmark option
+ <code class="literal">ROW_MARK_EXCLUSIVE</code>, <code class="literal">ROW_MARK_NOKEYEXCLUSIVE</code>,
+ <code class="literal">ROW_MARK_SHARE</code>, or <code class="literal">ROW_MARK_KEYSHARE</code> depending
+ on the requested lock strength. (The core code will act the same
+ regardless of which of these four options you choose.)
+ Elsewhere, you can detect whether a foreign table was specified to be
+ locked by this type of command by using <code class="function">get_plan_rowmark</code> at
+ plan time, or <code class="function">ExecFindRowMark</code> at execution time; you must
+ check not only whether a non-null rowmark struct is returned, but that
+ its <code class="structfield">strength</code> field is not <code class="literal">LCS_NONE</code>.
+ </p><p>
+ Lastly, for foreign tables that are used in an <code class="command">UPDATE</code>,
+ <code class="command">DELETE</code> or <code class="command">SELECT FOR UPDATE/SHARE</code> command but
+ are not specified to be row-locked, you can override the default choice
+ to copy entire rows by having <code class="function">GetForeignRowMarkType</code> select
+ option <code class="literal">ROW_MARK_REFERENCE</code> when it sees lock strength
+ <code class="literal">LCS_NONE</code>. This will cause <code class="function">RefetchForeignRow</code> to
+ be called with that value for <code class="structfield">markType</code>; it should then
+ re-fetch the row without acquiring any new lock. (If you have
+ a <code class="function">GetForeignRowMarkType</code> function but don't wish to re-fetch
+ unlocked rows, select option <code class="literal">ROW_MARK_COPY</code>
+ for <code class="literal">LCS_NONE</code>.)
+ </p><p>
+ See <code class="filename">src/include/nodes/lockoptions.h</code>, the comments
+ for <code class="type">RowMarkType</code> and <code class="type">PlanRowMark</code>
+ in <code class="filename">src/include/nodes/plannodes.h</code>, and the comments for
+ <code class="type">ExecRowMark</code> in <code class="filename">src/include/nodes/execnodes.h</code> for
+ additional information.
+ </p></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="fdw-planning.html" title="59.4. Foreign Data Wrapper Query Planning">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="fdwhandler.html" title="Chapter 59. Writing a Foreign Data Wrapper">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="tablesample-method.html" title="Chapter 60. Writing a Table Sampling Method">Next</a></td></tr><tr><td width="40%" align="left" valign="top">59.4. Foreign Data Wrapper Query Planning </td><td width="20%" align="center"><a accesskey="h" href="index.html" title="PostgreSQL 15.4 Documentation">Home</a></td><td width="40%" align="right" valign="top"> Chapter 60. Writing a Table Sampling Method</td></tr></table></div></body></html> \ No newline at end of file