PostgreSQL Source Code git master
Loading...
Searching...
No Matches
predicate.c File Reference
#include "postgres.h"
#include "access/parallel.h"
#include "access/slru.h"
#include "access/transam.h"
#include "access/twophase.h"
#include "access/twophase_rmgr.h"
#include "access/xact.h"
#include "access/xlog.h"
#include "miscadmin.h"
#include "pgstat.h"
#include "port/pg_lfind.h"
#include "storage/predicate.h"
#include "storage/predicate_internals.h"
#include "storage/proc.h"
#include "storage/procarray.h"
#include "utils/guc_hooks.h"
#include "utils/rel.h"
#include "utils/snapmgr.h"
#include "utils/wait_event.h"
Include dependency graph for predicate.c:

Go to the source code of this file.

Data Structures

struct  SerialControlData
 

Macros

#define TargetTagIsCoveredBy(covered_target, covering_target)
 
#define PredicateLockHashPartition(hashcode)    ((hashcode) % NUM_PREDICATELOCK_PARTITIONS)
 
#define PredicateLockHashPartitionLock(hashcode)
 
#define PredicateLockHashPartitionLockByIndex(i)    (&MainLWLockArray[PREDICATELOCK_MANAGER_LWLOCK_OFFSET + (i)].lock)
 
#define NPREDICATELOCKTARGETENTS()    mul_size(max_predicate_locks_per_xact, add_size(MaxBackends, max_prepared_xacts))
 
#define SxactIsOnFinishedList(sxact)   (!dlist_node_is_detached(&(sxact)->finishedLink))
 
#define SxactIsCommitted(sxact)   (((sxact)->flags & SXACT_FLAG_COMMITTED) != 0)
 
#define SxactIsPrepared(sxact)   (((sxact)->flags & SXACT_FLAG_PREPARED) != 0)
 
#define SxactIsRolledBack(sxact)   (((sxact)->flags & SXACT_FLAG_ROLLED_BACK) != 0)
 
#define SxactIsDoomed(sxact)   (((sxact)->flags & SXACT_FLAG_DOOMED) != 0)
 
#define SxactIsReadOnly(sxact)   (((sxact)->flags & SXACT_FLAG_READ_ONLY) != 0)
 
#define SxactHasSummaryConflictIn(sxact)   (((sxact)->flags & SXACT_FLAG_SUMMARY_CONFLICT_IN) != 0)
 
#define SxactHasSummaryConflictOut(sxact)   (((sxact)->flags & SXACT_FLAG_SUMMARY_CONFLICT_OUT) != 0)
 
#define SxactHasConflictOut(sxact)   (((sxact)->flags & SXACT_FLAG_CONFLICT_OUT) != 0)
 
#define SxactIsDeferrableWaiting(sxact)   (((sxact)->flags & SXACT_FLAG_DEFERRABLE_WAITING) != 0)
 
#define SxactIsROSafe(sxact)   (((sxact)->flags & SXACT_FLAG_RO_SAFE) != 0)
 
#define SxactIsROUnsafe(sxact)   (((sxact)->flags & SXACT_FLAG_RO_UNSAFE) != 0)
 
#define SxactIsPartiallyReleased(sxact)   (((sxact)->flags & SXACT_FLAG_PARTIALLY_RELEASED) != 0)
 
#define PredicateLockTargetTagHashCode(predicatelocktargettag)    get_hash_value(PredicateLockTargetHash, predicatelocktargettag)
 
#define PredicateLockHashCodeFromTargetHashCode(predicatelocktag, targethash)
 
#define SerialSlruCtl   (&SerialSlruCtlData)
 
#define SERIAL_PAGESIZE   BLCKSZ
 
#define SERIAL_ENTRYSIZE   sizeof(SerCommitSeqNo)
 
#define SERIAL_ENTRIESPERPAGE   (SERIAL_PAGESIZE / SERIAL_ENTRYSIZE)
 
#define SERIAL_MAX_PAGE   (MaxTransactionId / SERIAL_ENTRIESPERPAGE)
 
#define SerialNextPage(page)   (((page) >= SERIAL_MAX_PAGE) ? 0 : (page) + 1)
 
#define SerialValue(slotno, xid)
 
#define SerialPage(xid)   (((uint32) (xid)) / SERIAL_ENTRIESPERPAGE)
 

Typedefs

typedef struct SerialControlData SerialControlData
 
typedef struct SerialControlDataSerialControl
 

Functions

static SERIALIZABLEXACTCreatePredXact (void)
 
static void ReleasePredXact (SERIALIZABLEXACT *sxact)
 
static bool RWConflictExists (const SERIALIZABLEXACT *reader, const SERIALIZABLEXACT *writer)
 
static void SetRWConflict (SERIALIZABLEXACT *reader, SERIALIZABLEXACT *writer)
 
static void SetPossibleUnsafeConflict (SERIALIZABLEXACT *roXact, SERIALIZABLEXACT *activeXact)
 
static void ReleaseRWConflict (RWConflict conflict)
 
static void FlagSxactUnsafe (SERIALIZABLEXACT *sxact)
 
static bool SerialPagePrecedesLogically (int64 page1, int64 page2)
 
static void SerialInit (void)
 
static void SerialAdd (TransactionId xid, SerCommitSeqNo minConflictCommitSeqNo)
 
static SerCommitSeqNo SerialGetMinConflictCommitSeqNo (TransactionId xid)
 
static void SerialSetActiveSerXmin (TransactionId xid)
 
static uint32 predicatelock_hash (const void *key, Size keysize)
 
static void SummarizeOldestCommittedSxact (void)
 
static Snapshot GetSafeSnapshot (Snapshot origSnapshot)
 
static Snapshot GetSerializableTransactionSnapshotInt (Snapshot snapshot, VirtualTransactionId *sourcevxid, int sourcepid)
 
static bool PredicateLockExists (const PREDICATELOCKTARGETTAG *targettag)
 
static bool GetParentPredicateLockTag (const PREDICATELOCKTARGETTAG *tag, PREDICATELOCKTARGETTAG *parent)
 
static bool CoarserLockCovers (const PREDICATELOCKTARGETTAG *newtargettag)
 
static void RemoveScratchTarget (bool lockheld)
 
static void RestoreScratchTarget (bool lockheld)
 
static void RemoveTargetIfNoLongerUsed (PREDICATELOCKTARGET *target, uint32 targettaghash)
 
static void DeleteChildTargetLocks (const PREDICATELOCKTARGETTAG *newtargettag)
 
static int MaxPredicateChildLocks (const PREDICATELOCKTARGETTAG *tag)
 
static bool CheckAndPromotePredicateLockRequest (const PREDICATELOCKTARGETTAG *reqtag)
 
static void DecrementParentLocks (const PREDICATELOCKTARGETTAG *targettag)
 
static void CreatePredicateLock (const PREDICATELOCKTARGETTAG *targettag, uint32 targettaghash, SERIALIZABLEXACT *sxact)
 
static void DeleteLockTarget (PREDICATELOCKTARGET *target, uint32 targettaghash)
 
static bool TransferPredicateLocksToNewTarget (PREDICATELOCKTARGETTAG oldtargettag, PREDICATELOCKTARGETTAG newtargettag, bool removeOld)
 
static void PredicateLockAcquire (const PREDICATELOCKTARGETTAG *targettag)
 
static void DropAllPredicateLocksFromTable (Relation relation, bool transfer)
 
static void SetNewSxactGlobalXmin (void)
 
static void ClearOldPredicateLocks (void)
 
static void ReleaseOneSerializableXact (SERIALIZABLEXACT *sxact, bool partial, bool summarize)
 
static bool XidIsConcurrent (TransactionId xid)
 
static void CheckTargetForConflictsIn (PREDICATELOCKTARGETTAG *targettag)
 
static void FlagRWConflict (SERIALIZABLEXACT *reader, SERIALIZABLEXACT *writer)
 
static void OnConflict_CheckForSerializationFailure (const SERIALIZABLEXACT *reader, SERIALIZABLEXACT *writer)
 
static void CreateLocalPredicateLockHash (void)
 
static void ReleasePredicateLocksLocal (void)
 
static bool PredicateLockingNeededForRelation (Relation relation)
 
static bool SerializationNeededForRead (Relation relation, Snapshot snapshot)
 
static bool SerializationNeededForWrite (Relation relation)
 
bool check_serial_buffers (int *newval, void **extra, GucSource source)
 
void CheckPointPredicate (void)
 
void PredicateLockShmemInit (void)
 
Size PredicateLockShmemSize (void)
 
PredicateLockDataGetPredicateLockStatusData (void)
 
int GetSafeSnapshotBlockingPids (int blocked_pid, int *output, int output_size)
 
Snapshot GetSerializableTransactionSnapshot (Snapshot snapshot)
 
void SetSerializableTransactionSnapshot (Snapshot snapshot, VirtualTransactionId *sourcevxid, int sourcepid)
 
void RegisterPredicateLockingXid (TransactionId xid)
 
bool PageIsPredicateLocked (Relation relation, BlockNumber blkno)
 
void PredicateLockRelation (Relation relation, Snapshot snapshot)
 
void PredicateLockPage (Relation relation, BlockNumber blkno, Snapshot snapshot)
 
void PredicateLockTID (Relation relation, const ItemPointerData *tid, Snapshot snapshot, TransactionId tuple_xid)
 
void TransferPredicateLocksToHeapRelation (Relation relation)
 
void PredicateLockPageSplit (Relation relation, BlockNumber oldblkno, BlockNumber newblkno)
 
void PredicateLockPageCombine (Relation relation, BlockNumber oldblkno, BlockNumber newblkno)
 
void ReleasePredicateLocks (bool isCommit, bool isReadOnlySafe)
 
bool CheckForSerializableConflictOutNeeded (Relation relation, Snapshot snapshot)
 
void CheckForSerializableConflictOut (Relation relation, TransactionId xid, Snapshot snapshot)
 
void CheckForSerializableConflictIn (Relation relation, const ItemPointerData *tid, BlockNumber blkno)
 
void CheckTableForSerializableConflictIn (Relation relation)
 
void PreCommit_CheckForSerializationFailure (void)
 
void AtPrepare_PredicateLocks (void)
 
void PostPrepare_PredicateLocks (FullTransactionId fxid)
 
void PredicateLockTwoPhaseFinish (FullTransactionId fxid, bool isCommit)
 
void predicatelock_twophase_recover (FullTransactionId fxid, uint16 info, void *recdata, uint32 len)
 
SerializableXactHandle ShareSerializableXact (void)
 
void AttachSerializableXact (SerializableXactHandle handle)
 

Variables

static SlruCtlData SerialSlruCtlData
 
static SerialControl serialControl
 
static SERIALIZABLEXACTOldCommittedSxact
 
int max_predicate_locks_per_xact
 
int max_predicate_locks_per_relation
 
int max_predicate_locks_per_page
 
static PredXactList PredXact
 
static RWConflictPoolHeader RWConflictPool
 
static HTABSerializableXidHash
 
static HTABPredicateLockTargetHash
 
static HTABPredicateLockHash
 
static dlist_headFinishedSerializableTransactions
 
static const PREDICATELOCKTARGETTAG ScratchTargetTag = {0, 0, 0, 0}
 
static uint32 ScratchTargetTagHash
 
static LWLockScratchPartitionLock
 
static HTABLocalPredicateLockHash = NULL
 
static SERIALIZABLEXACTMySerializableXact = InvalidSerializableXact
 
static bool MyXactDidWrite = false
 
static SERIALIZABLEXACTSavedSerializableXact = InvalidSerializableXact
 

Macro Definition Documentation

◆ NPREDICATELOCKTARGETENTS

Definition at line 265 of file predicate.c.

337 : (page) + 1)
338
339#define SerialValue(slotno, xid) (*((SerCommitSeqNo *) \
340 (SerialSlruCtl->shared->page_buffer[slotno] + \
341 ((((uint32) (xid)) % SERIAL_ENTRIESPERPAGE) * SERIAL_ENTRYSIZE))))
342
343#define SerialPage(xid) (((uint32) (xid)) / SERIAL_ENTRIESPERPAGE)
344
345typedef struct SerialControlData
346{
347 int64 headPage; /* newest initialized page */
348 TransactionId headXid; /* newest valid Xid in the SLRU */
349 TransactionId tailXid; /* oldest xmin we might be interested in */
351
352typedef struct SerialControlData *SerialControl;
353
355
356/*
357 * When the oldest committed transaction on the "finished" list is moved to
358 * SLRU, its predicate locks will be moved to this "dummy" transaction,
359 * collapsing duplicate targets. When a duplicate is found, the later
360 * commitSeqNo is used.
361 */
363
364
365/*
366 * These configuration variables are used to set the predicate lock table size
367 * and to control promotion of predicate locks to coarser granularity in an
368 * attempt to degrade performance (mostly as false positive serialization
369 * failure) gracefully in the face of memory pressure.
370 */
371int max_predicate_locks_per_xact; /* in guc_tables.c */
372int max_predicate_locks_per_relation; /* in guc_tables.c */
373int max_predicate_locks_per_page; /* in guc_tables.c */
374
375/*
376 * This provides a list of objects in order to track transactions
377 * participating in predicate locking. Entries in the list are fixed size,
378 * and reside in shared memory. The memory address of an entry must remain
379 * fixed during its lifetime. The list will be protected from concurrent
380 * update externally; no provision is made in this code to manage that. The
381 * number of entries in the list, and the size allowed for each entry is
382 * fixed upon creation.
383 */
385
386/*
387 * This provides a pool of RWConflict data elements to use in conflict lists
388 * between transactions.
389 */
391
392/*
393 * The predicate locking hash tables are in shared memory.
394 * Each backend keeps pointers to them.
395 */
398static HTAB *PredicateLockHash;
400
401/*
402 * Tag for a dummy entry in PredicateLockTargetHash. By temporarily removing
403 * this entry, you can ensure that there's enough scratch space available for
404 * inserting one entry in the hash table. This is an otherwise-invalid tag.
405 */
406static const PREDICATELOCKTARGETTAG ScratchTargetTag = {0, 0, 0, 0};
409
410/*
411 * The local hash table used to determine when to combine multiple fine-
412 * grained locks into a single courser-grained lock.
413 */
415
416/*
417 * Keep a pointer to the currently-running serializable transaction (if any)
418 * for quick reference. Also, remember if we have written anything that could
419 * cause a rw-conflict.
420 */
422static bool MyXactDidWrite = false;
423
424/*
425 * The SXACT_FLAG_RO_UNSAFE optimization might lead us to release
426 * MySerializableXact early. If that happens in a parallel query, the leader
427 * needs to defer the destruction of the SERIALIZABLEXACT until end of
428 * transaction, because the workers still have a reference to it. In that
429 * case, the leader stores it here.
430 */
432
433/* local functions */
434
435static SERIALIZABLEXACT *CreatePredXact(void);
437
438static bool RWConflictExists(const SERIALIZABLEXACT *reader, const SERIALIZABLEXACT *writer);
443
445static void SerialInit(void);
449
450static uint32 predicatelock_hash(const void *key, Size keysize);
451static void SummarizeOldestCommittedSxact(void);
455 int sourcepid);
458 PREDICATELOCKTARGETTAG *parent);
460static void RemoveScratchTarget(bool lockheld);
461static void RestoreScratchTarget(bool lockheld);
474 bool removeOld);
476static void DropAllPredicateLocksFromTable(Relation relation,
477 bool transfer);
478static void SetNewSxactGlobalXmin(void);
479static void ClearOldPredicateLocks(void);
480static void ReleaseOneSerializableXact(SERIALIZABLEXACT *sxact, bool partial,
481 bool summarize);
482static bool XidIsConcurrent(TransactionId xid);
487static void CreateLocalPredicateLockHash(void);
488static void ReleasePredicateLocksLocal(void);
489
490
491/*------------------------------------------------------------------------*/
492
493/*
494 * Does this relation participate in predicate locking? Temporary and system
495 * relations are exempt.
496 */
497static inline bool
499{
500 return !(relation->rd_id < FirstUnpinnedObjectId ||
501 RelationUsesLocalBuffers(relation));
502}
503
504/*
505 * When a public interface method is called for a read, this is the test to
506 * see if we should do a quick return.
507 *
508 * Note: this function has side-effects! If this transaction has been flagged
509 * as RO-safe since the last call, we release all predicate locks and reset
510 * MySerializableXact. That makes subsequent calls to return quickly.
511 *
512 * This is marked as 'inline' to eliminate the function call overhead in the
513 * common case that serialization is not needed.
514 */
515static inline bool
517{
518 /* Nothing to do if this is not a serializable transaction */
520 return false;
521
522 /*
523 * Don't acquire locks or conflict when scanning with a special snapshot.
524 * This excludes things like CLUSTER and REINDEX. They use the wholesale
525 * functions TransferPredicateLocksToHeapRelation() and
526 * CheckTableForSerializableConflictIn() to participate in serialization,
527 * but the scans involved don't need serialization.
528 */
529 if (!IsMVCCSnapshot(snapshot))
530 return false;
531
532 /*
533 * Check if we have just become "RO-safe". If we have, immediately release
534 * all locks as they're not needed anymore. This also resets
535 * MySerializableXact, so that subsequent calls to this function can exit
536 * quickly.
537 *
538 * A transaction is flagged as RO_SAFE if all concurrent R/W transactions
539 * commit without having conflicts out to an earlier snapshot, thus
540 * ensuring that no conflicts are possible for this transaction.
541 */
543 {
544 ReleasePredicateLocks(false, true);
545 return false;
546 }
547
548 /* Check if the relation doesn't participate in predicate locking */
550 return false;
551
552 return true; /* no excuse to skip predicate locking */
553}
554
555/*
556 * Like SerializationNeededForRead(), but called on writes.
557 * The logic is the same, but there is no snapshot and we can't be RO-safe.
558 */
559static inline bool
561{
562 /* Nothing to do if this is not a serializable transaction */
564 return false;
565
566 /* Check if the relation doesn't participate in predicate locking */
568 return false;
569
570 return true; /* no excuse to skip predicate locking */
571}
572
573
574/*------------------------------------------------------------------------*/
575
576/*
577 * These functions are a simple implementation of a list for this specific
578 * type of struct. If there is ever a generalized shared memory list, we
579 * should probably switch to that.
580 */
581static SERIALIZABLEXACT *
582CreatePredXact(void)
583{
585
587 return NULL;
588
592 return sxact;
593}
594
595static void
597{
599
600 dlist_delete(&sxact->xactLink);
602}
603
604/*------------------------------------------------------------------------*/
605
606/*
607 * These functions manage primitive access to the RWConflict pool and lists.
608 */
609static bool
611{
612 dlist_iter iter;
613
614 Assert(reader != writer);
615
616 /* Check the ends of the purported conflict first. */
617 if (SxactIsDoomed(reader)
619 || dlist_is_empty(&reader->outConflicts)
620 || dlist_is_empty(&writer->inConflicts))
621 return false;
622
623 /*
624 * A conflict is possible; walk the list to find out.
625 *
626 * The unconstify is needed as we have no const version of
627 * dlist_foreach().
628 */
629 dlist_foreach(iter, &unconstify(SERIALIZABLEXACT *, reader)->outConflicts)
630 {
632 dlist_container(RWConflictData, outLink, iter.cur);
633
634 if (conflict->sxactIn == writer)
635 return true;
636 }
637
638 /* No conflict found. */
639 return false;
640}
641
642static void
644{
646
647 Assert(reader != writer);
648 Assert(!RWConflictExists(reader, writer));
649
653 errmsg("not enough elements in RWConflictPool to record a read/write conflict"),
654 errhint("You might need to run fewer transactions at a time or increase \"max_connections\".")));
655
657 dlist_delete(&conflict->outLink);
658
659 conflict->sxactOut = reader;
660 conflict->sxactIn = writer;
661 dlist_push_tail(&reader->outConflicts, &conflict->outLink);
662 dlist_push_tail(&writer->inConflicts, &conflict->inLink);
663}
664
665static void
668{
670
674
678 errmsg("not enough elements in RWConflictPool to record a potential read/write conflict"),
679 errhint("You might need to run fewer transactions at a time or increase \"max_connections\".")));
680
682 dlist_delete(&conflict->outLink);
683
684 conflict->sxactOut = activeXact;
685 conflict->sxactIn = roXact;
686 dlist_push_tail(&activeXact->possibleUnsafeConflicts, &conflict->outLink);
687 dlist_push_tail(&roXact->possibleUnsafeConflicts, &conflict->inLink);
688}
689
690static void
692{
693 dlist_delete(&conflict->inLink);
694 dlist_delete(&conflict->outLink);
696}
697
698static void
700{
702
705
706 sxact->flags |= SXACT_FLAG_RO_UNSAFE;
707
708 /*
709 * We know this isn't a safe snapshot, so we can stop looking for other
710 * potential conflicts.
711 */
712 dlist_foreach_modify(iter, &sxact->possibleUnsafeConflicts)
713 {
715 dlist_container(RWConflictData, inLink, iter.cur);
716
717 Assert(!SxactIsReadOnly(conflict->sxactOut));
718 Assert(sxact == conflict->sxactIn);
719
721 }
722}
723
724/*------------------------------------------------------------------------*/
725
726/*
727 * Decide whether a Serial page number is "older" for truncation purposes.
728 * Analogous to CLOGPagePrecedes().
729 */
730static bool
732{
735
740
741 return (TransactionIdPrecedes(xid1, xid2) &&
743}
744
745#ifdef USE_ASSERT_CHECKING
746static void
748{
750 offset = per_page / 2;
753 headPage,
756 oldestXact;
757
758 /* GetNewTransactionId() has assigned the last XID it can safely use. */
759 newestPage = 2 * SLRU_PAGES_PER_SEGMENT - 1; /* nothing special */
760 newestXact = newestPage * per_page + offset;
762 oldestXact = newestXact + 1;
763 oldestXact -= 1U << 31;
764 oldestPage = oldestXact / per_page;
765
766 /*
767 * In this scenario, the SLRU headPage pertains to the last ~1000 XIDs
768 * assigned. oldestXact finishes, ~2B XIDs having elapsed since it
769 * started. Further transactions cause us to summarize oldestXact to
770 * tailPage. Function must return false so SerialAdd() doesn't zero
771 * tailPage (which may contain entries for other old, recently-finished
772 * XIDs) and half the SLRU. Reaching this requires burning ~2B XIDs in
773 * single-user mode, a negligible possibility.
774 */
778
779 /*
780 * In this scenario, the SLRU headPage pertains to oldestXact. We're
781 * summarizing an XID near newestXact. (Assume few other XIDs used
782 * SERIALIZABLE, hence the minimal headPage advancement. Assume
783 * oldestXact was long-running and only recently reached the SLRU.)
784 * Function must return true to make SerialAdd() create targetPage.
785 *
786 * Today's implementation mishandles this case, but it doesn't matter
787 * enough to fix. Verify that the defect affects just one page by
788 * asserting correct treatment of its prior page. Reaching this case
789 * requires burning ~2B XIDs in single-user mode, a negligible
790 * possibility. Moreover, if it does happen, the consequence would be
791 * mild, namely a new transaction failing in SimpleLruReadPage().
792 */
796#if 0
798#endif
799}
800#endif
801
802/*
803 * Initialize for the tracking of old serializable committed xids.
804 */
805static void
806SerialInit(void)
807{
808 bool found;
809
810 /*
811 * Set up SLRU management of the pg_serial data.
812 */
814 SimpleLruInit(SerialSlruCtl, "serializable",
815 serializable_buffers, 0, "pg_serial",
817 SYNC_HANDLER_NONE, false);
818#ifdef USE_ASSERT_CHECKING
820#endif
822
823 /*
824 * Create or attach to the SerialControl structure.
825 */
827 ShmemInitStruct("SerialControlData", sizeof(SerialControlData), &found);
828
829 Assert(found == IsUnderPostmaster);
830 if (!found)
831 {
832 /*
833 * Set control information to reflect empty SLRU.
834 */
840 }
841}
842
843/*
844 * GUC check_hook for serializable_buffers
845 */
846bool
847check_serial_buffers(int *newval, void **extra, GucSource source)
848{
849 return check_slru_buffers("serializable_buffers", newval);
850}
851
852/*
853 * Record a committed read write serializable xid and the minimum
854 * commitSeqNo of any transactions to which this xid had a rw-conflict out.
855 * An invalid commitSeqNo means that there were no conflicts out from xid.
856 */
857static void
859{
862 int slotno;
864 bool isNewPage;
865 LWLock *lock;
866
868
869 targetPage = SerialPage(xid);
871
872 /*
873 * In this routine, we must hold both SerialControlLock and the SLRU bank
874 * lock simultaneously while making the SLRU data catch up with the new
875 * state that we determine.
876 */
878
879 /*
880 * If 'xid' is older than the global xmin (== tailXid), there's no need to
881 * store it, after all. This can happen if the oldest transaction holding
882 * back the global xmin just finished, making 'xid' uninteresting, but
883 * ClearOldPredicateLocks() has not yet run.
884 */
887 {
889 return;
890 }
891
892 /*
893 * If the SLRU is currently unused, zero out the whole active region from
894 * tailXid to headXid before taking it into use. Otherwise zero out only
895 * any new pages that enter the tailXid-headXid range as we advance
896 * headXid.
897 */
898 if (serialControl->headPage < 0)
899 {
901 isNewPage = true;
902 }
903 else
904 {
907 targetPage);
908 }
909
912 serialControl->headXid = xid;
913 if (isNewPage)
915
916 if (isNewPage)
917 {
918 /* Initialize intervening pages; might involve trading locks */
919 for (;;)
920 {
925 break;
927 LWLockRelease(lock);
928 }
929 }
930 else
931 {
934 }
935
937 SerialSlruCtl->shared->page_dirty[slotno] = true;
938
939 LWLockRelease(lock);
941}
942
943/*
944 * Get the minimum commitSeqNo for any conflict out for the given xid. For
945 * a transaction which exists but has no conflict out, InvalidSerCommitSeqNo
946 * will be returned.
947 */
948static SerCommitSeqNo
950{
954 int slotno;
955
957
962
964 return 0;
965
967
970 return 0;
971
972 /*
973 * The following function must be called without holding SLRU bank lock,
974 * but will return with that lock held, which must then be released.
975 */
977 SerialPage(xid), xid);
978 val = SerialValue(slotno, xid);
980 return val;
981}
982
983/*
984 * Call this whenever there is a new xmin for active serializable
985 * transactions. We don't need to keep information on transactions which
986 * precede that. InvalidTransactionId means none active, so everything in
987 * the SLRU can be discarded.
988 */
989static void
991{
993
994 /*
995 * When no sxacts are active, nothing overlaps, set the xid values to
996 * invalid to show that there are no valid entries. Don't clear headPage,
997 * though. A new xmin might still land on that page, and we don't want to
998 * repeatedly zero out the same page.
999 */
1000 if (!TransactionIdIsValid(xid))
1001 {
1005 return;
1006 }
1007
1008 /*
1009 * When we're recovering prepared transactions, the global xmin might move
1010 * backwards depending on the order they're recovered. Normally that's not
1011 * OK, but during recovery no serializable transactions will commit, so
1012 * the SLRU is empty and we can get away with it.
1013 */
1014 if (RecoveryInProgress())
1015 {
1019 {
1020 serialControl->tailXid = xid;
1021 }
1023 return;
1024 }
1025
1028
1029 serialControl->tailXid = xid;
1030
1032}
1033
1034/*
1035 * Perform a checkpoint --- either during shutdown, or on-the-fly
1036 *
1037 * We don't have any data that needs to survive a restart, but this is a
1038 * convenient place to truncate the SLRU.
1039 */
1040void
1042{
1044
1046
1047 /* Exit quickly if the SLRU is currently not in use. */
1048 if (serialControl->headPage < 0)
1049 {
1051 return;
1052 }
1053
1055 {
1057
1059
1060 /*
1061 * It is possible for the tailXid to be ahead of the headXid. This
1062 * occurs if we checkpoint while there are in-progress serializable
1063 * transaction(s) advancing the tail but we are yet to summarize the
1064 * transactions. In this case, we cutoff up to the headPage and the
1065 * next summary will advance the headXid.
1066 */
1068 {
1069 /* We can truncate the SLRU up to the page containing tailXid */
1071 }
1072 else
1074 }
1075 else
1076 {
1077 /*----------
1078 * The SLRU is no longer needed. Truncate to head before we set head
1079 * invalid.
1080 *
1081 * XXX: It's possible that the SLRU is not needed again until XID
1082 * wrap-around has happened, so that the segment containing headPage
1083 * that we leave behind will appear to be new again. In that case it
1084 * won't be removed until XID horizon advances enough to make it
1085 * current again.
1086 *
1087 * XXX: This should happen in vac_truncate_clog(), not in checkpoints.
1088 * Consider this scenario, starting from a system with no in-progress
1089 * transactions and VACUUM FREEZE having maximized oldestXact:
1090 * - Start a SERIALIZABLE transaction.
1091 * - Start, finish, and summarize a SERIALIZABLE transaction, creating
1092 * one SLRU page.
1093 * - Consume XIDs to reach xidStopLimit.
1094 * - Finish all transactions. Due to the long-running SERIALIZABLE
1095 * transaction, earlier checkpoints did not touch headPage. The
1096 * next checkpoint will change it, but that checkpoint happens after
1097 * the end of the scenario.
1098 * - VACUUM to advance XID limits.
1099 * - Consume ~2M XIDs, crossing the former xidWrapLimit.
1100 * - Start, finish, and summarize a SERIALIZABLE transaction.
1101 * SerialAdd() declines to create the targetPage, because headPage
1102 * is not regarded as in the past relative to that targetPage. The
1103 * transaction instigating the summarize fails in
1104 * SimpleLruReadPage().
1105 */
1107 serialControl->headPage = -1;
1108 }
1109
1111
1112 /*
1113 * Truncate away pages that are no longer required. Note that no
1114 * additional locking is required, because this is only called as part of
1115 * a checkpoint, and the validity limits have already been determined.
1116 */
1118
1119 /*
1120 * Write dirty SLRU pages to disk
1121 *
1122 * This is not actually necessary from a correctness point of view. We do
1123 * it merely as a debugging aid.
1124 *
1125 * We're doing this after the truncation to avoid writing pages right
1126 * before deleting the file in which they sit, which would be completely
1127 * pointless.
1128 */
1130}
1131
1132/*------------------------------------------------------------------------*/
1133
1134/*
1135 * PredicateLockShmemInit -- Initialize the predicate locking data structures.
1136 *
1137 * This is called from CreateSharedMemoryAndSemaphores(), which see for
1138 * more comments. In the normal postmaster case, the shared hash tables
1139 * are created here. Backends inherit the pointers
1140 * to the shared tables via fork(). In the EXEC_BACKEND case, each
1141 * backend re-executes this code to obtain pointers to the already existing
1142 * shared hash tables.
1143 */
1144void
1146{
1147 HASHCTL info;
1150 bool found;
1151
1152#ifndef EXEC_BACKEND
1154#endif
1155
1156 /*
1157 * Compute size of predicate lock target hashtable. Note these
1158 * calculations must agree with PredicateLockShmemSize!
1159 */
1161
1162 /*
1163 * Allocate hash table for PREDICATELOCKTARGET structs. This stores
1164 * per-predicate-lock-target information.
1165 */
1166 info.keysize = sizeof(PREDICATELOCKTARGETTAG);
1167 info.entrysize = sizeof(PREDICATELOCKTARGET);
1169
1170 PredicateLockTargetHash = ShmemInitHash("PREDICATELOCKTARGET hash",
1173 &info,
1176
1177 /*
1178 * Reserve a dummy entry in the hash table; we use it to make sure there's
1179 * always one entry available when we need to split or combine a page,
1180 * because running out of space there could mean aborting a
1181 * non-serializable transaction.
1182 */
1183 if (!IsUnderPostmaster)
1184 {
1186 HASH_ENTER, &found);
1187 Assert(!found);
1188 }
1189
1190 /* Pre-calculate the hash and partition lock of the scratch entry */
1193
1194 /*
1195 * Allocate hash table for PREDICATELOCK structs. This stores per
1196 * xact-lock-of-a-target information.
1197 */
1198 info.keysize = sizeof(PREDICATELOCKTAG);
1199 info.entrysize = sizeof(PREDICATELOCK);
1200 info.hash = predicatelock_hash;
1202
1203 /* Assume an average of 2 xacts per target */
1204 max_table_size *= 2;
1205
1206 PredicateLockHash = ShmemInitHash("PREDICATELOCK hash",
1209 &info,
1212
1213 /*
1214 * Compute size for serializable transaction hashtable. Note these
1215 * calculations must agree with PredicateLockShmemSize!
1216 */
1218
1219 /*
1220 * Allocate a list to hold information on transactions participating in
1221 * predicate locking.
1222 *
1223 * Assume an average of 10 predicate locking transactions per backend.
1224 * This allows aggressive cleanup while detail is present before data must
1225 * be summarized for storage in SLRU and the "dummy" transaction.
1226 */
1227 max_table_size *= 10;
1228
1231 sizeof(SERIALIZABLEXACT))));
1232
1233 PredXact = ShmemInitStruct("PredXactList",
1235 &found);
1236 Assert(found == IsUnderPostmaster);
1237 if (!found)
1238 {
1239 int i;
1240
1241 /* clean everything, both the header and the element */
1243
1254 /* Add all elements to available list, clean. */
1255 for (i = 0; i < max_table_size; i++)
1256 {
1260 }
1277 }
1278 /* This never changes, so let's keep a local copy. */
1280
1281 /*
1282 * Allocate hash table for SERIALIZABLEXID structs. This stores per-xid
1283 * information for serializable transactions which have accessed data.
1284 */
1285 info.keysize = sizeof(SERIALIZABLEXIDTAG);
1286 info.entrysize = sizeof(SERIALIZABLEXID);
1287
1288 SerializableXidHash = ShmemInitHash("SERIALIZABLEXID hash",
1291 &info,
1294
1295 /*
1296 * Allocate space for tracking rw-conflicts in lists attached to the
1297 * transactions.
1298 *
1299 * Assume an average of 5 conflicts per transaction. Calculations suggest
1300 * that this will prevent resource exhaustion in even the most pessimal
1301 * loads up to max_connections = 200 with all 200 connections pounding the
1302 * database with serializable transactions. Beyond that, there may be
1303 * occasional transactions canceled when trying to flag conflicts. That's
1304 * probably OK.
1305 */
1306 max_table_size *= 5;
1307
1311
1312 RWConflictPool = ShmemInitStruct("RWConflictPool",
1314 &found);
1315 Assert(found == IsUnderPostmaster);
1316 if (!found)
1317 {
1318 int i;
1319
1320 /* clean everything, including the elements */
1322
1326 /* Add all elements to available list, clean. */
1327 for (i = 0; i < max_table_size; i++)
1328 {
1331 }
1332 }
1333
1334 /*
1335 * Create or attach to the header for the list of finished serializable
1336 * transactions.
1337 */
1339 ShmemInitStruct("FinishedSerializableTransactions",
1340 sizeof(dlist_head),
1341 &found);
1342 Assert(found == IsUnderPostmaster);
1343 if (!found)
1345
1346 /*
1347 * Initialize the SLRU storage for old committed serializable
1348 * transactions.
1349 */
1350 SerialInit();
1351}
1352
1353/*
1354 * Estimate shared-memory space used for predicate lock table
1355 */
1356Size
1358{
1359 Size size = 0;
1360 long max_table_size;
1361
1362 /* predicate lock target hash table */
1365 sizeof(PREDICATELOCKTARGET)));
1366
1367 /* predicate lock hash table */
1368 max_table_size *= 2;
1370 sizeof(PREDICATELOCK)));
1371
1372 /*
1373 * Since NPREDICATELOCKTARGETENTS is only an estimate, add 10% safety
1374 * margin.
1375 */
1376 size = add_size(size, size / 10);
1377
1378 /* transaction list */
1380 max_table_size *= 10;
1381 size = add_size(size, PredXactListDataSize);
1382 size = add_size(size, mul_size((Size) max_table_size,
1383 sizeof(SERIALIZABLEXACT)));
1384
1385 /* transaction xid table */
1387 sizeof(SERIALIZABLEXID)));
1388
1389 /* rw-conflict pool */
1390 max_table_size *= 5;
1392 size = add_size(size, mul_size((Size) max_table_size,
1394
1395 /* Head for list of finished serializable transactions. */
1396 size = add_size(size, sizeof(dlist_head));
1397
1398 /* Shared memory structures for SLRU tracking of old committed xids. */
1399 size = add_size(size, sizeof(SerialControlData));
1401
1402 return size;
1403}
1404
1405
1406/*
1407 * Compute the hash code associated with a PREDICATELOCKTAG.
1408 *
1409 * Because we want to use just one set of partition locks for both the
1410 * PREDICATELOCKTARGET and PREDICATELOCK hash tables, we have to make sure
1411 * that PREDICATELOCKs fall into the same partition number as their
1412 * associated PREDICATELOCKTARGETs. dynahash.c expects the partition number
1413 * to be the low-order bits of the hash code, and therefore a
1414 * PREDICATELOCKTAG's hash code must have the same low-order bits as the
1415 * associated PREDICATELOCKTARGETTAG's hash code. We achieve this with this
1416 * specialized hash function.
1417 */
1418static uint32
1419predicatelock_hash(const void *key, Size keysize)
1420{
1421 const PREDICATELOCKTAG *predicatelocktag = (const PREDICATELOCKTAG *) key;
1423
1424 Assert(keysize == sizeof(PREDICATELOCKTAG));
1425
1426 /* Look into the associated target object, and compute its hash code */
1428
1430}
1431
1432
1433/*
1434 * GetPredicateLockStatusData
1435 * Return a table containing the internal state of the predicate
1436 * lock manager for use in pg_lock_status.
1437 *
1438 * Like GetLockStatusData, this function tries to hold the partition LWLocks
1439 * for as short a time as possible by returning two arrays that simply
1440 * contain the PREDICATELOCKTARGETTAG and SERIALIZABLEXACT for each lock
1441 * table entry. Multiple copies of the same PREDICATELOCKTARGETTAG and
1442 * SERIALIZABLEXACT will likely appear.
1443 */
1446{
1448 int i;
1449 int els,
1450 el;
1453
1455
1456 /*
1457 * To ensure consistency, take simultaneous locks on all partition locks
1458 * in ascending order, then SerializableXactHashLock.
1459 */
1460 for (i = 0; i < NUM_PREDICATELOCK_PARTITIONS; i++)
1463
1464 /* Get number of locks and allocate appropriately-sized arrays. */
1466 data->nelements = els;
1469
1470
1471 /* Scan through PredicateLockHash and copy contents */
1473
1474 el = 0;
1475
1477 {
1478 data->locktags[el] = predlock->tag.myTarget->tag;
1479 data->xacts[el] = *predlock->tag.myXact;
1480 el++;
1481 }
1482
1483 Assert(el == els);
1484
1485 /* Release locks in reverse order */
1487 for (i = NUM_PREDICATELOCK_PARTITIONS - 1; i >= 0; i--)
1489
1490 return data;
1491}
1492
1493/*
1494 * Free up shared memory structures by pushing the oldest sxact (the one at
1495 * the front of the SummarizeOldestCommittedSxact queue) into summary form.
1496 * Each call will free exactly one SERIALIZABLEXACT structure and may also
1497 * free one or more of these structures: SERIALIZABLEXID, PREDICATELOCK,
1498 * PREDICATELOCKTARGET, RWConflictData.
1499 */
1500static void
1502{
1504
1506
1507 /*
1508 * This function is only called if there are no sxact slots available.
1509 * Some of them must belong to old, already-finished transactions, so
1510 * there should be something in FinishedSerializableTransactions list that
1511 * we can summarize. However, there's a race condition: while we were not
1512 * holding any locks, a transaction might have ended and cleaned up all
1513 * the finished sxact entries already, freeing up their sxact slots. In
1514 * that case, we have nothing to do here. The caller will find one of the
1515 * slots released by the other backend when it retries.
1516 */
1518 {
1520 return;
1521 }
1522
1523 /*
1524 * Grab the first sxact off the finished list -- this will be the earliest
1525 * commit. Remove it from the list.
1526 */
1529 dlist_delete_thoroughly(&sxact->finishedLink);
1530
1531 /* Add to SLRU summary information. */
1534 ? sxact->SeqNo.earliestOutConflictCommit : InvalidSerCommitSeqNo);
1535
1536 /* Summarize and release the detail. */
1537 ReleaseOneSerializableXact(sxact, false, true);
1538
1540}
1541
1542/*
1543 * GetSafeSnapshot
1544 * Obtain and register a snapshot for a READ ONLY DEFERRABLE
1545 * transaction. Ensures that the snapshot is "safe", i.e. a
1546 * read-only transaction running on it can execute serializably
1547 * without further checks. This requires waiting for concurrent
1548 * transactions to complete, and retrying with a new snapshot if
1549 * one of them could possibly create a conflict.
1550 *
1551 * As with GetSerializableTransactionSnapshot (which this is a subroutine
1552 * for), the passed-in Snapshot pointer should reference a static data
1553 * area that can safely be passed to GetSnapshotData.
1554 */
1555static Snapshot
1557{
1558 Snapshot snapshot;
1559
1561
1562 while (true)
1563 {
1564 /*
1565 * GetSerializableTransactionSnapshotInt is going to call
1566 * GetSnapshotData, so we need to provide it the static snapshot area
1567 * our caller passed to us. The pointer returned is actually the same
1568 * one passed to it, but we avoid assuming that here.
1569 */
1571 NULL, InvalidPid);
1572
1574 return snapshot; /* no concurrent r/w xacts; it's safe */
1575
1577
1578 /*
1579 * Wait for concurrent transactions to finish. Stop early if one of
1580 * them marked us as conflicted.
1581 */
1585 {
1589 }
1591
1593 {
1595 break; /* success */
1596 }
1597
1599
1600 /* else, need to retry... */
1603 errmsg_internal("deferrable snapshot was unsafe; trying a new one")));
1604 ReleasePredicateLocks(false, false);
1605 }
1606
1607 /*
1608 * Now we have a safe snapshot, so we don't need to do any further checks.
1609 */
1611 ReleasePredicateLocks(false, true);
1612
1613 return snapshot;
1614}
1615
1616/*
1617 * GetSafeSnapshotBlockingPids
1618 * If the specified process is currently blocked in GetSafeSnapshot,
1619 * write the process IDs of all processes that it is blocked by
1620 * into the caller-supplied buffer output[]. The list is truncated at
1621 * output_size, and the number of PIDs written into the buffer is
1622 * returned. Returns zero if the given PID is not currently blocked
1623 * in GetSafeSnapshot.
1624 */
1625int
1627{
1628 int num_written = 0;
1629 dlist_iter iter;
1631
1633
1634 /* Find blocked_pid's SERIALIZABLEXACT by linear search. */
1636 {
1638 dlist_container(SERIALIZABLEXACT, xactLink, iter.cur);
1639
1640 if (sxact->pid == blocked_pid)
1641 {
1643 break;
1644 }
1645 }
1646
1647 /* Did we find it, and is it currently waiting in GetSafeSnapshot? */
1649 {
1650 /* Traverse the list of possible unsafe conflicts collecting PIDs. */
1651 dlist_foreach(iter, &blocking_sxact->possibleUnsafeConflicts)
1652 {
1654 dlist_container(RWConflictData, inLink, iter.cur);
1655
1656 output[num_written++] = possibleUnsafeConflict->sxactOut->pid;
1657
1658 if (num_written >= output_size)
1659 break;
1660 }
1661 }
1662
1664
1665 return num_written;
1666}
1667
1668/*
1669 * Acquire a snapshot that can be used for the current transaction.
1670 *
1671 * Make sure we have a SERIALIZABLEXACT reference in MySerializableXact.
1672 * It should be current for this process and be contained in PredXact.
1673 *
1674 * The passed-in Snapshot pointer should reference a static data area that
1675 * can safely be passed to GetSnapshotData. The return value is actually
1676 * always this same pointer; no new snapshot data structure is allocated
1677 * within this function.
1678 */
1681{
1683
1684 /*
1685 * Can't use serializable mode while recovery is still active, as it is,
1686 * for example, on a hot standby. We could get here despite the check in
1687 * check_transaction_isolation() if default_transaction_isolation is set
1688 * to serializable, so phrase the hint accordingly.
1689 */
1690 if (RecoveryInProgress())
1691 ereport(ERROR,
1693 errmsg("cannot use serializable mode in a hot standby"),
1694 errdetail("\"default_transaction_isolation\" is set to \"serializable\"."),
1695 errhint("You can use \"SET default_transaction_isolation = 'repeatable read'\" to change the default.")));
1696
1697 /*
1698 * A special optimization is available for SERIALIZABLE READ ONLY
1699 * DEFERRABLE transactions -- we can wait for a suitable snapshot and
1700 * thereby avoid all SSI overhead once it's running.
1701 */
1703 return GetSafeSnapshot(snapshot);
1704
1706 NULL, InvalidPid);
1707}
1708
1709/*
1710 * Import a snapshot to be used for the current transaction.
1711 *
1712 * This is nearly the same as GetSerializableTransactionSnapshot, except that
1713 * we don't take a new snapshot, but rather use the data we're handed.
1714 *
1715 * The caller must have verified that the snapshot came from a serializable
1716 * transaction; and if we're read-write, the source transaction must not be
1717 * read-only.
1718 */
1719void
1722 int sourcepid)
1723{
1725
1726 /*
1727 * If this is called by parallel.c in a parallel worker, we don't want to
1728 * create a SERIALIZABLEXACT just yet because the leader's
1729 * SERIALIZABLEXACT will be installed with AttachSerializableXact(). We
1730 * also don't want to reject SERIALIZABLE READ ONLY DEFERRABLE in this
1731 * case, because the leader has already determined that the snapshot it
1732 * has passed us is safe. So there is nothing for us to do.
1733 */
1734 if (IsParallelWorker())
1735 return;
1736
1737 /*
1738 * We do not allow SERIALIZABLE READ ONLY DEFERRABLE transactions to
1739 * import snapshots, since there's no way to wait for a safe snapshot when
1740 * we're using the snap we're told to. (XXX instead of throwing an error,
1741 * we could just ignore the XactDeferrable flag?)
1742 */
1744 ereport(ERROR,
1746 errmsg("a snapshot-importing transaction must not be READ ONLY DEFERRABLE")));
1747
1749 sourcepid);
1750}
1751
1752/*
1753 * Guts of GetSerializableTransactionSnapshot
1754 *
1755 * If sourcevxid is valid, this is actually an import operation and we should
1756 * skip calling GetSnapshotData, because the snapshot contents are already
1757 * loaded up. HOWEVER: to avoid race conditions, we must check that the
1758 * source xact is still running after we acquire SerializableXactHashLock.
1759 * We do that by calling ProcArrayInstallImportedXmin.
1760 */
1761static Snapshot
1764 int sourcepid)
1765{
1766 PGPROC *proc;
1769 *othersxact;
1770
1771 /* We only do this for serializable transactions. Once. */
1773
1775
1776 /*
1777 * Since all parts of a serializable transaction must use the same
1778 * snapshot, it is too late to establish one after a parallel operation
1779 * has begun.
1780 */
1781 if (IsInParallelMode())
1782 elog(ERROR, "cannot establish serializable snapshot during a parallel operation");
1783
1784 proc = MyProc;
1785 Assert(proc != NULL);
1786 GET_VXID_FROM_PGPROC(vxid, *proc);
1787
1788 /*
1789 * First we get the sxact structure, which may involve looping and access
1790 * to the "finished" list to free a structure for use.
1791 *
1792 * We must hold SerializableXactHashLock when taking/checking the snapshot
1793 * to avoid race conditions, for much the same reasons that
1794 * GetSnapshotData takes the ProcArrayLock. Since we might have to
1795 * release SerializableXactHashLock to call SummarizeOldestCommittedSxact,
1796 * this means we have to create the sxact first, which is a bit annoying
1797 * (in particular, an elog(ERROR) in procarray.c would cause us to leak
1798 * the sxact). Consider refactoring to avoid this.
1799 */
1800#ifdef TEST_SUMMARIZE_SERIAL
1802#endif
1804 do
1805 {
1807 /* If null, push out committed sxact to SLRU summary & retry. */
1808 if (!sxact)
1809 {
1813 }
1814 } while (!sxact);
1815
1816 /* Get the snapshot, or check that it's safe to use */
1817 if (!sourcevxid)
1818 snapshot = GetSnapshotData(snapshot);
1819 else if (!ProcArrayInstallImportedXmin(snapshot->xmin, sourcevxid))
1820 {
1823 ereport(ERROR,
1825 errmsg("could not import the requested snapshot"),
1826 errdetail("The source process with PID %d is not running anymore.",
1827 sourcepid)));
1828 }
1829
1830 /*
1831 * If there are no serializable transactions which are not read-only, we
1832 * can "opt out" of predicate locking and conflict checking for a
1833 * read-only transaction.
1834 *
1835 * The reason this is safe is that a read-only transaction can only become
1836 * part of a dangerous structure if it overlaps a writable transaction
1837 * which in turn overlaps a writable transaction which committed before
1838 * the read-only transaction started. A new writable transaction can
1839 * overlap this one, but it can't meet the other condition of overlapping
1840 * a transaction which committed before this one started.
1841 */
1843 {
1846 return snapshot;
1847 }
1848
1849 /* Initialize the structure. */
1850 sxact->vxid = vxid;
1851 sxact->SeqNo.lastCommitBeforeSnapshot = PredXact->LastSxactCommitSeqNo;
1852 sxact->prepareSeqNo = InvalidSerCommitSeqNo;
1853 sxact->commitSeqNo = InvalidSerCommitSeqNo;
1854 dlist_init(&(sxact->outConflicts));
1855 dlist_init(&(sxact->inConflicts));
1856 dlist_init(&(sxact->possibleUnsafeConflicts));
1857 sxact->topXid = GetTopTransactionIdIfAny();
1858 sxact->finishedBefore = InvalidTransactionId;
1859 sxact->xmin = snapshot->xmin;
1860 sxact->pid = MyProcPid;
1861 sxact->pgprocno = MyProcNumber;
1862 dlist_init(&sxact->predicateLocks);
1863 dlist_node_init(&sxact->finishedLink);
1864 sxact->flags = 0;
1865 if (XactReadOnly)
1866 {
1867 dlist_iter iter;
1868
1869 sxact->flags |= SXACT_FLAG_READ_ONLY;
1870
1871 /*
1872 * Register all concurrent r/w transactions as possible conflicts; if
1873 * all of them commit without any outgoing conflicts to earlier
1874 * transactions then this snapshot can be deemed safe (and we can run
1875 * without tracking predicate locks).
1876 */
1878 {
1880
1884 {
1886 }
1887 }
1888
1889 /*
1890 * If we didn't find any possibly unsafe conflicts because every
1891 * uncommitted writable transaction turned out to be doomed, then we
1892 * can "opt out" immediately. See comments above the earlier check
1893 * for PredXact->WritableSxactCount == 0.
1894 */
1895 if (dlist_is_empty(&sxact->possibleUnsafeConflicts))
1896 {
1899 return snapshot;
1900 }
1901 }
1902 else
1903 {
1907 }
1908
1909 /* Maintain serializable global xmin info. */
1911 {
1913 PredXact->SxactGlobalXmin = snapshot->xmin;
1915 SerialSetActiveSerXmin(snapshot->xmin);
1916 }
1917 else if (TransactionIdEquals(snapshot->xmin, PredXact->SxactGlobalXmin))
1918 {
1921 }
1922 else
1923 {
1925 }
1926
1928 MyXactDidWrite = false; /* haven't written anything yet */
1929
1931
1933
1934 return snapshot;
1935}
1936
1937static void
1939{
1941
1942 /* Initialize the backend-local hash table of parent locks */
1944 hash_ctl.keysize = sizeof(PREDICATELOCKTARGETTAG);
1945 hash_ctl.entrysize = sizeof(LOCALPREDICATELOCK);
1946 LocalPredicateLockHash = hash_create("Local predicate lock",
1948 &hash_ctl,
1950}
1951
1952/*
1953 * Register the top level XID in SerializableXidHash.
1954 * Also store it for easy reference in MySerializableXact.
1955 */
1956void
1958{
1961 bool found;
1962
1963 /*
1964 * If we're not tracking predicate lock data for this transaction, we
1965 * should ignore the request and return quickly.
1966 */
1968 return;
1969
1970 /* We should have a valid XID and be at the top level. */
1972
1974
1975 /* This should only be done once per transaction. */
1977
1979
1980 sxidtag.xid = xid;
1982 &sxidtag,
1983 HASH_ENTER, &found);
1984 Assert(!found);
1985
1986 /* Initialize the structure. */
1987 sxid->myXact = MySerializableXact;
1989}
1990
1991
1992/*
1993 * Check whether there are any predicate locks held by any transaction
1994 * for the page at the given block number.
1995 *
1996 * Note that the transaction may be completed but not yet subject to
1997 * cleanup due to overlapping serializable transactions. This must
1998 * return valid information regardless of transaction isolation level.
1999 *
2000 * Also note that this doesn't check for a conflicting relation lock,
2001 * just a lock specifically on the given page.
2002 *
2003 * One use is to support proper behavior during GiST index vacuum.
2004 */
2005bool
2007{
2011 PREDICATELOCKTARGET *target;
2012
2014 relation->rd_locator.dbOid,
2015 relation->rd_id,
2016 blkno);
2017
2021 target = (PREDICATELOCKTARGET *)
2024 HASH_FIND, NULL);
2026
2027 return (target != NULL);
2028}
2029
2030
2031/*
2032 * Check whether a particular lock is held by this transaction.
2033 *
2034 * Important note: this function may return false even if the lock is
2035 * being held, because it uses the local lock table which is not
2036 * updated if another transaction modifies our lock list (e.g. to
2037 * split an index page). It can also return true when a coarser
2038 * granularity lock that covers this target is being held. Be careful
2039 * to only use this function in circumstances where such errors are
2040 * acceptable!
2041 */
2042static bool
2044{
2045 LOCALPREDICATELOCK *lock;
2046
2047 /* check local hash table */
2049 targettag,
2050 HASH_FIND, NULL);
2051
2052 if (!lock)
2053 return false;
2054
2055 /*
2056 * Found entry in the table, but still need to check whether it's actually
2057 * held -- it could just be a parent of some held lock.
2058 */
2059 return lock->held;
2060}
2061
2062/*
2063 * Return the parent lock tag in the lock hierarchy: the next coarser
2064 * lock that covers the provided tag.
2065 *
2066 * Returns true and sets *parent to the parent tag if one exists,
2067 * returns false if none exists.
2068 */
2069static bool
2071 PREDICATELOCKTARGETTAG *parent)
2072{
2073 switch (GET_PREDICATELOCKTARGETTAG_TYPE(*tag))
2074 {
2076 /* relation locks have no parent lock */
2077 return false;
2078
2079 case PREDLOCKTAG_PAGE:
2080 /* parent lock is relation lock */
2084
2085 return true;
2086
2087 case PREDLOCKTAG_TUPLE:
2088 /* parent lock is page lock */
2093 return true;
2094 }
2095
2096 /* not reachable */
2097 Assert(false);
2098 return false;
2099}
2100
2101/*
2102 * Check whether the lock we are considering is already covered by a
2103 * coarser lock for our transaction.
2104 *
2105 * Like PredicateLockExists, this function might return a false
2106 * negative, but it will never return a false positive.
2107 */
2108static bool
2110{
2112 parenttag;
2113
2115
2116 /* check parents iteratively until no more */
2118 {
2121 return true;
2122 }
2123
2124 /* no more parents to check; lock is not covered */
2125 return false;
2126}
2127
2128/*
2129 * Remove the dummy entry from the predicate lock target hash, to free up some
2130 * scratch space. The caller must be holding SerializablePredicateListLock,
2131 * and must restore the entry with RestoreScratchTarget() before releasing the
2132 * lock.
2133 *
2134 * If lockheld is true, the caller is already holding the partition lock
2135 * of the partition containing the scratch entry.
2136 */
2137static void
2139{
2140 bool found;
2141
2143
2144 if (!lockheld)
2149 HASH_REMOVE, &found);
2150 Assert(found);
2151 if (!lockheld)
2153}
2154
2155/*
2156 * Re-insert the dummy entry in predicate lock target hash.
2157 */
2158static void
2160{
2161 bool found;
2162
2164
2165 if (!lockheld)
2170 HASH_ENTER, &found);
2171 Assert(!found);
2172 if (!lockheld)
2174}
2175
2176/*
2177 * Check whether the list of related predicate locks is empty for a
2178 * predicate lock target, and remove the target if it is.
2179 */
2180static void
2182{
2184
2186
2187 /* Can't remove it until no locks at this target. */
2188 if (!dlist_is_empty(&target->predicateLocks))
2189 return;
2190
2191 /* Actually remove the target. */
2193 &target->tag,
2195 HASH_REMOVE, NULL);
2196 Assert(rmtarget == target);
2197}
2198
2199/*
2200 * Delete child target locks owned by this process.
2201 * This implementation is assuming that the usage of each target tag field
2202 * is uniform. No need to make this hard if we don't have to.
2203 *
2204 * We acquire an LWLock in the case of parallel mode, because worker
2205 * backends have access to the leader's SERIALIZABLEXACT. Otherwise,
2206 * we aren't acquiring LWLocks for the predicate lock or lock
2207 * target structures associated with this transaction unless we're going
2208 * to modify them, because no other process is permitted to modify our
2209 * locks.
2210 */
2211static void
2213{
2216 dlist_mutable_iter iter;
2217
2220 if (IsInParallelMode())
2221 LWLockAcquire(&sxact->perXactPredicateListLock, LW_EXCLUSIVE);
2222
2223 dlist_foreach_modify(iter, &sxact->predicateLocks)
2224 {
2228
2229 predlock = dlist_container(PREDICATELOCK, xactLink, iter.cur);
2230
2231 oldlocktag = predlock->tag;
2232 Assert(oldlocktag.myXact == sxact);
2233 oldtarget = oldlocktag.myTarget;
2234 oldtargettag = oldtarget->tag;
2235
2237 {
2241
2244
2246
2247 dlist_delete(&predlock->xactLink);
2248 dlist_delete(&predlock->targetLink);
2251 &oldlocktag,
2254 HASH_REMOVE, NULL);
2256
2258
2260
2262 }
2263 }
2264 if (IsInParallelMode())
2265 LWLockRelease(&sxact->perXactPredicateListLock);
2267}
2268
2269/*
2270 * Returns the promotion limit for a given predicate lock target. This is the
2271 * max number of descendant locks allowed before promoting to the specified
2272 * tag. Note that the limit includes non-direct descendants (e.g., both tuples
2273 * and pages for a relation lock).
2274 *
2275 * Currently the default limit is 2 for a page lock, and half of the value of
2276 * max_pred_locks_per_transaction - 1 for a relation lock, to match behavior
2277 * of earlier releases when upgrading.
2278 *
2279 * TODO SSI: We should probably add additional GUCs to allow a maximum ratio
2280 * of page and tuple locks based on the pages in a relation, and the maximum
2281 * ratio of tuple locks to tuples in a page. This would provide more
2282 * generally "balanced" allocation of locks to where they are most useful,
2283 * while still allowing the absolute numbers to prevent one relation from
2284 * tying up all predicate lock resources.
2285 */
2286static int
2288{
2289 switch (GET_PREDICATELOCKTARGETTAG_TYPE(*tag))
2290 {
2296
2297 case PREDLOCKTAG_PAGE:
2299
2300 case PREDLOCKTAG_TUPLE:
2301
2302 /*
2303 * not reachable: nothing is finer-granularity than a tuple, so we
2304 * should never try to promote to it.
2305 */
2306 Assert(false);
2307 return 0;
2308 }
2309
2310 /* not reachable */
2311 Assert(false);
2312 return 0;
2313}
2314
2315/*
2316 * For all ancestors of a newly-acquired predicate lock, increment
2317 * their child count in the parent hash table. If any of them have
2318 * more descendants than their promotion threshold, acquire the
2319 * coarsest such lock.
2320 *
2321 * Returns true if a parent lock was acquired and false otherwise.
2322 */
2323static bool
2325{
2327 nexttag,
2330 bool found,
2331 promote;
2332
2333 promote = false;
2334
2335 targettag = *reqtag;
2336
2337 /* check parents iteratively */
2339 {
2342 &targettag,
2343 HASH_ENTER,
2344 &found);
2345 if (!found)
2346 {
2347 parentlock->held = false;
2348 parentlock->childLocks = 1;
2349 }
2350 else
2351 parentlock->childLocks++;
2352
2353 if (parentlock->childLocks >
2355 {
2356 /*
2357 * We should promote to this parent lock. Continue to check its
2358 * ancestors, however, both to get their child counts right and to
2359 * check whether we should just go ahead and promote to one of
2360 * them.
2361 */
2363 promote = true;
2364 }
2365 }
2366
2367 if (promote)
2368 {
2369 /* acquire coarsest ancestor eligible for promotion */
2371 return true;
2372 }
2373 else
2374 return false;
2375}
2376
2377/*
2378 * When releasing a lock, decrement the child count on all ancestor
2379 * locks.
2380 *
2381 * This is called only when releasing a lock via
2382 * DeleteChildTargetLocks (i.e. when a lock becomes redundant because
2383 * we've acquired its parent, possibly due to promotion) or when a new
2384 * MVCC write lock makes the predicate lock unnecessary. There's no
2385 * point in calling it when locks are released at transaction end, as
2386 * this information is no longer needed.
2387 */
2388static void
2390{
2392 nexttag;
2393
2395
2397 {
2401
2407 HASH_FIND, NULL);
2408
2409 /*
2410 * There's a small chance the parent lock doesn't exist in the lock
2411 * table. This can happen if we prematurely removed it because an
2412 * index split caused the child refcount to be off.
2413 */
2414 if (parentlock == NULL)
2415 continue;
2416
2417 parentlock->childLocks--;
2418
2419 /*
2420 * Under similar circumstances the parent lock's refcount might be
2421 * zero. This only happens if we're holding that lock (otherwise we
2422 * would have removed the entry).
2423 */
2424 if (parentlock->childLocks < 0)
2425 {
2426 Assert(parentlock->held);
2427 parentlock->childLocks = 0;
2428 }
2429
2430 if ((parentlock->childLocks == 0) && (!parentlock->held))
2431 {
2435 HASH_REMOVE, NULL);
2437 }
2438 }
2439}
2440
2441/*
2442 * Indicate that a predicate lock on the given target is held by the
2443 * specified transaction. Has no effect if the lock is already held.
2444 *
2445 * This updates the lock table and the sxact's lock list, and creates
2446 * the lock target if necessary, but does *not* do anything related to
2447 * granularity promotion or the local lock table. See
2448 * PredicateLockAcquire for that.
2449 */
2450static void
2454{
2455 PREDICATELOCKTARGET *target;
2456 PREDICATELOCKTAG locktag;
2457 PREDICATELOCK *lock;
2459 bool found;
2460
2462
2464 if (IsInParallelMode())
2465 LWLockAcquire(&sxact->perXactPredicateListLock, LW_EXCLUSIVE);
2467
2468 /* Make sure that the target is represented. */
2469 target = (PREDICATELOCKTARGET *)
2472 HASH_ENTER_NULL, &found);
2473 if (!target)
2474 ereport(ERROR,
2476 errmsg("out of shared memory"),
2477 errhint("You might need to increase \"%s\".", "max_pred_locks_per_transaction")));
2478 if (!found)
2479 dlist_init(&target->predicateLocks);
2480
2481 /* We've got the sxact and target, make sure they're joined. */
2482 locktag.myTarget = target;
2483 locktag.myXact = sxact;
2484 lock = (PREDICATELOCK *)
2487 HASH_ENTER_NULL, &found);
2488 if (!lock)
2489 ereport(ERROR,
2491 errmsg("out of shared memory"),
2492 errhint("You might need to increase \"%s\".", "max_pred_locks_per_transaction")));
2493
2494 if (!found)
2495 {
2496 dlist_push_tail(&target->predicateLocks, &lock->targetLink);
2497 dlist_push_tail(&sxact->predicateLocks, &lock->xactLink);
2499 }
2500
2502 if (IsInParallelMode())
2503 LWLockRelease(&sxact->perXactPredicateListLock);
2505}
2506
2507/*
2508 * Acquire a predicate lock on the specified target for the current
2509 * connection if not already held. This updates the local lock table
2510 * and uses it to implement granularity promotion. It will consolidate
2511 * multiple locks into a coarser lock if warranted, and will release
2512 * any finer-grained locks covered by the new one.
2513 */
2514static void
2516{
2518 bool found;
2520
2521 /* Do we have the lock already, or a covering lock? */
2523 return;
2524
2526 return;
2527
2528 /* the same hash and LW lock apply to the lock target and the local lock. */
2530
2531 /* Acquire lock in local table */
2535 HASH_ENTER, &found);
2536 locallock->held = true;
2537 if (!found)
2538 locallock->childLocks = 0;
2539
2540 /* Actually create the lock */
2542
2543 /*
2544 * Lock has been acquired. Check whether it should be promoted to a
2545 * coarser granularity, or whether there are finer-granularity locks to
2546 * clean up.
2547 */
2549 {
2550 /*
2551 * Lock request was promoted to a coarser-granularity lock, and that
2552 * lock was acquired. It will delete this lock and any of its
2553 * children, so we're done.
2554 */
2555 }
2556 else
2557 {
2558 /* Clean up any finer-granularity locks */
2561 }
2562}
2563
2564
2565/*
2566 * PredicateLockRelation
2567 *
2568 * Gets a predicate lock at the relation level.
2569 * Skip if not in full serializable transaction isolation level.
2570 * Skip if this is a temporary table.
2571 * Clear any finer-grained predicate locks this session has on the relation.
2572 */
2573void
2574PredicateLockRelation(Relation relation, Snapshot snapshot)
2575{
2577
2578 if (!SerializationNeededForRead(relation, snapshot))
2579 return;
2580
2582 relation->rd_locator.dbOid,
2583 relation->rd_id);
2585}
2586
2587/*
2588 * PredicateLockPage
2589 *
2590 * Gets a predicate lock at the page level.
2591 * Skip if not in full serializable transaction isolation level.
2592 * Skip if this is a temporary table.
2593 * Skip if a coarser predicate lock already covers this page.
2594 * Clear any finer-grained predicate locks this session has on the relation.
2595 */
2596void
2597PredicateLockPage(Relation relation, BlockNumber blkno, Snapshot snapshot)
2598{
2600
2601 if (!SerializationNeededForRead(relation, snapshot))
2602 return;
2603
2605 relation->rd_locator.dbOid,
2606 relation->rd_id,
2607 blkno);
2609}
2610
2611/*
2612 * PredicateLockTID
2613 *
2614 * Gets a predicate lock at the tuple level.
2615 * Skip if not in full serializable transaction isolation level.
2616 * Skip if this is a temporary table.
2617 */
2618void
2619PredicateLockTID(Relation relation, const ItemPointerData *tid, Snapshot snapshot,
2621{
2623
2624 if (!SerializationNeededForRead(relation, snapshot))
2625 return;
2626
2627 /*
2628 * Return if this xact wrote it.
2629 */
2630 if (relation->rd_index == NULL)
2631 {
2632 /* If we wrote it; we already have a write lock. */
2634 return;
2635 }
2636
2637 /*
2638 * Do quick-but-not-definitive test for a relation lock first. This will
2639 * never cause a return when the relation is *not* locked, but will
2640 * occasionally let the check continue when there really *is* a relation
2641 * level lock.
2642 */
2644 relation->rd_locator.dbOid,
2645 relation->rd_id);
2646 if (PredicateLockExists(&tag))
2647 return;
2648
2650 relation->rd_locator.dbOid,
2651 relation->rd_id,
2655}
2656
2657
2658/*
2659 * DeleteLockTarget
2660 *
2661 * Remove a predicate lock target along with any locks held for it.
2662 *
2663 * Caller must hold SerializablePredicateListLock and the
2664 * appropriate hash partition lock for the target.
2665 */
2666static void
2668{
2669 dlist_mutable_iter iter;
2670
2672 LW_EXCLUSIVE));
2674
2676
2677 dlist_foreach_modify(iter, &target->predicateLocks)
2678 {
2680 dlist_container(PREDICATELOCK, targetLink, iter.cur);
2681 bool found;
2682
2683 dlist_delete(&(predlock->xactLink));
2684 dlist_delete(&(predlock->targetLink));
2685
2688 &predlock->tag,
2691 HASH_REMOVE, &found);
2692 Assert(found);
2693 }
2695
2696 /* Remove the target itself, if possible. */
2698}
2699
2700
2701/*
2702 * TransferPredicateLocksToNewTarget
2703 *
2704 * Move or copy all the predicate locks for a lock target, for use by
2705 * index page splits/combines and other things that create or replace
2706 * lock targets. If 'removeOld' is true, the old locks and the target
2707 * will be removed.
2708 *
2709 * Returns true on success, or false if we ran out of shared memory to
2710 * allocate the new target or locks. Guaranteed to always succeed if
2711 * removeOld is set (by using the scratch entry in PredicateLockTargetHash
2712 * for scratch space).
2713 *
2714 * Warning: the "removeOld" option should be used only with care,
2715 * because this function does not (indeed, can not) update other
2716 * backends' LocalPredicateLockHash. If we are only adding new
2717 * entries, this is not a problem: the local lock table is used only
2718 * as a hint, so missing entries for locks that are held are
2719 * OK. Having entries for locks that are no longer held, as can happen
2720 * when using "removeOld", is not in general OK. We can only use it
2721 * safely when replacing a lock with a coarser-granularity lock that
2722 * covers it, or if we are absolutely certain that no one will need to
2723 * refer to that lock in the future.
2724 *
2725 * Caller must hold SerializablePredicateListLock exclusively.
2726 */
2727static bool
2730 bool removeOld)
2731{
2737 bool found;
2738 bool outOfShmem = false;
2739
2741 LW_EXCLUSIVE));
2742
2747
2748 if (removeOld)
2749 {
2750 /*
2751 * Remove the dummy entry to give us scratch space, so we know we'll
2752 * be able to create the new lock target.
2753 */
2754 RemoveScratchTarget(false);
2755 }
2756
2757 /*
2758 * We must get the partition locks in ascending sequence to avoid
2759 * deadlocks. If old and new partitions are the same, we must request the
2760 * lock only once.
2761 */
2763 {
2767 }
2769 {
2773 }
2774 else
2776
2777 /*
2778 * Look for the old target. If not found, that's OK; no predicate locks
2779 * are affected, so we can just clean up and return. If it does exist,
2780 * walk its list of predicate locks and move or copy them to the new
2781 * target.
2782 */
2784 &oldtargettag,
2786 HASH_FIND, NULL);
2787
2788 if (oldtarget)
2789 {
2792 dlist_mutable_iter iter;
2793
2795 &newtargettag,
2797 HASH_ENTER_NULL, &found);
2798
2799 if (!newtarget)
2800 {
2801 /* Failed to allocate due to insufficient shmem */
2802 outOfShmem = true;
2803 goto exit;
2804 }
2805
2806 /* If we created a new entry, initialize it */
2807 if (!found)
2808 dlist_init(&newtarget->predicateLocks);
2809
2810 newpredlocktag.myTarget = newtarget;
2811
2812 /*
2813 * Loop through all the locks on the old target, replacing them with
2814 * locks on the new target.
2815 */
2817
2818 dlist_foreach_modify(iter, &oldtarget->predicateLocks)
2819 {
2821 dlist_container(PREDICATELOCK, targetLink, iter.cur);
2824
2825 newpredlocktag.myXact = oldpredlock->tag.myXact;
2826
2827 if (removeOld)
2828 {
2829 dlist_delete(&(oldpredlock->xactLink));
2830 dlist_delete(&(oldpredlock->targetLink));
2831
2834 &oldpredlock->tag,
2837 HASH_REMOVE, &found);
2838 Assert(found);
2839 }
2840
2847 &found);
2848 if (!newpredlock)
2849 {
2850 /* Out of shared memory. Undo what we've done so far. */
2853 outOfShmem = true;
2854 goto exit;
2855 }
2856 if (!found)
2857 {
2858 dlist_push_tail(&(newtarget->predicateLocks),
2859 &(newpredlock->targetLink));
2860 dlist_push_tail(&(newpredlocktag.myXact->predicateLocks),
2861 &(newpredlock->xactLink));
2862 newpredlock->commitSeqNo = oldCommitSeqNo;
2863 }
2864 else
2865 {
2866 if (newpredlock->commitSeqNo < oldCommitSeqNo)
2867 newpredlock->commitSeqNo = oldCommitSeqNo;
2868 }
2869
2870 Assert(newpredlock->commitSeqNo != 0);
2871 Assert((newpredlock->commitSeqNo == InvalidSerCommitSeqNo)
2872 || (newpredlock->tag.myXact == OldCommittedSxact));
2873 }
2875
2876 if (removeOld)
2877 {
2878 Assert(dlist_is_empty(&oldtarget->predicateLocks));
2880 }
2881 }
2882
2883
2884exit:
2885 /* Release partition locks in reverse order of acquisition. */
2887 {
2890 }
2892 {
2895 }
2896 else
2898
2899 if (removeOld)
2900 {
2901 /* We shouldn't run out of memory if we're moving locks */
2903
2904 /* Put the scratch entry back */
2905 RestoreScratchTarget(false);
2906 }
2907
2908 return !outOfShmem;
2909}
2910
2911/*
2912 * Drop all predicate locks of any granularity from the specified relation,
2913 * which can be a heap relation or an index relation. If 'transfer' is true,
2914 * acquire a relation lock on the heap for any transactions with any lock(s)
2915 * on the specified relation.
2916 *
2917 * This requires grabbing a lot of LW locks and scanning the entire lock
2918 * target table for matches. That makes this more expensive than most
2919 * predicate lock management functions, but it will only be called for DDL
2920 * type commands that are expensive anyway, and there are fast returns when
2921 * no serializable transactions are active or the relation is temporary.
2922 *
2923 * We don't use the TransferPredicateLocksToNewTarget function because it
2924 * acquires its own locks on the partitions of the two targets involved,
2925 * and we'll already be holding all partition locks.
2926 *
2927 * We can't throw an error from here, because the call could be from a
2928 * transaction which is not serializable.
2929 *
2930 * NOTE: This is currently only called with transfer set to true, but that may
2931 * change. If we decide to clean up the locks from a table on commit of a
2932 * transaction which executed DROP TABLE, the false condition will be useful.
2933 */
2934static void
2936{
2940 Oid dbId;
2941 Oid relId;
2942 Oid heapId;
2943 int i;
2944 bool isIndex;
2945 bool found;
2947
2948 /*
2949 * Bail out quickly if there are no serializable transactions running.
2950 * It's safe to check this without taking locks because the caller is
2951 * holding an ACCESS EXCLUSIVE lock on the relation. No new locks which
2952 * would matter here can be acquired while that is held.
2953 */
2955 return;
2956
2957 if (!PredicateLockingNeededForRelation(relation))
2958 return;
2959
2960 dbId = relation->rd_locator.dbOid;
2961 relId = relation->rd_id;
2962 if (relation->rd_index == NULL)
2963 {
2964 isIndex = false;
2965 heapId = relId;
2966 }
2967 else
2968 {
2969 isIndex = true;
2970 heapId = relation->rd_index->indrelid;
2971 }
2973 Assert(transfer || !isIndex); /* index OID only makes sense with
2974 * transfer */
2975
2976 /* Retrieve first time needed, then keep. */
2978 heaptarget = NULL;
2979
2980 /* Acquire locks on all lock partitions */
2982 for (i = 0; i < NUM_PREDICATELOCK_PARTITIONS; i++)
2985
2986 /*
2987 * Remove the dummy entry to give us scratch space, so we know we'll be
2988 * able to create the new lock target.
2989 */
2990 if (transfer)
2991 RemoveScratchTarget(true);
2992
2993 /* Scan through target map */
2995
2997 {
2998 dlist_mutable_iter iter;
2999
3000 /*
3001 * Check whether this is a target which needs attention.
3002 */
3004 continue; /* wrong relation id */
3005 if (GET_PREDICATELOCKTARGETTAG_DB(oldtarget->tag) != dbId)
3006 continue; /* wrong database id */
3007 if (transfer && !isIndex
3009 continue; /* already the right lock */
3010
3011 /*
3012 * If we made it here, we have work to do. We make sure the heap
3013 * relation lock exists, then we walk the list of predicate locks for
3014 * the old target we found, moving all locks to the heap relation lock
3015 * -- unless they already hold that.
3016 */
3017
3018 /*
3019 * First make sure we have the heap relation target. We only need to
3020 * do this once.
3021 */
3022 if (transfer && heaptarget == NULL)
3023 {
3025
3031 HASH_ENTER, &found);
3032 if (!found)
3033 dlist_init(&heaptarget->predicateLocks);
3034 }
3035
3036 /*
3037 * Loop through all the locks on the old target, replacing them with
3038 * locks on the new target.
3039 */
3040 dlist_foreach_modify(iter, &oldtarget->predicateLocks)
3041 {
3043 dlist_container(PREDICATELOCK, targetLink, iter.cur);
3047
3048 /*
3049 * Remove the old lock first. This avoids the chance of running
3050 * out of lock structure entries for the hash table.
3051 */
3053 oldXact = oldpredlock->tag.myXact;
3054
3055 dlist_delete(&(oldpredlock->xactLink));
3056
3057 /*
3058 * No need for retail delete from oldtarget list, we're removing
3059 * the whole target anyway.
3060 */
3062 &oldpredlock->tag,
3063 HASH_REMOVE, &found);
3064 Assert(found);
3065
3066 if (transfer)
3067 {
3069
3071 newpredlocktag.myXact = oldXact;
3077 HASH_ENTER,
3078 &found);
3079 if (!found)
3080 {
3081 dlist_push_tail(&(heaptarget->predicateLocks),
3082 &(newpredlock->targetLink));
3083 dlist_push_tail(&(newpredlocktag.myXact->predicateLocks),
3084 &(newpredlock->xactLink));
3085 newpredlock->commitSeqNo = oldCommitSeqNo;
3086 }
3087 else
3088 {
3089 if (newpredlock->commitSeqNo < oldCommitSeqNo)
3090 newpredlock->commitSeqNo = oldCommitSeqNo;
3091 }
3092
3093 Assert(newpredlock->commitSeqNo != 0);
3094 Assert((newpredlock->commitSeqNo == InvalidSerCommitSeqNo)
3095 || (newpredlock->tag.myXact == OldCommittedSxact));
3096 }
3097 }
3098
3100 &found);
3101 Assert(found);
3102 }
3103
3104 /* Put the scratch entry back */
3105 if (transfer)
3107
3108 /* Release locks in reverse order */
3110 for (i = NUM_PREDICATELOCK_PARTITIONS - 1; i >= 0; i--)
3113}
3114
3115/*
3116 * TransferPredicateLocksToHeapRelation
3117 * For all transactions, transfer all predicate locks for the given
3118 * relation to a single relation lock on the heap.
3119 */
3120void
3122{
3123 DropAllPredicateLocksFromTable(relation, true);
3124}
3125
3126
3127/*
3128 * PredicateLockPageSplit
3129 *
3130 * Copies any predicate locks for the old page to the new page.
3131 * Skip if this is a temporary table or toast table.
3132 *
3133 * NOTE: A page split (or overflow) affects all serializable transactions,
3134 * even if it occurs in the context of another transaction isolation level.
3135 *
3136 * NOTE: This currently leaves the local copy of the locks without
3137 * information on the new lock which is in shared memory. This could cause
3138 * problems if enough page splits occur on locked pages without the processes
3139 * which hold the locks getting in and noticing.
3140 */
3141void
3144{
3147 bool success;
3148
3149 /*
3150 * Bail out quickly if there are no serializable transactions running.
3151 *
3152 * It's safe to do this check without taking any additional locks. Even if
3153 * a serializable transaction starts concurrently, we know it can't take
3154 * any SIREAD locks on the page being split because the caller is holding
3155 * the associated buffer page lock. Memory reordering isn't an issue; the
3156 * memory barrier in the LWLock acquisition guarantees that this read
3157 * occurs while the buffer page lock is held.
3158 */
3160 return;
3161
3162 if (!PredicateLockingNeededForRelation(relation))
3163 return;
3164
3168
3170 relation->rd_locator.dbOid,
3171 relation->rd_id,
3172 oldblkno);
3174 relation->rd_locator.dbOid,
3175 relation->rd_id,
3176 newblkno);
3177
3179
3180 /*
3181 * Try copying the locks over to the new page's tag, creating it if
3182 * necessary.
3183 */
3186 false);
3187
3188 if (!success)
3189 {
3190 /*
3191 * No more predicate lock entries are available. Failure isn't an
3192 * option here, so promote the page lock to a relation lock.
3193 */
3194
3195 /* Get the parent relation lock's lock tag */
3197 &newtargettag);
3198 Assert(success);
3199
3200 /*
3201 * Move the locks to the parent. This shouldn't fail.
3202 *
3203 * Note that here we are removing locks held by other backends,
3204 * leading to a possible inconsistency in their local lock hash table.
3205 * This is OK because we're replacing it with a lock that covers the
3206 * old one.
3207 */
3210 true);
3211 Assert(success);
3212 }
3213
3215}
3216
3217/*
3218 * PredicateLockPageCombine
3219 *
3220 * Combines predicate locks for two existing pages.
3221 * Skip if this is a temporary table or toast table.
3222 *
3223 * NOTE: A page combine affects all serializable transactions, even if it
3224 * occurs in the context of another transaction isolation level.
3225 */
3226void
3229{
3230 /*
3231 * Page combines differ from page splits in that we ought to be able to
3232 * remove the locks on the old page after transferring them to the new
3233 * page, instead of duplicating them. However, because we can't edit other
3234 * backends' local lock tables, removing the old lock would leave them
3235 * with an entry in their LocalPredicateLockHash for a lock they're not
3236 * holding, which isn't acceptable. So we wind up having to do the same
3237 * work as a page split, acquiring a lock on the new page and keeping the
3238 * old page locked too. That can lead to some false positives, but should
3239 * be rare in practice.
3240 */
3242}
3243
3244/*
3245 * Walk the list of in-progress serializable transactions and find the new
3246 * xmin.
3247 */
3248static void
3250{
3251 dlist_iter iter;
3252
3254
3257
3259 {
3261 dlist_container(SERIALIZABLEXACT, xactLink, iter.cur);
3262
3266 {
3271 {
3274 }
3275 else if (TransactionIdEquals(sxact->xmin,
3278 }
3279 }
3280
3282}
3283
3284/*
3285 * ReleasePredicateLocks
3286 *
3287 * Releases predicate locks based on completion of the current transaction,
3288 * whether committed or rolled back. It can also be called for a read only
3289 * transaction when it becomes impossible for the transaction to become
3290 * part of a dangerous structure.
3291 *
3292 * We do nothing unless this is a serializable transaction.
3293 *
3294 * This method must ensure that shared memory hash tables are cleaned
3295 * up in some relatively timely fashion.
3296 *
3297 * If this transaction is committing and is holding any predicate locks,
3298 * it must be added to a list of completed serializable transactions still
3299 * holding locks.
3300 *
3301 * If isReadOnlySafe is true, then predicate locks are being released before
3302 * the end of the transaction because MySerializableXact has been determined
3303 * to be RO_SAFE. In non-parallel mode we can release it completely, but it
3304 * in parallel mode we partially release the SERIALIZABLEXACT and keep it
3305 * around until the end of the transaction, allowing each backend to clear its
3306 * MySerializableXact variable and benefit from the optimization in its own
3307 * time.
3308 */
3309void
3311{
3312 bool partiallyReleasing = false;
3313 bool needToClear;
3315 dlist_mutable_iter iter;
3316
3317 /*
3318 * We can't trust XactReadOnly here, because a transaction which started
3319 * as READ WRITE can show as READ ONLY later, e.g., within
3320 * subtransactions. We want to flag a transaction as READ ONLY if it
3321 * commits without writing so that de facto READ ONLY transactions get the
3322 * benefit of some RO optimizations, so we will use this local variable to
3323 * get some cleanup logic right which is based on whether the transaction
3324 * was declared READ ONLY at the top level.
3325 */
3327
3328 /* We can't be both committing and releasing early due to RO_SAFE. */
3330
3331 /* Are we at the end of a transaction, that is, a commit or abort? */
3332 if (!isReadOnlySafe)
3333 {
3334 /*
3335 * Parallel workers mustn't release predicate locks at the end of
3336 * their transaction. The leader will do that at the end of its
3337 * transaction.
3338 */
3339 if (IsParallelWorker())
3340 {
3342 return;
3343 }
3344
3345 /*
3346 * By the time the leader in a parallel query reaches end of
3347 * transaction, it has waited for all workers to exit.
3348 */
3350
3351 /*
3352 * If the leader in a parallel query earlier stashed a partially
3353 * released SERIALIZABLEXACT for final clean-up at end of transaction
3354 * (because workers might still have been accessing it), then it's
3355 * time to restore it.
3356 */
3358 {
3363 }
3364 }
3365
3367 {
3369 return;
3370 }
3371
3373
3374 /*
3375 * If the transaction is committing, but it has been partially released
3376 * already, then treat this as a roll back. It was marked as rolled back.
3377 */
3379 isCommit = false;
3380
3381 /*
3382 * If we're called in the middle of a transaction because we discovered
3383 * that the SXACT_FLAG_RO_SAFE flag was set, then we'll partially release
3384 * it (that is, release the predicate locks and conflicts, but not the
3385 * SERIALIZABLEXACT itself) if we're the first backend to have noticed.
3386 */
3388 {
3389 /*
3390 * The leader needs to stash a pointer to it, so that it can
3391 * completely release it at end-of-transaction.
3392 */
3393 if (!IsParallelWorker())
3395
3396 /*
3397 * The first backend to reach this condition will partially release
3398 * the SERIALIZABLEXACT. All others will just clear their
3399 * backend-local state so that they stop doing SSI checks for the rest
3400 * of the transaction.
3401 */
3403 {
3406 return;
3407 }
3408 else
3409 {
3411 partiallyReleasing = true;
3412 /* ... and proceed to perform the partial release below. */
3413 }
3414 }
3420
3421 /* may not be serializable during COMMIT/ROLLBACK PREPARED */
3423
3424 /* We'd better not already be on the cleanup list. */
3426
3428
3429 /*
3430 * We don't hold XidGenLock lock here, assuming that TransactionId is
3431 * atomic!
3432 *
3433 * If this value is changing, we don't care that much whether we get the
3434 * old or new value -- it is just used to determine how far
3435 * SxactGlobalXmin must advance before this transaction can be fully
3436 * cleaned up. The worst that could happen is we wait for one more
3437 * transaction to complete before freeing some RAM; correctness of visible
3438 * behavior is not affected.
3439 */
3441
3442 /*
3443 * If it's not a commit it's either a rollback or a read-only transaction
3444 * flagged SXACT_FLAG_RO_SAFE, and we can clear our locks immediately.
3445 */
3446 if (isCommit)
3447 {
3450 /* Recognize implicit read-only transaction (commit without write). */
3451 if (!MyXactDidWrite)
3453 }
3454 else
3455 {
3456 /*
3457 * The DOOMED flag indicates that we intend to roll back this
3458 * transaction and so it should not cause serialization failures for
3459 * other transactions that conflict with it. Note that this flag might
3460 * already be set, if another backend marked this transaction for
3461 * abort.
3462 *
3463 * The ROLLED_BACK flag further indicates that ReleasePredicateLocks
3464 * has been called, and so the SerializableXact is eligible for
3465 * cleanup. This means it should not be considered when calculating
3466 * SxactGlobalXmin.
3467 */
3470
3471 /*
3472 * If the transaction was previously prepared, but is now failing due
3473 * to a ROLLBACK PREPARED or (hopefully very rare) error after the
3474 * prepare, clear the prepared flag. This simplifies conflict
3475 * checking.
3476 */
3478 }
3479
3481 {
3483 if (--(PredXact->WritableSxactCount) == 0)
3484 {
3485 /*
3486 * Release predicate locks and rw-conflicts in for all committed
3487 * transactions. There are no longer any transactions which might
3488 * conflict with the locks and no chance for new transactions to
3489 * overlap. Similarly, existing conflicts in can't cause pivots,
3490 * and any conflicts in which could have completed a dangerous
3491 * structure would already have caused a rollback, so any
3492 * remaining ones must be benign.
3493 */
3495 }
3496 }
3497 else
3498 {
3499 /*
3500 * Read-only transactions: clear the list of transactions that might
3501 * make us unsafe. Note that we use 'inLink' for the iteration as
3502 * opposed to 'outLink' for the r/w xacts.
3503 */
3505 {
3507 dlist_container(RWConflictData, inLink, iter.cur);
3508
3511
3513 }
3514 }
3515
3516 /* Check for conflict out to old committed transactions. */
3517 if (isCommit
3520 {
3521 /*
3522 * we don't know which old committed transaction we conflicted with,
3523 * so be conservative and use FirstNormalSerCommitSeqNo here
3524 */
3528 }
3529
3530 /*
3531 * Release all outConflicts to committed transactions. If we're rolling
3532 * back clear them all. Set SXACT_FLAG_CONFLICT_OUT if any point to
3533 * previously committed transactions.
3534 */
3536 {
3538 dlist_container(RWConflictData, outLink, iter.cur);
3539
3540 if (isCommit
3542 && SxactIsCommitted(conflict->sxactIn))
3543 {
3545 || conflict->sxactIn->prepareSeqNo < MySerializableXact->SeqNo.earliestOutConflictCommit)
3548 }
3549
3550 if (!isCommit
3551 || SxactIsCommitted(conflict->sxactIn)
3552 || (conflict->sxactIn->SeqNo.lastCommitBeforeSnapshot >= PredXact->LastSxactCommitSeqNo))
3554 }
3555
3556 /*
3557 * Release all inConflicts from committed and read-only transactions. If
3558 * we're rolling back, clear them all.
3559 */
3561 {
3563 dlist_container(RWConflictData, inLink, iter.cur);
3564
3565 if (!isCommit
3566 || SxactIsCommitted(conflict->sxactOut)
3567 || SxactIsReadOnly(conflict->sxactOut))
3569 }
3570
3572 {
3573 /*
3574 * Remove ourselves from the list of possible conflicts for concurrent
3575 * READ ONLY transactions, flagging them as unsafe if we have a
3576 * conflict out. If any are waiting DEFERRABLE transactions, wake them
3577 * up if they are known safe or known unsafe.
3578 */
3580 {
3582 dlist_container(RWConflictData, outLink, iter.cur);
3583
3584 roXact = possibleUnsafeConflict->sxactIn;
3587
3588 /* Mark conflicted if necessary. */
3589 if (isCommit
3593 <= roXact->SeqNo.lastCommitBeforeSnapshot))
3594 {
3595 /*
3596 * This releases possibleUnsafeConflict (as well as all other
3597 * possible conflicts for roXact)
3598 */
3600 }
3601 else
3602 {
3604
3605 /*
3606 * If we were the last possible conflict, flag it safe. The
3607 * transaction can now safely release its predicate locks (but
3608 * that transaction's backend has to do that itself).
3609 */
3610 if (dlist_is_empty(&roXact->possibleUnsafeConflicts))
3611 roXact->flags |= SXACT_FLAG_RO_SAFE;
3612 }
3613
3614 /*
3615 * Wake up the process for a waiting DEFERRABLE transaction if we
3616 * now know it's either safe or conflicted.
3617 */
3620 ProcSendSignal(roXact->pgprocno);
3621 }
3622 }
3623
3624 /*
3625 * Check whether it's time to clean up old transactions. This can only be
3626 * done when the last serializable transaction with the oldest xmin among
3627 * serializable transactions completes. We then find the "new oldest"
3628 * xmin and purge any transactions which finished before this transaction
3629 * was launched.
3630 *
3631 * For parallel queries in read-only transactions, it might run twice. We
3632 * only release the reference on the first call.
3633 */
3634 needToClear = false;
3635 if ((partiallyReleasing ||
3639 {
3641 if (--(PredXact->SxactGlobalXminCount) == 0)
3642 {
3644 needToClear = true;
3645 }
3646 }
3647
3649
3651
3652 /* Add this to the list of transactions to check for later cleanup. */
3653 if (isCommit)
3656
3657 /*
3658 * If we're releasing a RO_SAFE transaction in parallel mode, we'll only
3659 * partially release it. That's necessary because other backends may have
3660 * a reference to it. The leader will release the SERIALIZABLEXACT itself
3661 * at the end of the transaction after workers have stopped running.
3662 */
3663 if (!isCommit)
3666 false);
3667
3669
3670 if (needToClear)
3672
3674}
3675
3676static void
3678{
3680 MyXactDidWrite = false;
3681
3682 /* Delete per-transaction lock table */
3684 {
3687 }
3688}
3689
3690/*
3691 * Clear old predicate locks, belonging to committed transactions that are no
3692 * longer interesting to any in-progress transaction.
3693 */
3694static void
3696{
3697 dlist_mutable_iter iter;
3698
3699 /*
3700 * Loop through finished transactions. They are in commit order, so we can
3701 * stop as soon as we find one that's still interesting.
3702 */
3706 {
3708 dlist_container(SERIALIZABLEXACT, finishedLink, iter.cur);
3709
3713 {
3714 /*
3715 * This transaction committed before any in-progress transaction
3716 * took its snapshot. It's no longer interesting.
3717 */
3719 dlist_delete_thoroughly(&finishedSxact->finishedLink);
3722 }
3723 else if (finishedSxact->commitSeqNo > PredXact->HavePartialClearedThrough
3724 && finishedSxact->commitSeqNo <= PredXact->CanPartialClearThrough)
3725 {
3726 /*
3727 * Any active transactions that took their snapshot before this
3728 * transaction committed are read-only, so we can clear part of
3729 * its state.
3730 */
3732
3734 {
3735 /* A read-only transaction can be removed entirely */
3736 dlist_delete_thoroughly(&(finishedSxact->finishedLink));
3738 }
3739 else
3740 {
3741 /*
3742 * A read-write transaction can only be partially cleared. We
3743 * need to keep the SERIALIZABLEXACT but can release the
3744 * SIREAD locks and conflicts in.
3745 */
3747 }
3748
3751 }
3752 else
3753 {
3754 /* Still interesting. */
3755 break;
3756 }
3757 }
3759
3760 /*
3761 * Loop through predicate locks on dummy transaction for summarized data.
3762 */
3765 {
3767 dlist_container(PREDICATELOCK, xactLink, iter.cur);
3769
3771 Assert(predlock->commitSeqNo != 0);
3772 Assert(predlock->commitSeqNo != InvalidSerCommitSeqNo);
3775
3776 /*
3777 * If this lock originally belonged to an old enough transaction, we
3778 * can release it.
3779 */
3781 {
3782 PREDICATELOCKTAG tag;
3783 PREDICATELOCKTARGET *target;
3787
3788 tag = predlock->tag;
3789 target = tag.myTarget;
3790 targettag = target->tag;
3793
3795
3796 dlist_delete(&(predlock->targetLink));
3797 dlist_delete(&(predlock->xactLink));
3798
3802 HASH_REMOVE, NULL);
3804
3806 }
3807 }
3808
3811}
3812
3813/*
3814 * This is the normal way to delete anything from any of the predicate
3815 * locking hash tables. Given a transaction which we know can be deleted:
3816 * delete all predicate locks held by that transaction and any predicate
3817 * lock targets which are now unreferenced by a lock; delete all conflicts
3818 * for the transaction; delete all xid values for the transaction; then
3819 * delete the transaction.
3820 *
3821 * When the partial flag is set, we can release all predicate locks and
3822 * in-conflict information -- we've established that there are no longer
3823 * any overlapping read write transactions for which this transaction could
3824 * matter -- but keep the transaction entry itself and any outConflicts.
3825 *
3826 * When the summarize flag is set, we've run short of room for sxact data
3827 * and must summarize to the SLRU. Predicate locks are transferred to a
3828 * dummy "old" transaction, with duplicate locks on a single target
3829 * collapsing to a single lock with the "latest" commitSeqNo from among
3830 * the conflicting locks..
3831 */
3832static void
3834 bool summarize)
3835{
3837 dlist_mutable_iter iter;
3838
3839 Assert(sxact != NULL);
3841 Assert(partial || !SxactIsOnFinishedList(sxact));
3843
3844 /*
3845 * First release all the predicate locks held by this xact (or transfer
3846 * them to OldCommittedSxact if summarize is true)
3847 */
3849 if (IsInParallelMode())
3850 LWLockAcquire(&sxact->perXactPredicateListLock, LW_EXCLUSIVE);
3851 dlist_foreach_modify(iter, &sxact->predicateLocks)
3852 {
3854 dlist_container(PREDICATELOCK, xactLink, iter.cur);
3855 PREDICATELOCKTAG tag;
3856 PREDICATELOCKTARGET *target;
3860
3861 tag = predlock->tag;
3862 target = tag.myTarget;
3863 targettag = target->tag;
3866
3868
3869 dlist_delete(&predlock->targetLink);
3870
3874 HASH_REMOVE, NULL);
3875 if (summarize)
3876 {
3877 bool found;
3878
3879 /* Fold into dummy transaction list. */
3884 HASH_ENTER_NULL, &found);
3885 if (!predlock)
3886 ereport(ERROR,
3888 errmsg("out of shared memory"),
3889 errhint("You might need to increase \"%s\".", "max_pred_locks_per_transaction")));
3890 if (found)
3891 {
3892 Assert(predlock->commitSeqNo != 0);
3893 Assert(predlock->commitSeqNo != InvalidSerCommitSeqNo);
3894 if (predlock->commitSeqNo < sxact->commitSeqNo)
3895 predlock->commitSeqNo = sxact->commitSeqNo;
3896 }
3897 else
3898 {
3900 &predlock->targetLink);
3902 &predlock->xactLink);
3903 predlock->commitSeqNo = sxact->commitSeqNo;
3904 }
3905 }
3906 else
3908
3910 }
3911
3912 /*
3913 * Rather than retail removal, just re-init the head after we've run
3914 * through the list.
3915 */
3916 dlist_init(&sxact->predicateLocks);
3917
3918 if (IsInParallelMode())
3919 LWLockRelease(&sxact->perXactPredicateListLock);
3921
3922 sxidtag.xid = sxact->topXid;
3924
3925 /* Release all outConflicts (unless 'partial' is true) */
3926 if (!partial)
3927 {
3928 dlist_foreach_modify(iter, &sxact->outConflicts)
3929 {
3931 dlist_container(RWConflictData, outLink, iter.cur);
3932
3933 if (summarize)
3934 conflict->sxactIn->flags |= SXACT_FLAG_SUMMARY_CONFLICT_IN;
3936 }
3937 }
3938
3939 /* Release all inConflicts. */
3940 dlist_foreach_modify(iter, &sxact->inConflicts)
3941 {
3943 dlist_container(RWConflictData, inLink, iter.cur);
3944
3945 if (summarize)
3946 conflict->sxactOut->flags |= SXACT_FLAG_SUMMARY_CONFLICT_OUT;
3948 }
3949
3950 /* Finally, get rid of the xid and the record of the transaction itself. */
3951 if (!partial)
3952 {
3953 if (sxidtag.xid != InvalidTransactionId)
3956 }
3957
3959}
3960
3961/*
3962 * Tests whether the given top level transaction is concurrent with
3963 * (overlaps) our current transaction.
3964 *
3965 * We need to identify the top level transaction for SSI, anyway, so pass
3966 * that to this function to save the overhead of checking the snapshot's
3967 * subxip array.
3968 */
3969static bool
3971{
3972 Snapshot snap;
3973
3976
3978
3979 if (TransactionIdPrecedes(xid, snap->xmin))
3980 return false;
3981
3982 if (TransactionIdFollowsOrEquals(xid, snap->xmax))
3983 return true;
3984
3985 return pg_lfind32(xid, snap->xip, snap->xcnt);
3986}
3987
3988bool
3990{
3991 if (!SerializationNeededForRead(relation, snapshot))
3992 return false;
3993
3994 /* Check if someone else has already decided that we need to die */
3996 {
3997 ereport(ERROR,
3999 errmsg("could not serialize access due to read/write dependencies among transactions"),
4000 errdetail_internal("Reason code: Canceled on identification as a pivot, during conflict out checking."),
4001 errhint("The transaction might succeed if retried.")));
4002 }
4003
4004 return true;
4005}
4006
4007/*
4008 * CheckForSerializableConflictOut
4009 * A table AM is reading a tuple that has been modified. If it determines
4010 * that the tuple version it is reading is not visible to us, it should
4011 * pass in the top level xid of the transaction that created it.
4012 * Otherwise, if it determines that it is visible to us but it has been
4013 * deleted or there is a newer version available due to an update, it
4014 * should pass in the top level xid of the modifying transaction.
4015 *
4016 * This function will check for overlap with our own transaction. If the given
4017 * xid is also serializable and the transactions overlap (i.e., they cannot see
4018 * each other's writes), then we have a conflict out.
4019 */
4020void
4022{
4026
4027 if (!SerializationNeededForRead(relation, snapshot))
4028 return;
4029
4030 /* Check if someone else has already decided that we need to die */
4032 {
4033 ereport(ERROR,
4035 errmsg("could not serialize access due to read/write dependencies among transactions"),
4036 errdetail_internal("Reason code: Canceled on identification as a pivot, during conflict out checking."),
4037 errhint("The transaction might succeed if retried.")));
4038 }
4040
4042 return;
4043
4044 /*
4045 * Find sxact or summarized info for the top level xid.
4046 */
4047 sxidtag.xid = xid;
4049 sxid = (SERIALIZABLEXID *)
4051 if (!sxid)
4052 {
4053 /*
4054 * Transaction not found in "normal" SSI structures. Check whether it
4055 * got pushed out to SLRU storage for "old committed" transactions.
4056 */
4058
4060 if (conflictCommitSeqNo != 0)
4061 {
4066 ereport(ERROR,
4068 errmsg("could not serialize access due to read/write dependencies among transactions"),
4069 errdetail_internal("Reason code: Canceled on conflict out to old pivot %u.", xid),
4070 errhint("The transaction might succeed if retried.")));
4071
4074 ereport(ERROR,
4076 errmsg("could not serialize access due to read/write dependencies among transactions"),
4077 errdetail_internal("Reason code: Canceled on identification as a pivot, with conflict out to old committed transaction %u.", xid),
4078 errhint("The transaction might succeed if retried.")));
4079
4081 }
4082
4083 /* It's not serializable or otherwise not important. */
4085 return;
4086 }
4087 sxact = sxid->myXact;
4088 Assert(TransactionIdEquals(sxact->topXid, xid));
4090 {
4091 /* Can't conflict with ourself or a transaction that will roll back. */
4093 return;
4094 }
4095
4096 /*
4097 * We have a conflict out to a transaction which has a conflict out to a
4098 * summarized transaction. That summarized transaction must have
4099 * committed first, and we can't tell when it committed in relation to our
4100 * snapshot acquisition, so something needs to be canceled.
4101 */
4103 {
4104 if (!SxactIsPrepared(sxact))
4105 {
4106 sxact->flags |= SXACT_FLAG_DOOMED;
4108 return;
4109 }
4110 else
4111 {
4113 ereport(ERROR,
4115 errmsg("could not serialize access due to read/write dependencies among transactions"),
4116 errdetail_internal("Reason code: Canceled on conflict out to old pivot."),
4117 errhint("The transaction might succeed if retried.")));
4118 }
4119 }
4120
4121 /*
4122 * If this is a read-only transaction and the writing transaction has
4123 * committed, and it doesn't have a rw-conflict to a transaction which
4124 * committed before it, no conflict.
4125 */
4130 || MySerializableXact->SeqNo.lastCommitBeforeSnapshot < sxact->SeqNo.earliestOutConflictCommit))
4131 {
4132 /* Read-only transaction will appear to run first. No conflict. */
4134 return;
4135 }
4136
4137 if (!XidIsConcurrent(xid))
4138 {
4139 /* This write was already in our snapshot; no conflict. */
4141 return;
4142 }
4143
4145 {
4146 /* We don't want duplicate conflict records in the list. */
4148 return;
4149 }
4150
4151 /*
4152 * Flag the conflict. But first, if this conflict creates a dangerous
4153 * structure, ereport an error.
4154 */
4157}
4158
4159/*
4160 * Check a particular target for rw-dependency conflict in. A subroutine of
4161 * CheckForSerializableConflictIn().
4162 */
4163static void
4165{
4168 PREDICATELOCKTARGET *target;
4171 dlist_mutable_iter iter;
4172
4174
4175 /*
4176 * The same hash and LW lock apply to the lock target and the lock itself.
4177 */
4181 target = (PREDICATELOCKTARGET *)
4184 HASH_FIND, NULL);
4185 if (!target)
4186 {
4187 /* Nothing has this target locked; we're done here. */
4189 return;
4190 }
4191
4192 /*
4193 * Each lock for an overlapping transaction represents a conflict: a
4194 * rw-dependency in to this transaction.
4195 */
4197
4198 dlist_foreach_modify(iter, &target->predicateLocks)
4199 {
4201 dlist_container(PREDICATELOCK, targetLink, iter.cur);
4202 SERIALIZABLEXACT *sxact = predlock->tag.myXact;
4203
4205 {
4206 /*
4207 * If we're getting a write lock on a tuple, we don't need a
4208 * predicate (SIREAD) lock on the same tuple. We can safely remove
4209 * our SIREAD lock, but we'll defer doing so until after the loop
4210 * because that requires upgrading to an exclusive partition lock.
4211 *
4212 * We can't use this optimization within a subtransaction because
4213 * the subtransaction could roll back, and we would be left
4214 * without any lock at the top level.
4215 */
4216 if (!IsSubTransaction()
4218 {
4220 mypredlocktag = predlock->tag;
4221 }
4222 }
4223 else if (!SxactIsDoomed(sxact)
4226 sxact->finishedBefore))
4228 {
4231
4232 /*
4233 * Re-check after getting exclusive lock because the other
4234 * transaction may have flagged a conflict.
4235 */
4236 if (!SxactIsDoomed(sxact)
4239 sxact->finishedBefore))
4241 {
4243 }
4244
4247 }
4248 }
4251
4252 /*
4253 * If we found one of our own SIREAD locks to remove, remove it now.
4254 *
4255 * At this point our transaction already has a RowExclusiveLock on the
4256 * relation, so we are OK to drop the predicate lock on the tuple, if
4257 * found, without fearing that another write against the tuple will occur
4258 * before the MVCC information makes it to the buffer.
4259 */
4260 if (mypredlock != NULL)
4261 {
4264
4266 if (IsInParallelMode())
4270
4271 /*
4272 * Remove the predicate lock from shared memory, if it wasn't removed
4273 * while the locks were released. One way that could happen is from
4274 * autovacuum cleaning up an index.
4275 */
4282 HASH_FIND, NULL);
4283 if (rmpredlock != NULL)
4284 {
4286
4287 dlist_delete(&(mypredlock->targetLink));
4288 dlist_delete(&(mypredlock->xactLink));
4289
4294 HASH_REMOVE, NULL);
4296
4298 }
4299
4302 if (IsInParallelMode())
4305
4306 if (rmpredlock != NULL)
4307 {
4308 /*
4309 * Remove entry in local lock table if it exists. It's OK if it
4310 * doesn't exist; that means the lock was transferred to a new
4311 * target by a different backend.
4312 */
4315 HASH_REMOVE, NULL);
4316
4318 }
4319 }
4320}
4321
4322/*
4323 * CheckForSerializableConflictIn
4324 * We are writing the given tuple. If that indicates a rw-conflict
4325 * in from another serializable transaction, take appropriate action.
4326 *
4327 * Skip checking for any granularity for which a parameter is missing.
4328 *
4329 * A tuple update or delete is in conflict if we have a predicate lock
4330 * against the relation or page in which the tuple exists, or against the
4331 * tuple itself.
4332 */
4333void
4335{
4337
4338 if (!SerializationNeededForWrite(relation))
4339 return;
4340
4341 /* Check if someone else has already decided that we need to die */
4343 ereport(ERROR,
4345 errmsg("could not serialize access due to read/write dependencies among transactions"),
4346 errdetail_internal("Reason code: Canceled on identification as a pivot, during conflict in checking."),
4347 errhint("The transaction might succeed if retried.")));
4348
4349 /*
4350 * We're doing a write which might cause rw-conflicts now or later.
4351 * Memorize that fact.
4352 */
4353 MyXactDidWrite = true;
4354
4355 /*
4356 * It is important that we check for locks from the finest granularity to
4357 * the coarsest granularity, so that granularity promotion doesn't cause
4358 * us to miss a lock. The new (coarser) lock will be acquired before the
4359 * old (finer) locks are released.
4360 *
4361 * It is not possible to take and hold a lock across the checks for all
4362 * granularities because each target could be in a separate partition.
4363 */
4364 if (tid != NULL)
4365 {
4367 relation->rd_locator.dbOid,
4368 relation->rd_id,
4372 }
4373
4374 if (blkno != InvalidBlockNumber)
4375 {
4377 relation->rd_locator.dbOid,
4378 relation->rd_id,
4379 blkno);
4381 }
4382
4384 relation->rd_locator.dbOid,
4385 relation->rd_id);
4387}
4388
4389/*
4390 * CheckTableForSerializableConflictIn
4391 * The entire table is going through a DDL-style logical mass delete
4392 * like TRUNCATE or DROP TABLE. If that causes a rw-conflict in from
4393 * another serializable transaction, take appropriate action.
4394 *
4395 * While these operations do not operate entirely within the bounds of
4396 * snapshot isolation, they can occur inside a serializable transaction, and
4397 * will logically occur after any reads which saw rows which were destroyed
4398 * by these operations, so we do what we can to serialize properly under
4399 * SSI.
4400 *
4401 * The relation passed in must be a heap relation. Any predicate lock of any
4402 * granularity on the heap will cause a rw-conflict in to this transaction.
4403 * Predicate locks on indexes do not matter because they only exist to guard
4404 * against conflicting inserts into the index, and this is a mass *delete*.
4405 * When a table is truncated or dropped, the index will also be truncated
4406 * or dropped, and we'll deal with locks on the index when that happens.
4407 *
4408 * Dropping or truncating a table also needs to drop any existing predicate
4409 * locks on heap tuples or pages, because they're about to go away. This
4410 * should be done before altering the predicate locks because the transaction
4411 * could be rolled back because of a conflict, in which case the lock changes
4412 * are not needed. (At the moment, we don't actually bother to drop the
4413 * existing locks on a dropped or truncated table at the moment. That might
4414 * lead to some false positives, but it doesn't seem worth the trouble.)
4415 */
4416void
4418{
4420 PREDICATELOCKTARGET *target;
4421 Oid dbId;
4422 Oid heapId;
4423 int i;
4424
4425 /*
4426 * Bail out quickly if there are no serializable transactions running.
4427 * It's safe to check this without taking locks because the caller is
4428 * holding an ACCESS EXCLUSIVE lock on the relation. No new locks which
4429 * would matter here can be acquired while that is held.
4430 */
4432 return;
4433
4434 if (!SerializationNeededForWrite(relation))
4435 return;
4436
4437 /*
4438 * We're doing a write which might cause rw-conflicts now or later.
4439 * Memorize that fact.
4440 */
4441 MyXactDidWrite = true;
4442
4443 Assert(relation->rd_index == NULL); /* not an index relation */
4444
4445 dbId = relation->rd_locator.dbOid;
4446 heapId = relation->rd_id;
4447
4449 for (i = 0; i < NUM_PREDICATELOCK_PARTITIONS; i++)
4452
4453 /* Scan through target list */
4455
4456 while ((target = (PREDICATELOCKTARGET *) hash_seq_search(&seqstat)))
4457 {
4458 dlist_mutable_iter iter;
4459
4460 /*
4461 * Check whether this is a target which needs attention.
4462 */
4464 continue; /* wrong relation id */
4465 if (GET_PREDICATELOCKTARGETTAG_DB(target->tag) != dbId)
4466 continue; /* wrong database id */
4467
4468 /*
4469 * Loop through locks for this target and flag conflicts.
4470 */
4471 dlist_foreach_modify(iter, &target->predicateLocks)
4472 {
4474 dlist_container(PREDICATELOCK, targetLink, iter.cur);
4475
4476 if (predlock->tag.myXact != MySerializableXact
4478 {
4480 }
4481 }
4482 }
4483
4484 /* Release locks in reverse order */
4486 for (i = NUM_PREDICATELOCK_PARTITIONS - 1; i >= 0; i--)
4489}
4490
4491
4492/*
4493 * Flag a rw-dependency between two serializable transactions.
4494 *
4495 * The caller is responsible for ensuring that we have a LW lock on
4496 * the transaction hash table.
4497 */
4498static void
4500{
4501 Assert(reader != writer);
4502
4503 /* First, see if this conflict causes failure. */
4505
4506 /* Actually do the conflict flagging. */
4507 if (reader == OldCommittedSxact)
4509 else if (writer == OldCommittedSxact)
4511 else
4512 SetRWConflict(reader, writer);
4513}
4514
4515/*----------------------------------------------------------------------------
4516 * We are about to add a RW-edge to the dependency graph - check that we don't
4517 * introduce a dangerous structure by doing so, and abort one of the
4518 * transactions if so.
4519 *
4520 * A serialization failure can only occur if there is a dangerous structure
4521 * in the dependency graph:
4522 *
4523 * Tin ------> Tpivot ------> Tout
4524 * rw rw
4525 *
4526 * Furthermore, Tout must commit first.
4527 *
4528 * One more optimization is that if Tin is declared READ ONLY (or commits
4529 * without writing), we can only have a problem if Tout committed before Tin
4530 * acquired its snapshot.
4531 *----------------------------------------------------------------------------
4532 */
4533static void
4536{
4537 bool failure;
4538
4540
4541 failure = false;
4542
4543 /*------------------------------------------------------------------------
4544 * Check for already-committed writer with rw-conflict out flagged
4545 * (conflict-flag on W means that T2 committed before W):
4546 *
4547 * R ------> W ------> T2
4548 * rw rw
4549 *
4550 * That is a dangerous structure, so we must abort. (Since the writer
4551 * has already committed, we must be the reader)
4552 *------------------------------------------------------------------------
4553 */
4556 failure = true;
4557
4558 /*------------------------------------------------------------------------
4559 * Check whether the writer has become a pivot with an out-conflict
4560 * committed transaction (T2), and T2 committed first:
4561 *
4562 * R ------> W ------> T2
4563 * rw rw
4564 *
4565 * Because T2 must've committed first, there is no anomaly if:
4566 * - the reader committed before T2
4567 * - the writer committed before T2
4568 * - the reader is a READ ONLY transaction and the reader was concurrent
4569 * with T2 (= reader acquired its snapshot before T2 committed)
4570 *
4571 * We also handle the case that T2 is prepared but not yet committed
4572 * here. In that case T2 has already checked for conflicts, so if it
4573 * commits first, making the above conflict real, it's too late for it
4574 * to abort.
4575 *------------------------------------------------------------------------
4576 */
4578 failure = true;
4579 else if (!failure)
4580 {
4581 dlist_iter iter;
4582
4583 dlist_foreach(iter, &writer->outConflicts)
4584 {
4586 dlist_container(RWConflictData, outLink, iter.cur);
4587 SERIALIZABLEXACT *t2 = conflict->sxactIn;
4588
4589 if (SxactIsPrepared(t2)
4590 && (!SxactIsCommitted(reader)
4591 || t2->prepareSeqNo <= reader->commitSeqNo)
4593 || t2->prepareSeqNo <= writer->commitSeqNo)
4594 && (!SxactIsReadOnly(reader)
4595 || t2->prepareSeqNo <= reader->SeqNo.lastCommitBeforeSnapshot))
4596 {
4597 failure = true;
4598 break;
4599 }
4600 }
4601 }
4602
4603 /*------------------------------------------------------------------------
4604 * Check whether the reader has become a pivot with a writer
4605 * that's committed (or prepared):
4606 *
4607 * T0 ------> R ------> W
4608 * rw rw
4609 *
4610 * Because W must've committed first for an anomaly to occur, there is no
4611 * anomaly if:
4612 * - T0 committed before the writer
4613 * - T0 is READ ONLY, and overlaps the writer
4614 *------------------------------------------------------------------------
4615 */
4616 if (!failure && SxactIsPrepared(writer) && !SxactIsReadOnly(reader))
4617 {
4618 if (SxactHasSummaryConflictIn(reader))
4619 {
4620 failure = true;
4621 }
4622 else
4623 {
4624 dlist_iter iter;
4625
4626 /*
4627 * The unconstify is needed as we have no const version of
4628 * dlist_foreach().
4629 */
4630 dlist_foreach(iter, &unconstify(SERIALIZABLEXACT *, reader)->inConflicts)
4631 {
4632 const RWConflict conflict =
4633 dlist_container(RWConflictData, inLink, iter.cur);
4634 const SERIALIZABLEXACT *t0 = conflict->sxactOut;
4635
4636 if (!SxactIsDoomed(t0)
4637 && (!SxactIsCommitted(t0)
4638 || t0->commitSeqNo >= writer->prepareSeqNo)
4639 && (!SxactIsReadOnly(t0)
4640 || t0->SeqNo.lastCommitBeforeSnapshot >= writer->prepareSeqNo))
4641 {
4642 failure = true;
4643 break;
4644 }
4645 }
4646 }
4647 }
4648
4649 if (failure)
4650 {
4651 /*
4652 * We have to kill a transaction to avoid a possible anomaly from
4653 * occurring. If the writer is us, we can just ereport() to cause a
4654 * transaction abort. Otherwise we flag the writer for termination,
4655 * causing it to abort when it tries to commit. However, if the writer
4656 * is a prepared transaction, already prepared, we can't abort it
4657 * anymore, so we have to kill the reader instead.
4658 */
4660 {
4662 ereport(ERROR,
4664 errmsg("could not serialize access due to read/write dependencies among transactions"),
4665 errdetail_internal("Reason code: Canceled on identification as a pivot, during write."),
4666 errhint("The transaction might succeed if retried.")));
4667 }
4668 else if (SxactIsPrepared(writer))
4669 {
4671
4672 /* if we're not the writer, we have to be the reader */
4673 Assert(MySerializableXact == reader);
4674 ereport(ERROR,
4676 errmsg("could not serialize access due to read/write dependencies among transactions"),
4677 errdetail_internal("Reason code: Canceled on conflict out to pivot %u, during read.", writer->topXid),
4678 errhint("The transaction might succeed if retried.")));
4679 }
4680 writer->flags |= SXACT_FLAG_DOOMED;
4681 }
4682}
4683
4684/*
4685 * PreCommit_CheckForSerializationFailure
4686 * Check for dangerous structures in a serializable transaction
4687 * at commit.
4688 *
4689 * We're checking for a dangerous structure as each conflict is recorded.
4690 * The only way we could have a problem at commit is if this is the "out"
4691 * side of a pivot, and neither the "in" side nor the pivot has yet
4692 * committed.
4693 *
4694 * If a dangerous structure is found, the pivot (the near conflict) is
4695 * marked for death, because rolling back another transaction might mean
4696 * that we fail without ever making progress. This transaction is
4697 * committing writes, so letting it commit ensures progress. If we
4698 * canceled the far conflict, it might immediately fail again on retry.
4699 */
4700void
4702{
4704
4706 return;
4707
4709
4711
4712 /*
4713 * Check if someone else has already decided that we need to die. Since
4714 * we set our own DOOMED flag when partially releasing, ignore in that
4715 * case.
4716 */
4719 {
4721 ereport(ERROR,
4723 errmsg("could not serialize access due to read/write dependencies among transactions"),
4724 errdetail_internal("Reason code: Canceled on identification as a pivot, during commit attempt."),
4725 errhint("The transaction might succeed if retried.")));
4726 }
4727
4729 {
4732
4733 if (!SxactIsCommitted(nearConflict->sxactOut)
4734 && !SxactIsDoomed(nearConflict->sxactOut))
4735 {
4737
4738 dlist_foreach(far_iter, &nearConflict->sxactOut->inConflicts)
4739 {
4742
4743 if (farConflict->sxactOut == MySerializableXact
4744 || (!SxactIsCommitted(farConflict->sxactOut)
4745 && !SxactIsReadOnly(farConflict->sxactOut)
4746 && !SxactIsDoomed(farConflict->sxactOut)))
4747 {
4748 /*
4749 * Normally, we kill the pivot transaction to make sure we
4750 * make progress if the failing transaction is retried.
4751 * However, we can't kill it if it's already prepared, so
4752 * in that case we commit suicide instead.
4753 */
4754 if (SxactIsPrepared(nearConflict->sxactOut))
4755 {
4757 ereport(ERROR,
4759 errmsg("could not serialize access due to read/write dependencies among transactions"),
4760 errdetail_internal("Reason code: Canceled on commit attempt with conflict in from prepared pivot."),
4761 errhint("The transaction might succeed if retried.")));
4762 }
4763 nearConflict->sxactOut->flags |= SXACT_FLAG_DOOMED;
4764 break;
4765 }
4766 }
4767 }
4768 }
4769
4772
4774}
4775
4776/*------------------------------------------------------------------------*/
4777
4778/*
4779 * Two-phase commit support
4780 */
4781
4782/*
4783 * AtPrepare_Locks
4784 * Do the preparatory work for a PREPARE: make 2PC state file
4785 * records for all predicate locks currently held.
4786 */
4787void
4789{
4792 TwoPhasePredicateXactRecord *xactRecord;
4793 TwoPhasePredicateLockRecord *lockRecord;
4794 dlist_iter iter;
4795
4797 xactRecord = &(record.data.xactRecord);
4798 lockRecord = &(record.data.lockRecord);
4799
4801 return;
4802
4803 /* Generate an xact record for our SERIALIZABLEXACT */
4805 xactRecord->xmin = MySerializableXact->xmin;
4806 xactRecord->flags = MySerializableXact->flags;
4807
4808 /*
4809 * Note that we don't include the list of conflicts in our out in the
4810 * statefile, because new conflicts can be added even after the
4811 * transaction prepares. We'll just make a conservative assumption during
4812 * recovery instead.
4813 */
4814
4816 &record, sizeof(record));
4817
4818 /*
4819 * Generate a lock record for each lock.
4820 *
4821 * To do this, we need to walk the predicate lock list in our sxact rather
4822 * than using the local predicate lock table because the latter is not
4823 * guaranteed to be accurate.
4824 */
4826
4827 /*
4828 * No need to take sxact->perXactPredicateListLock in parallel mode
4829 * because there cannot be any parallel workers running while we are
4830 * preparing a transaction.
4831 */
4833
4834 dlist_foreach(iter, &sxact->predicateLocks)
4835 {
4837 dlist_container(PREDICATELOCK, xactLink, iter.cur);
4838
4840 lockRecord->target = predlock->tag.myTarget->tag;
4841
4843 &record, sizeof(record));
4844 }
4845
4847}
4848
4849/*
4850 * PostPrepare_Locks
4851 * Clean up after successful PREPARE. Unlike the non-predicate
4852 * lock manager, we do not need to transfer locks to a dummy
4853 * PGPROC because our SERIALIZABLEXACT will stay around
4854 * anyway. We only need to clean up our local state.
4855 */
4856void
4858{
4860 return;
4861
4863
4866
4869
4871 MyXactDidWrite = false;
4872}
4873
4874/*
4875 * PredicateLockTwoPhaseFinish
4876 * Release a prepared transaction's predicate locks once it
4877 * commits or aborts.
4878 */
4879void
4881{
4884
4886
4888 sxid = (SERIALIZABLEXID *)
4891
4892 /* xid will not be found if it wasn't a serializable transaction */
4893 if (sxid == NULL)
4894 return;
4895
4896 /* Release its locks */
4897 MySerializableXact = sxid->myXact;
4898 MyXactDidWrite = true; /* conservatively assume that we wrote
4899 * something */
4901}
4902
4903/*
4904 * Re-acquire a predicate lock belonging to a transaction that was prepared.
4905 */
4906void
4908 void *recdata, uint32 len)
4909{
4912
4914
4915 record = (TwoPhasePredicateRecord *) recdata;
4916
4918 (record->type == TWOPHASEPREDICATERECORD_LOCK));
4919
4920 if (record->type == TWOPHASEPREDICATERECORD_XACT)
4921 {
4922 /* Per-transaction record. Set up a SERIALIZABLEXACT. */
4923 TwoPhasePredicateXactRecord *xactRecord;
4927 bool found;
4928
4929 xactRecord = (TwoPhasePredicateXactRecord *) &record->data.xactRecord;
4930
4933 if (!sxact)
4934 ereport(ERROR,
4936 errmsg("out of shared memory")));
4937
4938 /* vxid for a prepared xact is INVALID_PROC_NUMBER/xid; no pid */
4939 sxact->vxid.procNumber = INVALID_PROC_NUMBER;
4940 sxact->vxid.localTransactionId = (LocalTransactionId) xid;
4941 sxact->pid = 0;
4942 sxact->pgprocno = INVALID_PROC_NUMBER;
4943
4944 /* a prepared xact hasn't committed yet */
4945 sxact->prepareSeqNo = RecoverySerCommitSeqNo;
4946 sxact->commitSeqNo = InvalidSerCommitSeqNo;
4947 sxact->finishedBefore = InvalidTransactionId;
4948
4949 sxact->SeqNo.lastCommitBeforeSnapshot = RecoverySerCommitSeqNo;
4950
4951 /*
4952 * Don't need to track this; no transactions running at the time the
4953 * recovered xact started are still active, except possibly other
4954 * prepared xacts and we don't care whether those are RO_SAFE or not.
4955 */
4956 dlist_init(&(sxact->possibleUnsafeConflicts));
4957
4958 dlist_init(&(sxact->predicateLocks));
4959 dlist_node_init(&sxact->finishedLink);
4960
4961 sxact->topXid = xid;
4962 sxact->xmin = xactRecord->xmin;
4963 sxact->flags = xactRecord->flags;
4965 if (!SxactIsReadOnly(sxact))
4966 {
4970 }
4971
4972 /*
4973 * We don't know whether the transaction had any conflicts or not, so
4974 * we'll conservatively assume that it had both a conflict in and a
4975 * conflict out, and represent that with the summary conflict flags.
4976 */
4977 dlist_init(&(sxact->outConflicts));
4978 dlist_init(&(sxact->inConflicts));
4981
4982 /* Register the transaction's xid */
4983 sxidtag.xid = xid;
4985 &sxidtag,
4986 HASH_ENTER, &found);
4987 Assert(sxid != NULL);
4988 Assert(!found);
4989 sxid->myXact = sxact;
4990
4991 /*
4992 * Update global xmin. Note that this is a special case compared to
4993 * registering a normal transaction, because the global xmin might go
4994 * backwards. That's OK, because until recovery is over we're not
4995 * going to complete any transactions or create any non-prepared
4996 * transactions, so there's no danger of throwing away.
4997 */
5000 {
5004 }
5006 {
5009 }
5010
5012 }
5013 else if (record->type == TWOPHASEPREDICATERECORD_LOCK)
5014 {
5015 /* Lock record. Recreate the PREDICATELOCK */
5016 TwoPhasePredicateLockRecord *lockRecord;
5021
5022 lockRecord = (TwoPhasePredicateLockRecord *) &record->data.lockRecord;
5024
5026 sxidtag.xid = xid;
5027 sxid = (SERIALIZABLEXID *)
5030
5031 Assert(sxid != NULL);
5032 sxact = sxid->myXact;
5034
5036 }
5037}
5038
5039/*
5040 * Prepare to share the current SERIALIZABLEXACT with parallel workers.
5041 * Return a handle object that can be used by AttachSerializableXact() in a
5042 * parallel worker.
5043 */
5046{
5047 return MySerializableXact;
5048}
5049
5050/*
5051 * Allow parallel workers to import the leader's SERIALIZABLEXACT.
5052 */
5053void
5055{
5056
5058
5062}
bool ParallelContextActive(void)
Definition parallel.c:1033
uint32 BlockNumber
Definition block.h:31
#define InvalidBlockNumber
Definition block.h:33
static bool BlockNumberIsValid(BlockNumber blockNumber)
Definition block.h:71
#define unconstify(underlying_type, expr)
Definition c.h:1288
#define PG_USED_FOR_ASSERTS_ONLY
Definition c.h:235
#define Assert(condition)
Definition c.h:906
int64_t int64
Definition c.h:576
uint16_t uint16
Definition c.h:578
uint32_t uint32
Definition c.h:579
uint32 LocalTransactionId
Definition c.h:701
uint32 TransactionId
Definition c.h:699
size_t Size
Definition c.h:652
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition dynahash.c:952
Size hash_estimate_size(int64 num_entries, Size entrysize)
Definition dynahash.c:783
HTAB * hash_create(const char *tabname, int64 nelem, const HASHCTL *info, int flags)
Definition dynahash.c:358
void hash_destroy(HTAB *hashp)
Definition dynahash.c:865
void * hash_search_with_hash_value(HTAB *hashp, const void *keyPtr, uint32 hashvalue, HASHACTION action, bool *foundPtr)
Definition dynahash.c:965
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition dynahash.c:1415
int64 hash_get_num_entries(HTAB *hashp)
Definition dynahash.c:1336
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition dynahash.c:1380
int errcode(int sqlerrcode)
Definition elog.c:874
int int errdetail_internal(const char *fmt,...) pg_attribute_printf(1
int errhint(const char *fmt,...) pg_attribute_printf(1
int errdetail(const char *fmt,...) pg_attribute_printf(1
int int errmsg_internal(const char *fmt,...) pg_attribute_printf(1
#define DEBUG2
Definition elog.h:29
#define ERROR
Definition elog.h:39
#define elog(elevel,...)
Definition elog.h:226
#define ereport(elevel,...)
Definition elog.h:150
#define palloc_object(type)
Definition fe_memutils.h:74
#define palloc_array(type, count)
Definition fe_memutils.h:76
int MyProcPid
Definition globals.c:47
ProcNumber MyProcNumber
Definition globals.c:90
bool IsUnderPostmaster
Definition globals.c:120
int MaxBackends
Definition globals.c:146
int serializable_buffers
Definition globals.c:165
#define newval
GucSource
Definition guc.h:112
@ HASH_FIND
Definition hsearch.h:113
@ HASH_REMOVE
Definition hsearch.h:115
@ HASH_ENTER
Definition hsearch.h:114
@ HASH_ENTER_NULL
Definition hsearch.h:116
#define HASH_ELEM
Definition hsearch.h:95
#define HASH_FUNCTION
Definition hsearch.h:98
#define HASH_BLOBS
Definition hsearch.h:97
#define HASH_FIXED_SIZE
Definition hsearch.h:105
#define HASH_PARTITION
Definition hsearch.h:92
static dlist_node * dlist_pop_head_node(dlist_head *head)
Definition ilist.h:450
#define dlist_foreach(iter, lhead)
Definition ilist.h:623
static void dlist_init(dlist_head *head)
Definition ilist.h:314
#define dlist_head_element(type, membername, lhead)
Definition ilist.h:603
static void dlist_delete_thoroughly(dlist_node *node)
Definition ilist.h:416
static void dlist_delete(dlist_node *node)
Definition ilist.h:405
#define dlist_foreach_modify(iter, lhead)
Definition ilist.h:640
static bool dlist_is_empty(const dlist_head *head)
Definition ilist.h:336
static void dlist_push_tail(dlist_head *head, dlist_node *node)
Definition ilist.h:364
static void dlist_node_init(dlist_node *node)
Definition ilist.h:325
#define dlist_container(type, membername, ptr)
Definition ilist.h:593
#define IsParallelWorker()
Definition parallel.h:62
FILE * output
long val
Definition informix.c:689
static bool success
Definition initdb.c:187
int i
Definition isn.c:77
static OffsetNumber ItemPointerGetOffsetNumber(const ItemPointerData *pointer)
Definition itemptr.h:124
static BlockNumber ItemPointerGetBlockNumber(const ItemPointerData *pointer)
Definition itemptr.h:103
#define GET_VXID_FROM_PGPROC(vxid_dst, proc)
Definition lock.h:79
#define SetInvalidVirtualTransactionId(vxid)
Definition lock.h:76
bool LWLockHeldByMe(LWLock *lock)
Definition lwlock.c:1912
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition lwlock.c:1177
bool LWLockHeldByMeInMode(LWLock *lock, LWLockMode mode)
Definition lwlock.c:1956
void LWLockRelease(LWLock *lock)
Definition lwlock.c:1794
void LWLockInitialize(LWLock *lock, int tranche_id)
Definition lwlock.c:699
@ LW_SHARED
Definition lwlock.h:113
@ LW_EXCLUSIVE
Definition lwlock.h:112
#define NUM_PREDICATELOCK_PARTITIONS
Definition lwlock.h:99
#define InvalidPid
Definition miscadmin.h:32
static char * errmsg
#define SLRU_PAGES_PER_SEGMENT
const void size_t len
const void * data
static bool pg_lfind32(uint32 key, const uint32 *base, uint32 nelem)
Definition pg_lfind.h:153
static rewind_source * source
Definition pg_rewind.c:89
#define ERRCODE_T_R_SERIALIZATION_FAILURE
Definition pgbench.c:77
#define InvalidOid
unsigned int Oid
PredicateLockData * GetPredicateLockStatusData(void)
Definition predicate.c:1446
void CheckPointPredicate(void)
Definition predicate.c:1042
void PredicateLockPageSplit(Relation relation, BlockNumber oldblkno, BlockNumber newblkno)
Definition predicate.c:3143
static void DecrementParentLocks(const PREDICATELOCKTARGETTAG *targettag)
Definition predicate.c:2390
static HTAB * PredicateLockHash
Definition predicate.c:399
static void SetPossibleUnsafeConflict(SERIALIZABLEXACT *roXact, SERIALIZABLEXACT *activeXact)
Definition predicate.c:667
#define PredicateLockTargetTagHashCode(predicatelocktargettag)
Definition predicate.c:304
static void SetNewSxactGlobalXmin(void)
Definition predicate.c:3250
void CheckForSerializableConflictIn(Relation relation, const ItemPointerData *tid, BlockNumber blkno)
Definition predicate.c:4335
#define SerialPage(xid)
Definition predicate.c:344
static void ReleasePredXact(SERIALIZABLEXACT *sxact)
Definition predicate.c:597
void SetSerializableTransactionSnapshot(Snapshot snapshot, VirtualTransactionId *sourcevxid, int sourcepid)
Definition predicate.c:1721
static bool RWConflictExists(const SERIALIZABLEXACT *reader, const SERIALIZABLEXACT *writer)
Definition predicate.c:611
static bool PredicateLockingNeededForRelation(Relation relation)
Definition predicate.c:499
static bool SerializationNeededForRead(Relation relation, Snapshot snapshot)
Definition predicate.c:517
static Snapshot GetSafeSnapshot(Snapshot origSnapshot)
Definition predicate.c:1557
#define SxactIsCommitted(sxact)
Definition predicate.c:278
static SerialControl serialControl
Definition predicate.c:355
void PredicateLockPage(Relation relation, BlockNumber blkno, Snapshot snapshot)
Definition predicate.c:2598
#define SxactIsROUnsafe(sxact)
Definition predicate.c:293
static Snapshot GetSerializableTransactionSnapshotInt(Snapshot snapshot, VirtualTransactionId *sourcevxid, int sourcepid)
Definition predicate.c:1763
static LWLock * ScratchPartitionLock
Definition predicate.c:409
static void PredicateLockAcquire(const PREDICATELOCKTARGETTAG *targettag)
Definition predicate.c:2516
#define SxactIsDeferrableWaiting(sxact)
Definition predicate.c:291
static void ReleasePredicateLocksLocal(void)
Definition predicate.c:3678
static HTAB * LocalPredicateLockHash
Definition predicate.c:415
int max_predicate_locks_per_page
Definition predicate.c:374
struct SerialControlData * SerialControl
Definition predicate.c:353
static PredXactList PredXact
Definition predicate.c:385
static void SetRWConflict(SERIALIZABLEXACT *reader, SERIALIZABLEXACT *writer)
Definition predicate.c:644
int GetSafeSnapshotBlockingPids(int blocked_pid, int *output, int output_size)
Definition predicate.c:1627
static uint32 ScratchTargetTagHash
Definition predicate.c:408
static void RemoveTargetIfNoLongerUsed(PREDICATELOCKTARGET *target, uint32 targettaghash)
Definition predicate.c:2182
static uint32 predicatelock_hash(const void *key, Size keysize)
Definition predicate.c:1420
void CheckForSerializableConflictOut(Relation relation, TransactionId xid, Snapshot snapshot)
Definition predicate.c:4022
#define SxactIsReadOnly(sxact)
Definition predicate.c:282
#define SerialNextPage(page)
Definition predicate.c:338
static void DropAllPredicateLocksFromTable(Relation relation, bool transfer)
Definition predicate.c:2936
bool PageIsPredicateLocked(Relation relation, BlockNumber blkno)
Definition predicate.c:2007
static void CreatePredicateLock(const PREDICATELOCKTARGETTAG *targettag, uint32 targettaghash, SERIALIZABLEXACT *sxact)
Definition predicate.c:2452
static void SerialAdd(TransactionId xid, SerCommitSeqNo minConflictCommitSeqNo)
Definition predicate.c:859
static void ClearOldPredicateLocks(void)
Definition predicate.c:3696
#define SxactHasSummaryConflictIn(sxact)
Definition predicate.c:283
static SERIALIZABLEXACT * CreatePredXact(void)
Definition predicate.c:583
static bool GetParentPredicateLockTag(const PREDICATELOCKTARGETTAG *tag, PREDICATELOCKTARGETTAG *parent)
Definition predicate.c:2071
#define PredicateLockHashCodeFromTargetHashCode(predicatelocktag, targethash)
Definition predicate.c:317
static void RestoreScratchTarget(bool lockheld)
Definition predicate.c:2160
#define SerialValue(slotno, xid)
Definition predicate.c:340
static void DeleteChildTargetLocks(const PREDICATELOCKTARGETTAG *newtargettag)
Definition predicate.c:2213
static void DeleteLockTarget(PREDICATELOCKTARGET *target, uint32 targettaghash)
Definition predicate.c:2668
void PredicateLockTwoPhaseFinish(FullTransactionId fxid, bool isCommit)
Definition predicate.c:4881
void predicatelock_twophase_recover(FullTransactionId fxid, uint16 info, void *recdata, uint32 len)
Definition predicate.c:4908
static SERIALIZABLEXACT * OldCommittedSxact
Definition predicate.c:363
#define SxactHasConflictOut(sxact)
Definition predicate.c:290
static bool MyXactDidWrite
Definition predicate.c:423
static int MaxPredicateChildLocks(const PREDICATELOCKTARGETTAG *tag)
Definition predicate.c:2288
static void FlagSxactUnsafe(SERIALIZABLEXACT *sxact)
Definition predicate.c:700
static void SerialInit(void)
Definition predicate.c:807
void CheckTableForSerializableConflictIn(Relation relation)
Definition predicate.c:4418
#define SxactIsPrepared(sxact)
Definition predicate.c:279
void AttachSerializableXact(SerializableXactHandle handle)
Definition predicate.c:5055
SerializableXactHandle ShareSerializableXact(void)
Definition predicate.c:5046
static bool PredicateLockExists(const PREDICATELOCKTARGETTAG *targettag)
Definition predicate.c:2044
static void RemoveScratchTarget(bool lockheld)
Definition predicate.c:2139
#define SxactIsOnFinishedList(sxact)
Definition predicate.c:268
#define SxactIsPartiallyReleased(sxact)
Definition predicate.c:294
static void SerialSetActiveSerXmin(TransactionId xid)
Definition predicate.c:991
static dlist_head * FinishedSerializableTransactions
Definition predicate.c:400
static bool SerializationNeededForWrite(Relation relation)
Definition predicate.c:561
static HTAB * SerializableXidHash
Definition predicate.c:397
static bool CheckAndPromotePredicateLockRequest(const PREDICATELOCKTARGETTAG *reqtag)
Definition predicate.c:2325
void PredicateLockPageCombine(Relation relation, BlockNumber oldblkno, BlockNumber newblkno)
Definition predicate.c:3228
static bool SerialPagePrecedesLogically(int64 page1, int64 page2)
Definition predicate.c:732
static void CheckTargetForConflictsIn(PREDICATELOCKTARGETTAG *targettag)
Definition predicate.c:4165
int max_predicate_locks_per_relation
Definition predicate.c:373
#define SxactIsROSafe(sxact)
Definition predicate.c:292
void PreCommit_CheckForSerializationFailure(void)
Definition predicate.c:4702
void ReleasePredicateLocks(bool isCommit, bool isReadOnlySafe)
Definition predicate.c:3311
static void FlagRWConflict(SERIALIZABLEXACT *reader, SERIALIZABLEXACT *writer)
Definition predicate.c:4500
static const PREDICATELOCKTARGETTAG ScratchTargetTag
Definition predicate.c:407
#define PredicateLockHashPartitionLockByIndex(i)
Definition predicate.c:262
static void OnConflict_CheckForSerializationFailure(const SERIALIZABLEXACT *reader, SERIALIZABLEXACT *writer)
Definition predicate.c:4535
static bool CoarserLockCovers(const PREDICATELOCKTARGETTAG *newtargettag)
Definition predicate.c:2110
void PredicateLockRelation(Relation relation, Snapshot snapshot)
Definition predicate.c:2575
static SERIALIZABLEXACT * MySerializableXact
Definition predicate.c:422
void PredicateLockShmemInit(void)
Definition predicate.c:1146
void PredicateLockTID(Relation relation, const ItemPointerData *tid, Snapshot snapshot, TransactionId tuple_xid)
Definition predicate.c:2620
Size PredicateLockShmemSize(void)
Definition predicate.c:1358
#define SxactIsDoomed(sxact)
Definition predicate.c:281
#define NPREDICATELOCKTARGETENTS()
Definition predicate.c:265
static SerCommitSeqNo SerialGetMinConflictCommitSeqNo(TransactionId xid)
Definition predicate.c:950
static void SummarizeOldestCommittedSxact(void)
Definition predicate.c:1502
bool check_serial_buffers(int *newval, void **extra, GucSource source)
Definition predicate.c:848
void PostPrepare_PredicateLocks(FullTransactionId fxid)
Definition predicate.c:4858
#define TargetTagIsCoveredBy(covered_target, covering_target)
Definition predicate.c:234
static RWConflictPoolHeader RWConflictPool
Definition predicate.c:391
static void ReleaseRWConflict(RWConflict conflict)
Definition predicate.c:692
static bool TransferPredicateLocksToNewTarget(PREDICATELOCKTARGETTAG oldtargettag, PREDICATELOCKTARGETTAG newtargettag, bool removeOld)
Definition predicate.c:2729
void AtPrepare_PredicateLocks(void)
Definition predicate.c:4789
void RegisterPredicateLockingXid(TransactionId xid)
Definition predicate.c:1958
#define PredicateLockHashPartitionLock(hashcode)
Definition predicate.c:259
#define SERIAL_ENTRIESPERPAGE
Definition predicate.c:331
static bool XidIsConcurrent(TransactionId xid)
Definition predicate.c:3971
static void ReleaseOneSerializableXact(SERIALIZABLEXACT *sxact, bool partial, bool summarize)
Definition predicate.c:3834
static HTAB * PredicateLockTargetHash
Definition predicate.c:398
bool CheckForSerializableConflictOutNeeded(Relation relation, Snapshot snapshot)
Definition predicate.c:3990
#define SxactIsRolledBack(sxact)
Definition predicate.c:280
static SERIALIZABLEXACT * SavedSerializableXact
Definition predicate.c:432
#define SxactHasSummaryConflictOut(sxact)
Definition predicate.c:284
void TransferPredicateLocksToHeapRelation(Relation relation)
Definition predicate.c:3122
static void CreateLocalPredicateLockHash(void)
Definition predicate.c:1939
#define SerialSlruCtl
Definition predicate.c:327
int max_predicate_locks_per_xact
Definition predicate.c:372
Snapshot GetSerializableTransactionSnapshot(Snapshot snapshot)
Definition predicate.c:1681
void * SerializableXactHandle
Definition predicate.h:34
#define RWConflictDataSize
#define SXACT_FLAG_DEFERRABLE_WAITING
#define SXACT_FLAG_SUMMARY_CONFLICT_IN
@ TWOPHASEPREDICATERECORD_XACT
@ TWOPHASEPREDICATERECORD_LOCK
#define FirstNormalSerCommitSeqNo
#define InvalidSerCommitSeqNo
@ PREDLOCKTAG_RELATION
@ PREDLOCKTAG_PAGE
@ PREDLOCKTAG_TUPLE
#define SXACT_FLAG_CONFLICT_OUT
#define PredXactListDataSize
#define SXACT_FLAG_READ_ONLY
#define SXACT_FLAG_DOOMED
#define GET_PREDICATELOCKTARGETTAG_DB(locktag)
#define GET_PREDICATELOCKTARGETTAG_RELATION(locktag)
#define RWConflictPoolHeaderDataSize
#define InvalidSerializableXact
#define SET_PREDICATELOCKTARGETTAG_PAGE(locktag, dboid, reloid, blocknum)
#define RecoverySerCommitSeqNo
struct RWConflictData * RWConflict
#define GET_PREDICATELOCKTARGETTAG_TYPE(locktag)
#define SET_PREDICATELOCKTARGETTAG_RELATION(locktag, dboid, reloid)
uint64 SerCommitSeqNo
#define SXACT_FLAG_ROLLED_BACK
#define SXACT_FLAG_COMMITTED
#define SXACT_FLAG_RO_UNSAFE
#define SXACT_FLAG_PREPARED
#define SET_PREDICATELOCKTARGETTAG_TUPLE(locktag, dboid, reloid, blocknum, offnum)
#define SXACT_FLAG_PARTIALLY_RELEASED
#define GET_PREDICATELOCKTARGETTAG_PAGE(locktag)
#define SXACT_FLAG_RO_SAFE
#define SXACT_FLAG_SUMMARY_CONFLICT_OUT
#define GET_PREDICATELOCKTARGETTAG_OFFSET(locktag)
static int fb(int x)
Snapshot GetSnapshotData(Snapshot snapshot)
Definition procarray.c:2127
bool ProcArrayInstallImportedXmin(TransactionId xmin, VirtualTransactionId *sourcevxid)
Definition procarray.c:2484
#define INVALID_PROC_NUMBER
Definition procnumber.h:26
#define RelationUsesLocalBuffers(relation)
Definition rel.h:646
bool ShmemAddrIsValid(const void *addr)
Definition shmem.c:265
Size add_size(Size s1, Size s2)
Definition shmem.c:482
Size mul_size(Size s1, Size s2)
Definition shmem.c:497
HTAB * ShmemInitHash(const char *name, int64 init_size, int64 max_size, HASHCTL *infoP, int hash_flags)
Definition shmem.c:323
void * ShmemInitStruct(const char *name, Size size, bool *foundPtr)
Definition shmem.c:378
void SimpleLruInit(SlruCtl ctl, const char *name, int nslots, int nlsns, const char *subdir, int buffer_tranche_id, int bank_tranche_id, SyncRequestHandler sync_handler, bool long_segment_names)
Definition slru.c:253
int SimpleLruReadPage_ReadOnly(SlruCtl ctl, int64 pageno, TransactionId xid)
Definition slru.c:631
void SimpleLruWriteAll(SlruCtl ctl, bool allow_redirtied)
Definition slru.c:1348
int SimpleLruReadPage(SlruCtl ctl, int64 pageno, bool write_ok, TransactionId xid)
Definition slru.c:528
int SimpleLruZeroPage(SlruCtl ctl, int64 pageno)
Definition slru.c:376
void SimpleLruTruncate(SlruCtl ctl, int64 cutoffPage)
Definition slru.c:1434
Size SimpleLruShmemSize(int nslots, int nlsns)
Definition slru.c:199
bool check_slru_buffers(const char *name, int *newval)
Definition slru.c:356
static LWLock * SimpleLruGetBankLock(SlruCtl ctl, int64 pageno)
Definition slru.h:160
#define SlruPagePrecedesUnitTests(ctl, per_page)
Definition slru.h:185
Snapshot GetTransactionSnapshot(void)
Definition snapmgr.c:272
#define IsMVCCSnapshot(snapshot)
Definition snapmgr.h:55
void ProcSendSignal(ProcNumber procNumber)
Definition proc.c:1984
PGPROC * MyProc
Definition proc.c:68
void ProcWaitForSignal(uint32 wait_event_info)
Definition proc.c:1972
Size keysize
Definition hsearch.h:75
HashValueFunc hash
Definition hsearch.h:78
Size entrysize
Definition hsearch.h:76
int64 num_partitions
Definition hsearch.h:68
Definition proc.h:176
SERIALIZABLEXACT * myXact
PREDICATELOCKTARGET * myTarget
PREDICATELOCKTARGETTAG tag
SerCommitSeqNo commitSeqNo
SERIALIZABLEXACT * element
SerCommitSeqNo LastSxactCommitSeqNo
SerCommitSeqNo CanPartialClearThrough
SERIALIZABLEXACT * OldCommittedSxact
SerCommitSeqNo HavePartialClearedThrough
TransactionId SxactGlobalXmin
Form_pg_index rd_index
Definition rel.h:192
Oid rd_id
Definition rel.h:113
RelFileLocator rd_locator
Definition rel.h:57
VirtualTransactionId vxid
SerCommitSeqNo lastCommitBeforeSnapshot
dlist_head possibleUnsafeConflicts
SerCommitSeqNo prepareSeqNo
SerCommitSeqNo commitSeqNo
union SERIALIZABLEXACT::@131 SeqNo
TransactionId finishedBefore
SerCommitSeqNo earliestOutConflictCommit
TransactionId headXid
Definition predicate.c:349
TransactionId tailXid
Definition predicate.c:350
TransactionId xmin
Definition snapshot.h:153
FullTransactionId nextXid
Definition transam.h:220
PREDICATELOCKTARGETTAG target
TwoPhasePredicateRecordType type
TwoPhasePredicateLockRecord lockRecord
union TwoPhasePredicateRecord::@132 data
TwoPhasePredicateXactRecord xactRecord
dlist_node * cur
Definition ilist.h:179
dlist_node * cur
Definition ilist.h:200
@ SYNC_HANDLER_NONE
Definition sync.h:42
static bool TransactionIdFollows(TransactionId id1, TransactionId id2)
Definition transam.h:297
#define FirstUnpinnedObjectId
Definition transam.h:196
#define InvalidTransactionId
Definition transam.h:31
static bool TransactionIdPrecedesOrEquals(TransactionId id1, TransactionId id2)
Definition transam.h:282
static bool TransactionIdFollowsOrEquals(TransactionId id1, TransactionId id2)
Definition transam.h:312
#define TransactionIdEquals(id1, id2)
Definition transam.h:43
#define XidFromFullTransactionId(x)
Definition transam.h:48
#define FirstNormalTransactionId
Definition transam.h:34
#define TransactionIdIsValid(xid)
Definition transam.h:41
static bool TransactionIdPrecedes(TransactionId id1, TransactionId id2)
Definition transam.h:263
void RegisterTwoPhaseRecord(TwoPhaseRmgrId rmid, uint16 info, const void *data, uint32 len)
Definition twophase.c:1273
int max_prepared_xacts
Definition twophase.c:117
#define TWOPHASE_RM_PREDICATELOCK_ID
TransamVariablesData * TransamVariables
Definition varsup.c:34
bool XactDeferrable
Definition xact.c:87
bool XactReadOnly
Definition xact.c:84
TransactionId GetTopTransactionIdIfAny(void)
Definition xact.c:443
bool IsSubTransaction(void)
Definition xact.c:5067
bool TransactionIdIsCurrentTransactionId(TransactionId xid)
Definition xact.c:943
bool IsInParallelMode(void)
Definition xact.c:1091
#define IsolationIsSerializable()
Definition xact.h:53
bool RecoveryInProgress(void)
Definition xlog.c:6444

◆ PredicateLockHashCodeFromTargetHashCode

#define PredicateLockHashCodeFromTargetHashCode (   predicatelocktag,
  targethash 
)
Value:
#define LOG2_NUM_PREDICATELOCK_PARTITIONS
Definition lwlock.h:98
static Datum PointerGetDatum(const void *X)
Definition postgres.h:352

Definition at line 317 of file predicate.c.

◆ PredicateLockHashPartition

#define PredicateLockHashPartition (   hashcode)     ((hashcode) % NUM_PREDICATELOCK_PARTITIONS)

Definition at line 257 of file predicate.c.

◆ PredicateLockHashPartitionLock

#define PredicateLockHashPartitionLock (   hashcode)
Value:
LWLockPadded * MainLWLockArray
Definition lwlock.c:162
#define PREDICATELOCK_MANAGER_LWLOCK_OFFSET
Definition lwlock.h:105
LWLock lock
Definition lwlock.h:70

Definition at line 259 of file predicate.c.

◆ PredicateLockHashPartitionLockByIndex

#define PredicateLockHashPartitionLockByIndex (   i)     (&MainLWLockArray[PREDICATELOCK_MANAGER_LWLOCK_OFFSET + (i)].lock)

Definition at line 262 of file predicate.c.

◆ PredicateLockTargetTagHashCode

Definition at line 304 of file predicate.c.

◆ SERIAL_ENTRIESPERPAGE

#define SERIAL_ENTRIESPERPAGE   (SERIAL_PAGESIZE / SERIAL_ENTRYSIZE)

Definition at line 331 of file predicate.c.

◆ SERIAL_ENTRYSIZE

#define SERIAL_ENTRYSIZE   sizeof(SerCommitSeqNo)

Definition at line 330 of file predicate.c.

◆ SERIAL_MAX_PAGE

#define SERIAL_MAX_PAGE   (MaxTransactionId / SERIAL_ENTRIESPERPAGE)

Definition at line 336 of file predicate.c.

◆ SERIAL_PAGESIZE

#define SERIAL_PAGESIZE   BLCKSZ

Definition at line 329 of file predicate.c.

◆ SerialNextPage

#define SerialNextPage (   page)    (((page) >= SERIAL_MAX_PAGE) ? 0 : (page) + 1)

Definition at line 338 of file predicate.c.

◆ SerialPage

#define SerialPage (   xid)    (((uint32) (xid)) / SERIAL_ENTRIESPERPAGE)

Definition at line 344 of file predicate.c.

◆ SerialSlruCtl

#define SerialSlruCtl   (&SerialSlruCtlData)

Definition at line 327 of file predicate.c.

◆ SerialValue

#define SerialValue (   slotno,
  xid 
)
Value:
(*((SerCommitSeqNo *) \
(SerialSlruCtl->shared->page_buffer[slotno] + \
#define SERIAL_ENTRYSIZE
Definition predicate.c:330

Definition at line 340 of file predicate.c.

◆ SxactHasConflictOut

#define SxactHasConflictOut (   sxact)    (((sxact)->flags & SXACT_FLAG_CONFLICT_OUT) != 0)

Definition at line 290 of file predicate.c.

◆ SxactHasSummaryConflictIn

#define SxactHasSummaryConflictIn (   sxact)    (((sxact)->flags & SXACT_FLAG_SUMMARY_CONFLICT_IN) != 0)

Definition at line 283 of file predicate.c.

◆ SxactHasSummaryConflictOut

#define SxactHasSummaryConflictOut (   sxact)    (((sxact)->flags & SXACT_FLAG_SUMMARY_CONFLICT_OUT) != 0)

Definition at line 284 of file predicate.c.

◆ SxactIsCommitted

#define SxactIsCommitted (   sxact)    (((sxact)->flags & SXACT_FLAG_COMMITTED) != 0)

Definition at line 278 of file predicate.c.

◆ SxactIsDeferrableWaiting

#define SxactIsDeferrableWaiting (   sxact)    (((sxact)->flags & SXACT_FLAG_DEFERRABLE_WAITING) != 0)

Definition at line 291 of file predicate.c.

◆ SxactIsDoomed

#define SxactIsDoomed (   sxact)    (((sxact)->flags & SXACT_FLAG_DOOMED) != 0)

Definition at line 281 of file predicate.c.

◆ SxactIsOnFinishedList

#define SxactIsOnFinishedList (   sxact)    (!dlist_node_is_detached(&(sxact)->finishedLink))

Definition at line 268 of file predicate.c.

◆ SxactIsPartiallyReleased

#define SxactIsPartiallyReleased (   sxact)    (((sxact)->flags & SXACT_FLAG_PARTIALLY_RELEASED) != 0)

Definition at line 294 of file predicate.c.

◆ SxactIsPrepared

#define SxactIsPrepared (   sxact)    (((sxact)->flags & SXACT_FLAG_PREPARED) != 0)

Definition at line 279 of file predicate.c.

◆ SxactIsReadOnly

#define SxactIsReadOnly (   sxact)    (((sxact)->flags & SXACT_FLAG_READ_ONLY) != 0)

Definition at line 282 of file predicate.c.

◆ SxactIsRolledBack

#define SxactIsRolledBack (   sxact)    (((sxact)->flags & SXACT_FLAG_ROLLED_BACK) != 0)

Definition at line 280 of file predicate.c.

◆ SxactIsROSafe

#define SxactIsROSafe (   sxact)    (((sxact)->flags & SXACT_FLAG_RO_SAFE) != 0)

Definition at line 292 of file predicate.c.

◆ SxactIsROUnsafe

#define SxactIsROUnsafe (   sxact)    (((sxact)->flags & SXACT_FLAG_RO_UNSAFE) != 0)

Definition at line 293 of file predicate.c.

◆ TargetTagIsCoveredBy

Typedef Documentation

◆ SerialControl

Definition at line 353 of file predicate.c.

◆ SerialControlData

Function Documentation

◆ AtPrepare_PredicateLocks()

void AtPrepare_PredicateLocks ( void  )

Definition at line 4789 of file predicate.c.

4790{
4793 TwoPhasePredicateXactRecord *xactRecord;
4794 TwoPhasePredicateLockRecord *lockRecord;
4795 dlist_iter iter;
4796
4798 xactRecord = &(record.data.xactRecord);
4799 lockRecord = &(record.data.lockRecord);
4800
4802 return;
4803
4804 /* Generate an xact record for our SERIALIZABLEXACT */
4806 xactRecord->xmin = MySerializableXact->xmin;
4807 xactRecord->flags = MySerializableXact->flags;
4808
4809 /*
4810 * Note that we don't include the list of conflicts in our out in the
4811 * statefile, because new conflicts can be added even after the
4812 * transaction prepares. We'll just make a conservative assumption during
4813 * recovery instead.
4814 */
4815
4817 &record, sizeof(record));
4818
4819 /*
4820 * Generate a lock record for each lock.
4821 *
4822 * To do this, we need to walk the predicate lock list in our sxact rather
4823 * than using the local predicate lock table because the latter is not
4824 * guaranteed to be accurate.
4825 */
4827
4828 /*
4829 * No need to take sxact->perXactPredicateListLock in parallel mode
4830 * because there cannot be any parallel workers running while we are
4831 * preparing a transaction.
4832 */
4834
4835 dlist_foreach(iter, &sxact->predicateLocks)
4836 {
4838 dlist_container(PREDICATELOCK, xactLink, iter.cur);
4839
4841 lockRecord->target = predlock->tag.myTarget->tag;
4842
4844 &record, sizeof(record));
4845 }
4846
4848}

References Assert, dlist_iter::cur, TwoPhasePredicateRecord::data, dlist_container, dlist_foreach, fb(), SERIALIZABLEXACT::flags, TwoPhasePredicateXactRecord::flags, InvalidSerializableXact, IsParallelWorker, TwoPhasePredicateRecord::lockRecord, LW_SHARED, LWLockAcquire(), LWLockRelease(), MySerializableXact, ParallelContextActive(), RegisterTwoPhaseRecord(), TwoPhasePredicateLockRecord::target, TWOPHASE_RM_PREDICATELOCK_ID, TWOPHASEPREDICATERECORD_LOCK, TWOPHASEPREDICATERECORD_XACT, TwoPhasePredicateRecord::type, TwoPhasePredicateRecord::xactRecord, SERIALIZABLEXACT::xmin, and TwoPhasePredicateXactRecord::xmin.

Referenced by PrepareTransaction().

◆ AttachSerializableXact()

◆ check_serial_buffers()

bool check_serial_buffers ( int newval,
void **  extra,
GucSource  source 
)

Definition at line 848 of file predicate.c.

849{
850 return check_slru_buffers("serializable_buffers", newval);
851}

References check_slru_buffers(), and newval.

◆ CheckAndPromotePredicateLockRequest()

static bool CheckAndPromotePredicateLockRequest ( const PREDICATELOCKTARGETTAG reqtag)
static

Definition at line 2325 of file predicate.c.

2326{
2328 nexttag,
2331 bool found,
2332 promote;
2333
2334 promote = false;
2335
2336 targettag = *reqtag;
2337
2338 /* check parents iteratively */
2340 {
2343 &targettag,
2344 HASH_ENTER,
2345 &found);
2346 if (!found)
2347 {
2348 parentlock->held = false;
2349 parentlock->childLocks = 1;
2350 }
2351 else
2352 parentlock->childLocks++;
2353
2354 if (parentlock->childLocks >
2356 {
2357 /*
2358 * We should promote to this parent lock. Continue to check its
2359 * ancestors, however, both to get their child counts right and to
2360 * check whether we should just go ahead and promote to one of
2361 * them.
2362 */
2364 promote = true;
2365 }
2366 }
2367
2368 if (promote)
2369 {
2370 /* acquire coarsest ancestor eligible for promotion */
2372 return true;
2373 }
2374 else
2375 return false;
2376}

References fb(), GetParentPredicateLockTag(), HASH_ENTER, hash_search(), LOCALPREDICATELOCK::held, LocalPredicateLockHash, MaxPredicateChildLocks(), and PredicateLockAcquire().

Referenced by PredicateLockAcquire().

◆ CheckForSerializableConflictIn()

void CheckForSerializableConflictIn ( Relation  relation,
const ItemPointerData tid,
BlockNumber  blkno 
)

Definition at line 4335 of file predicate.c.

4336{
4338
4339 if (!SerializationNeededForWrite(relation))
4340 return;
4341
4342 /* Check if someone else has already decided that we need to die */
4344 ereport(ERROR,
4346 errmsg("could not serialize access due to read/write dependencies among transactions"),
4347 errdetail_internal("Reason code: Canceled on identification as a pivot, during conflict in checking."),
4348 errhint("The transaction might succeed if retried.")));
4349
4350 /*
4351 * We're doing a write which might cause rw-conflicts now or later.
4352 * Memorize that fact.
4353 */
4354 MyXactDidWrite = true;
4355
4356 /*
4357 * It is important that we check for locks from the finest granularity to
4358 * the coarsest granularity, so that granularity promotion doesn't cause
4359 * us to miss a lock. The new (coarser) lock will be acquired before the
4360 * old (finer) locks are released.
4361 *
4362 * It is not possible to take and hold a lock across the checks for all
4363 * granularities because each target could be in a separate partition.
4364 */
4365 if (tid != NULL)
4366 {
4368 relation->rd_locator.dbOid,
4369 relation->rd_id,
4373 }
4374
4375 if (blkno != InvalidBlockNumber)
4376 {
4378 relation->rd_locator.dbOid,
4379 relation->rd_id,
4380 blkno);
4382 }
4383
4385 relation->rd_locator.dbOid,
4386 relation->rd_id);
4388}

References CheckTargetForConflictsIn(), RelFileLocator::dbOid, ereport, errcode(), ERRCODE_T_R_SERIALIZATION_FAILURE, errdetail_internal(), errhint(), errmsg, ERROR, fb(), InvalidBlockNumber, ItemPointerGetBlockNumber(), ItemPointerGetOffsetNumber(), MySerializableXact, MyXactDidWrite, RelationData::rd_id, RelationData::rd_locator, SerializationNeededForWrite(), SET_PREDICATELOCKTARGETTAG_PAGE, SET_PREDICATELOCKTARGETTAG_RELATION, SET_PREDICATELOCKTARGETTAG_TUPLE, and SxactIsDoomed.

Referenced by _bt_check_unique(), _bt_doinsert(), _hash_doinsert(), ginEntryInsert(), ginFindLeafPage(), ginHeapTupleFastInsert(), gistinserttuples(), heap_delete(), heap_insert(), heap_multi_insert(), heap_update(), and index_insert().

◆ CheckForSerializableConflictOut()

void CheckForSerializableConflictOut ( Relation  relation,
TransactionId  xid,
Snapshot  snapshot 
)

Definition at line 4022 of file predicate.c.

4023{
4027
4028 if (!SerializationNeededForRead(relation, snapshot))
4029 return;
4030
4031 /* Check if someone else has already decided that we need to die */
4033 {
4034 ereport(ERROR,
4036 errmsg("could not serialize access due to read/write dependencies among transactions"),
4037 errdetail_internal("Reason code: Canceled on identification as a pivot, during conflict out checking."),
4038 errhint("The transaction might succeed if retried.")));
4039 }
4041
4043 return;
4044
4045 /*
4046 * Find sxact or summarized info for the top level xid.
4047 */
4048 sxidtag.xid = xid;
4050 sxid = (SERIALIZABLEXID *)
4052 if (!sxid)
4053 {
4054 /*
4055 * Transaction not found in "normal" SSI structures. Check whether it
4056 * got pushed out to SLRU storage for "old committed" transactions.
4057 */
4059
4061 if (conflictCommitSeqNo != 0)
4062 {
4067 ereport(ERROR,
4069 errmsg("could not serialize access due to read/write dependencies among transactions"),
4070 errdetail_internal("Reason code: Canceled on conflict out to old pivot %u.", xid),
4071 errhint("The transaction might succeed if retried.")));
4072
4075 ereport(ERROR,
4077 errmsg("could not serialize access due to read/write dependencies among transactions"),
4078 errdetail_internal("Reason code: Canceled on identification as a pivot, with conflict out to old committed transaction %u.", xid),
4079 errhint("The transaction might succeed if retried.")));
4080
4082 }
4083
4084 /* It's not serializable or otherwise not important. */
4086 return;
4087 }
4088 sxact = sxid->myXact;
4089 Assert(TransactionIdEquals(sxact->topXid, xid));
4091 {
4092 /* Can't conflict with ourself or a transaction that will roll back. */
4094 return;
4095 }
4096
4097 /*
4098 * We have a conflict out to a transaction which has a conflict out to a
4099 * summarized transaction. That summarized transaction must have
4100 * committed first, and we can't tell when it committed in relation to our
4101 * snapshot acquisition, so something needs to be canceled.
4102 */
4104 {
4105 if (!SxactIsPrepared(sxact))
4106 {
4107 sxact->flags |= SXACT_FLAG_DOOMED;
4109 return;
4110 }
4111 else
4112 {
4114 ereport(ERROR,
4116 errmsg("could not serialize access due to read/write dependencies among transactions"),
4117 errdetail_internal("Reason code: Canceled on conflict out to old pivot."),
4118 errhint("The transaction might succeed if retried.")));
4119 }
4120 }
4121
4122 /*
4123 * If this is a read-only transaction and the writing transaction has
4124 * committed, and it doesn't have a rw-conflict to a transaction which
4125 * committed before it, no conflict.
4126 */
4131 || MySerializableXact->SeqNo.lastCommitBeforeSnapshot < sxact->SeqNo.earliestOutConflictCommit))
4132 {
4133 /* Read-only transaction will appear to run first. No conflict. */
4135 return;
4136 }
4137
4138 if (!XidIsConcurrent(xid))
4139 {
4140 /* This write was already in our snapshot; no conflict. */
4142 return;
4143 }
4144
4146 {
4147 /* We don't want duplicate conflict records in the list. */
4149 return;
4150 }
4151
4152 /*
4153 * Flag the conflict. But first, if this conflict creates a dangerous
4154 * structure, ereport an error.
4155 */
4158}

References Assert, dlist_is_empty(), ereport, errcode(), ERRCODE_T_R_SERIALIZATION_FAILURE, errdetail_internal(), errhint(), errmsg, ERROR, fb(), FlagRWConflict(), SERIALIZABLEXACT::flags, GetTopTransactionIdIfAny(), HASH_FIND, hash_search(), SERIALIZABLEXACT::inConflicts, InvalidSerCommitSeqNo, SERIALIZABLEXACT::lastCommitBeforeSnapshot, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), MySerializableXact, RWConflictExists(), SERIALIZABLEXACT::SeqNo, SerialGetMinConflictCommitSeqNo(), SerializableXidHash, SerializationNeededForRead(), SXACT_FLAG_DOOMED, SXACT_FLAG_SUMMARY_CONFLICT_OUT, SxactHasConflictOut, SxactHasSummaryConflictIn, SxactHasSummaryConflictOut, SxactIsCommitted, SxactIsDoomed, SxactIsPrepared, SxactIsReadOnly, TransactionIdEquals, TransactionIdIsValid, and XidIsConcurrent().

Referenced by HeapCheckForSerializableConflictOut().

◆ CheckForSerializableConflictOutNeeded()

bool CheckForSerializableConflictOutNeeded ( Relation  relation,
Snapshot  snapshot 
)

Definition at line 3990 of file predicate.c.

3991{
3992 if (!SerializationNeededForRead(relation, snapshot))
3993 return false;
3994
3995 /* Check if someone else has already decided that we need to die */
3997 {
3998 ereport(ERROR,
4000 errmsg("could not serialize access due to read/write dependencies among transactions"),
4001 errdetail_internal("Reason code: Canceled on identification as a pivot, during conflict out checking."),
4002 errhint("The transaction might succeed if retried.")));
4003 }
4004
4005 return true;
4006}

References ereport, errcode(), ERRCODE_T_R_SERIALIZATION_FAILURE, errdetail_internal(), errhint(), errmsg, ERROR, MySerializableXact, SerializationNeededForRead(), and SxactIsDoomed.

Referenced by heap_prepare_pagescan(), and HeapCheckForSerializableConflictOut().

◆ CheckPointPredicate()

void CheckPointPredicate ( void  )

Definition at line 1042 of file predicate.c.

1043{
1045
1047
1048 /* Exit quickly if the SLRU is currently not in use. */
1049 if (serialControl->headPage < 0)
1050 {
1052 return;
1053 }
1054
1056 {
1058
1060
1061 /*
1062 * It is possible for the tailXid to be ahead of the headXid. This
1063 * occurs if we checkpoint while there are in-progress serializable
1064 * transaction(s) advancing the tail but we are yet to summarize the
1065 * transactions. In this case, we cutoff up to the headPage and the
1066 * next summary will advance the headXid.
1067 */
1069 {
1070 /* We can truncate the SLRU up to the page containing tailXid */
1072 }
1073 else
1075 }
1076 else
1077 {
1078 /*----------
1079 * The SLRU is no longer needed. Truncate to head before we set head
1080 * invalid.
1081 *
1082 * XXX: It's possible that the SLRU is not needed again until XID
1083 * wrap-around has happened, so that the segment containing headPage
1084 * that we leave behind will appear to be new again. In that case it
1085 * won't be removed until XID horizon advances enough to make it
1086 * current again.
1087 *
1088 * XXX: This should happen in vac_truncate_clog(), not in checkpoints.
1089 * Consider this scenario, starting from a system with no in-progress
1090 * transactions and VACUUM FREEZE having maximized oldestXact:
1091 * - Start a SERIALIZABLE transaction.
1092 * - Start, finish, and summarize a SERIALIZABLE transaction, creating
1093 * one SLRU page.
1094 * - Consume XIDs to reach xidStopLimit.
1095 * - Finish all transactions. Due to the long-running SERIALIZABLE
1096 * transaction, earlier checkpoints did not touch headPage. The
1097 * next checkpoint will change it, but that checkpoint happens after
1098 * the end of the scenario.
1099 * - VACUUM to advance XID limits.
1100 * - Consume ~2M XIDs, crossing the former xidWrapLimit.
1101 * - Start, finish, and summarize a SERIALIZABLE transaction.
1102 * SerialAdd() declines to create the targetPage, because headPage
1103 * is not regarded as in the past relative to that targetPage. The
1104 * transaction instigating the summarize fails in
1105 * SimpleLruReadPage().
1106 */
1108 serialControl->headPage = -1;
1109 }
1110
1112
1113 /*
1114 * Truncate away pages that are no longer required. Note that no
1115 * additional locking is required, because this is only called as part of
1116 * a checkpoint, and the validity limits have already been determined.
1117 */
1119
1120 /*
1121 * Write dirty SLRU pages to disk
1122 *
1123 * This is not actually necessary from a correctness point of view. We do
1124 * it merely as a debugging aid.
1125 *
1126 * We're doing this after the truncation to avoid writing pages right
1127 * before deleting the file in which they sit, which would be completely
1128 * pointless.
1129 */
1131}

References fb(), SerialControlData::headPage, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), serialControl, SerialPage, SerialPagePrecedesLogically(), SerialSlruCtl, SimpleLruTruncate(), SimpleLruWriteAll(), SerialControlData::tailXid, and TransactionIdIsValid.

Referenced by CheckPointGuts().

◆ CheckTableForSerializableConflictIn()

void CheckTableForSerializableConflictIn ( Relation  relation)

Definition at line 4418 of file predicate.c.

4419{
4421 PREDICATELOCKTARGET *target;
4422 Oid dbId;
4423 Oid heapId;
4424 int i;
4425
4426 /*
4427 * Bail out quickly if there are no serializable transactions running.
4428 * It's safe to check this without taking locks because the caller is
4429 * holding an ACCESS EXCLUSIVE lock on the relation. No new locks which
4430 * would matter here can be acquired while that is held.
4431 */
4433 return;
4434
4435 if (!SerializationNeededForWrite(relation))
4436 return;
4437
4438 /*
4439 * We're doing a write which might cause rw-conflicts now or later.
4440 * Memorize that fact.
4441 */
4442 MyXactDidWrite = true;
4443
4444 Assert(relation->rd_index == NULL); /* not an index relation */
4445
4446 dbId = relation->rd_locator.dbOid;
4447 heapId = relation->rd_id;
4448
4450 for (i = 0; i < NUM_PREDICATELOCK_PARTITIONS; i++)
4453
4454 /* Scan through target list */
4456
4457 while ((target = (PREDICATELOCKTARGET *) hash_seq_search(&seqstat)))
4458 {
4459 dlist_mutable_iter iter;
4460
4461 /*
4462 * Check whether this is a target which needs attention.
4463 */
4465 continue; /* wrong relation id */
4466 if (GET_PREDICATELOCKTARGETTAG_DB(target->tag) != dbId)
4467 continue; /* wrong database id */
4468
4469 /*
4470 * Loop through locks for this target and flag conflicts.
4471 */
4472 dlist_foreach_modify(iter, &target->predicateLocks)
4473 {
4475 dlist_container(PREDICATELOCK, targetLink, iter.cur);
4476
4477 if (predlock->tag.myXact != MySerializableXact
4479 {
4481 }
4482 }
4483 }
4484
4485 /* Release locks in reverse order */
4487 for (i = NUM_PREDICATELOCK_PARTITIONS - 1; i >= 0; i--)
4490}

References Assert, dlist_mutable_iter::cur, RelFileLocator::dbOid, dlist_container, dlist_foreach_modify, fb(), FlagRWConflict(), GET_PREDICATELOCKTARGETTAG_DB, GET_PREDICATELOCKTARGETTAG_RELATION, hash_seq_init(), hash_seq_search(), i, LW_EXCLUSIVE, LW_SHARED, LWLockAcquire(), LWLockRelease(), MySerializableXact, MyXactDidWrite, NUM_PREDICATELOCK_PARTITIONS, PredicateLockHashPartitionLockByIndex, PREDICATELOCKTARGET::predicateLocks, PredicateLockTargetHash, PredXact, RelationData::rd_id, RelationData::rd_index, RelationData::rd_locator, RWConflictExists(), SerializationNeededForWrite(), PredXactListData::SxactGlobalXmin, PREDICATELOCKTARGET::tag, and TransactionIdIsValid.

Referenced by ExecuteTruncateGuts(), and heap_drop_with_catalog().

◆ CheckTargetForConflictsIn()

static void CheckTargetForConflictsIn ( PREDICATELOCKTARGETTAG targettag)
static

Definition at line 4165 of file predicate.c.

4166{
4169 PREDICATELOCKTARGET *target;
4172 dlist_mutable_iter iter;
4173
4175
4176 /*
4177 * The same hash and LW lock apply to the lock target and the lock itself.
4178 */
4182 target = (PREDICATELOCKTARGET *)
4185 HASH_FIND, NULL);
4186 if (!target)
4187 {
4188 /* Nothing has this target locked; we're done here. */
4190 return;
4191 }
4192
4193 /*
4194 * Each lock for an overlapping transaction represents a conflict: a
4195 * rw-dependency in to this transaction.
4196 */
4198
4199 dlist_foreach_modify(iter, &target->predicateLocks)
4200 {
4202 dlist_container(PREDICATELOCK, targetLink, iter.cur);
4203 SERIALIZABLEXACT *sxact = predlock->tag.myXact;
4204
4206 {
4207 /*
4208 * If we're getting a write lock on a tuple, we don't need a
4209 * predicate (SIREAD) lock on the same tuple. We can safely remove
4210 * our SIREAD lock, but we'll defer doing so until after the loop
4211 * because that requires upgrading to an exclusive partition lock.
4212 *
4213 * We can't use this optimization within a subtransaction because
4214 * the subtransaction could roll back, and we would be left
4215 * without any lock at the top level.
4216 */
4217 if (!IsSubTransaction()
4219 {
4221 mypredlocktag = predlock->tag;
4222 }
4223 }
4224 else if (!SxactIsDoomed(sxact)
4227 sxact->finishedBefore))
4229 {
4232
4233 /*
4234 * Re-check after getting exclusive lock because the other
4235 * transaction may have flagged a conflict.
4236 */
4237 if (!SxactIsDoomed(sxact)
4240 sxact->finishedBefore))
4242 {
4244 }
4245
4248 }
4249 }
4252
4253 /*
4254 * If we found one of our own SIREAD locks to remove, remove it now.
4255 *
4256 * At this point our transaction already has a RowExclusiveLock on the
4257 * relation, so we are OK to drop the predicate lock on the tuple, if
4258 * found, without fearing that another write against the tuple will occur
4259 * before the MVCC information makes it to the buffer.
4260 */
4261 if (mypredlock != NULL)
4262 {
4265
4267 if (IsInParallelMode())
4271
4272 /*
4273 * Remove the predicate lock from shared memory, if it wasn't removed
4274 * while the locks were released. One way that could happen is from
4275 * autovacuum cleaning up an index.
4276 */
4283 HASH_FIND, NULL);
4284 if (rmpredlock != NULL)
4285 {
4287
4288 dlist_delete(&(mypredlock->targetLink));
4289 dlist_delete(&(mypredlock->xactLink));
4290
4295 HASH_REMOVE, NULL);
4297
4299 }
4300
4303 if (IsInParallelMode())
4306
4307 if (rmpredlock != NULL)
4308 {
4309 /*
4310 * Remove entry in local lock table if it exists. It's OK if it
4311 * doesn't exist; that means the lock was transferred to a new
4312 * target by a different backend.
4313 */
4316 HASH_REMOVE, NULL);
4317
4319 }
4320 }
4321}

References Assert, dlist_mutable_iter::cur, DecrementParentLocks(), dlist_container, dlist_delete(), dlist_foreach_modify, fb(), FlagRWConflict(), GET_PREDICATELOCKTARGETTAG_OFFSET, GetTransactionSnapshot(), HASH_FIND, HASH_REMOVE, hash_search_with_hash_value(), InvalidSerializableXact, IsInParallelMode(), IsSubTransaction(), LocalPredicateLockHash, LW_EXCLUSIVE, LW_SHARED, LWLockAcquire(), LWLockRelease(), MySerializableXact, SERIALIZABLEXACT::perXactPredicateListLock, PredicateLockHash, PredicateLockHashCodeFromTargetHashCode, PredicateLockHashPartitionLock, PREDICATELOCKTARGET::predicateLocks, PredicateLockTargetHash, PredicateLockTargetTagHashCode, RemoveTargetIfNoLongerUsed(), RWConflictExists(), SxactIsCommitted, SxactIsDoomed, and TransactionIdPrecedes().

Referenced by CheckForSerializableConflictIn().

◆ ClearOldPredicateLocks()

static void ClearOldPredicateLocks ( void  )
static

Definition at line 3696 of file predicate.c.

3697{
3698 dlist_mutable_iter iter;
3699
3700 /*
3701 * Loop through finished transactions. They are in commit order, so we can
3702 * stop as soon as we find one that's still interesting.
3703 */
3707 {
3709 dlist_container(SERIALIZABLEXACT, finishedLink, iter.cur);
3710
3714 {
3715 /*
3716 * This transaction committed before any in-progress transaction
3717 * took its snapshot. It's no longer interesting.
3718 */
3720 dlist_delete_thoroughly(&finishedSxact->finishedLink);
3723 }
3724 else if (finishedSxact->commitSeqNo > PredXact->HavePartialClearedThrough
3725 && finishedSxact->commitSeqNo <= PredXact->CanPartialClearThrough)
3726 {
3727 /*
3728 * Any active transactions that took their snapshot before this
3729 * transaction committed are read-only, so we can clear part of
3730 * its state.
3731 */
3733
3735 {
3736 /* A read-only transaction can be removed entirely */
3737 dlist_delete_thoroughly(&(finishedSxact->finishedLink));
3739 }
3740 else
3741 {
3742 /*
3743 * A read-write transaction can only be partially cleared. We
3744 * need to keep the SERIALIZABLEXACT but can release the
3745 * SIREAD locks and conflicts in.
3746 */
3748 }
3749
3752 }
3753 else
3754 {
3755 /* Still interesting. */
3756 break;
3757 }
3758 }
3760
3761 /*
3762 * Loop through predicate locks on dummy transaction for summarized data.
3763 */
3766 {
3768 dlist_container(PREDICATELOCK, xactLink, iter.cur);
3770
3772 Assert(predlock->commitSeqNo != 0);
3773 Assert(predlock->commitSeqNo != InvalidSerCommitSeqNo);
3776
3777 /*
3778 * If this lock originally belonged to an old enough transaction, we
3779 * can release it.
3780 */
3782 {
3783 PREDICATELOCKTAG tag;
3784 PREDICATELOCKTARGET *target;
3788
3789 tag = predlock->tag;
3790 target = tag.myTarget;
3791 targettag = target->tag;
3794
3796
3797 dlist_delete(&(predlock->targetLink));
3798 dlist_delete(&(predlock->xactLink));
3799
3803 HASH_REMOVE, NULL);
3805
3807 }
3808 }
3809
3812}

References Assert, PredXactListData::CanPartialClearThrough, dlist_mutable_iter::cur, dlist_container, dlist_delete(), dlist_delete_thoroughly(), dlist_foreach_modify, fb(), FinishedSerializableTransactions, HASH_REMOVE, hash_search_with_hash_value(), PredXactListData::HavePartialClearedThrough, InvalidSerCommitSeqNo, LW_EXCLUSIVE, LW_SHARED, LWLockAcquire(), LWLockRelease(), PREDICATELOCKTAG::myTarget, OldCommittedSxact, PredicateLockHash, PredicateLockHashCodeFromTargetHashCode, PredicateLockHashPartitionLock, SERIALIZABLEXACT::predicateLocks, PredicateLockTargetTagHashCode, PredXact, ReleaseOneSerializableXact(), RemoveTargetIfNoLongerUsed(), PredXactListData::SxactGlobalXmin, SxactIsReadOnly, PREDICATELOCKTARGET::tag, TransactionIdIsValid, and TransactionIdPrecedesOrEquals().

Referenced by ReleasePredicateLocks().

◆ CoarserLockCovers()

static bool CoarserLockCovers ( const PREDICATELOCKTARGETTAG newtargettag)
static

Definition at line 2110 of file predicate.c.

2111{
2113 parenttag;
2114
2116
2117 /* check parents iteratively until no more */
2119 {
2122 return true;
2123 }
2124
2125 /* no more parents to check; lock is not covered */
2126 return false;
2127}

References fb(), GetParentPredicateLockTag(), and PredicateLockExists().

Referenced by PredicateLockAcquire().

◆ CreateLocalPredicateLockHash()

static void CreateLocalPredicateLockHash ( void  )
static

Definition at line 1939 of file predicate.c.

1940{
1942
1943 /* Initialize the backend-local hash table of parent locks */
1945 hash_ctl.keysize = sizeof(PREDICATELOCKTARGETTAG);
1946 hash_ctl.entrysize = sizeof(LOCALPREDICATELOCK);
1947 LocalPredicateLockHash = hash_create("Local predicate lock",
1949 &hash_ctl,
1951}

References Assert, fb(), HASH_BLOBS, hash_create(), HASH_ELEM, LocalPredicateLockHash, and max_predicate_locks_per_xact.

Referenced by AttachSerializableXact(), and GetSerializableTransactionSnapshotInt().

◆ CreatePredicateLock()

static void CreatePredicateLock ( const PREDICATELOCKTARGETTAG targettag,
uint32  targettaghash,
SERIALIZABLEXACT sxact 
)
static

Definition at line 2452 of file predicate.c.

2455{
2456 PREDICATELOCKTARGET *target;
2457 PREDICATELOCKTAG locktag;
2458 PREDICATELOCK *lock;
2460 bool found;
2461
2463
2465 if (IsInParallelMode())
2466 LWLockAcquire(&sxact->perXactPredicateListLock, LW_EXCLUSIVE);
2468
2469 /* Make sure that the target is represented. */
2470 target = (PREDICATELOCKTARGET *)
2473 HASH_ENTER_NULL, &found);
2474 if (!target)
2475 ereport(ERROR,
2477 errmsg("out of shared memory"),
2478 errhint("You might need to increase \"%s\".", "max_pred_locks_per_transaction")));
2479 if (!found)
2480 dlist_init(&target->predicateLocks);
2481
2482 /* We've got the sxact and target, make sure they're joined. */
2483 locktag.myTarget = target;
2484 locktag.myXact = sxact;
2485 lock = (PREDICATELOCK *)
2488 HASH_ENTER_NULL, &found);
2489 if (!lock)
2490 ereport(ERROR,
2492 errmsg("out of shared memory"),
2493 errhint("You might need to increase \"%s\".", "max_pred_locks_per_transaction")));
2494
2495 if (!found)
2496 {
2497 dlist_push_tail(&target->predicateLocks, &lock->targetLink);
2498 dlist_push_tail(&sxact->predicateLocks, &lock->xactLink);
2500 }
2501
2503 if (IsInParallelMode())
2504 LWLockRelease(&sxact->perXactPredicateListLock);
2506}

References PREDICATELOCK::commitSeqNo, dlist_init(), dlist_push_tail(), ereport, errcode(), errhint(), errmsg, ERROR, fb(), HASH_ENTER_NULL, hash_search_with_hash_value(), InvalidSerCommitSeqNo, IsInParallelMode(), LW_EXCLUSIVE, LW_SHARED, LWLockAcquire(), LWLockRelease(), PREDICATELOCKTAG::myTarget, PREDICATELOCKTAG::myXact, PredicateLockHash, PredicateLockHashCodeFromTargetHashCode, PredicateLockHashPartitionLock, PREDICATELOCKTARGET::predicateLocks, PredicateLockTargetHash, PREDICATELOCK::targetLink, and PREDICATELOCK::xactLink.

Referenced by predicatelock_twophase_recover(), and PredicateLockAcquire().

◆ CreatePredXact()

◆ DecrementParentLocks()

static void DecrementParentLocks ( const PREDICATELOCKTARGETTAG targettag)
static

Definition at line 2390 of file predicate.c.

2391{
2393 nexttag;
2394
2396
2398 {
2402
2408 HASH_FIND, NULL);
2409
2410 /*
2411 * There's a small chance the parent lock doesn't exist in the lock
2412 * table. This can happen if we prematurely removed it because an
2413 * index split caused the child refcount to be off.
2414 */
2415 if (parentlock == NULL)
2416 continue;
2417
2418 parentlock->childLocks--;
2419
2420 /*
2421 * Under similar circumstances the parent lock's refcount might be
2422 * zero. This only happens if we're holding that lock (otherwise we
2423 * would have removed the entry).
2424 */
2425 if (parentlock->childLocks < 0)
2426 {
2427 Assert(parentlock->held);
2428 parentlock->childLocks = 0;
2429 }
2430
2431 if ((parentlock->childLocks == 0) && (!parentlock->held))
2432 {
2436 HASH_REMOVE, NULL);
2438 }
2439 }
2440}

References Assert, fb(), GetParentPredicateLockTag(), HASH_FIND, HASH_REMOVE, hash_search_with_hash_value(), LocalPredicateLockHash, PG_USED_FOR_ASSERTS_ONLY, and PredicateLockTargetTagHashCode.

Referenced by CheckTargetForConflictsIn(), and DeleteChildTargetLocks().

◆ DeleteChildTargetLocks()

static void DeleteChildTargetLocks ( const PREDICATELOCKTARGETTAG newtargettag)
static

Definition at line 2213 of file predicate.c.

2214{
2217 dlist_mutable_iter iter;
2218
2221 if (IsInParallelMode())
2222 LWLockAcquire(&sxact->perXactPredicateListLock, LW_EXCLUSIVE);
2223
2224 dlist_foreach_modify(iter, &sxact->predicateLocks)
2225 {
2229
2230 predlock = dlist_container(PREDICATELOCK, xactLink, iter.cur);
2231
2232 oldlocktag = predlock->tag;
2233 Assert(oldlocktag.myXact == sxact);
2234 oldtarget = oldlocktag.myTarget;
2235 oldtargettag = oldtarget->tag;
2236
2238 {
2242
2245
2247
2248 dlist_delete(&predlock->xactLink);
2249 dlist_delete(&predlock->targetLink);
2252 &oldlocktag,
2255 HASH_REMOVE, NULL);
2257
2259
2261
2263 }
2264 }
2265 if (IsInParallelMode())
2266 LWLockRelease(&sxact->perXactPredicateListLock);
2268}

References Assert, dlist_mutable_iter::cur, DecrementParentLocks(), dlist_container, dlist_delete(), dlist_foreach_modify, fb(), HASH_REMOVE, hash_search_with_hash_value(), IsInParallelMode(), LW_EXCLUSIVE, LW_SHARED, LWLockAcquire(), LWLockRelease(), MySerializableXact, PG_USED_FOR_ASSERTS_ONLY, PredicateLockHash, PredicateLockHashCodeFromTargetHashCode, PredicateLockHashPartitionLock, PredicateLockTargetTagHashCode, RemoveTargetIfNoLongerUsed(), and TargetTagIsCoveredBy.

Referenced by PredicateLockAcquire().

◆ DeleteLockTarget()

static void DeleteLockTarget ( PREDICATELOCKTARGET target,
uint32  targettaghash 
)
static

◆ DropAllPredicateLocksFromTable()

static void DropAllPredicateLocksFromTable ( Relation  relation,
bool  transfer 
)
static

Definition at line 2936 of file predicate.c.

2937{
2941 Oid dbId;
2942 Oid relId;
2943 Oid heapId;
2944 int i;
2945 bool isIndex;
2946 bool found;
2948
2949 /*
2950 * Bail out quickly if there are no serializable transactions running.
2951 * It's safe to check this without taking locks because the caller is
2952 * holding an ACCESS EXCLUSIVE lock on the relation. No new locks which
2953 * would matter here can be acquired while that is held.
2954 */
2956 return;
2957
2958 if (!PredicateLockingNeededForRelation(relation))
2959 return;
2960
2961 dbId = relation->rd_locator.dbOid;
2962 relId = relation->rd_id;
2963 if (relation->rd_index == NULL)
2964 {
2965 isIndex = false;
2966 heapId = relId;
2967 }
2968 else
2969 {
2970 isIndex = true;
2971 heapId = relation->rd_index->indrelid;
2972 }
2974 Assert(transfer || !isIndex); /* index OID only makes sense with
2975 * transfer */
2976
2977 /* Retrieve first time needed, then keep. */
2979 heaptarget = NULL;
2980
2981 /* Acquire locks on all lock partitions */
2983 for (i = 0; i < NUM_PREDICATELOCK_PARTITIONS; i++)
2986
2987 /*
2988 * Remove the dummy entry to give us scratch space, so we know we'll be
2989 * able to create the new lock target.
2990 */
2991 if (transfer)
2992 RemoveScratchTarget(true);
2993
2994 /* Scan through target map */
2996
2998 {
2999 dlist_mutable_iter iter;
3000
3001 /*
3002 * Check whether this is a target which needs attention.
3003 */
3005 continue; /* wrong relation id */
3006 if (GET_PREDICATELOCKTARGETTAG_DB(oldtarget->tag) != dbId)
3007 continue; /* wrong database id */
3008 if (transfer && !isIndex
3010 continue; /* already the right lock */
3011
3012 /*
3013 * If we made it here, we have work to do. We make sure the heap
3014 * relation lock exists, then we walk the list of predicate locks for
3015 * the old target we found, moving all locks to the heap relation lock
3016 * -- unless they already hold that.
3017 */
3018
3019 /*
3020 * First make sure we have the heap relation target. We only need to
3021 * do this once.
3022 */
3023 if (transfer && heaptarget == NULL)
3024 {
3026
3032 HASH_ENTER, &found);
3033 if (!found)
3034 dlist_init(&heaptarget->predicateLocks);
3035 }
3036
3037 /*
3038 * Loop through all the locks on the old target, replacing them with
3039 * locks on the new target.
3040 */
3041 dlist_foreach_modify(iter, &oldtarget->predicateLocks)
3042 {
3044 dlist_container(PREDICATELOCK, targetLink, iter.cur);
3048
3049 /*
3050 * Remove the old lock first. This avoids the chance of running
3051 * out of lock structure entries for the hash table.
3052 */
3054 oldXact = oldpredlock->tag.myXact;
3055
3056 dlist_delete(&(oldpredlock->xactLink));
3057
3058 /*
3059 * No need for retail delete from oldtarget list, we're removing
3060 * the whole target anyway.
3061 */
3063 &oldpredlock->tag,
3064 HASH_REMOVE, &found);
3065 Assert(found);
3066
3067 if (transfer)
3068 {
3070
3072 newpredlocktag.myXact = oldXact;
3078 HASH_ENTER,
3079 &found);
3080 if (!found)
3081 {
3082 dlist_push_tail(&(heaptarget->predicateLocks),
3083 &(newpredlock->targetLink));
3084 dlist_push_tail(&(newpredlocktag.myXact->predicateLocks),
3085 &(newpredlock->xactLink));
3086 newpredlock->commitSeqNo = oldCommitSeqNo;
3087 }
3088 else
3089 {
3090 if (newpredlock->commitSeqNo < oldCommitSeqNo)
3091 newpredlock->commitSeqNo = oldCommitSeqNo;
3092 }
3093
3094 Assert(newpredlock->commitSeqNo != 0);
3095 Assert((newpredlock->commitSeqNo == InvalidSerCommitSeqNo)
3096 || (newpredlock->tag.myXact == OldCommittedSxact));
3097 }
3098 }
3099
3101 &found);
3102 Assert(found);
3103 }
3104
3105 /* Put the scratch entry back */
3106 if (transfer)
3108
3109 /* Release locks in reverse order */
3111 for (i = NUM_PREDICATELOCK_PARTITIONS - 1; i >= 0; i--)
3114}

References Assert, SERIALIZABLEXACT::commitSeqNo, dlist_mutable_iter::cur, RelFileLocator::dbOid, dlist_container, dlist_delete(), dlist_foreach_modify, dlist_init(), dlist_push_tail(), fb(), GET_PREDICATELOCKTARGETTAG_DB, GET_PREDICATELOCKTARGETTAG_RELATION, GET_PREDICATELOCKTARGETTAG_TYPE, HASH_ENTER, HASH_REMOVE, hash_search(), hash_search_with_hash_value(), hash_seq_init(), hash_seq_search(), i, InvalidOid, InvalidSerCommitSeqNo, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), PREDICATELOCKTAG::myTarget, NUM_PREDICATELOCK_PARTITIONS, OldCommittedSxact, PredicateLockHash, PredicateLockHashCodeFromTargetHashCode, PredicateLockHashPartitionLockByIndex, PredicateLockingNeededForRelation(), PredicateLockTargetHash, PredicateLockTargetTagHashCode, PREDLOCKTAG_RELATION, PredXact, RelationData::rd_id, RelationData::rd_index, RelationData::rd_locator, RemoveScratchTarget(), RestoreScratchTarget(), SET_PREDICATELOCKTARGETTAG_RELATION, PredXactListData::SxactGlobalXmin, and TransactionIdIsValid.

Referenced by TransferPredicateLocksToHeapRelation().

◆ FlagRWConflict()

static void FlagRWConflict ( SERIALIZABLEXACT reader,
SERIALIZABLEXACT writer 
)
static

Definition at line 4500 of file predicate.c.

4501{
4502 Assert(reader != writer);
4503
4504 /* First, see if this conflict causes failure. */
4506
4507 /* Actually do the conflict flagging. */
4508 if (reader == OldCommittedSxact)
4510 else if (writer == OldCommittedSxact)
4512 else
4513 SetRWConflict(reader, writer);
4514}

References Assert, fb(), SERIALIZABLEXACT::flags, OldCommittedSxact, OnConflict_CheckForSerializationFailure(), SetRWConflict(), SXACT_FLAG_SUMMARY_CONFLICT_IN, and SXACT_FLAG_SUMMARY_CONFLICT_OUT.

Referenced by CheckForSerializableConflictOut(), CheckTableForSerializableConflictIn(), and CheckTargetForConflictsIn().

◆ FlagSxactUnsafe()

static void FlagSxactUnsafe ( SERIALIZABLEXACT sxact)
static

Definition at line 700 of file predicate.c.

701{
703
706
707 sxact->flags |= SXACT_FLAG_RO_UNSAFE;
708
709 /*
710 * We know this isn't a safe snapshot, so we can stop looking for other
711 * potential conflicts.
712 */
713 dlist_foreach_modify(iter, &sxact->possibleUnsafeConflicts)
714 {
716 dlist_container(RWConflictData, inLink, iter.cur);
717
718 Assert(!SxactIsReadOnly(conflict->sxactOut));
719 Assert(sxact == conflict->sxactIn);
720
722 }
723}

References Assert, dlist_mutable_iter::cur, dlist_container, dlist_foreach_modify, fb(), ReleaseRWConflict(), SXACT_FLAG_RO_UNSAFE, SxactIsReadOnly, and SxactIsROSafe.

Referenced by ReleasePredicateLocks().

◆ GetParentPredicateLockTag()

static bool GetParentPredicateLockTag ( const PREDICATELOCKTARGETTAG tag,
PREDICATELOCKTARGETTAG parent 
)
static

Definition at line 2071 of file predicate.c.

2073{
2074 switch (GET_PREDICATELOCKTARGETTAG_TYPE(*tag))
2075 {
2077 /* relation locks have no parent lock */
2078 return false;
2079
2080 case PREDLOCKTAG_PAGE:
2081 /* parent lock is relation lock */
2085
2086 return true;
2087
2088 case PREDLOCKTAG_TUPLE:
2089 /* parent lock is page lock */
2094 return true;
2095 }
2096
2097 /* not reachable */
2098 Assert(false);
2099 return false;
2100}

References Assert, GET_PREDICATELOCKTARGETTAG_DB, GET_PREDICATELOCKTARGETTAG_PAGE, GET_PREDICATELOCKTARGETTAG_RELATION, GET_PREDICATELOCKTARGETTAG_TYPE, PREDLOCKTAG_PAGE, PREDLOCKTAG_RELATION, PREDLOCKTAG_TUPLE, SET_PREDICATELOCKTARGETTAG_PAGE, and SET_PREDICATELOCKTARGETTAG_RELATION.

Referenced by CheckAndPromotePredicateLockRequest(), CoarserLockCovers(), DecrementParentLocks(), and PredicateLockPageSplit().

◆ GetPredicateLockStatusData()

PredicateLockData * GetPredicateLockStatusData ( void  )

Definition at line 1446 of file predicate.c.

1447{
1449 int i;
1450 int els,
1451 el;
1454
1456
1457 /*
1458 * To ensure consistency, take simultaneous locks on all partition locks
1459 * in ascending order, then SerializableXactHashLock.
1460 */
1461 for (i = 0; i < NUM_PREDICATELOCK_PARTITIONS; i++)
1464
1465 /* Get number of locks and allocate appropriately-sized arrays. */
1467 data->nelements = els;
1470
1471
1472 /* Scan through PredicateLockHash and copy contents */
1474
1475 el = 0;
1476
1478 {
1479 data->locktags[el] = predlock->tag.myTarget->tag;
1480 data->xacts[el] = *predlock->tag.myXact;
1481 el++;
1482 }
1483
1484 Assert(el == els);
1485
1486 /* Release locks in reverse order */
1488 for (i = NUM_PREDICATELOCK_PARTITIONS - 1; i >= 0; i--)
1490
1491 return data;
1492}

References Assert, data, fb(), hash_get_num_entries(), hash_seq_init(), hash_seq_search(), i, LW_SHARED, LWLockAcquire(), LWLockRelease(), NUM_PREDICATELOCK_PARTITIONS, palloc_array, palloc_object, PredicateLockHash, and PredicateLockHashPartitionLockByIndex.

Referenced by pg_lock_status().

◆ GetSafeSnapshot()

static Snapshot GetSafeSnapshot ( Snapshot  origSnapshot)
static

Definition at line 1557 of file predicate.c.

1558{
1559 Snapshot snapshot;
1560
1562
1563 while (true)
1564 {
1565 /*
1566 * GetSerializableTransactionSnapshotInt is going to call
1567 * GetSnapshotData, so we need to provide it the static snapshot area
1568 * our caller passed to us. The pointer returned is actually the same
1569 * one passed to it, but we avoid assuming that here.
1570 */
1572 NULL, InvalidPid);
1573
1575 return snapshot; /* no concurrent r/w xacts; it's safe */
1576
1578
1579 /*
1580 * Wait for concurrent transactions to finish. Stop early if one of
1581 * them marked us as conflicted.
1582 */
1586 {
1590 }
1592
1594 {
1596 break; /* success */
1597 }
1598
1600
1601 /* else, need to retry... */
1604 errmsg_internal("deferrable snapshot was unsafe; trying a new one")));
1605 ReleasePredicateLocks(false, false);
1606 }
1607
1608 /*
1609 * Now we have a safe snapshot, so we don't need to do any further checks.
1610 */
1612 ReleasePredicateLocks(false, true);
1613
1614 return snapshot;
1615}

References Assert, DEBUG2, dlist_is_empty(), ereport, errcode(), ERRCODE_T_R_SERIALIZATION_FAILURE, errmsg_internal(), fb(), SERIALIZABLEXACT::flags, GetSerializableTransactionSnapshotInt(), InvalidPid, InvalidSerializableXact, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), MySerializableXact, SERIALIZABLEXACT::possibleUnsafeConflicts, ProcWaitForSignal(), ReleasePredicateLocks(), SXACT_FLAG_DEFERRABLE_WAITING, SxactIsROSafe, SxactIsROUnsafe, XactDeferrable, and XactReadOnly.

Referenced by GetSerializableTransactionSnapshot().

◆ GetSafeSnapshotBlockingPids()

int GetSafeSnapshotBlockingPids ( int  blocked_pid,
int output,
int  output_size 
)

Definition at line 1627 of file predicate.c.

1628{
1629 int num_written = 0;
1630 dlist_iter iter;
1632
1634
1635 /* Find blocked_pid's SERIALIZABLEXACT by linear search. */
1637 {
1639 dlist_container(SERIALIZABLEXACT, xactLink, iter.cur);
1640
1641 if (sxact->pid == blocked_pid)
1642 {
1644 break;
1645 }
1646 }
1647
1648 /* Did we find it, and is it currently waiting in GetSafeSnapshot? */
1650 {
1651 /* Traverse the list of possible unsafe conflicts collecting PIDs. */
1652 dlist_foreach(iter, &blocking_sxact->possibleUnsafeConflicts)
1653 {
1655 dlist_container(RWConflictData, inLink, iter.cur);
1656
1657 output[num_written++] = possibleUnsafeConflict->sxactOut->pid;
1658
1659 if (num_written >= output_size)
1660 break;
1661 }
1662 }
1663
1665
1666 return num_written;
1667}

References PredXactListData::activeList, dlist_iter::cur, dlist_container, dlist_foreach, fb(), LW_SHARED, LWLockAcquire(), LWLockRelease(), output, PredXact, and SxactIsDeferrableWaiting.

Referenced by pg_isolation_test_session_is_blocked(), and pg_safe_snapshot_blocking_pids().

◆ GetSerializableTransactionSnapshot()

Snapshot GetSerializableTransactionSnapshot ( Snapshot  snapshot)

Definition at line 1681 of file predicate.c.

1682{
1684
1685 /*
1686 * Can't use serializable mode while recovery is still active, as it is,
1687 * for example, on a hot standby. We could get here despite the check in
1688 * check_transaction_isolation() if default_transaction_isolation is set
1689 * to serializable, so phrase the hint accordingly.
1690 */
1691 if (RecoveryInProgress())
1692 ereport(ERROR,
1694 errmsg("cannot use serializable mode in a hot standby"),
1695 errdetail("\"default_transaction_isolation\" is set to \"serializable\"."),
1696 errhint("You can use \"SET default_transaction_isolation = 'repeatable read'\" to change the default.")));
1697
1698 /*
1699 * A special optimization is available for SERIALIZABLE READ ONLY
1700 * DEFERRABLE transactions -- we can wait for a suitable snapshot and
1701 * thereby avoid all SSI overhead once it's running.
1702 */
1704 return GetSafeSnapshot(snapshot);
1705
1707 NULL, InvalidPid);
1708}

References Assert, ereport, errcode(), errdetail(), errhint(), errmsg, ERROR, fb(), GetSafeSnapshot(), GetSerializableTransactionSnapshotInt(), InvalidPid, IsolationIsSerializable, RecoveryInProgress(), XactDeferrable, and XactReadOnly.

Referenced by GetTransactionSnapshot().

◆ GetSerializableTransactionSnapshotInt()

static Snapshot GetSerializableTransactionSnapshotInt ( Snapshot  snapshot,
VirtualTransactionId sourcevxid,
int  sourcepid 
)
static

Definition at line 1763 of file predicate.c.

1766{
1767 PGPROC *proc;
1770 *othersxact;
1771
1772 /* We only do this for serializable transactions. Once. */
1774
1776
1777 /*
1778 * Since all parts of a serializable transaction must use the same
1779 * snapshot, it is too late to establish one after a parallel operation
1780 * has begun.
1781 */
1782 if (IsInParallelMode())
1783 elog(ERROR, "cannot establish serializable snapshot during a parallel operation");
1784
1785 proc = MyProc;
1786 Assert(proc != NULL);
1787 GET_VXID_FROM_PGPROC(vxid, *proc);
1788
1789 /*
1790 * First we get the sxact structure, which may involve looping and access
1791 * to the "finished" list to free a structure for use.
1792 *
1793 * We must hold SerializableXactHashLock when taking/checking the snapshot
1794 * to avoid race conditions, for much the same reasons that
1795 * GetSnapshotData takes the ProcArrayLock. Since we might have to
1796 * release SerializableXactHashLock to call SummarizeOldestCommittedSxact,
1797 * this means we have to create the sxact first, which is a bit annoying
1798 * (in particular, an elog(ERROR) in procarray.c would cause us to leak
1799 * the sxact). Consider refactoring to avoid this.
1800 */
1801#ifdef TEST_SUMMARIZE_SERIAL
1803#endif
1805 do
1806 {
1808 /* If null, push out committed sxact to SLRU summary & retry. */
1809 if (!sxact)
1810 {
1814 }
1815 } while (!sxact);
1816
1817 /* Get the snapshot, or check that it's safe to use */
1818 if (!sourcevxid)
1819 snapshot = GetSnapshotData(snapshot);
1820 else if (!ProcArrayInstallImportedXmin(snapshot->xmin, sourcevxid))
1821 {
1824 ereport(ERROR,
1826 errmsg("could not import the requested snapshot"),
1827 errdetail("The source process with PID %d is not running anymore.",
1828 sourcepid)));
1829 }
1830
1831 /*
1832 * If there are no serializable transactions which are not read-only, we
1833 * can "opt out" of predicate locking and conflict checking for a
1834 * read-only transaction.
1835 *
1836 * The reason this is safe is that a read-only transaction can only become
1837 * part of a dangerous structure if it overlaps a writable transaction
1838 * which in turn overlaps a writable transaction which committed before
1839 * the read-only transaction started. A new writable transaction can
1840 * overlap this one, but it can't meet the other condition of overlapping
1841 * a transaction which committed before this one started.
1842 */
1844 {
1847 return snapshot;
1848 }
1849
1850 /* Initialize the structure. */
1851 sxact->vxid = vxid;
1852 sxact->SeqNo.lastCommitBeforeSnapshot = PredXact->LastSxactCommitSeqNo;
1853 sxact->prepareSeqNo = InvalidSerCommitSeqNo;
1854 sxact->commitSeqNo = InvalidSerCommitSeqNo;
1855 dlist_init(&(sxact->outConflicts));
1856 dlist_init(&(sxact->inConflicts));
1857 dlist_init(&(sxact->possibleUnsafeConflicts));
1858 sxact->topXid = GetTopTransactionIdIfAny();
1859 sxact->finishedBefore = InvalidTransactionId;
1860 sxact->xmin = snapshot->xmin;
1861 sxact->pid = MyProcPid;
1862 sxact->pgprocno = MyProcNumber;
1863 dlist_init(&sxact->predicateLocks);
1864 dlist_node_init(&sxact->finishedLink);
1865 sxact->flags = 0;
1866 if (XactReadOnly)
1867 {
1868 dlist_iter iter;
1869
1870 sxact->flags |= SXACT_FLAG_READ_ONLY;
1871
1872 /*
1873 * Register all concurrent r/w transactions as possible conflicts; if
1874 * all of them commit without any outgoing conflicts to earlier
1875 * transactions then this snapshot can be deemed safe (and we can run
1876 * without tracking predicate locks).
1877 */
1879 {
1881
1885 {
1887 }
1888 }
1889
1890 /*
1891 * If we didn't find any possibly unsafe conflicts because every
1892 * uncommitted writable transaction turned out to be doomed, then we
1893 * can "opt out" immediately. See comments above the earlier check
1894 * for PredXact->WritableSxactCount == 0.
1895 */
1896 if (dlist_is_empty(&sxact->possibleUnsafeConflicts))
1897 {
1900 return snapshot;
1901 }
1902 }
1903 else
1904 {
1908 }
1909
1910 /* Maintain serializable global xmin info. */
1912 {
1914 PredXact->SxactGlobalXmin = snapshot->xmin;
1916 SerialSetActiveSerXmin(snapshot->xmin);
1917 }
1918 else if (TransactionIdEquals(snapshot->xmin, PredXact->SxactGlobalXmin))
1919 {
1922 }
1923 else
1924 {
1926 }
1927
1929 MyXactDidWrite = false; /* haven't written anything yet */
1930
1932
1934
1935 return snapshot;
1936}

References PredXactListData::activeList, Assert, CreateLocalPredicateLockHash(), CreatePredXact(), dlist_iter::cur, dlist_container, dlist_foreach, dlist_init(), dlist_is_empty(), dlist_node_init(), elog, ereport, errcode(), errdetail(), errmsg, ERROR, fb(), GET_VXID_FROM_PGPROC, GetSnapshotData(), GetTopTransactionIdIfAny(), InvalidSerCommitSeqNo, InvalidSerializableXact, InvalidTransactionId, IsInParallelMode(), PredXactListData::LastSxactCommitSeqNo, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), max_prepared_xacts, MaxBackends, MyProc, MyProcNumber, MyProcPid, MySerializableXact, MyXactDidWrite, PredXact, ProcArrayInstallImportedXmin(), RecoveryInProgress(), ReleasePredXact(), SerialSetActiveSerXmin(), SetPossibleUnsafeConflict(), SummarizeOldestCommittedSxact(), SXACT_FLAG_READ_ONLY, PredXactListData::SxactGlobalXmin, PredXactListData::SxactGlobalXminCount, SxactIsCommitted, SxactIsDoomed, SxactIsReadOnly, TransactionIdEquals, TransactionIdFollows(), TransactionIdIsValid, PredXactListData::WritableSxactCount, XactReadOnly, and SnapshotData::xmin.

Referenced by GetSafeSnapshot(), GetSerializableTransactionSnapshot(), and SetSerializableTransactionSnapshot().

◆ MaxPredicateChildLocks()

static int MaxPredicateChildLocks ( const PREDICATELOCKTARGETTAG tag)
static

Definition at line 2288 of file predicate.c.

2289{
2290 switch (GET_PREDICATELOCKTARGETTAG_TYPE(*tag))
2291 {
2297
2298 case PREDLOCKTAG_PAGE:
2300
2301 case PREDLOCKTAG_TUPLE:
2302
2303 /*
2304 * not reachable: nothing is finer-granularity than a tuple, so we
2305 * should never try to promote to it.
2306 */
2307 Assert(false);
2308 return 0;
2309 }
2310
2311 /* not reachable */
2312 Assert(false);
2313 return 0;
2314}

References Assert, GET_PREDICATELOCKTARGETTAG_TYPE, max_predicate_locks_per_page, max_predicate_locks_per_relation, max_predicate_locks_per_xact, PREDLOCKTAG_PAGE, PREDLOCKTAG_RELATION, and PREDLOCKTAG_TUPLE.

Referenced by CheckAndPromotePredicateLockRequest().

◆ OnConflict_CheckForSerializationFailure()

static void OnConflict_CheckForSerializationFailure ( const SERIALIZABLEXACT reader,
SERIALIZABLEXACT writer 
)
static

Definition at line 4535 of file predicate.c.

4537{
4538 bool failure;
4539
4541
4542 failure = false;
4543
4544 /*------------------------------------------------------------------------
4545 * Check for already-committed writer with rw-conflict out flagged
4546 * (conflict-flag on W means that T2 committed before W):
4547 *
4548 * R ------> W ------> T2
4549 * rw rw
4550 *
4551 * That is a dangerous structure, so we must abort. (Since the writer
4552 * has already committed, we must be the reader)
4553 *------------------------------------------------------------------------
4554 */
4557 failure = true;
4558
4559 /*------------------------------------------------------------------------
4560 * Check whether the writer has become a pivot with an out-conflict
4561 * committed transaction (T2), and T2 committed first:
4562 *
4563 * R ------> W ------> T2
4564 * rw rw
4565 *
4566 * Because T2 must've committed first, there is no anomaly if:
4567 * - the reader committed before T2
4568 * - the writer committed before T2
4569 * - the reader is a READ ONLY transaction and the reader was concurrent
4570 * with T2 (= reader acquired its snapshot before T2 committed)
4571 *
4572 * We also handle the case that T2 is prepared but not yet committed
4573 * here. In that case T2 has already checked for conflicts, so if it
4574 * commits first, making the above conflict real, it's too late for it
4575 * to abort.
4576 *------------------------------------------------------------------------
4577 */
4579 failure = true;
4580 else if (!failure)
4581 {
4582 dlist_iter iter;
4583
4584 dlist_foreach(iter, &writer->outConflicts)
4585 {
4587 dlist_container(RWConflictData, outLink, iter.cur);
4588 SERIALIZABLEXACT *t2 = conflict->sxactIn;
4589
4590 if (SxactIsPrepared(t2)
4591 && (!SxactIsCommitted(reader)
4592 || t2->prepareSeqNo <= reader->commitSeqNo)
4594 || t2->prepareSeqNo <= writer->commitSeqNo)
4595 && (!SxactIsReadOnly(reader)
4596 || t2->prepareSeqNo <= reader->SeqNo.lastCommitBeforeSnapshot))
4597 {
4598 failure = true;
4599 break;
4600 }
4601 }
4602 }
4603
4604 /*------------------------------------------------------------------------
4605 * Check whether the reader has become a pivot with a writer
4606 * that's committed (or prepared):
4607 *
4608 * T0 ------> R ------> W
4609 * rw rw
4610 *
4611 * Because W must've committed first for an anomaly to occur, there is no
4612 * anomaly if:
4613 * - T0 committed before the writer
4614 * - T0 is READ ONLY, and overlaps the writer
4615 *------------------------------------------------------------------------
4616 */
4617 if (!failure && SxactIsPrepared(writer) && !SxactIsReadOnly(reader))
4618 {
4619 if (SxactHasSummaryConflictIn(reader))
4620 {
4621 failure = true;
4622 }
4623 else
4624 {
4625 dlist_iter iter;
4626
4627 /*
4628 * The unconstify is needed as we have no const version of
4629 * dlist_foreach().
4630 */
4631 dlist_foreach(iter, &unconstify(SERIALIZABLEXACT *, reader)->inConflicts)
4632 {
4633 const RWConflict conflict =
4634 dlist_container(RWConflictData, inLink, iter.cur);
4635 const SERIALIZABLEXACT *t0 = conflict->sxactOut;
4636
4637 if (!SxactIsDoomed(t0)
4638 && (!SxactIsCommitted(t0)
4639 || t0->commitSeqNo >= writer->prepareSeqNo)
4640 && (!SxactIsReadOnly(t0)
4641 || t0->SeqNo.lastCommitBeforeSnapshot >= writer->prepareSeqNo))
4642 {
4643 failure = true;
4644 break;
4645 }
4646 }
4647 }
4648 }
4649
4650 if (failure)
4651 {
4652 /*
4653 * We have to kill a transaction to avoid a possible anomaly from
4654 * occurring. If the writer is us, we can just ereport() to cause a
4655 * transaction abort. Otherwise we flag the writer for termination,
4656 * causing it to abort when it tries to commit. However, if the writer
4657 * is a prepared transaction, already prepared, we can't abort it
4658 * anymore, so we have to kill the reader instead.
4659 */
4661 {
4663 ereport(ERROR,
4665 errmsg("could not serialize access due to read/write dependencies among transactions"),
4666 errdetail_internal("Reason code: Canceled on identification as a pivot, during write."),
4667 errhint("The transaction might succeed if retried.")));
4668 }
4669 else if (SxactIsPrepared(writer))
4670 {
4672
4673 /* if we're not the writer, we have to be the reader */
4674 Assert(MySerializableXact == reader);
4675 ereport(ERROR,
4677 errmsg("could not serialize access due to read/write dependencies among transactions"),
4678 errdetail_internal("Reason code: Canceled on conflict out to pivot %u, during read.", writer->topXid),
4679 errhint("The transaction might succeed if retried.")));
4680 }
4681 writer->flags |= SXACT_FLAG_DOOMED;
4682 }
4683}

References Assert, SERIALIZABLEXACT::commitSeqNo, dlist_iter::cur, dlist_container, dlist_foreach, ereport, errcode(), ERRCODE_T_R_SERIALIZATION_FAILURE, errdetail_internal(), errhint(), errmsg, ERROR, fb(), SERIALIZABLEXACT::lastCommitBeforeSnapshot, LWLockHeldByMe(), LWLockRelease(), MySerializableXact, SERIALIZABLEXACT::SeqNo, SXACT_FLAG_DOOMED, SxactHasConflictOut, SxactHasSummaryConflictIn, SxactHasSummaryConflictOut, SxactIsCommitted, SxactIsDoomed, SxactIsPrepared, SxactIsReadOnly, and unconstify.

Referenced by FlagRWConflict().

◆ PageIsPredicateLocked()

◆ PostPrepare_PredicateLocks()

◆ PreCommit_CheckForSerializationFailure()

void PreCommit_CheckForSerializationFailure ( void  )

Definition at line 4702 of file predicate.c.

4703{
4705
4707 return;
4708
4710
4712
4713 /*
4714 * Check if someone else has already decided that we need to die. Since
4715 * we set our own DOOMED flag when partially releasing, ignore in that
4716 * case.
4717 */
4720 {
4722 ereport(ERROR,
4724 errmsg("could not serialize access due to read/write dependencies among transactions"),
4725 errdetail_internal("Reason code: Canceled on identification as a pivot, during commit attempt."),
4726 errhint("The transaction might succeed if retried.")));
4727 }
4728
4730 {
4733
4734 if (!SxactIsCommitted(nearConflict->sxactOut)
4735 && !SxactIsDoomed(nearConflict->sxactOut))
4736 {
4738
4739 dlist_foreach(far_iter, &nearConflict->sxactOut->inConflicts)
4740 {
4743
4744 if (farConflict->sxactOut == MySerializableXact
4745 || (!SxactIsCommitted(farConflict->sxactOut)
4746 && !SxactIsReadOnly(farConflict->sxactOut)
4747 && !SxactIsDoomed(farConflict->sxactOut)))
4748 {
4749 /*
4750 * Normally, we kill the pivot transaction to make sure we
4751 * make progress if the failing transaction is retried.
4752 * However, we can't kill it if it's already prepared, so
4753 * in that case we commit suicide instead.
4754 */
4755 if (SxactIsPrepared(nearConflict->sxactOut))
4756 {
4758 ereport(ERROR,
4760 errmsg("could not serialize access due to read/write dependencies among transactions"),
4761 errdetail_internal("Reason code: Canceled on commit attempt with conflict in from prepared pivot."),
4762 errhint("The transaction might succeed if retried.")));
4763 }
4764 nearConflict->sxactOut->flags |= SXACT_FLAG_DOOMED;
4765 break;
4766 }
4767 }
4768 }
4769 }
4770
4773
4775}

References Assert, dlist_container, dlist_foreach, ereport, errcode(), ERRCODE_T_R_SERIALIZATION_FAILURE, errdetail_internal(), errhint(), errmsg, ERROR, fb(), SERIALIZABLEXACT::flags, SERIALIZABLEXACT::inConflicts, InvalidSerializableXact, IsolationIsSerializable, PredXactListData::LastSxactCommitSeqNo, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), MySerializableXact, PredXact, SERIALIZABLEXACT::prepareSeqNo, SXACT_FLAG_DOOMED, SXACT_FLAG_PREPARED, SxactIsCommitted, SxactIsDoomed, SxactIsPartiallyReleased, SxactIsPrepared, and SxactIsReadOnly.

Referenced by CommitTransaction(), and PrepareTransaction().

◆ predicatelock_hash()

static uint32 predicatelock_hash ( const void key,
Size  keysize 
)
static

Definition at line 1420 of file predicate.c.

1421{
1422 const PREDICATELOCKTAG *predicatelocktag = (const PREDICATELOCKTAG *) key;
1424
1425 Assert(keysize == sizeof(PREDICATELOCKTAG));
1426
1427 /* Look into the associated target object, and compute its hash code */
1429
1431}

References Assert, fb(), PredicateLockHashCodeFromTargetHashCode, and PredicateLockTargetTagHashCode.

Referenced by PredicateLockShmemInit().

◆ predicatelock_twophase_recover()

void predicatelock_twophase_recover ( FullTransactionId  fxid,
uint16  info,
void recdata,
uint32  len 
)

Definition at line 4908 of file predicate.c.

4910{
4913
4915
4916 record = (TwoPhasePredicateRecord *) recdata;
4917
4919 (record->type == TWOPHASEPREDICATERECORD_LOCK));
4920
4921 if (record->type == TWOPHASEPREDICATERECORD_XACT)
4922 {
4923 /* Per-transaction record. Set up a SERIALIZABLEXACT. */
4924 TwoPhasePredicateXactRecord *xactRecord;
4928 bool found;
4929
4930 xactRecord = (TwoPhasePredicateXactRecord *) &record->data.xactRecord;
4931
4934 if (!sxact)
4935 ereport(ERROR,
4937 errmsg("out of shared memory")));
4938
4939 /* vxid for a prepared xact is INVALID_PROC_NUMBER/xid; no pid */
4940 sxact->vxid.procNumber = INVALID_PROC_NUMBER;
4941 sxact->vxid.localTransactionId = (LocalTransactionId) xid;
4942 sxact->pid = 0;
4943 sxact->pgprocno = INVALID_PROC_NUMBER;
4944
4945 /* a prepared xact hasn't committed yet */
4946 sxact->prepareSeqNo = RecoverySerCommitSeqNo;
4947 sxact->commitSeqNo = InvalidSerCommitSeqNo;
4948 sxact->finishedBefore = InvalidTransactionId;
4949
4950 sxact->SeqNo.lastCommitBeforeSnapshot = RecoverySerCommitSeqNo;
4951
4952 /*
4953 * Don't need to track this; no transactions running at the time the
4954 * recovered xact started are still active, except possibly other
4955 * prepared xacts and we don't care whether those are RO_SAFE or not.
4956 */
4957 dlist_init(&(sxact->possibleUnsafeConflicts));
4958
4959 dlist_init(&(sxact->predicateLocks));
4960 dlist_node_init(&sxact->finishedLink);
4961
4962 sxact->topXid = xid;
4963 sxact->xmin = xactRecord->xmin;
4964 sxact->flags = xactRecord->flags;
4966 if (!SxactIsReadOnly(sxact))
4967 {
4971 }
4972
4973 /*
4974 * We don't know whether the transaction had any conflicts or not, so
4975 * we'll conservatively assume that it had both a conflict in and a
4976 * conflict out, and represent that with the summary conflict flags.
4977 */
4978 dlist_init(&(sxact->outConflicts));
4979 dlist_init(&(sxact->inConflicts));
4982
4983 /* Register the transaction's xid */
4984 sxidtag.xid = xid;
4986 &sxidtag,
4987 HASH_ENTER, &found);
4988 Assert(sxid != NULL);
4989 Assert(!found);
4990 sxid->myXact = sxact;
4991
4992 /*
4993 * Update global xmin. Note that this is a special case compared to
4994 * registering a normal transaction, because the global xmin might go
4995 * backwards. That's OK, because until recovery is over we're not
4996 * going to complete any transactions or create any non-prepared
4997 * transactions, so there's no danger of throwing away.
4998 */
5001 {
5005 }
5007 {
5010 }
5011
5013 }
5014 else if (record->type == TWOPHASEPREDICATERECORD_LOCK)
5015 {
5016 /* Lock record. Recreate the PREDICATELOCK */
5017 TwoPhasePredicateLockRecord *lockRecord;
5022
5023 lockRecord = (TwoPhasePredicateLockRecord *) &record->data.lockRecord;
5024 targettaghash = PredicateLockTargetTagHashCode(&lockRecord->target);
5025
5027 sxidtag.xid = xid;
5028 sxid = (SERIALIZABLEXID *)
5031
5032 Assert(sxid != NULL);
5033 sxact = sxid->myXact;
5035
5036 CreatePredicateLock(&lockRecord->target, targettaghash, sxact);
5037 }
5038}

References Assert, CreatePredicateLock(), CreatePredXact(), TwoPhasePredicateRecord::data, dlist_init(), dlist_node_init(), ereport, errcode(), errmsg, ERROR, fb(), TwoPhasePredicateXactRecord::flags, HASH_ENTER, HASH_FIND, hash_search(), INVALID_PROC_NUMBER, InvalidSerCommitSeqNo, InvalidSerializableXact, InvalidTransactionId, len, TwoPhasePredicateRecord::lockRecord, LW_EXCLUSIVE, LW_SHARED, LWLockAcquire(), LWLockRelease(), max_prepared_xacts, MaxBackends, PredicateLockTargetTagHashCode, PredXact, RecoverySerCommitSeqNo, SerializableXidHash, SerialSetActiveSerXmin(), SXACT_FLAG_SUMMARY_CONFLICT_IN, SXACT_FLAG_SUMMARY_CONFLICT_OUT, PredXactListData::SxactGlobalXmin, PredXactListData::SxactGlobalXminCount, SxactIsPrepared, SxactIsReadOnly, TwoPhasePredicateLockRecord::target, TransactionIdEquals, TransactionIdFollows(), TransactionIdIsValid, TWOPHASEPREDICATERECORD_LOCK, TWOPHASEPREDICATERECORD_XACT, TwoPhasePredicateRecord::type, PredXactListData::WritableSxactCount, TwoPhasePredicateRecord::xactRecord, XidFromFullTransactionId, and TwoPhasePredicateXactRecord::xmin.

◆ PredicateLockAcquire()

static void PredicateLockAcquire ( const PREDICATELOCKTARGETTAG targettag)
static

Definition at line 2516 of file predicate.c.

2517{
2519 bool found;
2521
2522 /* Do we have the lock already, or a covering lock? */
2524 return;
2525
2527 return;
2528
2529 /* the same hash and LW lock apply to the lock target and the local lock. */
2531
2532 /* Acquire lock in local table */
2536 HASH_ENTER, &found);
2537 locallock->held = true;
2538 if (!found)
2539 locallock->childLocks = 0;
2540
2541 /* Actually create the lock */
2543
2544 /*
2545 * Lock has been acquired. Check whether it should be promoted to a
2546 * coarser granularity, or whether there are finer-granularity locks to
2547 * clean up.
2548 */
2550 {
2551 /*
2552 * Lock request was promoted to a coarser-granularity lock, and that
2553 * lock was acquired. It will delete this lock and any of its
2554 * children, so we're done.
2555 */
2556 }
2557 else
2558 {
2559 /* Clean up any finer-granularity locks */
2562 }
2563}

References CheckAndPromotePredicateLockRequest(), CoarserLockCovers(), CreatePredicateLock(), DeleteChildTargetLocks(), fb(), GET_PREDICATELOCKTARGETTAG_TYPE, HASH_ENTER, hash_search_with_hash_value(), LocalPredicateLockHash, MySerializableXact, PredicateLockExists(), PredicateLockTargetTagHashCode, and PREDLOCKTAG_TUPLE.

Referenced by CheckAndPromotePredicateLockRequest(), PredicateLockPage(), PredicateLockRelation(), and PredicateLockTID().

◆ PredicateLockExists()

static bool PredicateLockExists ( const PREDICATELOCKTARGETTAG targettag)
static

Definition at line 2044 of file predicate.c.

2045{
2046 LOCALPREDICATELOCK *lock;
2047
2048 /* check local hash table */
2050 targettag,
2051 HASH_FIND, NULL);
2052
2053 if (!lock)
2054 return false;
2055
2056 /*
2057 * Found entry in the table, but still need to check whether it's actually
2058 * held -- it could just be a parent of some held lock.
2059 */
2060 return lock->held;
2061}

References fb(), HASH_FIND, hash_search(), LOCALPREDICATELOCK::held, and LocalPredicateLockHash.

Referenced by CoarserLockCovers(), PredicateLockAcquire(), and PredicateLockTID().

◆ PredicateLockingNeededForRelation()

static bool PredicateLockingNeededForRelation ( Relation  relation)
inlinestatic

◆ PredicateLockPage()

◆ PredicateLockPageCombine()

void PredicateLockPageCombine ( Relation  relation,
BlockNumber  oldblkno,
BlockNumber  newblkno 
)

Definition at line 3228 of file predicate.c.

3230{
3231 /*
3232 * Page combines differ from page splits in that we ought to be able to
3233 * remove the locks on the old page after transferring them to the new
3234 * page, instead of duplicating them. However, because we can't edit other
3235 * backends' local lock tables, removing the old lock would leave them
3236 * with an entry in their LocalPredicateLockHash for a lock they're not
3237 * holding, which isn't acceptable. So we wind up having to do the same
3238 * work as a page split, acquiring a lock on the new page and keeping the
3239 * old page locked too. That can lead to some false positives, but should
3240 * be rare in practice.
3241 */
3243}

References fb(), and PredicateLockPageSplit().

Referenced by _bt_mark_page_halfdead(), and ginDeletePage().

◆ PredicateLockPageSplit()

void PredicateLockPageSplit ( Relation  relation,
BlockNumber  oldblkno,
BlockNumber  newblkno 
)

Definition at line 3143 of file predicate.c.

3145{
3148 bool success;
3149
3150 /*
3151 * Bail out quickly if there are no serializable transactions running.
3152 *
3153 * It's safe to do this check without taking any additional locks. Even if
3154 * a serializable transaction starts concurrently, we know it can't take
3155 * any SIREAD locks on the page being split because the caller is holding
3156 * the associated buffer page lock. Memory reordering isn't an issue; the
3157 * memory barrier in the LWLock acquisition guarantees that this read
3158 * occurs while the buffer page lock is held.
3159 */
3161 return;
3162
3163 if (!PredicateLockingNeededForRelation(relation))
3164 return;
3165
3169
3171 relation->rd_locator.dbOid,
3172 relation->rd_id,
3173 oldblkno);
3175 relation->rd_locator.dbOid,
3176 relation->rd_id,
3177 newblkno);
3178
3180
3181 /*
3182 * Try copying the locks over to the new page's tag, creating it if
3183 * necessary.
3184 */
3187 false);
3188
3189 if (!success)
3190 {
3191 /*
3192 * No more predicate lock entries are available. Failure isn't an
3193 * option here, so promote the page lock to a relation lock.
3194 */
3195
3196 /* Get the parent relation lock's lock tag */
3198 &newtargettag);
3199 Assert(success);
3200
3201 /*
3202 * Move the locks to the parent. This shouldn't fail.
3203 *
3204 * Note that here we are removing locks held by other backends,
3205 * leading to a possible inconsistency in their local lock hash table.
3206 * This is OK because we're replacing it with a lock that covers the
3207 * old one.
3208 */
3211 true);
3212 Assert(success);
3213 }
3214
3216}

References Assert, BlockNumberIsValid(), RelFileLocator::dbOid, fb(), GetParentPredicateLockTag(), LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), PredicateLockingNeededForRelation(), PredXact, RelationData::rd_id, RelationData::rd_locator, SET_PREDICATELOCKTARGETTAG_PAGE, success, PredXactListData::SxactGlobalXmin, TransactionIdIsValid, and TransferPredicateLocksToNewTarget().

Referenced by _bt_insertonpg(), _hash_splitbucket(), createPostingTree(), ginPlaceToPage(), gistplacetopage(), and PredicateLockPageCombine().

◆ PredicateLockRelation()

void PredicateLockRelation ( Relation  relation,
Snapshot  snapshot 
)

◆ PredicateLockShmemInit()

void PredicateLockShmemInit ( void  )

Definition at line 1146 of file predicate.c.

1147{
1148 HASHCTL info;
1151 bool found;
1152
1153#ifndef EXEC_BACKEND
1155#endif
1156
1157 /*
1158 * Compute size of predicate lock target hashtable. Note these
1159 * calculations must agree with PredicateLockShmemSize!
1160 */
1162
1163 /*
1164 * Allocate hash table for PREDICATELOCKTARGET structs. This stores
1165 * per-predicate-lock-target information.
1166 */
1167 info.keysize = sizeof(PREDICATELOCKTARGETTAG);
1168 info.entrysize = sizeof(PREDICATELOCKTARGET);
1170
1171 PredicateLockTargetHash = ShmemInitHash("PREDICATELOCKTARGET hash",
1174 &info,
1177
1178 /*
1179 * Reserve a dummy entry in the hash table; we use it to make sure there's
1180 * always one entry available when we need to split or combine a page,
1181 * because running out of space there could mean aborting a
1182 * non-serializable transaction.
1183 */
1184 if (!IsUnderPostmaster)
1185 {
1187 HASH_ENTER, &found);
1188 Assert(!found);
1189 }
1190
1191 /* Pre-calculate the hash and partition lock of the scratch entry */
1194
1195 /*
1196 * Allocate hash table for PREDICATELOCK structs. This stores per
1197 * xact-lock-of-a-target information.
1198 */
1199 info.keysize = sizeof(PREDICATELOCKTAG);
1200 info.entrysize = sizeof(PREDICATELOCK);
1201 info.hash = predicatelock_hash;
1203
1204 /* Assume an average of 2 xacts per target */
1205 max_table_size *= 2;
1206
1207 PredicateLockHash = ShmemInitHash("PREDICATELOCK hash",
1210 &info,
1213
1214 /*
1215 * Compute size for serializable transaction hashtable. Note these
1216 * calculations must agree with PredicateLockShmemSize!
1217 */
1219
1220 /*
1221 * Allocate a list to hold information on transactions participating in
1222 * predicate locking.
1223 *
1224 * Assume an average of 10 predicate locking transactions per backend.
1225 * This allows aggressive cleanup while detail is present before data must
1226 * be summarized for storage in SLRU and the "dummy" transaction.
1227 */
1228 max_table_size *= 10;
1229
1232 sizeof(SERIALIZABLEXACT))));
1233
1234 PredXact = ShmemInitStruct("PredXactList",
1236 &found);
1237 Assert(found == IsUnderPostmaster);
1238 if (!found)
1239 {
1240 int i;
1241
1242 /* clean everything, both the header and the element */
1244
1255 /* Add all elements to available list, clean. */
1256 for (i = 0; i < max_table_size; i++)
1257 {
1261 }
1278 }
1279 /* This never changes, so let's keep a local copy. */
1281
1282 /*
1283 * Allocate hash table for SERIALIZABLEXID structs. This stores per-xid
1284 * information for serializable transactions which have accessed data.
1285 */
1286 info.keysize = sizeof(SERIALIZABLEXIDTAG);
1287 info.entrysize = sizeof(SERIALIZABLEXID);
1288
1289 SerializableXidHash = ShmemInitHash("SERIALIZABLEXID hash",
1292 &info,
1295
1296 /*
1297 * Allocate space for tracking rw-conflicts in lists attached to the
1298 * transactions.
1299 *
1300 * Assume an average of 5 conflicts per transaction. Calculations suggest
1301 * that this will prevent resource exhaustion in even the most pessimal
1302 * loads up to max_connections = 200 with all 200 connections pounding the
1303 * database with serializable transactions. Beyond that, there may be
1304 * occasional transactions canceled when trying to flag conflicts. That's
1305 * probably OK.
1306 */
1307 max_table_size *= 5;
1308
1312
1313 RWConflictPool = ShmemInitStruct("RWConflictPool",
1315 &found);
1316 Assert(found == IsUnderPostmaster);
1317 if (!found)
1318 {
1319 int i;
1320
1321 /* clean everything, including the elements */
1323
1327 /* Add all elements to available list, clean. */
1328 for (i = 0; i < max_table_size; i++)
1329 {
1332 }
1333 }
1334
1335 /*
1336 * Create or attach to the header for the list of finished serializable
1337 * transactions.
1338 */
1340 ShmemInitStruct("FinishedSerializableTransactions",
1341 sizeof(dlist_head),
1342 &found);
1343 Assert(found == IsUnderPostmaster);
1344 if (!found)
1346
1347 /*
1348 * Initialize the SLRU storage for old committed serializable
1349 * transactions.
1350 */
1351 SerialInit();
1352}

References PredXactListData::activeList, add_size(), Assert, PredXactListData::availableList, RWConflictPoolHeaderData::availableList, PredXactListData::CanPartialClearThrough, SERIALIZABLEXACT::commitSeqNo, CreatePredXact(), dlist_init(), dlist_node_init(), dlist_push_tail(), PredXactListData::element, RWConflictPoolHeaderData::element, HASHCTL::entrysize, fb(), SERIALIZABLEXACT::finishedBefore, SERIALIZABLEXACT::finishedLink, FinishedSerializableTransactions, FirstNormalSerCommitSeqNo, SERIALIZABLEXACT::flags, HASHCTL::hash, HASH_BLOBS, HASH_ELEM, HASH_ENTER, HASH_FIXED_SIZE, HASH_FUNCTION, HASH_PARTITION, hash_search(), PredXactListData::HavePartialClearedThrough, i, SERIALIZABLEXACT::inConflicts, INVALID_PROC_NUMBER, InvalidTransactionId, IsUnderPostmaster, HASHCTL::keysize, SERIALIZABLEXACT::lastCommitBeforeSnapshot, PredXactListData::LastSxactCommitSeqNo, LWLockInitialize(), max_prepared_xacts, MaxBackends, mul_size(), NPREDICATELOCKTARGETENTS, HASHCTL::num_partitions, NUM_PREDICATELOCK_PARTITIONS, OldCommittedSxact, PredXactListData::OldCommittedSxact, SERIALIZABLEXACT::outConflicts, RWConflictData::outLink, SERIALIZABLEXACT::perXactPredicateListLock, SERIALIZABLEXACT::pgprocno, SERIALIZABLEXACT::pid, SERIALIZABLEXACT::possibleUnsafeConflicts, predicatelock_hash(), PredicateLockHash, PredicateLockHashPartitionLock, SERIALIZABLEXACT::predicateLocks, PredicateLockTargetHash, PredicateLockTargetTagHashCode, PredXact, PredXactListDataSize, SERIALIZABLEXACT::prepareSeqNo, RWConflictDataSize, RWConflictPool, RWConflictPoolHeaderDataSize, ScratchPartitionLock, ScratchTargetTag, ScratchTargetTagHash, SERIALIZABLEXACT::SeqNo, SerialInit(), SerializableXidHash, SetInvalidVirtualTransactionId, ShmemInitHash(), ShmemInitStruct(), SXACT_FLAG_COMMITTED, PredXactListData::SxactGlobalXmin, PredXactListData::SxactGlobalXminCount, SERIALIZABLEXACT::topXid, SERIALIZABLEXACT::vxid, PredXactListData::WritableSxactCount, SERIALIZABLEXACT::xactLink, and SERIALIZABLEXACT::xmin.

Referenced by CreateOrAttachShmemStructs().

◆ PredicateLockShmemSize()

Size PredicateLockShmemSize ( void  )

Definition at line 1358 of file predicate.c.

1359{
1360 Size size = 0;
1361 long max_table_size;
1362
1363 /* predicate lock target hash table */
1366 sizeof(PREDICATELOCKTARGET)));
1367
1368 /* predicate lock hash table */
1369 max_table_size *= 2;
1371 sizeof(PREDICATELOCK)));
1372
1373 /*
1374 * Since NPREDICATELOCKTARGETENTS is only an estimate, add 10% safety
1375 * margin.
1376 */
1377 size = add_size(size, size / 10);
1378
1379 /* transaction list */
1381 max_table_size *= 10;
1382 size = add_size(size, PredXactListDataSize);
1383 size = add_size(size, mul_size((Size) max_table_size,
1384 sizeof(SERIALIZABLEXACT)));
1385
1386 /* transaction xid table */
1388 sizeof(SERIALIZABLEXID)));
1389
1390 /* rw-conflict pool */
1391 max_table_size *= 5;
1393 size = add_size(size, mul_size((Size) max_table_size,
1395
1396 /* Head for list of finished serializable transactions. */
1397 size = add_size(size, sizeof(dlist_head));
1398
1399 /* Shared memory structures for SLRU tracking of old committed xids. */
1400 size = add_size(size, sizeof(SerialControlData));
1402
1403 return size;
1404}

References add_size(), fb(), hash_estimate_size(), max_prepared_xacts, MaxBackends, mul_size(), NPREDICATELOCKTARGETENTS, PredXactListDataSize, RWConflictDataSize, RWConflictPoolHeaderDataSize, serializable_buffers, and SimpleLruShmemSize().

Referenced by CalculateShmemSize().

◆ PredicateLockTID()

void PredicateLockTID ( Relation  relation,
const ItemPointerData tid,
Snapshot  snapshot,
TransactionId  tuple_xid 
)

Definition at line 2620 of file predicate.c.

2622{
2624
2625 if (!SerializationNeededForRead(relation, snapshot))
2626 return;
2627
2628 /*
2629 * Return if this xact wrote it.
2630 */
2631 if (relation->rd_index == NULL)
2632 {
2633 /* If we wrote it; we already have a write lock. */
2635 return;
2636 }
2637
2638 /*
2639 * Do quick-but-not-definitive test for a relation lock first. This will
2640 * never cause a return when the relation is *not* locked, but will
2641 * occasionally let the check continue when there really *is* a relation
2642 * level lock.
2643 */
2645 relation->rd_locator.dbOid,
2646 relation->rd_id);
2647 if (PredicateLockExists(&tag))
2648 return;
2649
2651 relation->rd_locator.dbOid,
2652 relation->rd_id,
2656}

References RelFileLocator::dbOid, fb(), ItemPointerGetBlockNumber(), ItemPointerGetOffsetNumber(), PredicateLockAcquire(), PredicateLockExists(), RelationData::rd_id, RelationData::rd_index, RelationData::rd_locator, SerializationNeededForRead(), SET_PREDICATELOCKTARGETTAG_RELATION, SET_PREDICATELOCKTARGETTAG_TUPLE, and TransactionIdIsCurrentTransactionId().

Referenced by BitmapHeapScanNextBlock(), heap_fetch(), and heap_hot_search_buffer().

◆ PredicateLockTwoPhaseFinish()

void PredicateLockTwoPhaseFinish ( FullTransactionId  fxid,
bool  isCommit 
)

Definition at line 4881 of file predicate.c.

4882{
4885
4887
4889 sxid = (SERIALIZABLEXID *)
4892
4893 /* xid will not be found if it wasn't a serializable transaction */
4894 if (sxid == NULL)
4895 return;
4896
4897 /* Release its locks */
4898 MySerializableXact = sxid->myXact;
4899 MyXactDidWrite = true; /* conservatively assume that we wrote
4900 * something */
4902}

References fb(), HASH_FIND, hash_search(), LW_SHARED, LWLockAcquire(), LWLockRelease(), MySerializableXact, MyXactDidWrite, ReleasePredicateLocks(), SerializableXidHash, SERIALIZABLEXIDTAG::xid, and XidFromFullTransactionId.

Referenced by FinishPreparedTransaction().

◆ RegisterPredicateLockingXid()

void RegisterPredicateLockingXid ( TransactionId  xid)

Definition at line 1958 of file predicate.c.

1959{
1962 bool found;
1963
1964 /*
1965 * If we're not tracking predicate lock data for this transaction, we
1966 * should ignore the request and return quickly.
1967 */
1969 return;
1970
1971 /* We should have a valid XID and be at the top level. */
1973
1975
1976 /* This should only be done once per transaction. */
1978
1980
1981 sxidtag.xid = xid;
1983 &sxidtag,
1984 HASH_ENTER, &found);
1985 Assert(!found);
1986
1987 /* Initialize the structure. */
1988 sxid->myXact = MySerializableXact;
1990}

References Assert, fb(), HASH_ENTER, hash_search(), InvalidSerializableXact, InvalidTransactionId, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), MySerializableXact, SerializableXidHash, SERIALIZABLEXACT::topXid, and TransactionIdIsValid.

Referenced by AssignTransactionId().

◆ ReleaseOneSerializableXact()

static void ReleaseOneSerializableXact ( SERIALIZABLEXACT sxact,
bool  partial,
bool  summarize 
)
static

Definition at line 3834 of file predicate.c.

3836{
3838 dlist_mutable_iter iter;
3839
3840 Assert(sxact != NULL);
3842 Assert(partial || !SxactIsOnFinishedList(sxact));
3844
3845 /*
3846 * First release all the predicate locks held by this xact (or transfer
3847 * them to OldCommittedSxact if summarize is true)
3848 */
3850 if (IsInParallelMode())
3851 LWLockAcquire(&sxact->perXactPredicateListLock, LW_EXCLUSIVE);
3852 dlist_foreach_modify(iter, &sxact->predicateLocks)
3853 {
3855 dlist_container(PREDICATELOCK, xactLink, iter.cur);
3856 PREDICATELOCKTAG tag;
3857 PREDICATELOCKTARGET *target;
3861
3862 tag = predlock->tag;
3863 target = tag.myTarget;
3864 targettag = target->tag;
3867
3869
3870 dlist_delete(&predlock->targetLink);
3871
3875 HASH_REMOVE, NULL);
3876 if (summarize)
3877 {
3878 bool found;
3879
3880 /* Fold into dummy transaction list. */
3885 HASH_ENTER_NULL, &found);
3886 if (!predlock)
3887 ereport(ERROR,
3889 errmsg("out of shared memory"),
3890 errhint("You might need to increase \"%s\".", "max_pred_locks_per_transaction")));
3891 if (found)
3892 {
3893 Assert(predlock->commitSeqNo != 0);
3894 Assert(predlock->commitSeqNo != InvalidSerCommitSeqNo);
3895 if (predlock->commitSeqNo < sxact->commitSeqNo)
3896 predlock->commitSeqNo = sxact->commitSeqNo;
3897 }
3898 else
3899 {
3901 &predlock->targetLink);
3903 &predlock->xactLink);
3904 predlock->commitSeqNo = sxact->commitSeqNo;
3905 }
3906 }
3907 else
3909
3911 }
3912
3913 /*
3914 * Rather than retail removal, just re-init the head after we've run
3915 * through the list.
3916 */
3917 dlist_init(&sxact->predicateLocks);
3918
3919 if (IsInParallelMode())
3920 LWLockRelease(&sxact->perXactPredicateListLock);
3922
3923 sxidtag.xid = sxact->topXid;
3925
3926 /* Release all outConflicts (unless 'partial' is true) */
3927 if (!partial)
3928 {
3929 dlist_foreach_modify(iter, &sxact->outConflicts)
3930 {
3932 dlist_container(RWConflictData, outLink, iter.cur);
3933
3934 if (summarize)
3935 conflict->sxactIn->flags |= SXACT_FLAG_SUMMARY_CONFLICT_IN;
3937 }
3938 }
3939
3940 /* Release all inConflicts. */
3941 dlist_foreach_modify(iter, &sxact->inConflicts)
3942 {
3944 dlist_container(RWConflictData, inLink, iter.cur);
3945
3946 if (summarize)
3947 conflict->sxactOut->flags |= SXACT_FLAG_SUMMARY_CONFLICT_OUT;
3949 }
3950
3951 /* Finally, get rid of the xid and the record of the transaction itself. */
3952 if (!partial)
3953 {
3954 if (sxidtag.xid != InvalidTransactionId)
3957 }
3958
3960}

References Assert, dlist_mutable_iter::cur, dlist_container, dlist_delete(), dlist_foreach_modify, dlist_init(), dlist_push_tail(), ereport, errcode(), errhint(), errmsg, ERROR, fb(), HASH_ENTER_NULL, HASH_REMOVE, hash_search(), hash_search_with_hash_value(), InvalidSerCommitSeqNo, InvalidTransactionId, IsInParallelMode(), LW_EXCLUSIVE, LW_SHARED, LWLockAcquire(), LWLockHeldByMe(), LWLockRelease(), PREDICATELOCKTAG::myTarget, PREDICATELOCKTAG::myXact, OldCommittedSxact, PredicateLockHash, PredicateLockHashCodeFromTargetHashCode, PredicateLockHashPartitionLock, SERIALIZABLEXACT::predicateLocks, PREDICATELOCKTARGET::predicateLocks, PredicateLockTargetTagHashCode, ReleasePredXact(), ReleaseRWConflict(), RemoveTargetIfNoLongerUsed(), SerializableXidHash, SXACT_FLAG_SUMMARY_CONFLICT_IN, SXACT_FLAG_SUMMARY_CONFLICT_OUT, SxactIsCommitted, SxactIsOnFinishedList, SxactIsRolledBack, and PREDICATELOCKTARGET::tag.

Referenced by ClearOldPredicateLocks(), ReleasePredicateLocks(), and SummarizeOldestCommittedSxact().

◆ ReleasePredicateLocks()

void ReleasePredicateLocks ( bool  isCommit,
bool  isReadOnlySafe 
)

Definition at line 3311 of file predicate.c.

3312{
3313 bool partiallyReleasing = false;
3314 bool needToClear;
3316 dlist_mutable_iter iter;
3317
3318 /*
3319 * We can't trust XactReadOnly here, because a transaction which started
3320 * as READ WRITE can show as READ ONLY later, e.g., within
3321 * subtransactions. We want to flag a transaction as READ ONLY if it
3322 * commits without writing so that de facto READ ONLY transactions get the
3323 * benefit of some RO optimizations, so we will use this local variable to
3324 * get some cleanup logic right which is based on whether the transaction
3325 * was declared READ ONLY at the top level.
3326 */
3328
3329 /* We can't be both committing and releasing early due to RO_SAFE. */
3331
3332 /* Are we at the end of a transaction, that is, a commit or abort? */
3333 if (!isReadOnlySafe)
3334 {
3335 /*
3336 * Parallel workers mustn't release predicate locks at the end of
3337 * their transaction. The leader will do that at the end of its
3338 * transaction.
3339 */
3340 if (IsParallelWorker())
3341 {
3343 return;
3344 }
3345
3346 /*
3347 * By the time the leader in a parallel query reaches end of
3348 * transaction, it has waited for all workers to exit.
3349 */
3351
3352 /*
3353 * If the leader in a parallel query earlier stashed a partially
3354 * released SERIALIZABLEXACT for final clean-up at end of transaction
3355 * (because workers might still have been accessing it), then it's
3356 * time to restore it.
3357 */
3359 {
3364 }
3365 }
3366
3368 {
3370 return;
3371 }
3372
3374
3375 /*
3376 * If the transaction is committing, but it has been partially released
3377 * already, then treat this as a roll back. It was marked as rolled back.
3378 */
3380 isCommit = false;
3381
3382 /*
3383 * If we're called in the middle of a transaction because we discovered
3384 * that the SXACT_FLAG_RO_SAFE flag was set, then we'll partially release
3385 * it (that is, release the predicate locks and conflicts, but not the
3386 * SERIALIZABLEXACT itself) if we're the first backend to have noticed.
3387 */
3389 {
3390 /*
3391 * The leader needs to stash a pointer to it, so that it can
3392 * completely release it at end-of-transaction.
3393 */
3394 if (!IsParallelWorker())
3396
3397 /*
3398 * The first backend to reach this condition will partially release
3399 * the SERIALIZABLEXACT. All others will just clear their
3400 * backend-local state so that they stop doing SSI checks for the rest
3401 * of the transaction.
3402 */
3404 {
3407 return;
3408 }
3409 else
3410 {
3412 partiallyReleasing = true;
3413 /* ... and proceed to perform the partial release below. */
3414 }
3415 }
3421
3422 /* may not be serializable during COMMIT/ROLLBACK PREPARED */
3424
3425 /* We'd better not already be on the cleanup list. */
3427
3429
3430 /*
3431 * We don't hold XidGenLock lock here, assuming that TransactionId is
3432 * atomic!
3433 *
3434 * If this value is changing, we don't care that much whether we get the
3435 * old or new value -- it is just used to determine how far
3436 * SxactGlobalXmin must advance before this transaction can be fully
3437 * cleaned up. The worst that could happen is we wait for one more
3438 * transaction to complete before freeing some RAM; correctness of visible
3439 * behavior is not affected.
3440 */
3442
3443 /*
3444 * If it's not a commit it's either a rollback or a read-only transaction
3445 * flagged SXACT_FLAG_RO_SAFE, and we can clear our locks immediately.
3446 */
3447 if (isCommit)
3448 {
3451 /* Recognize implicit read-only transaction (commit without write). */
3452 if (!MyXactDidWrite)
3454 }
3455 else
3456 {
3457 /*
3458 * The DOOMED flag indicates that we intend to roll back this
3459 * transaction and so it should not cause serialization failures for
3460 * other transactions that conflict with it. Note that this flag might
3461 * already be set, if another backend marked this transaction for
3462 * abort.
3463 *
3464 * The ROLLED_BACK flag further indicates that ReleasePredicateLocks
3465 * has been called, and so the SerializableXact is eligible for
3466 * cleanup. This means it should not be considered when calculating
3467 * SxactGlobalXmin.
3468 */
3471
3472 /*
3473 * If the transaction was previously prepared, but is now failing due
3474 * to a ROLLBACK PREPARED or (hopefully very rare) error after the
3475 * prepare, clear the prepared flag. This simplifies conflict
3476 * checking.
3477 */
3479 }
3480
3482 {
3484 if (--(PredXact->WritableSxactCount) == 0)
3485 {
3486 /*
3487 * Release predicate locks and rw-conflicts in for all committed
3488 * transactions. There are no longer any transactions which might
3489 * conflict with the locks and no chance for new transactions to
3490 * overlap. Similarly, existing conflicts in can't cause pivots,
3491 * and any conflicts in which could have completed a dangerous
3492 * structure would already have caused a rollback, so any
3493 * remaining ones must be benign.
3494 */
3496 }
3497 }
3498 else
3499 {
3500 /*
3501 * Read-only transactions: clear the list of transactions that might
3502 * make us unsafe. Note that we use 'inLink' for the iteration as
3503 * opposed to 'outLink' for the r/w xacts.
3504 */
3506 {
3508 dlist_container(RWConflictData, inLink, iter.cur);
3509
3512
3514 }
3515 }
3516
3517 /* Check for conflict out to old committed transactions. */
3518 if (isCommit
3521 {
3522 /*
3523 * we don't know which old committed transaction we conflicted with,
3524 * so be conservative and use FirstNormalSerCommitSeqNo here
3525 */
3529 }
3530
3531 /*
3532 * Release all outConflicts to committed transactions. If we're rolling
3533 * back clear them all. Set SXACT_FLAG_CONFLICT_OUT if any point to
3534 * previously committed transactions.
3535 */
3537 {
3539 dlist_container(RWConflictData, outLink, iter.cur);
3540
3541 if (isCommit
3543 && SxactIsCommitted(conflict->sxactIn))
3544 {
3546 || conflict->sxactIn->prepareSeqNo < MySerializableXact->SeqNo.earliestOutConflictCommit)
3549 }
3550
3551 if (!isCommit
3552 || SxactIsCommitted(conflict->sxactIn)
3553 || (conflict->sxactIn->SeqNo.lastCommitBeforeSnapshot >= PredXact->LastSxactCommitSeqNo))
3555 }
3556
3557 /*
3558 * Release all inConflicts from committed and read-only transactions. If
3559 * we're rolling back, clear them all.
3560 */
3562 {
3564 dlist_container(RWConflictData, inLink, iter.cur);
3565
3566 if (!isCommit
3567 || SxactIsCommitted(conflict->sxactOut)
3568 || SxactIsReadOnly(conflict->sxactOut))
3570 }
3571
3573 {
3574 /*
3575 * Remove ourselves from the list of possible conflicts for concurrent
3576 * READ ONLY transactions, flagging them as unsafe if we have a
3577 * conflict out. If any are waiting DEFERRABLE transactions, wake them
3578 * up if they are known safe or known unsafe.
3579 */
3581 {
3583 dlist_container(RWConflictData, outLink, iter.cur);
3584
3585 roXact = possibleUnsafeConflict->sxactIn;
3588
3589 /* Mark conflicted if necessary. */
3590 if (isCommit
3594 <= roXact->SeqNo.lastCommitBeforeSnapshot))
3595 {
3596 /*
3597 * This releases possibleUnsafeConflict (as well as all other
3598 * possible conflicts for roXact)
3599 */
3601 }
3602 else
3603 {
3605
3606 /*
3607 * If we were the last possible conflict, flag it safe. The
3608 * transaction can now safely release its predicate locks (but
3609 * that transaction's backend has to do that itself).
3610 */
3611 if (dlist_is_empty(&roXact->possibleUnsafeConflicts))
3612 roXact->flags |= SXACT_FLAG_RO_SAFE;
3613 }
3614
3615 /*
3616 * Wake up the process for a waiting DEFERRABLE transaction if we
3617 * now know it's either safe or conflicted.
3618 */
3621 ProcSendSignal(roXact->pgprocno);
3622 }
3623 }
3624
3625 /*
3626 * Check whether it's time to clean up old transactions. This can only be
3627 * done when the last serializable transaction with the oldest xmin among
3628 * serializable transactions completes. We then find the "new oldest"
3629 * xmin and purge any transactions which finished before this transaction
3630 * was launched.
3631 *
3632 * For parallel queries in read-only transactions, it might run twice. We
3633 * only release the reference on the first call.
3634 */
3635 needToClear = false;
3636 if ((partiallyReleasing ||
3640 {
3642 if (--(PredXact->SxactGlobalXminCount) == 0)
3643 {
3645 needToClear = true;
3646 }
3647 }
3648
3650
3652
3653 /* Add this to the list of transactions to check for later cleanup. */
3654 if (isCommit)
3657
3658 /*
3659 * If we're releasing a RO_SAFE transaction in parallel mode, we'll only
3660 * partially release it. That's necessary because other backends may have
3661 * a reference to it. The leader will release the SERIALIZABLEXACT itself
3662 * at the end of the transaction after workers have stopped running.
3663 */
3664 if (!isCommit)
3667 false);
3668
3670
3671 if (needToClear)
3673
3675}

References Assert, PredXactListData::CanPartialClearThrough, ClearOldPredicateLocks(), SERIALIZABLEXACT::commitSeqNo, dlist_mutable_iter::cur, dlist_container, dlist_foreach_modify, dlist_is_empty(), dlist_push_tail(), SERIALIZABLEXACT::earliestOutConflictCommit, fb(), SERIALIZABLEXACT::finishedBefore, SERIALIZABLEXACT::finishedLink, FinishedSerializableTransactions, FirstNormalSerCommitSeqNo, SERIALIZABLEXACT::flags, FlagSxactUnsafe(), SERIALIZABLEXACT::inConflicts, InvalidSerializableXact, IsInParallelMode(), IsolationIsSerializable, IsParallelWorker, PredXactListData::LastSxactCommitSeqNo, LocalPredicateLockHash, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), MySerializableXact, MyXactDidWrite, TransamVariablesData::nextXid, SERIALIZABLEXACT::outConflicts, ParallelContextActive(), SERIALIZABLEXACT::pid, SERIALIZABLEXACT::possibleUnsafeConflicts, PredXact, ProcSendSignal(), ReleaseOneSerializableXact(), ReleasePredicateLocksLocal(), ReleaseRWConflict(), SavedSerializableXact, SERIALIZABLEXACT::SeqNo, SetNewSxactGlobalXmin(), SXACT_FLAG_COMMITTED, SXACT_FLAG_CONFLICT_OUT, SXACT_FLAG_DOOMED, SXACT_FLAG_PARTIALLY_RELEASED, SXACT_FLAG_READ_ONLY, SXACT_FLAG_RO_SAFE, SXACT_FLAG_ROLLED_BACK, PredXactListData::SxactGlobalXmin, PredXactListData::SxactGlobalXminCount, SxactHasConflictOut, SxactHasSummaryConflictOut, SxactIsCommitted, SxactIsDeferrableWaiting, SxactIsDoomed, SxactIsOnFinishedList, SxactIsPartiallyReleased, SxactIsPrepared, SxactIsReadOnly, SxactIsRolledBack, SxactIsROSafe, SxactIsROUnsafe, TransactionIdEquals, TransamVariables, PredXactListData::WritableSxactCount, XidFromFullTransactionId, and SERIALIZABLEXACT::xmin.

Referenced by GetSafeSnapshot(), PredicateLockTwoPhaseFinish(), ResourceOwnerReleaseInternal(), and SerializationNeededForRead().

◆ ReleasePredicateLocksLocal()

static void ReleasePredicateLocksLocal ( void  )
static

Definition at line 3678 of file predicate.c.

3679{
3681 MyXactDidWrite = false;
3682
3683 /* Delete per-transaction lock table */
3685 {
3688 }
3689}

References fb(), hash_destroy(), InvalidSerializableXact, LocalPredicateLockHash, MySerializableXact, and MyXactDidWrite.

Referenced by ReleasePredicateLocks().

◆ ReleasePredXact()

◆ ReleaseRWConflict()

static void ReleaseRWConflict ( RWConflict  conflict)
static

◆ RemoveScratchTarget()

◆ RemoveTargetIfNoLongerUsed()

◆ RestoreScratchTarget()

◆ RWConflictExists()

static bool RWConflictExists ( const SERIALIZABLEXACT reader,
const SERIALIZABLEXACT writer 
)
static

Definition at line 611 of file predicate.c.

612{
613 dlist_iter iter;
614
615 Assert(reader != writer);
616
617 /* Check the ends of the purported conflict first. */
618 if (SxactIsDoomed(reader)
620 || dlist_is_empty(&reader->outConflicts)
621 || dlist_is_empty(&writer->inConflicts))
622 return false;
623
624 /*
625 * A conflict is possible; walk the list to find out.
626 *
627 * The unconstify is needed as we have no const version of
628 * dlist_foreach().
629 */
630 dlist_foreach(iter, &unconstify(SERIALIZABLEXACT *, reader)->outConflicts)
631 {
633 dlist_container(RWConflictData, outLink, iter.cur);
634
635 if (conflict->sxactIn == writer)
636 return true;
637 }
638
639 /* No conflict found. */
640 return false;
641}

References Assert, dlist_iter::cur, dlist_container, dlist_foreach, dlist_is_empty(), fb(), SERIALIZABLEXACT::outConflicts, SxactIsDoomed, and unconstify.

Referenced by CheckForSerializableConflictOut(), CheckTableForSerializableConflictIn(), CheckTargetForConflictsIn(), and SetRWConflict().

◆ SerialAdd()

static void SerialAdd ( TransactionId  xid,
SerCommitSeqNo  minConflictCommitSeqNo 
)
static

Definition at line 859 of file predicate.c.

860{
861 TransactionId tailXid;
863 int slotno;
865 bool isNewPage;
866 LWLock *lock;
867
869
870 targetPage = SerialPage(xid);
872
873 /*
874 * In this routine, we must hold both SerialControlLock and the SLRU bank
875 * lock simultaneously while making the SLRU data catch up with the new
876 * state that we determine.
877 */
879
880 /*
881 * If 'xid' is older than the global xmin (== tailXid), there's no need to
882 * store it, after all. This can happen if the oldest transaction holding
883 * back the global xmin just finished, making 'xid' uninteresting, but
884 * ClearOldPredicateLocks() has not yet run.
885 */
886 tailXid = serialControl->tailXid;
887 if (!TransactionIdIsValid(tailXid) || TransactionIdPrecedes(xid, tailXid))
888 {
890 return;
891 }
892
893 /*
894 * If the SLRU is currently unused, zero out the whole active region from
895 * tailXid to headXid before taking it into use. Otherwise zero out only
896 * any new pages that enter the tailXid-headXid range as we advance
897 * headXid.
898 */
899 if (serialControl->headPage < 0)
900 {
901 firstZeroPage = SerialPage(tailXid);
902 isNewPage = true;
903 }
904 else
905 {
908 targetPage);
909 }
910
913 serialControl->headXid = xid;
914 if (isNewPage)
916
917 if (isNewPage)
918 {
919 /* Initialize intervening pages; might involve trading locks */
920 for (;;)
921 {
926 break;
928 LWLockRelease(lock);
929 }
930 }
931 else
932 {
935 }
936
938 SerialSlruCtl->shared->page_dirty[slotno] = true;
939
940 LWLockRelease(lock);
942}

References Assert, fb(), SerialControlData::headPage, SerialControlData::headXid, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), serialControl, SerialNextPage, SerialPage, SerialPagePrecedesLogically(), SerialSlruCtl, SerialValue, SimpleLruGetBankLock(), SimpleLruReadPage(), SimpleLruZeroPage(), SerialControlData::tailXid, TransactionIdFollows(), TransactionIdIsValid, and TransactionIdPrecedes().

Referenced by SummarizeOldestCommittedSxact().

◆ SerialGetMinConflictCommitSeqNo()

static SerCommitSeqNo SerialGetMinConflictCommitSeqNo ( TransactionId  xid)
static

Definition at line 950 of file predicate.c.

951{
952 TransactionId headXid;
953 TransactionId tailXid;
955 int slotno;
956
958
960 headXid = serialControl->headXid;
961 tailXid = serialControl->tailXid;
963
964 if (!TransactionIdIsValid(headXid))
965 return 0;
966
968
969 if (TransactionIdPrecedes(xid, tailXid)
970 || TransactionIdFollows(xid, headXid))
971 return 0;
972
973 /*
974 * The following function must be called without holding SLRU bank lock,
975 * but will return with that lock held, which must then be released.
976 */
978 SerialPage(xid), xid);
979 val = SerialValue(slotno, xid);
981 return val;
982}

References Assert, fb(), SerialControlData::headXid, LW_SHARED, LWLockAcquire(), LWLockRelease(), serialControl, SerialPage, SerialSlruCtl, SerialValue, SimpleLruGetBankLock(), SimpleLruReadPage_ReadOnly(), SerialControlData::tailXid, TransactionIdFollows(), TransactionIdIsValid, TransactionIdPrecedes(), and val.

Referenced by CheckForSerializableConflictOut().

◆ SerialInit()

static void SerialInit ( void  )
static

Definition at line 807 of file predicate.c.

808{
809 bool found;
810
811 /*
812 * Set up SLRU management of the pg_serial data.
813 */
815 SimpleLruInit(SerialSlruCtl, "serializable",
816 serializable_buffers, 0, "pg_serial",
818 SYNC_HANDLER_NONE, false);
819#ifdef USE_ASSERT_CHECKING
821#endif
823
824 /*
825 * Create or attach to the SerialControl structure.
826 */
828 ShmemInitStruct("SerialControlData", sizeof(SerialControlData), &found);
829
830 Assert(found == IsUnderPostmaster);
831 if (!found)
832 {
833 /*
834 * Set control information to reflect empty SLRU.
835 */
841 }
842}

References Assert, fb(), SerialControlData::headPage, SerialControlData::headXid, InvalidTransactionId, IsUnderPostmaster, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), SERIAL_ENTRIESPERPAGE, serialControl, serializable_buffers, SerialPagePrecedesLogically(), SerialSlruCtl, ShmemInitStruct(), SimpleLruInit(), SlruPagePrecedesUnitTests, SYNC_HANDLER_NONE, and SerialControlData::tailXid.

Referenced by PredicateLockShmemInit().

◆ SerializationNeededForRead()

static bool SerializationNeededForRead ( Relation  relation,
Snapshot  snapshot 
)
inlinestatic

Definition at line 517 of file predicate.c.

518{
519 /* Nothing to do if this is not a serializable transaction */
521 return false;
522
523 /*
524 * Don't acquire locks or conflict when scanning with a special snapshot.
525 * This excludes things like CLUSTER and REINDEX. They use the wholesale
526 * functions TransferPredicateLocksToHeapRelation() and
527 * CheckTableForSerializableConflictIn() to participate in serialization,
528 * but the scans involved don't need serialization.
529 */
530 if (!IsMVCCSnapshot(snapshot))
531 return false;
532
533 /*
534 * Check if we have just become "RO-safe". If we have, immediately release
535 * all locks as they're not needed anymore. This also resets
536 * MySerializableXact, so that subsequent calls to this function can exit
537 * quickly.
538 *
539 * A transaction is flagged as RO_SAFE if all concurrent R/W transactions
540 * commit without having conflicts out to an earlier snapshot, thus
541 * ensuring that no conflicts are possible for this transaction.
542 */
544 {
545 ReleasePredicateLocks(false, true);
546 return false;
547 }
548
549 /* Check if the relation doesn't participate in predicate locking */
551 return false;
552
553 return true; /* no excuse to skip predicate locking */
554}

References InvalidSerializableXact, IsMVCCSnapshot, MySerializableXact, PredicateLockingNeededForRelation(), ReleasePredicateLocks(), and SxactIsROSafe.

Referenced by CheckForSerializableConflictOut(), CheckForSerializableConflictOutNeeded(), PredicateLockPage(), PredicateLockRelation(), and PredicateLockTID().

◆ SerializationNeededForWrite()

static bool SerializationNeededForWrite ( Relation  relation)
inlinestatic

Definition at line 561 of file predicate.c.

562{
563 /* Nothing to do if this is not a serializable transaction */
565 return false;
566
567 /* Check if the relation doesn't participate in predicate locking */
569 return false;
570
571 return true; /* no excuse to skip predicate locking */
572}

References InvalidSerializableXact, MySerializableXact, and PredicateLockingNeededForRelation().

Referenced by CheckForSerializableConflictIn(), and CheckTableForSerializableConflictIn().

◆ SerialPagePrecedesLogically()

static bool SerialPagePrecedesLogically ( int64  page1,
int64  page2 
)
static

◆ SerialSetActiveSerXmin()

static void SerialSetActiveSerXmin ( TransactionId  xid)
static

Definition at line 991 of file predicate.c.

992{
994
995 /*
996 * When no sxacts are active, nothing overlaps, set the xid values to
997 * invalid to show that there are no valid entries. Don't clear headPage,
998 * though. A new xmin might still land on that page, and we don't want to
999 * repeatedly zero out the same page.
1000 */
1001 if (!TransactionIdIsValid(xid))
1002 {
1006 return;
1007 }
1008
1009 /*
1010 * When we're recovering prepared transactions, the global xmin might move
1011 * backwards depending on the order they're recovered. Normally that's not
1012 * OK, but during recovery no serializable transactions will commit, so
1013 * the SLRU is empty and we can get away with it.
1014 */
1015 if (RecoveryInProgress())
1016 {
1020 {
1021 serialControl->tailXid = xid;
1022 }
1024 return;
1025 }
1026
1029
1030 serialControl->tailXid = xid;
1031
1033}

References Assert, fb(), SerialControlData::headPage, SerialControlData::headXid, InvalidTransactionId, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), RecoveryInProgress(), serialControl, SerialControlData::tailXid, TransactionIdFollows(), TransactionIdIsValid, and TransactionIdPrecedes().

Referenced by GetSerializableTransactionSnapshotInt(), predicatelock_twophase_recover(), and SetNewSxactGlobalXmin().

◆ SetNewSxactGlobalXmin()

◆ SetPossibleUnsafeConflict()

static void SetPossibleUnsafeConflict ( SERIALIZABLEXACT roXact,
SERIALIZABLEXACT activeXact 
)
static

Definition at line 667 of file predicate.c.

669{
671
675
679 errmsg("not enough elements in RWConflictPool to record a potential read/write conflict"),
680 errhint("You might need to run fewer transactions at a time or increase \"max_connections\".")));
681
683 dlist_delete(&conflict->outLink);
684
685 conflict->sxactOut = activeXact;
686 conflict->sxactIn = roXact;
687 dlist_push_tail(&activeXact->possibleUnsafeConflicts, &conflict->outLink);
688 dlist_push_tail(&roXact->possibleUnsafeConflicts, &conflict->inLink);
689}

References Assert, RWConflictPoolHeaderData::availableList, dlist_delete(), dlist_head_element, dlist_is_empty(), dlist_push_tail(), ereport, errcode(), errhint(), errmsg, ERROR, fb(), RWConflictPool, and SxactIsReadOnly.

Referenced by GetSerializableTransactionSnapshotInt().

◆ SetRWConflict()

static void SetRWConflict ( SERIALIZABLEXACT reader,
SERIALIZABLEXACT writer 
)
static

Definition at line 644 of file predicate.c.

645{
647
648 Assert(reader != writer);
649 Assert(!RWConflictExists(reader, writer));
650
654 errmsg("not enough elements in RWConflictPool to record a read/write conflict"),
655 errhint("You might need to run fewer transactions at a time or increase \"max_connections\".")));
656
658 dlist_delete(&conflict->outLink);
659
660 conflict->sxactOut = reader;
661 conflict->sxactIn = writer;
662 dlist_push_tail(&reader->outConflicts, &conflict->outLink);
663 dlist_push_tail(&writer->inConflicts, &conflict->inLink);
664}

References Assert, RWConflictPoolHeaderData::availableList, dlist_delete(), dlist_head_element, dlist_is_empty(), dlist_push_tail(), ereport, errcode(), errhint(), errmsg, ERROR, fb(), SERIALIZABLEXACT::outConflicts, RWConflictExists(), and RWConflictPool.

Referenced by FlagRWConflict().

◆ SetSerializableTransactionSnapshot()

void SetSerializableTransactionSnapshot ( Snapshot  snapshot,
VirtualTransactionId sourcevxid,
int  sourcepid 
)

Definition at line 1721 of file predicate.c.

1724{
1726
1727 /*
1728 * If this is called by parallel.c in a parallel worker, we don't want to
1729 * create a SERIALIZABLEXACT just yet because the leader's
1730 * SERIALIZABLEXACT will be installed with AttachSerializableXact(). We
1731 * also don't want to reject SERIALIZABLE READ ONLY DEFERRABLE in this
1732 * case, because the leader has already determined that the snapshot it
1733 * has passed us is safe. So there is nothing for us to do.
1734 */
1735 if (IsParallelWorker())
1736 return;
1737
1738 /*
1739 * We do not allow SERIALIZABLE READ ONLY DEFERRABLE transactions to
1740 * import snapshots, since there's no way to wait for a safe snapshot when
1741 * we're using the snap we're told to. (XXX instead of throwing an error,
1742 * we could just ignore the XactDeferrable flag?)
1743 */
1745 ereport(ERROR,
1747 errmsg("a snapshot-importing transaction must not be READ ONLY DEFERRABLE")));
1748
1750 sourcepid);
1751}

References Assert, ereport, errcode(), errmsg, ERROR, fb(), GetSerializableTransactionSnapshotInt(), IsolationIsSerializable, IsParallelWorker, XactDeferrable, and XactReadOnly.

Referenced by SetTransactionSnapshot().

◆ ShareSerializableXact()

SerializableXactHandle ShareSerializableXact ( void  )

Definition at line 5046 of file predicate.c.

5047{
5048 return MySerializableXact;
5049}

References MySerializableXact.

Referenced by InitializeParallelDSM().

◆ SummarizeOldestCommittedSxact()

static void SummarizeOldestCommittedSxact ( void  )
static

Definition at line 1502 of file predicate.c.

1503{
1505
1507
1508 /*
1509 * This function is only called if there are no sxact slots available.
1510 * Some of them must belong to old, already-finished transactions, so
1511 * there should be something in FinishedSerializableTransactions list that
1512 * we can summarize. However, there's a race condition: while we were not
1513 * holding any locks, a transaction might have ended and cleaned up all
1514 * the finished sxact entries already, freeing up their sxact slots. In
1515 * that case, we have nothing to do here. The caller will find one of the
1516 * slots released by the other backend when it retries.
1517 */
1519 {
1521 return;
1522 }
1523
1524 /*
1525 * Grab the first sxact off the finished list -- this will be the earliest
1526 * commit. Remove it from the list.
1527 */
1530 dlist_delete_thoroughly(&sxact->finishedLink);
1531
1532 /* Add to SLRU summary information. */
1535 ? sxact->SeqNo.earliestOutConflictCommit : InvalidSerCommitSeqNo);
1536
1537 /* Summarize and release the detail. */
1538 ReleaseOneSerializableXact(sxact, false, true);
1539
1541}

References dlist_delete_thoroughly(), dlist_head_element, dlist_is_empty(), fb(), FinishedSerializableTransactions, InvalidSerCommitSeqNo, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), ReleaseOneSerializableXact(), SerialAdd(), SxactHasConflictOut, SxactIsReadOnly, and TransactionIdIsValid.

Referenced by GetSerializableTransactionSnapshotInt().

◆ TransferPredicateLocksToHeapRelation()

void TransferPredicateLocksToHeapRelation ( Relation  relation)

◆ TransferPredicateLocksToNewTarget()

static bool TransferPredicateLocksToNewTarget ( PREDICATELOCKTARGETTAG  oldtargettag,
PREDICATELOCKTARGETTAG  newtargettag,
bool  removeOld 
)
static

Definition at line 2729 of file predicate.c.

2732{
2738 bool found;
2739 bool outOfShmem = false;
2740
2742 LW_EXCLUSIVE));
2743
2748
2749 if (removeOld)
2750 {
2751 /*
2752 * Remove the dummy entry to give us scratch space, so we know we'll
2753 * be able to create the new lock target.
2754 */
2755 RemoveScratchTarget(false);
2756 }
2757
2758 /*
2759 * We must get the partition locks in ascending sequence to avoid
2760 * deadlocks. If old and new partitions are the same, we must request the
2761 * lock only once.
2762 */
2764 {
2768 }
2770 {
2774 }
2775 else
2777
2778 /*
2779 * Look for the old target. If not found, that's OK; no predicate locks
2780 * are affected, so we can just clean up and return. If it does exist,
2781 * walk its list of predicate locks and move or copy them to the new
2782 * target.
2783 */
2785 &oldtargettag,
2787 HASH_FIND, NULL);
2788
2789 if (oldtarget)
2790 {
2793 dlist_mutable_iter iter;
2794
2796 &newtargettag,
2798 HASH_ENTER_NULL, &found);
2799
2800 if (!newtarget)
2801 {
2802 /* Failed to allocate due to insufficient shmem */
2803 outOfShmem = true;
2804 goto exit;
2805 }
2806
2807 /* If we created a new entry, initialize it */
2808 if (!found)
2809 dlist_init(&newtarget->predicateLocks);
2810
2811 newpredlocktag.myTarget = newtarget;
2812
2813 /*
2814 * Loop through all the locks on the old target, replacing them with
2815 * locks on the new target.
2816 */
2818
2819 dlist_foreach_modify(iter, &oldtarget->predicateLocks)
2820 {
2822 dlist_container(PREDICATELOCK, targetLink, iter.cur);
2825
2826 newpredlocktag.myXact = oldpredlock->tag.myXact;
2827
2828 if (removeOld)
2829 {
2830 dlist_delete(&(oldpredlock->xactLink));
2831 dlist_delete(&(oldpredlock->targetLink));
2832
2835 &oldpredlock->tag,
2838 HASH_REMOVE, &found);
2839 Assert(found);
2840 }
2841
2848 &found);
2849 if (!newpredlock)
2850 {
2851 /* Out of shared memory. Undo what we've done so far. */
2854 outOfShmem = true;
2855 goto exit;
2856 }
2857 if (!found)
2858 {
2859 dlist_push_tail(&(newtarget->predicateLocks),
2860 &(newpredlock->targetLink));
2861 dlist_push_tail(&(newpredlocktag.myXact->predicateLocks),
2862 &(newpredlock->xactLink));
2863 newpredlock->commitSeqNo = oldCommitSeqNo;
2864 }
2865 else
2866 {
2867 if (newpredlock->commitSeqNo < oldCommitSeqNo)
2868 newpredlock->commitSeqNo = oldCommitSeqNo;
2869 }
2870
2871 Assert(newpredlock->commitSeqNo != 0);
2872 Assert((newpredlock->commitSeqNo == InvalidSerCommitSeqNo)
2873 || (newpredlock->tag.myXact == OldCommittedSxact));
2874 }
2876
2877 if (removeOld)
2878 {
2879 Assert(dlist_is_empty(&oldtarget->predicateLocks));
2881 }
2882 }
2883
2884
2885exit:
2886 /* Release partition locks in reverse order of acquisition. */
2888 {
2891 }
2893 {
2896 }
2897 else
2899
2900 if (removeOld)
2901 {
2902 /* We shouldn't run out of memory if we're moving locks */
2904
2905 /* Put the scratch entry back */
2906 RestoreScratchTarget(false);
2907 }
2908
2909 return !outOfShmem;
2910}

References Assert, PREDICATELOCK::commitSeqNo, dlist_mutable_iter::cur, DeleteLockTarget(), dlist_container, dlist_delete(), dlist_foreach_modify, dlist_init(), dlist_is_empty(), dlist_push_tail(), fb(), HASH_ENTER_NULL, HASH_FIND, HASH_REMOVE, hash_search_with_hash_value(), InvalidSerCommitSeqNo, LW_EXCLUSIVE, LW_SHARED, LWLockAcquire(), LWLockHeldByMeInMode(), LWLockRelease(), OldCommittedSxact, PredicateLockHash, PredicateLockHashCodeFromTargetHashCode, PredicateLockHashPartitionLock, PredicateLockTargetHash, PredicateLockTargetTagHashCode, RemoveScratchTarget(), RemoveTargetIfNoLongerUsed(), and RestoreScratchTarget().

Referenced by PredicateLockPageSplit().

◆ XidIsConcurrent()

static bool XidIsConcurrent ( TransactionId  xid)
static

Definition at line 3971 of file predicate.c.

3972{
3973 Snapshot snap;
3974
3977
3979
3980 if (TransactionIdPrecedes(xid, snap->xmin))
3981 return false;
3982
3983 if (TransactionIdFollowsOrEquals(xid, snap->xmax))
3984 return true;
3985
3986 return pg_lfind32(xid, snap->xip, snap->xcnt);
3987}

References Assert, fb(), GetTopTransactionIdIfAny(), GetTransactionSnapshot(), pg_lfind32(), TransactionIdEquals, TransactionIdFollowsOrEquals(), TransactionIdIsValid, and TransactionIdPrecedes().

Referenced by CheckForSerializableConflictOut().

Variable Documentation

◆ FinishedSerializableTransactions

dlist_head* FinishedSerializableTransactions
static

◆ LocalPredicateLockHash

◆ max_predicate_locks_per_page

int max_predicate_locks_per_page

Definition at line 374 of file predicate.c.

Referenced by MaxPredicateChildLocks().

◆ max_predicate_locks_per_relation

int max_predicate_locks_per_relation

Definition at line 373 of file predicate.c.

Referenced by MaxPredicateChildLocks().

◆ max_predicate_locks_per_xact

int max_predicate_locks_per_xact

Definition at line 372 of file predicate.c.

Referenced by CreateLocalPredicateLockHash(), and MaxPredicateChildLocks().

◆ MySerializableXact

◆ MyXactDidWrite

◆ OldCommittedSxact

◆ PredicateLockHash

◆ PredicateLockTargetHash

◆ PredXact

◆ RWConflictPool

RWConflictPoolHeader RWConflictPool
static

◆ SavedSerializableXact

SERIALIZABLEXACT* SavedSerializableXact = InvalidSerializableXact
static

Definition at line 432 of file predicate.c.

Referenced by ReleasePredicateLocks().

◆ ScratchPartitionLock

LWLock* ScratchPartitionLock
static

Definition at line 409 of file predicate.c.

Referenced by PredicateLockShmemInit(), RemoveScratchTarget(), and RestoreScratchTarget().

◆ ScratchTargetTag

const PREDICATELOCKTARGETTAG ScratchTargetTag = {0, 0, 0, 0}
static

Definition at line 407 of file predicate.c.

407{0, 0, 0, 0};

Referenced by PredicateLockShmemInit(), RemoveScratchTarget(), and RestoreScratchTarget().

◆ ScratchTargetTagHash

uint32 ScratchTargetTagHash
static

Definition at line 408 of file predicate.c.

Referenced by PredicateLockShmemInit(), RemoveScratchTarget(), and RestoreScratchTarget().

◆ serialControl

◆ SerializableXidHash

◆ SerialSlruCtlData

SlruCtlData SerialSlruCtlData
static

Definition at line 325 of file predicate.c.