]> begriffs open source - ai-pg/blob - full-docs/txt/fdw-row-locking.txt
Convert HTML docs to more streamlined TXT
[ai-pg] / full-docs / txt / fdw-row-locking.txt
1
2 58.5. Row Locking in Foreign Data Wrappers #
3
4    If an FDW's underlying storage mechanism has a concept of locking
5    individual rows to prevent concurrent updates of those rows, it is
6    usually worthwhile for the FDW to perform row-level locking with as
7    close an approximation as practical to the semantics used in ordinary
8    PostgreSQL tables. There are multiple considerations involved in this.
9
10    One key decision to be made is whether to perform early locking or late
11    locking. In early locking, a row is locked when it is first retrieved
12    from the underlying store, while in late locking, the row is locked
13    only when it is known that it needs to be locked. (The difference
14    arises because some rows may be discarded by locally-checked
15    restriction or join conditions.) Early locking is much simpler and
16    avoids extra round trips to a remote store, but it can cause locking of
17    rows that need not have been locked, resulting in reduced concurrency
18    or even unexpected deadlocks. Also, late locking is only possible if
19    the row to be locked can be uniquely re-identified later. Preferably
20    the row identifier should identify a specific version of the row, as
21    PostgreSQL TIDs do.
22
23    By default, PostgreSQL ignores locking considerations when interfacing
24    to FDWs, but an FDW can perform early locking without any explicit
25    support from the core code. The API functions described in
26    Section 58.2.6, which were added in PostgreSQL 9.5, allow an FDW to use
27    late locking if it wishes.
28
29    An additional consideration is that in READ COMMITTED isolation mode,
30    PostgreSQL may need to re-check restriction and join conditions against
31    an updated version of some target tuple. Rechecking join conditions
32    requires re-obtaining copies of the non-target rows that were
33    previously joined to the target tuple. When working with standard
34    PostgreSQL tables, this is done by including the TIDs of the non-target
35    tables in the column list projected through the join, and then
36    re-fetching non-target rows when required. This approach keeps the join
37    data set compact, but it requires inexpensive re-fetch capability, as
38    well as a TID that can uniquely identify the row version to be
39    re-fetched. By default, therefore, the approach used with foreign
40    tables is to include a copy of the entire row fetched from a foreign
41    table in the column list projected through the join. This puts no
42    special demands on the FDW but can result in reduced performance of
43    merge and hash joins. An FDW that is capable of meeting the re-fetch
44    requirements can choose to do it the first way.
45
46    For an UPDATE or DELETE on a foreign table, it is recommended that the
47    ForeignScan operation on the target table perform early locking on the
48    rows that it fetches, perhaps via the equivalent of SELECT FOR UPDATE.
49    An FDW can detect whether a table is an UPDATE/DELETE target at plan
50    time by comparing its relid to root->parse->resultRelation, or at
51    execution time by using ExecRelationIsTargetRelation(). An alternative
52    possibility is to perform late locking within the ExecForeignUpdate or
53    ExecForeignDelete callback, but no special support is provided for
54    this.
55
56    For foreign tables that are specified to be locked by a SELECT FOR
57    UPDATE/SHARE command, the ForeignScan operation can again perform early
58    locking by fetching tuples with the equivalent of SELECT FOR
59    UPDATE/SHARE. To perform late locking instead, provide the callback
60    functions defined in Section 58.2.6. In GetForeignRowMarkType, select
61    rowmark option ROW_MARK_EXCLUSIVE, ROW_MARK_NOKEYEXCLUSIVE,
62    ROW_MARK_SHARE, or ROW_MARK_KEYSHARE depending on the requested lock
63    strength. (The core code will act the same regardless of which of these
64    four options you choose.) Elsewhere, you can detect whether a foreign
65    table was specified to be locked by this type of command by using
66    get_plan_rowmark at plan time, or ExecFindRowMark at execution time;
67    you must check not only whether a non-null rowmark struct is returned,
68    but that its strength field is not LCS_NONE.
69
70    Lastly, for foreign tables that are used in an UPDATE, DELETE or SELECT
71    FOR UPDATE/SHARE command but are not specified to be row-locked, you
72    can override the default choice to copy entire rows by having
73    GetForeignRowMarkType select option ROW_MARK_REFERENCE when it sees
74    lock strength LCS_NONE. This will cause RefetchForeignRow to be called
75    with that value for markType; it should then re-fetch the row without
76    acquiring any new lock. (If you have a GetForeignRowMarkType function
77    but don't wish to re-fetch unlocked rows, select option ROW_MARK_COPY
78    for LCS_NONE.)
79
80    See src/include/nodes/lockoptions.h, the comments for RowMarkType and
81    PlanRowMark in src/include/nodes/plannodes.h, and the comments for
82    ExecRowMark in src/include/nodes/execnodes.h for additional
83    information.