]> granicus.if.org Git - postgresql/blob - src/backend/storage/lmgr/lmgr.c
9f335ed4868f70129e81d8481a16b9ce03f66b68
[postgresql] / src / backend / storage / lmgr / lmgr.c
1 /*-------------------------------------------------------------------------
2  *
3  * lmgr.c
4  *        POSTGRES lock manager code
5  *
6  * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  *        src/backend/storage/lmgr/lmgr.c
12  *
13  *-------------------------------------------------------------------------
14  */
15
16 #include "postgres.h"
17
18 #include "access/subtrans.h"
19 #include "access/transam.h"
20 #include "access/xact.h"
21 #include "catalog/catalog.h"
22 #include "miscadmin.h"
23 #include "storage/lmgr.h"
24 #include "storage/procarray.h"
25 #include "utils/inval.h"
26
27
28 /*
29  * RelationInitLockInfo
30  *              Initializes the lock information in a relation descriptor.
31  *
32  *              relcache.c must call this during creation of any reldesc.
33  */
34 void
35 RelationInitLockInfo(Relation relation)
36 {
37         Assert(RelationIsValid(relation));
38         Assert(OidIsValid(RelationGetRelid(relation)));
39
40         relation->rd_lockInfo.lockRelId.relId = RelationGetRelid(relation);
41
42         if (relation->rd_rel->relisshared)
43                 relation->rd_lockInfo.lockRelId.dbId = InvalidOid;
44         else
45                 relation->rd_lockInfo.lockRelId.dbId = MyDatabaseId;
46 }
47
48 /*
49  * SetLocktagRelationOid
50  *              Set up a locktag for a relation, given only relation OID
51  */
52 static inline void
53 SetLocktagRelationOid(LOCKTAG *tag, Oid relid)
54 {
55         Oid                     dbid;
56
57         if (IsSharedRelation(relid))
58                 dbid = InvalidOid;
59         else
60                 dbid = MyDatabaseId;
61
62         SET_LOCKTAG_RELATION(*tag, dbid, relid);
63 }
64
65 /*
66  *              LockRelationOid
67  *
68  * Lock a relation given only its OID.  This should generally be used
69  * before attempting to open the relation's relcache entry.
70  */
71 void
72 LockRelationOid(Oid relid, LOCKMODE lockmode)
73 {
74         LOCKTAG         tag;
75         LockAcquireResult res;
76
77         SetLocktagRelationOid(&tag, relid);
78
79         res = LockAcquire(&tag, lockmode, false, false);
80
81         /*
82          * Now that we have the lock, check for invalidation messages, so that we
83          * will update or flush any stale relcache entry before we try to use it.
84          * We can skip this in the not-uncommon case that we already had the same
85          * type of lock being requested, since then no one else could have
86          * modified the relcache entry in an undesirable way.  (In the case where
87          * our own xact modifies the rel, the relcache update happens via
88          * CommandCounterIncrement, not here.)
89          */
90         if (res != LOCKACQUIRE_ALREADY_HELD)
91                 AcceptInvalidationMessages();
92 }
93
94 /*
95  *              ConditionalLockRelationOid
96  *
97  * As above, but only lock if we can get the lock without blocking.
98  * Returns TRUE iff the lock was acquired.
99  *
100  * NOTE: we do not currently need conditional versions of all the
101  * LockXXX routines in this file, but they could easily be added if needed.
102  */
103 bool
104 ConditionalLockRelationOid(Oid relid, LOCKMODE lockmode)
105 {
106         LOCKTAG         tag;
107         LockAcquireResult res;
108
109         SetLocktagRelationOid(&tag, relid);
110
111         res = LockAcquire(&tag, lockmode, false, true);
112
113         if (res == LOCKACQUIRE_NOT_AVAIL)
114                 return false;
115
116         /*
117          * Now that we have the lock, check for invalidation messages; see notes
118          * in LockRelationOid.
119          */
120         if (res != LOCKACQUIRE_ALREADY_HELD)
121                 AcceptInvalidationMessages();
122
123         return true;
124 }
125
126 /*
127  *              UnlockRelationId
128  *
129  * Unlock, given a LockRelId.  This is preferred over UnlockRelationOid
130  * for speed reasons.
131  */
132 void
133 UnlockRelationId(LockRelId *relid, LOCKMODE lockmode)
134 {
135         LOCKTAG         tag;
136
137         SET_LOCKTAG_RELATION(tag, relid->dbId, relid->relId);
138
139         LockRelease(&tag, lockmode, false);
140 }
141
142 /*
143  *              UnlockRelationOid
144  *
145  * Unlock, given only a relation Oid.  Use UnlockRelationId if you can.
146  */
147 void
148 UnlockRelationOid(Oid relid, LOCKMODE lockmode)
149 {
150         LOCKTAG         tag;
151
152         SetLocktagRelationOid(&tag, relid);
153
154         LockRelease(&tag, lockmode, false);
155 }
156
157 /*
158  *              LockRelation
159  *
160  * This is a convenience routine for acquiring an additional lock on an
161  * already-open relation.  Never try to do "relation_open(foo, NoLock)"
162  * and then lock with this.
163  */
164 void
165 LockRelation(Relation relation, LOCKMODE lockmode)
166 {
167         LOCKTAG         tag;
168         LockAcquireResult res;
169
170         SET_LOCKTAG_RELATION(tag,
171                                                  relation->rd_lockInfo.lockRelId.dbId,
172                                                  relation->rd_lockInfo.lockRelId.relId);
173
174         res = LockAcquire(&tag, lockmode, false, false);
175
176         /*
177          * Now that we have the lock, check for invalidation messages; see notes
178          * in LockRelationOid.
179          */
180         if (res != LOCKACQUIRE_ALREADY_HELD)
181                 AcceptInvalidationMessages();
182 }
183
184 /*
185  *              ConditionalLockRelation
186  *
187  * This is a convenience routine for acquiring an additional lock on an
188  * already-open relation.  Never try to do "relation_open(foo, NoLock)"
189  * and then lock with this.
190  */
191 bool
192 ConditionalLockRelation(Relation relation, LOCKMODE lockmode)
193 {
194         LOCKTAG         tag;
195         LockAcquireResult res;
196
197         SET_LOCKTAG_RELATION(tag,
198                                                  relation->rd_lockInfo.lockRelId.dbId,
199                                                  relation->rd_lockInfo.lockRelId.relId);
200
201         res = LockAcquire(&tag, lockmode, false, true);
202
203         if (res == LOCKACQUIRE_NOT_AVAIL)
204                 return false;
205
206         /*
207          * Now that we have the lock, check for invalidation messages; see notes
208          * in LockRelationOid.
209          */
210         if (res != LOCKACQUIRE_ALREADY_HELD)
211                 AcceptInvalidationMessages();
212
213         return true;
214 }
215
216 /*
217  *              UnlockRelation
218  *
219  * This is a convenience routine for unlocking a relation without also
220  * closing it.
221  */
222 void
223 UnlockRelation(Relation relation, LOCKMODE lockmode)
224 {
225         LOCKTAG         tag;
226
227         SET_LOCKTAG_RELATION(tag,
228                                                  relation->rd_lockInfo.lockRelId.dbId,
229                                                  relation->rd_lockInfo.lockRelId.relId);
230
231         LockRelease(&tag, lockmode, false);
232 }
233
234 /*
235  *              LockRelationIdForSession
236  *
237  * This routine grabs a session-level lock on the target relation.      The
238  * session lock persists across transaction boundaries.  It will be removed
239  * when UnlockRelationIdForSession() is called, or if an ereport(ERROR) occurs,
240  * or if the backend exits.
241  *
242  * Note that one should also grab a transaction-level lock on the rel
243  * in any transaction that actually uses the rel, to ensure that the
244  * relcache entry is up to date.
245  */
246 void
247 LockRelationIdForSession(LockRelId *relid, LOCKMODE lockmode)
248 {
249         LOCKTAG         tag;
250
251         SET_LOCKTAG_RELATION(tag, relid->dbId, relid->relId);
252
253         (void) LockAcquire(&tag, lockmode, true, false);
254 }
255
256 /*
257  *              UnlockRelationIdForSession
258  */
259 void
260 UnlockRelationIdForSession(LockRelId *relid, LOCKMODE lockmode)
261 {
262         LOCKTAG         tag;
263
264         SET_LOCKTAG_RELATION(tag, relid->dbId, relid->relId);
265
266         LockRelease(&tag, lockmode, true);
267 }
268
269 /*
270  *              LockRelationForExtension
271  *
272  * This lock tag is used to interlock addition of pages to relations.
273  * We need such locking because bufmgr/smgr definition of P_NEW is not
274  * race-condition-proof.
275  *
276  * We assume the caller is already holding some type of regular lock on
277  * the relation, so no AcceptInvalidationMessages call is needed here.
278  */
279 void
280 LockRelationForExtension(Relation relation, LOCKMODE lockmode)
281 {
282         LOCKTAG         tag;
283
284         SET_LOCKTAG_RELATION_EXTEND(tag,
285                                                                 relation->rd_lockInfo.lockRelId.dbId,
286                                                                 relation->rd_lockInfo.lockRelId.relId);
287
288         (void) LockAcquire(&tag, lockmode, false, false);
289 }
290
291 /*
292  *              UnlockRelationForExtension
293  */
294 void
295 UnlockRelationForExtension(Relation relation, LOCKMODE lockmode)
296 {
297         LOCKTAG         tag;
298
299         SET_LOCKTAG_RELATION_EXTEND(tag,
300                                                                 relation->rd_lockInfo.lockRelId.dbId,
301                                                                 relation->rd_lockInfo.lockRelId.relId);
302
303         LockRelease(&tag, lockmode, false);
304 }
305
306 /*
307  *              LockPage
308  *
309  * Obtain a page-level lock.  This is currently used by some index access
310  * methods to lock individual index pages.
311  */
312 void
313 LockPage(Relation relation, BlockNumber blkno, LOCKMODE lockmode)
314 {
315         LOCKTAG         tag;
316
317         SET_LOCKTAG_PAGE(tag,
318                                          relation->rd_lockInfo.lockRelId.dbId,
319                                          relation->rd_lockInfo.lockRelId.relId,
320                                          blkno);
321
322         (void) LockAcquire(&tag, lockmode, false, false);
323 }
324
325 /*
326  *              ConditionalLockPage
327  *
328  * As above, but only lock if we can get the lock without blocking.
329  * Returns TRUE iff the lock was acquired.
330  */
331 bool
332 ConditionalLockPage(Relation relation, BlockNumber blkno, LOCKMODE lockmode)
333 {
334         LOCKTAG         tag;
335
336         SET_LOCKTAG_PAGE(tag,
337                                          relation->rd_lockInfo.lockRelId.dbId,
338                                          relation->rd_lockInfo.lockRelId.relId,
339                                          blkno);
340
341         return (LockAcquire(&tag, lockmode, false, true) != LOCKACQUIRE_NOT_AVAIL);
342 }
343
344 /*
345  *              UnlockPage
346  */
347 void
348 UnlockPage(Relation relation, BlockNumber blkno, LOCKMODE lockmode)
349 {
350         LOCKTAG         tag;
351
352         SET_LOCKTAG_PAGE(tag,
353                                          relation->rd_lockInfo.lockRelId.dbId,
354                                          relation->rd_lockInfo.lockRelId.relId,
355                                          blkno);
356
357         LockRelease(&tag, lockmode, false);
358 }
359
360 /*
361  *              LockTuple
362  *
363  * Obtain a tuple-level lock.  This is used in a less-than-intuitive fashion
364  * because we can't afford to keep a separate lock in shared memory for every
365  * tuple.  See heap_lock_tuple before using this!
366  */
367 void
368 LockTuple(Relation relation, ItemPointer tid, LOCKMODE lockmode)
369 {
370         LOCKTAG         tag;
371
372         SET_LOCKTAG_TUPLE(tag,
373                                           relation->rd_lockInfo.lockRelId.dbId,
374                                           relation->rd_lockInfo.lockRelId.relId,
375                                           ItemPointerGetBlockNumber(tid),
376                                           ItemPointerGetOffsetNumber(tid));
377
378         (void) LockAcquire(&tag, lockmode, false, false);
379 }
380
381 /*
382  *              ConditionalLockTuple
383  *
384  * As above, but only lock if we can get the lock without blocking.
385  * Returns TRUE iff the lock was acquired.
386  */
387 bool
388 ConditionalLockTuple(Relation relation, ItemPointer tid, LOCKMODE lockmode)
389 {
390         LOCKTAG         tag;
391
392         SET_LOCKTAG_TUPLE(tag,
393                                           relation->rd_lockInfo.lockRelId.dbId,
394                                           relation->rd_lockInfo.lockRelId.relId,
395                                           ItemPointerGetBlockNumber(tid),
396                                           ItemPointerGetOffsetNumber(tid));
397
398         return (LockAcquire(&tag, lockmode, false, true) != LOCKACQUIRE_NOT_AVAIL);
399 }
400
401 /*
402  *              UnlockTuple
403  */
404 void
405 UnlockTuple(Relation relation, ItemPointer tid, LOCKMODE lockmode)
406 {
407         LOCKTAG         tag;
408
409         SET_LOCKTAG_TUPLE(tag,
410                                           relation->rd_lockInfo.lockRelId.dbId,
411                                           relation->rd_lockInfo.lockRelId.relId,
412                                           ItemPointerGetBlockNumber(tid),
413                                           ItemPointerGetOffsetNumber(tid));
414
415         LockRelease(&tag, lockmode, false);
416 }
417
418 /*
419  *              XactLockTableInsert
420  *
421  * Insert a lock showing that the given transaction ID is running ---
422  * this is done when an XID is acquired by a transaction or subtransaction.
423  * The lock can then be used to wait for the transaction to finish.
424  */
425 void
426 XactLockTableInsert(TransactionId xid)
427 {
428         LOCKTAG         tag;
429
430         SET_LOCKTAG_TRANSACTION(tag, xid);
431
432         (void) LockAcquire(&tag, ExclusiveLock, false, false);
433 }
434
435 /*
436  *              XactLockTableDelete
437  *
438  * Delete the lock showing that the given transaction ID is running.
439  * (This is never used for main transaction IDs; those locks are only
440  * released implicitly at transaction end.      But we do use it for subtrans IDs.)
441  */
442 void
443 XactLockTableDelete(TransactionId xid)
444 {
445         LOCKTAG         tag;
446
447         SET_LOCKTAG_TRANSACTION(tag, xid);
448
449         LockRelease(&tag, ExclusiveLock, false);
450 }
451
452 /*
453  *              XactLockTableWait
454  *
455  * Wait for the specified transaction to commit or abort.
456  *
457  * Note that this does the right thing for subtransactions: if we wait on a
458  * subtransaction, we will exit as soon as it aborts or its top parent commits.
459  * It takes some extra work to ensure this, because to save on shared memory
460  * the XID lock of a subtransaction is released when it ends, whether
461  * successfully or unsuccessfully.      So we have to check if it's "still running"
462  * and if so wait for its parent.
463  */
464 void
465 XactLockTableWait(TransactionId xid)
466 {
467         LOCKTAG         tag;
468
469         for (;;)
470         {
471                 Assert(TransactionIdIsValid(xid));
472                 Assert(!TransactionIdEquals(xid, GetTopTransactionIdIfAny()));
473
474                 SET_LOCKTAG_TRANSACTION(tag, xid);
475
476                 (void) LockAcquire(&tag, ShareLock, false, false);
477
478                 LockRelease(&tag, ShareLock, false);
479
480                 if (!TransactionIdIsInProgress(xid))
481                         break;
482                 xid = SubTransGetParent(xid);
483         }
484 }
485
486 /*
487  *              ConditionalXactLockTableWait
488  *
489  * As above, but only lock if we can get the lock without blocking.
490  * Returns TRUE if the lock was acquired.
491  */
492 bool
493 ConditionalXactLockTableWait(TransactionId xid)
494 {
495         LOCKTAG         tag;
496
497         for (;;)
498         {
499                 Assert(TransactionIdIsValid(xid));
500                 Assert(!TransactionIdEquals(xid, GetTopTransactionIdIfAny()));
501
502                 SET_LOCKTAG_TRANSACTION(tag, xid);
503
504                 if (LockAcquire(&tag, ShareLock, false, true) == LOCKACQUIRE_NOT_AVAIL)
505                         return false;
506
507                 LockRelease(&tag, ShareLock, false);
508
509                 if (!TransactionIdIsInProgress(xid))
510                         break;
511                 xid = SubTransGetParent(xid);
512         }
513
514         return true;
515 }
516
517
518 /*
519  *              VirtualXactLockTableInsert
520  *
521  * Insert a lock showing that the given virtual transaction ID is running ---
522  * this is done at main transaction start when its VXID is assigned.
523  * The lock can then be used to wait for the transaction to finish.
524  */
525 void
526 VirtualXactLockTableInsert(VirtualTransactionId vxid)
527 {
528         LOCKTAG         tag;
529
530         Assert(VirtualTransactionIdIsValid(vxid));
531
532         SET_LOCKTAG_VIRTUALTRANSACTION(tag, vxid);
533
534         (void) LockAcquire(&tag, ExclusiveLock, false, false);
535 }
536
537 /*
538  *              VirtualXactLockTableWait
539  *
540  * Waits until the lock on the given VXID is released, which shows that
541  * the top-level transaction owning the VXID has ended.
542  */
543 void
544 VirtualXactLockTableWait(VirtualTransactionId vxid)
545 {
546         LOCKTAG         tag;
547
548         Assert(VirtualTransactionIdIsValid(vxid));
549
550         SET_LOCKTAG_VIRTUALTRANSACTION(tag, vxid);
551
552         (void) LockAcquire(&tag, ShareLock, false, false);
553
554         LockRelease(&tag, ShareLock, false);
555 }
556
557 /*
558  *              ConditionalVirtualXactLockTableWait
559  *
560  * As above, but only lock if we can get the lock without blocking.
561  * Returns TRUE if the lock was acquired.
562  */
563 bool
564 ConditionalVirtualXactLockTableWait(VirtualTransactionId vxid)
565 {
566         LOCKTAG         tag;
567
568         Assert(VirtualTransactionIdIsValid(vxid));
569
570         SET_LOCKTAG_VIRTUALTRANSACTION(tag, vxid);
571
572         if (LockAcquire(&tag, ShareLock, false, true) == LOCKACQUIRE_NOT_AVAIL)
573                 return false;
574
575         LockRelease(&tag, ShareLock, false);
576
577         return true;
578 }
579
580
581 /*
582  *              LockDatabaseObject
583  *
584  * Obtain a lock on a general object of the current database.  Don't use
585  * this for shared objects (such as tablespaces).  It's unwise to apply it
586  * to relations, also, since a lock taken this way will NOT conflict with
587  * locks taken via LockRelation and friends.
588  */
589 void
590 LockDatabaseObject(Oid classid, Oid objid, uint16 objsubid,
591                                    LOCKMODE lockmode)
592 {
593         LOCKTAG         tag;
594
595         SET_LOCKTAG_OBJECT(tag,
596                                            MyDatabaseId,
597                                            classid,
598                                            objid,
599                                            objsubid);
600
601         (void) LockAcquire(&tag, lockmode, false, false);
602
603         /* Make sure syscaches are up-to-date with any changes we waited for */
604         AcceptInvalidationMessages();
605 }
606
607 /*
608  *              UnlockDatabaseObject
609  */
610 void
611 UnlockDatabaseObject(Oid classid, Oid objid, uint16 objsubid,
612                                          LOCKMODE lockmode)
613 {
614         LOCKTAG         tag;
615
616         SET_LOCKTAG_OBJECT(tag,
617                                            MyDatabaseId,
618                                            classid,
619                                            objid,
620                                            objsubid);
621
622         LockRelease(&tag, lockmode, false);
623 }
624
625 /*
626  *              LockSharedObject
627  *
628  * Obtain a lock on a shared-across-databases object.
629  */
630 void
631 LockSharedObject(Oid classid, Oid objid, uint16 objsubid,
632                                  LOCKMODE lockmode)
633 {
634         LOCKTAG         tag;
635
636         SET_LOCKTAG_OBJECT(tag,
637                                            InvalidOid,
638                                            classid,
639                                            objid,
640                                            objsubid);
641
642         (void) LockAcquire(&tag, lockmode, false, false);
643
644         /* Make sure syscaches are up-to-date with any changes we waited for */
645         AcceptInvalidationMessages();
646 }
647
648 /*
649  *              UnlockSharedObject
650  */
651 void
652 UnlockSharedObject(Oid classid, Oid objid, uint16 objsubid,
653                                    LOCKMODE lockmode)
654 {
655         LOCKTAG         tag;
656
657         SET_LOCKTAG_OBJECT(tag,
658                                            InvalidOid,
659                                            classid,
660                                            objid,
661                                            objsubid);
662
663         LockRelease(&tag, lockmode, false);
664 }
665
666 /*
667  *              LockSharedObjectForSession
668  *
669  * Obtain a session-level lock on a shared-across-databases object.
670  * See LockRelationIdForSession for notes about session-level locks.
671  */
672 void
673 LockSharedObjectForSession(Oid classid, Oid objid, uint16 objsubid,
674                                                    LOCKMODE lockmode)
675 {
676         LOCKTAG         tag;
677
678         SET_LOCKTAG_OBJECT(tag,
679                                            InvalidOid,
680                                            classid,
681                                            objid,
682                                            objsubid);
683
684         (void) LockAcquire(&tag, lockmode, true, false);
685 }
686
687 /*
688  *              UnlockSharedObjectForSession
689  */
690 void
691 UnlockSharedObjectForSession(Oid classid, Oid objid, uint16 objsubid,
692                                                          LOCKMODE lockmode)
693 {
694         LOCKTAG         tag;
695
696         SET_LOCKTAG_OBJECT(tag,
697                                            InvalidOid,
698                                            classid,
699                                            objid,
700                                            objsubid);
701
702         LockRelease(&tag, lockmode, true);
703 }
704
705
706 /*
707  * Append a description of a lockable object to buf.
708  *
709  * Ideally we would print names for the numeric values, but that requires
710  * getting locks on system tables, which might cause problems since this is
711  * typically used to report deadlock situations.
712  */
713 void
714 DescribeLockTag(StringInfo buf, const LOCKTAG *tag)
715 {
716         switch ((LockTagType) tag->locktag_type)
717         {
718                 case LOCKTAG_RELATION:
719                         appendStringInfo(buf,
720                                                          _("relation %u of database %u"),
721                                                          tag->locktag_field2,
722                                                          tag->locktag_field1);
723                         break;
724                 case LOCKTAG_RELATION_EXTEND:
725                         appendStringInfo(buf,
726                                                          _("extension of relation %u of database %u"),
727                                                          tag->locktag_field2,
728                                                          tag->locktag_field1);
729                         break;
730                 case LOCKTAG_PAGE:
731                         appendStringInfo(buf,
732                                                          _("page %u of relation %u of database %u"),
733                                                          tag->locktag_field3,
734                                                          tag->locktag_field2,
735                                                          tag->locktag_field1);
736                         break;
737                 case LOCKTAG_TUPLE:
738                         appendStringInfo(buf,
739                                                          _("tuple (%u,%u) of relation %u of database %u"),
740                                                          tag->locktag_field3,
741                                                          tag->locktag_field4,
742                                                          tag->locktag_field2,
743                                                          tag->locktag_field1);
744                         break;
745                 case LOCKTAG_TRANSACTION:
746                         appendStringInfo(buf,
747                                                          _("transaction %u"),
748                                                          tag->locktag_field1);
749                         break;
750                 case LOCKTAG_VIRTUALTRANSACTION:
751                         appendStringInfo(buf,
752                                                          _("virtual transaction %d/%u"),
753                                                          tag->locktag_field1,
754                                                          tag->locktag_field2);
755                         break;
756                 case LOCKTAG_OBJECT:
757                         appendStringInfo(buf,
758                                                          _("object %u of class %u of database %u"),
759                                                          tag->locktag_field3,
760                                                          tag->locktag_field2,
761                                                          tag->locktag_field1);
762                         break;
763                 case LOCKTAG_USERLOCK:
764                         /* reserved for old contrib code, now on pgfoundry */
765                         appendStringInfo(buf,
766                                                          _("user lock [%u,%u,%u]"),
767                                                          tag->locktag_field1,
768                                                          tag->locktag_field2,
769                                                          tag->locktag_field3);
770                         break;
771                 case LOCKTAG_ADVISORY:
772                         appendStringInfo(buf,
773                                                          _("advisory lock [%u,%u,%u,%u]"),
774                                                          tag->locktag_field1,
775                                                          tag->locktag_field2,
776                                                          tag->locktag_field3,
777                                                          tag->locktag_field4);
778                         break;
779                 default:
780                         appendStringInfo(buf,
781                                                          _("unrecognized locktag type %d"),
782                                                          (int) tag->locktag_type);
783                         break;
784         }
785 }