Si le mécanisme de stockage sous-jacent à un FDW a un concept de verrouillage individuel des lignes pour prévenir des mises à jour concurrentes de ces lignes, il est généralement intéressant pour le FDW d'effectuer des verrouillages de niveau ligne avec une approximation aussi proche que possible de la sémantique utilisée pour les tables ordinaires de PostgreSQL. Ceci implique de multiples considérations.
Une décision clef à prendre est si il vaut mieux effectuer un verrouillage précoce ou un verrouillage tardif. Dans le verrouillage précoce, une ligne est verrouillée lorsqu'elle est récupérée pour la première fois à partir du stockage sous-jacent, alors qu'avec le verrouillage tardif, la ligne est verrouillée seulement lorsque le besoin est connu et nécessaire. (La différence survient parce que certaines lignes peuvent être abandonnées par des restrictions vérifiées localement ou des conditions de jointure.) Le verrouillage précoce est beaucoup plus simple et évite des allers-retours supplémentaires vers le stockage distant, mais il peut entraîner des verrouillages de lignes qui n'auraient pas eu besoin de l'être, résultant en une réduction de la concurrence voire même des deadlocks inattendus. De plus, le verrouillage tardif n'est possible seulement que si la ligne à verrouiller peut être identifiée de manière unique à nouveau plus tard. Idéalement, l'identifiant de ligne devrait identifier une version spécifique de la ligne, comme les TID de PostgreSQL le font.
Par défaut, PostgreSQL ignore les considérations de verrouillage lorsqu'il s'interface avec les FDW, mais un FDW peut effectuer un verrouillage précoce sans un support explicite du code du serveur principal. Les fonctions de l'API décrites dans le Section 59.2.6, qui ont été ajoutées dans la version 9.5 de PostgreSQL, autorise un FDW à utiliser un verrouillage tardif si il le désire.
Une considération supplémentaire est que dans le
niveau d'isolation READ COMMITTED
,
PostgreSQL peut avoir besoin de vérifier
à nouveau les restrictions et conditions de jointures avec une
version mise à jour de certaines lignes. Vérifier à nouveau
des conditions de jointure requiert d'obtenir à nouveau des
copies des lignes non ciblées qui étaient auparavant jointes
à la ligne cible. En travaillant avec des tables standards
PostgreSQL, ceci est effectué en
incluant les TID des tables non ciblées dans la liste des colonnes
projetées via la jointure, puis en récupérant à nouveau les
lignes non ciblées si nécessaire. Cette approche maintient
l'ensemble des données jointes compact, mais il demande une
capacité peu coûteuse de récupération à nouveau, ainsi qu'un TID
qui peut identifier de manière unique la version de la ligne à
récupérer à nouveau. Par défaut, donc, l'approche utilisée
avec les tables distantes est d'inclure une copie de la ligne
entière récupérée dans la liste de colonnes projetée via
la jointure. Ceci n'impose rien au FDW mais peut entraîner des
performances réduites des jointures par fusion ou hachage. Un FDW qui
remplit les conditions pour récupérer à nouveau peut choisir de
le faire.
Pour une commande UPDATE
ou
DELETE
sur une table distante, il est recommandé
que l'opération de ForeignScan
sur la table cible
effectue un verrouillage précoce sur les lignes qu'elle récupère,
peut-être via un équivalent de la commande SELECT FOR
UPDATE
. Un FDW peut détecter si une table est la cible
d'une commande UPDATE
/DELETE
lors de la planification en comparant son relid à
root->parse->resultRelation
,
ou lors de l'exécution en utilisant la fonction
ExecRelationIsTargetRelation()
. Une possibilité
alternative est d'effectuer un verrouillage tardif à l'intérieur
des fonctions callback ExecForeignUpdate
ou
ExecForeignDelete
, mais aucun support spécial
n'est fourni pour cela.
Pour les tables distantes qui sont verrouillées par une
commande SELECT FOR UPDATE/SHARE
, l'opération
ForeignScan
peut encore effectuer un verrouillage
précoce en récupérant des lignes avec l'équivalent de la commande
SELECT FOR UPDATE/SHARE
. Pour effectuer à la
place un verrouillage tardif, fournissez les fonctions callback
définies à Section 59.2.6. Dans
GetForeignRowMarkType
, sélectionner
l'option rowmark ROW_MARK_EXCLUSIVE
,
ROW_MARK_NOKEYEXCLUSIVE
,
ROW_MARK_SHARE
ou
ROW_MARK_KEYSHARE
en fonction de la force
du verrouillage demandé. (Le code du serveur principal agira
de la même manière indépendamment de l'option choisie parmi
ces quatre options.) Ailleurs, vous pouvez détecter si une
table distante a été verrouillée par ce type de commandes en
utilisant la fonction get_plan_rowmark
lors de
la planification ou la fonction ExecFindRowMark
lors de l'exécution ; vous devez vérifier non seulement si une
structure rowmark non nulle est renvoyée, mais également que
son champ strength
n'est pas égal à
LCS_NONE
.
Enfin, pour les tables distantes qui sont utilisées dans une
commande UPDATE
, DELETE
ou SELECT FOR UPDATE/SHARE
sans demande
de verrouillage de ligne, vous pouvez passer outre le choix
par défaut de copier les lignes entières dans la fonction
GetForeignRowMarkType
en sélectionnant l'option
ROW_MARK_REFERENCE
lorsqu'elle voit comme valeur
de puissance de verrouillage LCS_NONE
. Ceci aura
pour conséquence d'appeler RefetchForeignRow
avec cette valeur pour le champ markType
;
elle devrait alors récupérer à nouveau la ligne sans
prendre aucun nouveau verrouillage. (Si vous avez une fonction
GetForeignRowMarkType
mais ne souhaitez
pas récupérer à nouveau des lignes non verrouillées,
sélectionnez l'option ROW_MARK_COPY
pour
LCS_NONE
.)
Voir les commentaires dans
src/include/nodes/lockoptions.h
,
pour RowMarkType
et dans
src/include/nodes/plannodes.h
pour PlanRowMark
, et les
commentaires pour ExecRowMark
dans
src/include/nodes/execnodes.h
pour des
informations complémentaires.