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 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 264 of file predicate.c.

336 : (page) + 1)
337
338#define SerialValue(slotno, xid) (*((SerCommitSeqNo *) \
339 (SerialSlruCtl->shared->page_buffer[slotno] + \
340 ((((uint32) (xid)) % SERIAL_ENTRIESPERPAGE) * SERIAL_ENTRYSIZE))))
341
342#define SerialPage(xid) (((uint32) (xid)) / SERIAL_ENTRIESPERPAGE)
343
344typedef struct SerialControlData
345{
346 int64 headPage; /* newest initialized page */
347 TransactionId headXid; /* newest valid Xid in the SLRU */
348 TransactionId tailXid; /* oldest xmin we might be interested in */
350
351typedef struct SerialControlData *SerialControl;
352
354
355/*
356 * When the oldest committed transaction on the "finished" list is moved to
357 * SLRU, its predicate locks will be moved to this "dummy" transaction,
358 * collapsing duplicate targets. When a duplicate is found, the later
359 * commitSeqNo is used.
360 */
362
363
364/*
365 * These configuration variables are used to set the predicate lock table size
366 * and to control promotion of predicate locks to coarser granularity in an
367 * attempt to degrade performance (mostly as false positive serialization
368 * failure) gracefully in the face of memory pressure.
369 */
370int max_predicate_locks_per_xact; /* in guc_tables.c */
371int max_predicate_locks_per_relation; /* in guc_tables.c */
372int max_predicate_locks_per_page; /* in guc_tables.c */
373
374/*
375 * This provides a list of objects in order to track transactions
376 * participating in predicate locking. Entries in the list are fixed size,
377 * and reside in shared memory. The memory address of an entry must remain
378 * fixed during its lifetime. The list will be protected from concurrent
379 * update externally; no provision is made in this code to manage that. The
380 * number of entries in the list, and the size allowed for each entry is
381 * fixed upon creation.
382 */
384
385/*
386 * This provides a pool of RWConflict data elements to use in conflict lists
387 * between transactions.
388 */
390
391/*
392 * The predicate locking hash tables are in shared memory.
393 * Each backend keeps pointers to them.
394 */
397static HTAB *PredicateLockHash;
399
400/*
401 * Tag for a dummy entry in PredicateLockTargetHash. By temporarily removing
402 * this entry, you can ensure that there's enough scratch space available for
403 * inserting one entry in the hash table. This is an otherwise-invalid tag.
404 */
405static const PREDICATELOCKTARGETTAG ScratchTargetTag = {0, 0, 0, 0};
408
409/*
410 * The local hash table used to determine when to combine multiple fine-
411 * grained locks into a single courser-grained lock.
412 */
414
415/*
416 * Keep a pointer to the currently-running serializable transaction (if any)
417 * for quick reference. Also, remember if we have written anything that could
418 * cause a rw-conflict.
419 */
421static bool MyXactDidWrite = false;
422
423/*
424 * The SXACT_FLAG_RO_UNSAFE optimization might lead us to release
425 * MySerializableXact early. If that happens in a parallel query, the leader
426 * needs to defer the destruction of the SERIALIZABLEXACT until end of
427 * transaction, because the workers still have a reference to it. In that
428 * case, the leader stores it here.
429 */
431
432/* local functions */
433
434static SERIALIZABLEXACT *CreatePredXact(void);
436
437static bool RWConflictExists(const SERIALIZABLEXACT *reader, const SERIALIZABLEXACT *writer);
442
444static void SerialInit(void);
448
449static uint32 predicatelock_hash(const void *key, Size keysize);
450static void SummarizeOldestCommittedSxact(void);
454 int sourcepid);
457 PREDICATELOCKTARGETTAG *parent);
459static void RemoveScratchTarget(bool lockheld);
460static void RestoreScratchTarget(bool lockheld);
473 bool removeOld);
475static void DropAllPredicateLocksFromTable(Relation relation,
476 bool transfer);
477static void SetNewSxactGlobalXmin(void);
478static void ClearOldPredicateLocks(void);
479static void ReleaseOneSerializableXact(SERIALIZABLEXACT *sxact, bool partial,
480 bool summarize);
481static bool XidIsConcurrent(TransactionId xid);
486static void CreateLocalPredicateLockHash(void);
487static void ReleasePredicateLocksLocal(void);
488
489
490/*------------------------------------------------------------------------*/
491
492/*
493 * Does this relation participate in predicate locking? Temporary and system
494 * relations are exempt.
495 */
496static inline bool
498{
499 return !(relation->rd_id < FirstUnpinnedObjectId ||
500 RelationUsesLocalBuffers(relation));
501}
502
503/*
504 * When a public interface method is called for a read, this is the test to
505 * see if we should do a quick return.
506 *
507 * Note: this function has side-effects! If this transaction has been flagged
508 * as RO-safe since the last call, we release all predicate locks and reset
509 * MySerializableXact. That makes subsequent calls to return quickly.
510 *
511 * This is marked as 'inline' to eliminate the function call overhead in the
512 * common case that serialization is not needed.
513 */
514static inline bool
516{
517 /* Nothing to do if this is not a serializable transaction */
519 return false;
520
521 /*
522 * Don't acquire locks or conflict when scanning with a special snapshot.
523 * This excludes things like CLUSTER and REINDEX. They use the wholesale
524 * functions TransferPredicateLocksToHeapRelation() and
525 * CheckTableForSerializableConflictIn() to participate in serialization,
526 * but the scans involved don't need serialization.
527 */
528 if (!IsMVCCSnapshot(snapshot))
529 return false;
530
531 /*
532 * Check if we have just become "RO-safe". If we have, immediately release
533 * all locks as they're not needed anymore. This also resets
534 * MySerializableXact, so that subsequent calls to this function can exit
535 * quickly.
536 *
537 * A transaction is flagged as RO_SAFE if all concurrent R/W transactions
538 * commit without having conflicts out to an earlier snapshot, thus
539 * ensuring that no conflicts are possible for this transaction.
540 */
542 {
543 ReleasePredicateLocks(false, true);
544 return false;
545 }
546
547 /* Check if the relation doesn't participate in predicate locking */
549 return false;
550
551 return true; /* no excuse to skip predicate locking */
552}
553
554/*
555 * Like SerializationNeededForRead(), but called on writes.
556 * The logic is the same, but there is no snapshot and we can't be RO-safe.
557 */
558static inline bool
560{
561 /* Nothing to do if this is not a serializable transaction */
563 return false;
564
565 /* Check if the relation doesn't participate in predicate locking */
567 return false;
568
569 return true; /* no excuse to skip predicate locking */
570}
571
572
573/*------------------------------------------------------------------------*/
574
575/*
576 * These functions are a simple implementation of a list for this specific
577 * type of struct. If there is ever a generalized shared memory list, we
578 * should probably switch to that.
579 */
580static SERIALIZABLEXACT *
581CreatePredXact(void)
582{
584
586 return NULL;
587
591 return sxact;
592}
593
594static void
596{
598
599 dlist_delete(&sxact->xactLink);
601}
602
603/*------------------------------------------------------------------------*/
604
605/*
606 * These functions manage primitive access to the RWConflict pool and lists.
607 */
608static bool
610{
611 dlist_iter iter;
612
613 Assert(reader != writer);
614
615 /* Check the ends of the purported conflict first. */
616 if (SxactIsDoomed(reader)
618 || dlist_is_empty(&reader->outConflicts)
619 || dlist_is_empty(&writer->inConflicts))
620 return false;
621
622 /*
623 * A conflict is possible; walk the list to find out.
624 *
625 * The unconstify is needed as we have no const version of
626 * dlist_foreach().
627 */
628 dlist_foreach(iter, &unconstify(SERIALIZABLEXACT *, reader)->outConflicts)
629 {
631 dlist_container(RWConflictData, outLink, iter.cur);
632
633 if (conflict->sxactIn == writer)
634 return true;
635 }
636
637 /* No conflict found. */
638 return false;
639}
640
641static void
643{
645
646 Assert(reader != writer);
647 Assert(!RWConflictExists(reader, writer));
648
652 errmsg("not enough elements in RWConflictPool to record a read/write conflict"),
653 errhint("You might need to run fewer transactions at a time or increase \"max_connections\".")));
654
656 dlist_delete(&conflict->outLink);
657
658 conflict->sxactOut = reader;
659 conflict->sxactIn = writer;
660 dlist_push_tail(&reader->outConflicts, &conflict->outLink);
661 dlist_push_tail(&writer->inConflicts, &conflict->inLink);
662}
663
664static void
667{
669
673
677 errmsg("not enough elements in RWConflictPool to record a potential read/write conflict"),
678 errhint("You might need to run fewer transactions at a time or increase \"max_connections\".")));
679
681 dlist_delete(&conflict->outLink);
682
683 conflict->sxactOut = activeXact;
684 conflict->sxactIn = roXact;
685 dlist_push_tail(&activeXact->possibleUnsafeConflicts, &conflict->outLink);
686 dlist_push_tail(&roXact->possibleUnsafeConflicts, &conflict->inLink);
687}
688
689static void
691{
692 dlist_delete(&conflict->inLink);
693 dlist_delete(&conflict->outLink);
695}
696
697static void
699{
701
704
705 sxact->flags |= SXACT_FLAG_RO_UNSAFE;
706
707 /*
708 * We know this isn't a safe snapshot, so we can stop looking for other
709 * potential conflicts.
710 */
711 dlist_foreach_modify(iter, &sxact->possibleUnsafeConflicts)
712 {
714 dlist_container(RWConflictData, inLink, iter.cur);
715
716 Assert(!SxactIsReadOnly(conflict->sxactOut));
717 Assert(sxact == conflict->sxactIn);
718
720 }
721}
722
723/*------------------------------------------------------------------------*/
724
725/*
726 * Decide whether a Serial page number is "older" for truncation purposes.
727 * Analogous to CLOGPagePrecedes().
728 */
729static bool
731{
734
739
740 return (TransactionIdPrecedes(xid1, xid2) &&
742}
743
744#ifdef USE_ASSERT_CHECKING
745static void
747{
749 offset = per_page / 2;
752 headPage,
755 oldestXact;
756
757 /* GetNewTransactionId() has assigned the last XID it can safely use. */
758 newestPage = 2 * SLRU_PAGES_PER_SEGMENT - 1; /* nothing special */
759 newestXact = newestPage * per_page + offset;
761 oldestXact = newestXact + 1;
762 oldestXact -= 1U << 31;
763 oldestPage = oldestXact / per_page;
764
765 /*
766 * In this scenario, the SLRU headPage pertains to the last ~1000 XIDs
767 * assigned. oldestXact finishes, ~2B XIDs having elapsed since it
768 * started. Further transactions cause us to summarize oldestXact to
769 * tailPage. Function must return false so SerialAdd() doesn't zero
770 * tailPage (which may contain entries for other old, recently-finished
771 * XIDs) and half the SLRU. Reaching this requires burning ~2B XIDs in
772 * single-user mode, a negligible possibility.
773 */
777
778 /*
779 * In this scenario, the SLRU headPage pertains to oldestXact. We're
780 * summarizing an XID near newestXact. (Assume few other XIDs used
781 * SERIALIZABLE, hence the minimal headPage advancement. Assume
782 * oldestXact was long-running and only recently reached the SLRU.)
783 * Function must return true to make SerialAdd() create targetPage.
784 *
785 * Today's implementation mishandles this case, but it doesn't matter
786 * enough to fix. Verify that the defect affects just one page by
787 * asserting correct treatment of its prior page. Reaching this case
788 * requires burning ~2B XIDs in single-user mode, a negligible
789 * possibility. Moreover, if it does happen, the consequence would be
790 * mild, namely a new transaction failing in SimpleLruReadPage().
791 */
795#if 0
797#endif
798}
799#endif
800
801/*
802 * Initialize for the tracking of old serializable committed xids.
803 */
804static void
805SerialInit(void)
806{
807 bool found;
808
809 /*
810 * Set up SLRU management of the pg_serial data.
811 */
813 SimpleLruInit(SerialSlruCtl, "serializable",
814 serializable_buffers, 0, "pg_serial",
816 SYNC_HANDLER_NONE, false);
817#ifdef USE_ASSERT_CHECKING
819#endif
821
822 /*
823 * Create or attach to the SerialControl structure.
824 */
826 ShmemInitStruct("SerialControlData", sizeof(SerialControlData), &found);
827
828 Assert(found == IsUnderPostmaster);
829 if (!found)
830 {
831 /*
832 * Set control information to reflect empty SLRU.
833 */
839 }
840}
841
842/*
843 * GUC check_hook for serializable_buffers
844 */
845bool
846check_serial_buffers(int *newval, void **extra, GucSource source)
847{
848 return check_slru_buffers("serializable_buffers", newval);
849}
850
851/*
852 * Record a committed read write serializable xid and the minimum
853 * commitSeqNo of any transactions to which this xid had a rw-conflict out.
854 * An invalid commitSeqNo means that there were no conflicts out from xid.
855 */
856static void
858{
861 int slotno;
863 bool isNewPage;
864 LWLock *lock;
865
867
868 targetPage = SerialPage(xid);
870
871 /*
872 * In this routine, we must hold both SerialControlLock and the SLRU bank
873 * lock simultaneously while making the SLRU data catch up with the new
874 * state that we determine.
875 */
877
878 /*
879 * If 'xid' is older than the global xmin (== tailXid), there's no need to
880 * store it, after all. This can happen if the oldest transaction holding
881 * back the global xmin just finished, making 'xid' uninteresting, but
882 * ClearOldPredicateLocks() has not yet run.
883 */
886 {
888 return;
889 }
890
891 /*
892 * If the SLRU is currently unused, zero out the whole active region from
893 * tailXid to headXid before taking it into use. Otherwise zero out only
894 * any new pages that enter the tailXid-headXid range as we advance
895 * headXid.
896 */
897 if (serialControl->headPage < 0)
898 {
900 isNewPage = true;
901 }
902 else
903 {
906 targetPage);
907 }
908
911 serialControl->headXid = xid;
912 if (isNewPage)
914
915 if (isNewPage)
916 {
917 /* Initialize intervening pages; might involve trading locks */
918 for (;;)
919 {
924 break;
926 LWLockRelease(lock);
927 }
928 }
929 else
930 {
933 }
934
936 SerialSlruCtl->shared->page_dirty[slotno] = true;
937
938 LWLockRelease(lock);
940}
941
942/*
943 * Get the minimum commitSeqNo for any conflict out for the given xid. For
944 * a transaction which exists but has no conflict out, InvalidSerCommitSeqNo
945 * will be returned.
946 */
947static SerCommitSeqNo
949{
953 int slotno;
954
956
961
963 return 0;
964
966
969 return 0;
970
971 /*
972 * The following function must be called without holding SLRU bank lock,
973 * but will return with that lock held, which must then be released.
974 */
976 SerialPage(xid), xid);
977 val = SerialValue(slotno, xid);
979 return val;
980}
981
982/*
983 * Call this whenever there is a new xmin for active serializable
984 * transactions. We don't need to keep information on transactions which
985 * precede that. InvalidTransactionId means none active, so everything in
986 * the SLRU can be discarded.
987 */
988static void
990{
992
993 /*
994 * When no sxacts are active, nothing overlaps, set the xid values to
995 * invalid to show that there are no valid entries. Don't clear headPage,
996 * though. A new xmin might still land on that page, and we don't want to
997 * repeatedly zero out the same page.
998 */
999 if (!TransactionIdIsValid(xid))
1000 {
1004 return;
1005 }
1006
1007 /*
1008 * When we're recovering prepared transactions, the global xmin might move
1009 * backwards depending on the order they're recovered. Normally that's not
1010 * OK, but during recovery no serializable transactions will commit, so
1011 * the SLRU is empty and we can get away with it.
1012 */
1013 if (RecoveryInProgress())
1014 {
1018 {
1019 serialControl->tailXid = xid;
1020 }
1022 return;
1023 }
1024
1027
1028 serialControl->tailXid = xid;
1029
1031}
1032
1033/*
1034 * Perform a checkpoint --- either during shutdown, or on-the-fly
1035 *
1036 * We don't have any data that needs to survive a restart, but this is a
1037 * convenient place to truncate the SLRU.
1038 */
1039void
1041{
1043
1045
1046 /* Exit quickly if the SLRU is currently not in use. */
1047 if (serialControl->headPage < 0)
1048 {
1050 return;
1051 }
1052
1054 {
1056
1058
1059 /*
1060 * It is possible for the tailXid to be ahead of the headXid. This
1061 * occurs if we checkpoint while there are in-progress serializable
1062 * transaction(s) advancing the tail but we are yet to summarize the
1063 * transactions. In this case, we cutoff up to the headPage and the
1064 * next summary will advance the headXid.
1065 */
1067 {
1068 /* We can truncate the SLRU up to the page containing tailXid */
1070 }
1071 else
1073 }
1074 else
1075 {
1076 /*----------
1077 * The SLRU is no longer needed. Truncate to head before we set head
1078 * invalid.
1079 *
1080 * XXX: It's possible that the SLRU is not needed again until XID
1081 * wrap-around has happened, so that the segment containing headPage
1082 * that we leave behind will appear to be new again. In that case it
1083 * won't be removed until XID horizon advances enough to make it
1084 * current again.
1085 *
1086 * XXX: This should happen in vac_truncate_clog(), not in checkpoints.
1087 * Consider this scenario, starting from a system with no in-progress
1088 * transactions and VACUUM FREEZE having maximized oldestXact:
1089 * - Start a SERIALIZABLE transaction.
1090 * - Start, finish, and summarize a SERIALIZABLE transaction, creating
1091 * one SLRU page.
1092 * - Consume XIDs to reach xidStopLimit.
1093 * - Finish all transactions. Due to the long-running SERIALIZABLE
1094 * transaction, earlier checkpoints did not touch headPage. The
1095 * next checkpoint will change it, but that checkpoint happens after
1096 * the end of the scenario.
1097 * - VACUUM to advance XID limits.
1098 * - Consume ~2M XIDs, crossing the former xidWrapLimit.
1099 * - Start, finish, and summarize a SERIALIZABLE transaction.
1100 * SerialAdd() declines to create the targetPage, because headPage
1101 * is not regarded as in the past relative to that targetPage. The
1102 * transaction instigating the summarize fails in
1103 * SimpleLruReadPage().
1104 */
1106 serialControl->headPage = -1;
1107 }
1108
1110
1111 /*
1112 * Truncate away pages that are no longer required. Note that no
1113 * additional locking is required, because this is only called as part of
1114 * a checkpoint, and the validity limits have already been determined.
1115 */
1117
1118 /*
1119 * Write dirty SLRU pages to disk
1120 *
1121 * This is not actually necessary from a correctness point of view. We do
1122 * it merely as a debugging aid.
1123 *
1124 * We're doing this after the truncation to avoid writing pages right
1125 * before deleting the file in which they sit, which would be completely
1126 * pointless.
1127 */
1129}
1130
1131/*------------------------------------------------------------------------*/
1132
1133/*
1134 * PredicateLockShmemInit -- Initialize the predicate locking data structures.
1135 *
1136 * This is called from CreateSharedMemoryAndSemaphores(), which see for
1137 * more comments. In the normal postmaster case, the shared hash tables
1138 * are created here. Backends inherit the pointers
1139 * to the shared tables via fork(). In the EXEC_BACKEND case, each
1140 * backend re-executes this code to obtain pointers to the already existing
1141 * shared hash tables.
1142 */
1143void
1145{
1146 HASHCTL info;
1149 bool found;
1150
1151#ifndef EXEC_BACKEND
1153#endif
1154
1155 /*
1156 * Compute size of predicate lock target hashtable. Note these
1157 * calculations must agree with PredicateLockShmemSize!
1158 */
1160
1161 /*
1162 * Allocate hash table for PREDICATELOCKTARGET structs. This stores
1163 * per-predicate-lock-target information.
1164 */
1165 info.keysize = sizeof(PREDICATELOCKTARGETTAG);
1166 info.entrysize = sizeof(PREDICATELOCKTARGET);
1168
1169 PredicateLockTargetHash = ShmemInitHash("PREDICATELOCKTARGET hash",
1172 &info,
1175
1176 /*
1177 * Reserve a dummy entry in the hash table; we use it to make sure there's
1178 * always one entry available when we need to split or combine a page,
1179 * because running out of space there could mean aborting a
1180 * non-serializable transaction.
1181 */
1182 if (!IsUnderPostmaster)
1183 {
1185 HASH_ENTER, &found);
1186 Assert(!found);
1187 }
1188
1189 /* Pre-calculate the hash and partition lock of the scratch entry */
1192
1193 /*
1194 * Allocate hash table for PREDICATELOCK structs. This stores per
1195 * xact-lock-of-a-target information.
1196 */
1197 info.keysize = sizeof(PREDICATELOCKTAG);
1198 info.entrysize = sizeof(PREDICATELOCK);
1199 info.hash = predicatelock_hash;
1201
1202 /* Assume an average of 2 xacts per target */
1203 max_table_size *= 2;
1204
1205 PredicateLockHash = ShmemInitHash("PREDICATELOCK hash",
1208 &info,
1211
1212 /*
1213 * Compute size for serializable transaction hashtable. Note these
1214 * calculations must agree with PredicateLockShmemSize!
1215 */
1217
1218 /*
1219 * Allocate a list to hold information on transactions participating in
1220 * predicate locking.
1221 *
1222 * Assume an average of 10 predicate locking transactions per backend.
1223 * This allows aggressive cleanup while detail is present before data must
1224 * be summarized for storage in SLRU and the "dummy" transaction.
1225 */
1226 max_table_size *= 10;
1227
1230 sizeof(SERIALIZABLEXACT))));
1231
1232 PredXact = ShmemInitStruct("PredXactList",
1234 &found);
1235 Assert(found == IsUnderPostmaster);
1236 if (!found)
1237 {
1238 int i;
1239
1240 /* clean everything, both the header and the element */
1242
1253 /* Add all elements to available list, clean. */
1254 for (i = 0; i < max_table_size; i++)
1255 {
1259 }
1276 }
1277 /* This never changes, so let's keep a local copy. */
1279
1280 /*
1281 * Allocate hash table for SERIALIZABLEXID structs. This stores per-xid
1282 * information for serializable transactions which have accessed data.
1283 */
1284 info.keysize = sizeof(SERIALIZABLEXIDTAG);
1285 info.entrysize = sizeof(SERIALIZABLEXID);
1286
1287 SerializableXidHash = ShmemInitHash("SERIALIZABLEXID hash",
1290 &info,
1293
1294 /*
1295 * Allocate space for tracking rw-conflicts in lists attached to the
1296 * transactions.
1297 *
1298 * Assume an average of 5 conflicts per transaction. Calculations suggest
1299 * that this will prevent resource exhaustion in even the most pessimal
1300 * loads up to max_connections = 200 with all 200 connections pounding the
1301 * database with serializable transactions. Beyond that, there may be
1302 * occasional transactions canceled when trying to flag conflicts. That's
1303 * probably OK.
1304 */
1305 max_table_size *= 5;
1306
1310
1311 RWConflictPool = ShmemInitStruct("RWConflictPool",
1313 &found);
1314 Assert(found == IsUnderPostmaster);
1315 if (!found)
1316 {
1317 int i;
1318
1319 /* clean everything, including the elements */
1321
1325 /* Add all elements to available list, clean. */
1326 for (i = 0; i < max_table_size; i++)
1327 {
1330 }
1331 }
1332
1333 /*
1334 * Create or attach to the header for the list of finished serializable
1335 * transactions.
1336 */
1338 ShmemInitStruct("FinishedSerializableTransactions",
1339 sizeof(dlist_head),
1340 &found);
1341 Assert(found == IsUnderPostmaster);
1342 if (!found)
1344
1345 /*
1346 * Initialize the SLRU storage for old committed serializable
1347 * transactions.
1348 */
1349 SerialInit();
1350}
1351
1352/*
1353 * Estimate shared-memory space used for predicate lock table
1354 */
1355Size
1357{
1358 Size size = 0;
1359 long max_table_size;
1360
1361 /* predicate lock target hash table */
1364 sizeof(PREDICATELOCKTARGET)));
1365
1366 /* predicate lock hash table */
1367 max_table_size *= 2;
1369 sizeof(PREDICATELOCK)));
1370
1371 /*
1372 * Since NPREDICATELOCKTARGETENTS is only an estimate, add 10% safety
1373 * margin.
1374 */
1375 size = add_size(size, size / 10);
1376
1377 /* transaction list */
1379 max_table_size *= 10;
1380 size = add_size(size, PredXactListDataSize);
1381 size = add_size(size, mul_size((Size) max_table_size,
1382 sizeof(SERIALIZABLEXACT)));
1383
1384 /* transaction xid table */
1386 sizeof(SERIALIZABLEXID)));
1387
1388 /* rw-conflict pool */
1389 max_table_size *= 5;
1391 size = add_size(size, mul_size((Size) max_table_size,
1393
1394 /* Head for list of finished serializable transactions. */
1395 size = add_size(size, sizeof(dlist_head));
1396
1397 /* Shared memory structures for SLRU tracking of old committed xids. */
1398 size = add_size(size, sizeof(SerialControlData));
1400
1401 return size;
1402}
1403
1404
1405/*
1406 * Compute the hash code associated with a PREDICATELOCKTAG.
1407 *
1408 * Because we want to use just one set of partition locks for both the
1409 * PREDICATELOCKTARGET and PREDICATELOCK hash tables, we have to make sure
1410 * that PREDICATELOCKs fall into the same partition number as their
1411 * associated PREDICATELOCKTARGETs. dynahash.c expects the partition number
1412 * to be the low-order bits of the hash code, and therefore a
1413 * PREDICATELOCKTAG's hash code must have the same low-order bits as the
1414 * associated PREDICATELOCKTARGETTAG's hash code. We achieve this with this
1415 * specialized hash function.
1416 */
1417static uint32
1418predicatelock_hash(const void *key, Size keysize)
1419{
1420 const PREDICATELOCKTAG *predicatelocktag = (const PREDICATELOCKTAG *) key;
1422
1423 Assert(keysize == sizeof(PREDICATELOCKTAG));
1424
1425 /* Look into the associated target object, and compute its hash code */
1427
1429}
1430
1431
1432/*
1433 * GetPredicateLockStatusData
1434 * Return a table containing the internal state of the predicate
1435 * lock manager for use in pg_lock_status.
1436 *
1437 * Like GetLockStatusData, this function tries to hold the partition LWLocks
1438 * for as short a time as possible by returning two arrays that simply
1439 * contain the PREDICATELOCKTARGETTAG and SERIALIZABLEXACT for each lock
1440 * table entry. Multiple copies of the same PREDICATELOCKTARGETTAG and
1441 * SERIALIZABLEXACT will likely appear.
1442 */
1445{
1447 int i;
1448 int els,
1449 el;
1452
1454
1455 /*
1456 * To ensure consistency, take simultaneous locks on all partition locks
1457 * in ascending order, then SerializableXactHashLock.
1458 */
1459 for (i = 0; i < NUM_PREDICATELOCK_PARTITIONS; i++)
1462
1463 /* Get number of locks and allocate appropriately-sized arrays. */
1465 data->nelements = els;
1468
1469
1470 /* Scan through PredicateLockHash and copy contents */
1472
1473 el = 0;
1474
1476 {
1477 data->locktags[el] = predlock->tag.myTarget->tag;
1478 data->xacts[el] = *predlock->tag.myXact;
1479 el++;
1480 }
1481
1482 Assert(el == els);
1483
1484 /* Release locks in reverse order */
1486 for (i = NUM_PREDICATELOCK_PARTITIONS - 1; i >= 0; i--)
1488
1489 return data;
1490}
1491
1492/*
1493 * Free up shared memory structures by pushing the oldest sxact (the one at
1494 * the front of the SummarizeOldestCommittedSxact queue) into summary form.
1495 * Each call will free exactly one SERIALIZABLEXACT structure and may also
1496 * free one or more of these structures: SERIALIZABLEXID, PREDICATELOCK,
1497 * PREDICATELOCKTARGET, RWConflictData.
1498 */
1499static void
1501{
1503
1505
1506 /*
1507 * This function is only called if there are no sxact slots available.
1508 * Some of them must belong to old, already-finished transactions, so
1509 * there should be something in FinishedSerializableTransactions list that
1510 * we can summarize. However, there's a race condition: while we were not
1511 * holding any locks, a transaction might have ended and cleaned up all
1512 * the finished sxact entries already, freeing up their sxact slots. In
1513 * that case, we have nothing to do here. The caller will find one of the
1514 * slots released by the other backend when it retries.
1515 */
1517 {
1519 return;
1520 }
1521
1522 /*
1523 * Grab the first sxact off the finished list -- this will be the earliest
1524 * commit. Remove it from the list.
1525 */
1528 dlist_delete_thoroughly(&sxact->finishedLink);
1529
1530 /* Add to SLRU summary information. */
1533 ? sxact->SeqNo.earliestOutConflictCommit : InvalidSerCommitSeqNo);
1534
1535 /* Summarize and release the detail. */
1536 ReleaseOneSerializableXact(sxact, false, true);
1537
1539}
1540
1541/*
1542 * GetSafeSnapshot
1543 * Obtain and register a snapshot for a READ ONLY DEFERRABLE
1544 * transaction. Ensures that the snapshot is "safe", i.e. a
1545 * read-only transaction running on it can execute serializably
1546 * without further checks. This requires waiting for concurrent
1547 * transactions to complete, and retrying with a new snapshot if
1548 * one of them could possibly create a conflict.
1549 *
1550 * As with GetSerializableTransactionSnapshot (which this is a subroutine
1551 * for), the passed-in Snapshot pointer should reference a static data
1552 * area that can safely be passed to GetSnapshotData.
1553 */
1554static Snapshot
1556{
1557 Snapshot snapshot;
1558
1560
1561 while (true)
1562 {
1563 /*
1564 * GetSerializableTransactionSnapshotInt is going to call
1565 * GetSnapshotData, so we need to provide it the static snapshot area
1566 * our caller passed to us. The pointer returned is actually the same
1567 * one passed to it, but we avoid assuming that here.
1568 */
1570 NULL, InvalidPid);
1571
1573 return snapshot; /* no concurrent r/w xacts; it's safe */
1574
1576
1577 /*
1578 * Wait for concurrent transactions to finish. Stop early if one of
1579 * them marked us as conflicted.
1580 */
1584 {
1588 }
1590
1592 {
1594 break; /* success */
1595 }
1596
1598
1599 /* else, need to retry... */
1602 errmsg_internal("deferrable snapshot was unsafe; trying a new one")));
1603 ReleasePredicateLocks(false, false);
1604 }
1605
1606 /*
1607 * Now we have a safe snapshot, so we don't need to do any further checks.
1608 */
1610 ReleasePredicateLocks(false, true);
1611
1612 return snapshot;
1613}
1614
1615/*
1616 * GetSafeSnapshotBlockingPids
1617 * If the specified process is currently blocked in GetSafeSnapshot,
1618 * write the process IDs of all processes that it is blocked by
1619 * into the caller-supplied buffer output[]. The list is truncated at
1620 * output_size, and the number of PIDs written into the buffer is
1621 * returned. Returns zero if the given PID is not currently blocked
1622 * in GetSafeSnapshot.
1623 */
1624int
1626{
1627 int num_written = 0;
1628 dlist_iter iter;
1630
1632
1633 /* Find blocked_pid's SERIALIZABLEXACT by linear search. */
1635 {
1637 dlist_container(SERIALIZABLEXACT, xactLink, iter.cur);
1638
1639 if (sxact->pid == blocked_pid)
1640 {
1642 break;
1643 }
1644 }
1645
1646 /* Did we find it, and is it currently waiting in GetSafeSnapshot? */
1648 {
1649 /* Traverse the list of possible unsafe conflicts collecting PIDs. */
1650 dlist_foreach(iter, &blocking_sxact->possibleUnsafeConflicts)
1651 {
1653 dlist_container(RWConflictData, inLink, iter.cur);
1654
1655 output[num_written++] = possibleUnsafeConflict->sxactOut->pid;
1656
1657 if (num_written >= output_size)
1658 break;
1659 }
1660 }
1661
1663
1664 return num_written;
1665}
1666
1667/*
1668 * Acquire a snapshot that can be used for the current transaction.
1669 *
1670 * Make sure we have a SERIALIZABLEXACT reference in MySerializableXact.
1671 * It should be current for this process and be contained in PredXact.
1672 *
1673 * The passed-in Snapshot pointer should reference a static data area that
1674 * can safely be passed to GetSnapshotData. The return value is actually
1675 * always this same pointer; no new snapshot data structure is allocated
1676 * within this function.
1677 */
1680{
1682
1683 /*
1684 * Can't use serializable mode while recovery is still active, as it is,
1685 * for example, on a hot standby. We could get here despite the check in
1686 * check_transaction_isolation() if default_transaction_isolation is set
1687 * to serializable, so phrase the hint accordingly.
1688 */
1689 if (RecoveryInProgress())
1690 ereport(ERROR,
1692 errmsg("cannot use serializable mode in a hot standby"),
1693 errdetail("\"default_transaction_isolation\" is set to \"serializable\"."),
1694 errhint("You can use \"SET default_transaction_isolation = 'repeatable read'\" to change the default.")));
1695
1696 /*
1697 * A special optimization is available for SERIALIZABLE READ ONLY
1698 * DEFERRABLE transactions -- we can wait for a suitable snapshot and
1699 * thereby avoid all SSI overhead once it's running.
1700 */
1702 return GetSafeSnapshot(snapshot);
1703
1705 NULL, InvalidPid);
1706}
1707
1708/*
1709 * Import a snapshot to be used for the current transaction.
1710 *
1711 * This is nearly the same as GetSerializableTransactionSnapshot, except that
1712 * we don't take a new snapshot, but rather use the data we're handed.
1713 *
1714 * The caller must have verified that the snapshot came from a serializable
1715 * transaction; and if we're read-write, the source transaction must not be
1716 * read-only.
1717 */
1718void
1721 int sourcepid)
1722{
1724
1725 /*
1726 * If this is called by parallel.c in a parallel worker, we don't want to
1727 * create a SERIALIZABLEXACT just yet because the leader's
1728 * SERIALIZABLEXACT will be installed with AttachSerializableXact(). We
1729 * also don't want to reject SERIALIZABLE READ ONLY DEFERRABLE in this
1730 * case, because the leader has already determined that the snapshot it
1731 * has passed us is safe. So there is nothing for us to do.
1732 */
1733 if (IsParallelWorker())
1734 return;
1735
1736 /*
1737 * We do not allow SERIALIZABLE READ ONLY DEFERRABLE transactions to
1738 * import snapshots, since there's no way to wait for a safe snapshot when
1739 * we're using the snap we're told to. (XXX instead of throwing an error,
1740 * we could just ignore the XactDeferrable flag?)
1741 */
1743 ereport(ERROR,
1745 errmsg("a snapshot-importing transaction must not be READ ONLY DEFERRABLE")));
1746
1748 sourcepid);
1749}
1750
1751/*
1752 * Guts of GetSerializableTransactionSnapshot
1753 *
1754 * If sourcevxid is valid, this is actually an import operation and we should
1755 * skip calling GetSnapshotData, because the snapshot contents are already
1756 * loaded up. HOWEVER: to avoid race conditions, we must check that the
1757 * source xact is still running after we acquire SerializableXactHashLock.
1758 * We do that by calling ProcArrayInstallImportedXmin.
1759 */
1760static Snapshot
1763 int sourcepid)
1764{
1765 PGPROC *proc;
1768 *othersxact;
1769
1770 /* We only do this for serializable transactions. Once. */
1772
1774
1775 /*
1776 * Since all parts of a serializable transaction must use the same
1777 * snapshot, it is too late to establish one after a parallel operation
1778 * has begun.
1779 */
1780 if (IsInParallelMode())
1781 elog(ERROR, "cannot establish serializable snapshot during a parallel operation");
1782
1783 proc = MyProc;
1784 Assert(proc != NULL);
1785 GET_VXID_FROM_PGPROC(vxid, *proc);
1786
1787 /*
1788 * First we get the sxact structure, which may involve looping and access
1789 * to the "finished" list to free a structure for use.
1790 *
1791 * We must hold SerializableXactHashLock when taking/checking the snapshot
1792 * to avoid race conditions, for much the same reasons that
1793 * GetSnapshotData takes the ProcArrayLock. Since we might have to
1794 * release SerializableXactHashLock to call SummarizeOldestCommittedSxact,
1795 * this means we have to create the sxact first, which is a bit annoying
1796 * (in particular, an elog(ERROR) in procarray.c would cause us to leak
1797 * the sxact). Consider refactoring to avoid this.
1798 */
1799#ifdef TEST_SUMMARIZE_SERIAL
1801#endif
1803 do
1804 {
1806 /* If null, push out committed sxact to SLRU summary & retry. */
1807 if (!sxact)
1808 {
1812 }
1813 } while (!sxact);
1814
1815 /* Get the snapshot, or check that it's safe to use */
1816 if (!sourcevxid)
1817 snapshot = GetSnapshotData(snapshot);
1818 else if (!ProcArrayInstallImportedXmin(snapshot->xmin, sourcevxid))
1819 {
1822 ereport(ERROR,
1824 errmsg("could not import the requested snapshot"),
1825 errdetail("The source process with PID %d is not running anymore.",
1826 sourcepid)));
1827 }
1828
1829 /*
1830 * If there are no serializable transactions which are not read-only, we
1831 * can "opt out" of predicate locking and conflict checking for a
1832 * read-only transaction.
1833 *
1834 * The reason this is safe is that a read-only transaction can only become
1835 * part of a dangerous structure if it overlaps a writable transaction
1836 * which in turn overlaps a writable transaction which committed before
1837 * the read-only transaction started. A new writable transaction can
1838 * overlap this one, but it can't meet the other condition of overlapping
1839 * a transaction which committed before this one started.
1840 */
1842 {
1845 return snapshot;
1846 }
1847
1848 /* Initialize the structure. */
1849 sxact->vxid = vxid;
1850 sxact->SeqNo.lastCommitBeforeSnapshot = PredXact->LastSxactCommitSeqNo;
1851 sxact->prepareSeqNo = InvalidSerCommitSeqNo;
1852 sxact->commitSeqNo = InvalidSerCommitSeqNo;
1853 dlist_init(&(sxact->outConflicts));
1854 dlist_init(&(sxact->inConflicts));
1855 dlist_init(&(sxact->possibleUnsafeConflicts));
1856 sxact->topXid = GetTopTransactionIdIfAny();
1857 sxact->finishedBefore = InvalidTransactionId;
1858 sxact->xmin = snapshot->xmin;
1859 sxact->pid = MyProcPid;
1860 sxact->pgprocno = MyProcNumber;
1861 dlist_init(&sxact->predicateLocks);
1862 dlist_node_init(&sxact->finishedLink);
1863 sxact->flags = 0;
1864 if (XactReadOnly)
1865 {
1866 dlist_iter iter;
1867
1868 sxact->flags |= SXACT_FLAG_READ_ONLY;
1869
1870 /*
1871 * Register all concurrent r/w transactions as possible conflicts; if
1872 * all of them commit without any outgoing conflicts to earlier
1873 * transactions then this snapshot can be deemed safe (and we can run
1874 * without tracking predicate locks).
1875 */
1877 {
1879
1883 {
1885 }
1886 }
1887
1888 /*
1889 * If we didn't find any possibly unsafe conflicts because every
1890 * uncommitted writable transaction turned out to be doomed, then we
1891 * can "opt out" immediately. See comments above the earlier check
1892 * for PredXact->WritableSxactCount == 0.
1893 */
1894 if (dlist_is_empty(&sxact->possibleUnsafeConflicts))
1895 {
1898 return snapshot;
1899 }
1900 }
1901 else
1902 {
1906 }
1907
1908 /* Maintain serializable global xmin info. */
1910 {
1912 PredXact->SxactGlobalXmin = snapshot->xmin;
1914 SerialSetActiveSerXmin(snapshot->xmin);
1915 }
1916 else if (TransactionIdEquals(snapshot->xmin, PredXact->SxactGlobalXmin))
1917 {
1920 }
1921 else
1922 {
1924 }
1925
1927 MyXactDidWrite = false; /* haven't written anything yet */
1928
1930
1932
1933 return snapshot;
1934}
1935
1936static void
1938{
1940
1941 /* Initialize the backend-local hash table of parent locks */
1943 hash_ctl.keysize = sizeof(PREDICATELOCKTARGETTAG);
1944 hash_ctl.entrysize = sizeof(LOCALPREDICATELOCK);
1945 LocalPredicateLockHash = hash_create("Local predicate lock",
1947 &hash_ctl,
1949}
1950
1951/*
1952 * Register the top level XID in SerializableXidHash.
1953 * Also store it for easy reference in MySerializableXact.
1954 */
1955void
1957{
1960 bool found;
1961
1962 /*
1963 * If we're not tracking predicate lock data for this transaction, we
1964 * should ignore the request and return quickly.
1965 */
1967 return;
1968
1969 /* We should have a valid XID and be at the top level. */
1971
1973
1974 /* This should only be done once per transaction. */
1976
1978
1979 sxidtag.xid = xid;
1981 &sxidtag,
1982 HASH_ENTER, &found);
1983 Assert(!found);
1984
1985 /* Initialize the structure. */
1986 sxid->myXact = MySerializableXact;
1988}
1989
1990
1991/*
1992 * Check whether there are any predicate locks held by any transaction
1993 * for the page at the given block number.
1994 *
1995 * Note that the transaction may be completed but not yet subject to
1996 * cleanup due to overlapping serializable transactions. This must
1997 * return valid information regardless of transaction isolation level.
1998 *
1999 * Also note that this doesn't check for a conflicting relation lock,
2000 * just a lock specifically on the given page.
2001 *
2002 * One use is to support proper behavior during GiST index vacuum.
2003 */
2004bool
2006{
2010 PREDICATELOCKTARGET *target;
2011
2013 relation->rd_locator.dbOid,
2014 relation->rd_id,
2015 blkno);
2016
2020 target = (PREDICATELOCKTARGET *)
2023 HASH_FIND, NULL);
2025
2026 return (target != NULL);
2027}
2028
2029
2030/*
2031 * Check whether a particular lock is held by this transaction.
2032 *
2033 * Important note: this function may return false even if the lock is
2034 * being held, because it uses the local lock table which is not
2035 * updated if another transaction modifies our lock list (e.g. to
2036 * split an index page). It can also return true when a coarser
2037 * granularity lock that covers this target is being held. Be careful
2038 * to only use this function in circumstances where such errors are
2039 * acceptable!
2040 */
2041static bool
2043{
2044 LOCALPREDICATELOCK *lock;
2045
2046 /* check local hash table */
2048 targettag,
2049 HASH_FIND, NULL);
2050
2051 if (!lock)
2052 return false;
2053
2054 /*
2055 * Found entry in the table, but still need to check whether it's actually
2056 * held -- it could just be a parent of some held lock.
2057 */
2058 return lock->held;
2059}
2060
2061/*
2062 * Return the parent lock tag in the lock hierarchy: the next coarser
2063 * lock that covers the provided tag.
2064 *
2065 * Returns true and sets *parent to the parent tag if one exists,
2066 * returns false if none exists.
2067 */
2068static bool
2070 PREDICATELOCKTARGETTAG *parent)
2071{
2072 switch (GET_PREDICATELOCKTARGETTAG_TYPE(*tag))
2073 {
2075 /* relation locks have no parent lock */
2076 return false;
2077
2078 case PREDLOCKTAG_PAGE:
2079 /* parent lock is relation lock */
2083
2084 return true;
2085
2086 case PREDLOCKTAG_TUPLE:
2087 /* parent lock is page lock */
2092 return true;
2093 }
2094
2095 /* not reachable */
2096 Assert(false);
2097 return false;
2098}
2099
2100/*
2101 * Check whether the lock we are considering is already covered by a
2102 * coarser lock for our transaction.
2103 *
2104 * Like PredicateLockExists, this function might return a false
2105 * negative, but it will never return a false positive.
2106 */
2107static bool
2109{
2111 parenttag;
2112
2114
2115 /* check parents iteratively until no more */
2117 {
2120 return true;
2121 }
2122
2123 /* no more parents to check; lock is not covered */
2124 return false;
2125}
2126
2127/*
2128 * Remove the dummy entry from the predicate lock target hash, to free up some
2129 * scratch space. The caller must be holding SerializablePredicateListLock,
2130 * and must restore the entry with RestoreScratchTarget() before releasing the
2131 * lock.
2132 *
2133 * If lockheld is true, the caller is already holding the partition lock
2134 * of the partition containing the scratch entry.
2135 */
2136static void
2138{
2139 bool found;
2140
2142
2143 if (!lockheld)
2148 HASH_REMOVE, &found);
2149 Assert(found);
2150 if (!lockheld)
2152}
2153
2154/*
2155 * Re-insert the dummy entry in predicate lock target hash.
2156 */
2157static void
2159{
2160 bool found;
2161
2163
2164 if (!lockheld)
2169 HASH_ENTER, &found);
2170 Assert(!found);
2171 if (!lockheld)
2173}
2174
2175/*
2176 * Check whether the list of related predicate locks is empty for a
2177 * predicate lock target, and remove the target if it is.
2178 */
2179static void
2181{
2183
2185
2186 /* Can't remove it until no locks at this target. */
2187 if (!dlist_is_empty(&target->predicateLocks))
2188 return;
2189
2190 /* Actually remove the target. */
2192 &target->tag,
2194 HASH_REMOVE, NULL);
2195 Assert(rmtarget == target);
2196}
2197
2198/*
2199 * Delete child target locks owned by this process.
2200 * This implementation is assuming that the usage of each target tag field
2201 * is uniform. No need to make this hard if we don't have to.
2202 *
2203 * We acquire an LWLock in the case of parallel mode, because worker
2204 * backends have access to the leader's SERIALIZABLEXACT. Otherwise,
2205 * we aren't acquiring LWLocks for the predicate lock or lock
2206 * target structures associated with this transaction unless we're going
2207 * to modify them, because no other process is permitted to modify our
2208 * locks.
2209 */
2210static void
2212{
2215 dlist_mutable_iter iter;
2216
2219 if (IsInParallelMode())
2220 LWLockAcquire(&sxact->perXactPredicateListLock, LW_EXCLUSIVE);
2221
2222 dlist_foreach_modify(iter, &sxact->predicateLocks)
2223 {
2227
2228 predlock = dlist_container(PREDICATELOCK, xactLink, iter.cur);
2229
2230 oldlocktag = predlock->tag;
2231 Assert(oldlocktag.myXact == sxact);
2232 oldtarget = oldlocktag.myTarget;
2233 oldtargettag = oldtarget->tag;
2234
2236 {
2240
2243
2245
2246 dlist_delete(&predlock->xactLink);
2247 dlist_delete(&predlock->targetLink);
2250 &oldlocktag,
2253 HASH_REMOVE, NULL);
2255
2257
2259
2261 }
2262 }
2263 if (IsInParallelMode())
2264 LWLockRelease(&sxact->perXactPredicateListLock);
2266}
2267
2268/*
2269 * Returns the promotion limit for a given predicate lock target. This is the
2270 * max number of descendant locks allowed before promoting to the specified
2271 * tag. Note that the limit includes non-direct descendants (e.g., both tuples
2272 * and pages for a relation lock).
2273 *
2274 * Currently the default limit is 2 for a page lock, and half of the value of
2275 * max_pred_locks_per_transaction - 1 for a relation lock, to match behavior
2276 * of earlier releases when upgrading.
2277 *
2278 * TODO SSI: We should probably add additional GUCs to allow a maximum ratio
2279 * of page and tuple locks based on the pages in a relation, and the maximum
2280 * ratio of tuple locks to tuples in a page. This would provide more
2281 * generally "balanced" allocation of locks to where they are most useful,
2282 * while still allowing the absolute numbers to prevent one relation from
2283 * tying up all predicate lock resources.
2284 */
2285static int
2287{
2288 switch (GET_PREDICATELOCKTARGETTAG_TYPE(*tag))
2289 {
2295
2296 case PREDLOCKTAG_PAGE:
2298
2299 case PREDLOCKTAG_TUPLE:
2300
2301 /*
2302 * not reachable: nothing is finer-granularity than a tuple, so we
2303 * should never try to promote to it.
2304 */
2305 Assert(false);
2306 return 0;
2307 }
2308
2309 /* not reachable */
2310 Assert(false);
2311 return 0;
2312}
2313
2314/*
2315 * For all ancestors of a newly-acquired predicate lock, increment
2316 * their child count in the parent hash table. If any of them have
2317 * more descendants than their promotion threshold, acquire the
2318 * coarsest such lock.
2319 *
2320 * Returns true if a parent lock was acquired and false otherwise.
2321 */
2322static bool
2324{
2326 nexttag,
2329 bool found,
2330 promote;
2331
2332 promote = false;
2333
2334 targettag = *reqtag;
2335
2336 /* check parents iteratively */
2338 {
2341 &targettag,
2342 HASH_ENTER,
2343 &found);
2344 if (!found)
2345 {
2346 parentlock->held = false;
2347 parentlock->childLocks = 1;
2348 }
2349 else
2350 parentlock->childLocks++;
2351
2352 if (parentlock->childLocks >
2354 {
2355 /*
2356 * We should promote to this parent lock. Continue to check its
2357 * ancestors, however, both to get their child counts right and to
2358 * check whether we should just go ahead and promote to one of
2359 * them.
2360 */
2362 promote = true;
2363 }
2364 }
2365
2366 if (promote)
2367 {
2368 /* acquire coarsest ancestor eligible for promotion */
2370 return true;
2371 }
2372 else
2373 return false;
2374}
2375
2376/*
2377 * When releasing a lock, decrement the child count on all ancestor
2378 * locks.
2379 *
2380 * This is called only when releasing a lock via
2381 * DeleteChildTargetLocks (i.e. when a lock becomes redundant because
2382 * we've acquired its parent, possibly due to promotion) or when a new
2383 * MVCC write lock makes the predicate lock unnecessary. There's no
2384 * point in calling it when locks are released at transaction end, as
2385 * this information is no longer needed.
2386 */
2387static void
2389{
2391 nexttag;
2392
2394
2396 {
2400
2406 HASH_FIND, NULL);
2407
2408 /*
2409 * There's a small chance the parent lock doesn't exist in the lock
2410 * table. This can happen if we prematurely removed it because an
2411 * index split caused the child refcount to be off.
2412 */
2413 if (parentlock == NULL)
2414 continue;
2415
2416 parentlock->childLocks--;
2417
2418 /*
2419 * Under similar circumstances the parent lock's refcount might be
2420 * zero. This only happens if we're holding that lock (otherwise we
2421 * would have removed the entry).
2422 */
2423 if (parentlock->childLocks < 0)
2424 {
2425 Assert(parentlock->held);
2426 parentlock->childLocks = 0;
2427 }
2428
2429 if ((parentlock->childLocks == 0) && (!parentlock->held))
2430 {
2434 HASH_REMOVE, NULL);
2436 }
2437 }
2438}
2439
2440/*
2441 * Indicate that a predicate lock on the given target is held by the
2442 * specified transaction. Has no effect if the lock is already held.
2443 *
2444 * This updates the lock table and the sxact's lock list, and creates
2445 * the lock target if necessary, but does *not* do anything related to
2446 * granularity promotion or the local lock table. See
2447 * PredicateLockAcquire for that.
2448 */
2449static void
2453{
2454 PREDICATELOCKTARGET *target;
2455 PREDICATELOCKTAG locktag;
2456 PREDICATELOCK *lock;
2458 bool found;
2459
2461
2463 if (IsInParallelMode())
2464 LWLockAcquire(&sxact->perXactPredicateListLock, LW_EXCLUSIVE);
2466
2467 /* Make sure that the target is represented. */
2468 target = (PREDICATELOCKTARGET *)
2471 HASH_ENTER_NULL, &found);
2472 if (!target)
2473 ereport(ERROR,
2475 errmsg("out of shared memory"),
2476 errhint("You might need to increase \"%s\".", "max_pred_locks_per_transaction")));
2477 if (!found)
2478 dlist_init(&target->predicateLocks);
2479
2480 /* We've got the sxact and target, make sure they're joined. */
2481 locktag.myTarget = target;
2482 locktag.myXact = sxact;
2483 lock = (PREDICATELOCK *)
2486 HASH_ENTER_NULL, &found);
2487 if (!lock)
2488 ereport(ERROR,
2490 errmsg("out of shared memory"),
2491 errhint("You might need to increase \"%s\".", "max_pred_locks_per_transaction")));
2492
2493 if (!found)
2494 {
2495 dlist_push_tail(&target->predicateLocks, &lock->targetLink);
2496 dlist_push_tail(&sxact->predicateLocks, &lock->xactLink);
2498 }
2499
2501 if (IsInParallelMode())
2502 LWLockRelease(&sxact->perXactPredicateListLock);
2504}
2505
2506/*
2507 * Acquire a predicate lock on the specified target for the current
2508 * connection if not already held. This updates the local lock table
2509 * and uses it to implement granularity promotion. It will consolidate
2510 * multiple locks into a coarser lock if warranted, and will release
2511 * any finer-grained locks covered by the new one.
2512 */
2513static void
2515{
2517 bool found;
2519
2520 /* Do we have the lock already, or a covering lock? */
2522 return;
2523
2525 return;
2526
2527 /* the same hash and LW lock apply to the lock target and the local lock. */
2529
2530 /* Acquire lock in local table */
2534 HASH_ENTER, &found);
2535 locallock->held = true;
2536 if (!found)
2537 locallock->childLocks = 0;
2538
2539 /* Actually create the lock */
2541
2542 /*
2543 * Lock has been acquired. Check whether it should be promoted to a
2544 * coarser granularity, or whether there are finer-granularity locks to
2545 * clean up.
2546 */
2548 {
2549 /*
2550 * Lock request was promoted to a coarser-granularity lock, and that
2551 * lock was acquired. It will delete this lock and any of its
2552 * children, so we're done.
2553 */
2554 }
2555 else
2556 {
2557 /* Clean up any finer-granularity locks */
2560 }
2561}
2562
2563
2564/*
2565 * PredicateLockRelation
2566 *
2567 * Gets a predicate lock at the relation level.
2568 * Skip if not in full serializable transaction isolation level.
2569 * Skip if this is a temporary table.
2570 * Clear any finer-grained predicate locks this session has on the relation.
2571 */
2572void
2573PredicateLockRelation(Relation relation, Snapshot snapshot)
2574{
2576
2577 if (!SerializationNeededForRead(relation, snapshot))
2578 return;
2579
2581 relation->rd_locator.dbOid,
2582 relation->rd_id);
2584}
2585
2586/*
2587 * PredicateLockPage
2588 *
2589 * Gets a predicate lock at the page level.
2590 * Skip if not in full serializable transaction isolation level.
2591 * Skip if this is a temporary table.
2592 * Skip if a coarser predicate lock already covers this page.
2593 * Clear any finer-grained predicate locks this session has on the relation.
2594 */
2595void
2596PredicateLockPage(Relation relation, BlockNumber blkno, Snapshot snapshot)
2597{
2599
2600 if (!SerializationNeededForRead(relation, snapshot))
2601 return;
2602
2604 relation->rd_locator.dbOid,
2605 relation->rd_id,
2606 blkno);
2608}
2609
2610/*
2611 * PredicateLockTID
2612 *
2613 * Gets a predicate lock at the tuple level.
2614 * Skip if not in full serializable transaction isolation level.
2615 * Skip if this is a temporary table.
2616 */
2617void
2618PredicateLockTID(Relation relation, const ItemPointerData *tid, Snapshot snapshot,
2620{
2622
2623 if (!SerializationNeededForRead(relation, snapshot))
2624 return;
2625
2626 /*
2627 * Return if this xact wrote it.
2628 */
2629 if (relation->rd_index == NULL)
2630 {
2631 /* If we wrote it; we already have a write lock. */
2633 return;
2634 }
2635
2636 /*
2637 * Do quick-but-not-definitive test for a relation lock first. This will
2638 * never cause a return when the relation is *not* locked, but will
2639 * occasionally let the check continue when there really *is* a relation
2640 * level lock.
2641 */
2643 relation->rd_locator.dbOid,
2644 relation->rd_id);
2645 if (PredicateLockExists(&tag))
2646 return;
2647
2649 relation->rd_locator.dbOid,
2650 relation->rd_id,
2654}
2655
2656
2657/*
2658 * DeleteLockTarget
2659 *
2660 * Remove a predicate lock target along with any locks held for it.
2661 *
2662 * Caller must hold SerializablePredicateListLock and the
2663 * appropriate hash partition lock for the target.
2664 */
2665static void
2667{
2668 dlist_mutable_iter iter;
2669
2671 LW_EXCLUSIVE));
2673
2675
2676 dlist_foreach_modify(iter, &target->predicateLocks)
2677 {
2679 dlist_container(PREDICATELOCK, targetLink, iter.cur);
2680 bool found;
2681
2682 dlist_delete(&(predlock->xactLink));
2683 dlist_delete(&(predlock->targetLink));
2684
2687 &predlock->tag,
2690 HASH_REMOVE, &found);
2691 Assert(found);
2692 }
2694
2695 /* Remove the target itself, if possible. */
2697}
2698
2699
2700/*
2701 * TransferPredicateLocksToNewTarget
2702 *
2703 * Move or copy all the predicate locks for a lock target, for use by
2704 * index page splits/combines and other things that create or replace
2705 * lock targets. If 'removeOld' is true, the old locks and the target
2706 * will be removed.
2707 *
2708 * Returns true on success, or false if we ran out of shared memory to
2709 * allocate the new target or locks. Guaranteed to always succeed if
2710 * removeOld is set (by using the scratch entry in PredicateLockTargetHash
2711 * for scratch space).
2712 *
2713 * Warning: the "removeOld" option should be used only with care,
2714 * because this function does not (indeed, can not) update other
2715 * backends' LocalPredicateLockHash. If we are only adding new
2716 * entries, this is not a problem: the local lock table is used only
2717 * as a hint, so missing entries for locks that are held are
2718 * OK. Having entries for locks that are no longer held, as can happen
2719 * when using "removeOld", is not in general OK. We can only use it
2720 * safely when replacing a lock with a coarser-granularity lock that
2721 * covers it, or if we are absolutely certain that no one will need to
2722 * refer to that lock in the future.
2723 *
2724 * Caller must hold SerializablePredicateListLock exclusively.
2725 */
2726static bool
2729 bool removeOld)
2730{
2736 bool found;
2737 bool outOfShmem = false;
2738
2740 LW_EXCLUSIVE));
2741
2746
2747 if (removeOld)
2748 {
2749 /*
2750 * Remove the dummy entry to give us scratch space, so we know we'll
2751 * be able to create the new lock target.
2752 */
2753 RemoveScratchTarget(false);
2754 }
2755
2756 /*
2757 * We must get the partition locks in ascending sequence to avoid
2758 * deadlocks. If old and new partitions are the same, we must request the
2759 * lock only once.
2760 */
2762 {
2766 }
2768 {
2772 }
2773 else
2775
2776 /*
2777 * Look for the old target. If not found, that's OK; no predicate locks
2778 * are affected, so we can just clean up and return. If it does exist,
2779 * walk its list of predicate locks and move or copy them to the new
2780 * target.
2781 */
2783 &oldtargettag,
2785 HASH_FIND, NULL);
2786
2787 if (oldtarget)
2788 {
2791 dlist_mutable_iter iter;
2792
2794 &newtargettag,
2796 HASH_ENTER_NULL, &found);
2797
2798 if (!newtarget)
2799 {
2800 /* Failed to allocate due to insufficient shmem */
2801 outOfShmem = true;
2802 goto exit;
2803 }
2804
2805 /* If we created a new entry, initialize it */
2806 if (!found)
2807 dlist_init(&newtarget->predicateLocks);
2808
2809 newpredlocktag.myTarget = newtarget;
2810
2811 /*
2812 * Loop through all the locks on the old target, replacing them with
2813 * locks on the new target.
2814 */
2816
2817 dlist_foreach_modify(iter, &oldtarget->predicateLocks)
2818 {
2820 dlist_container(PREDICATELOCK, targetLink, iter.cur);
2823
2824 newpredlocktag.myXact = oldpredlock->tag.myXact;
2825
2826 if (removeOld)
2827 {
2828 dlist_delete(&(oldpredlock->xactLink));
2829 dlist_delete(&(oldpredlock->targetLink));
2830
2833 &oldpredlock->tag,
2836 HASH_REMOVE, &found);
2837 Assert(found);
2838 }
2839
2846 &found);
2847 if (!newpredlock)
2848 {
2849 /* Out of shared memory. Undo what we've done so far. */
2852 outOfShmem = true;
2853 goto exit;
2854 }
2855 if (!found)
2856 {
2857 dlist_push_tail(&(newtarget->predicateLocks),
2858 &(newpredlock->targetLink));
2859 dlist_push_tail(&(newpredlocktag.myXact->predicateLocks),
2860 &(newpredlock->xactLink));
2861 newpredlock->commitSeqNo = oldCommitSeqNo;
2862 }
2863 else
2864 {
2865 if (newpredlock->commitSeqNo < oldCommitSeqNo)
2866 newpredlock->commitSeqNo = oldCommitSeqNo;
2867 }
2868
2869 Assert(newpredlock->commitSeqNo != 0);
2870 Assert((newpredlock->commitSeqNo == InvalidSerCommitSeqNo)
2871 || (newpredlock->tag.myXact == OldCommittedSxact));
2872 }
2874
2875 if (removeOld)
2876 {
2877 Assert(dlist_is_empty(&oldtarget->predicateLocks));
2879 }
2880 }
2881
2882
2883exit:
2884 /* Release partition locks in reverse order of acquisition. */
2886 {
2889 }
2891 {
2894 }
2895 else
2897
2898 if (removeOld)
2899 {
2900 /* We shouldn't run out of memory if we're moving locks */
2902
2903 /* Put the scratch entry back */
2904 RestoreScratchTarget(false);
2905 }
2906
2907 return !outOfShmem;
2908}
2909
2910/*
2911 * Drop all predicate locks of any granularity from the specified relation,
2912 * which can be a heap relation or an index relation. If 'transfer' is true,
2913 * acquire a relation lock on the heap for any transactions with any lock(s)
2914 * on the specified relation.
2915 *
2916 * This requires grabbing a lot of LW locks and scanning the entire lock
2917 * target table for matches. That makes this more expensive than most
2918 * predicate lock management functions, but it will only be called for DDL
2919 * type commands that are expensive anyway, and there are fast returns when
2920 * no serializable transactions are active or the relation is temporary.
2921 *
2922 * We don't use the TransferPredicateLocksToNewTarget function because it
2923 * acquires its own locks on the partitions of the two targets involved,
2924 * and we'll already be holding all partition locks.
2925 *
2926 * We can't throw an error from here, because the call could be from a
2927 * transaction which is not serializable.
2928 *
2929 * NOTE: This is currently only called with transfer set to true, but that may
2930 * change. If we decide to clean up the locks from a table on commit of a
2931 * transaction which executed DROP TABLE, the false condition will be useful.
2932 */
2933static void
2935{
2939 Oid dbId;
2940 Oid relId;
2941 Oid heapId;
2942 int i;
2943 bool isIndex;
2944 bool found;
2946
2947 /*
2948 * Bail out quickly if there are no serializable transactions running.
2949 * It's safe to check this without taking locks because the caller is
2950 * holding an ACCESS EXCLUSIVE lock on the relation. No new locks which
2951 * would matter here can be acquired while that is held.
2952 */
2954 return;
2955
2956 if (!PredicateLockingNeededForRelation(relation))
2957 return;
2958
2959 dbId = relation->rd_locator.dbOid;
2960 relId = relation->rd_id;
2961 if (relation->rd_index == NULL)
2962 {
2963 isIndex = false;
2964 heapId = relId;
2965 }
2966 else
2967 {
2968 isIndex = true;
2969 heapId = relation->rd_index->indrelid;
2970 }
2972 Assert(transfer || !isIndex); /* index OID only makes sense with
2973 * transfer */
2974
2975 /* Retrieve first time needed, then keep. */
2977 heaptarget = NULL;
2978
2979 /* Acquire locks on all lock partitions */
2981 for (i = 0; i < NUM_PREDICATELOCK_PARTITIONS; i++)
2984
2985 /*
2986 * Remove the dummy entry to give us scratch space, so we know we'll be
2987 * able to create the new lock target.
2988 */
2989 if (transfer)
2990 RemoveScratchTarget(true);
2991
2992 /* Scan through target map */
2994
2996 {
2997 dlist_mutable_iter iter;
2998
2999 /*
3000 * Check whether this is a target which needs attention.
3001 */
3003 continue; /* wrong relation id */
3004 if (GET_PREDICATELOCKTARGETTAG_DB(oldtarget->tag) != dbId)
3005 continue; /* wrong database id */
3006 if (transfer && !isIndex
3008 continue; /* already the right lock */
3009
3010 /*
3011 * If we made it here, we have work to do. We make sure the heap
3012 * relation lock exists, then we walk the list of predicate locks for
3013 * the old target we found, moving all locks to the heap relation lock
3014 * -- unless they already hold that.
3015 */
3016
3017 /*
3018 * First make sure we have the heap relation target. We only need to
3019 * do this once.
3020 */
3021 if (transfer && heaptarget == NULL)
3022 {
3024
3030 HASH_ENTER, &found);
3031 if (!found)
3032 dlist_init(&heaptarget->predicateLocks);
3033 }
3034
3035 /*
3036 * Loop through all the locks on the old target, replacing them with
3037 * locks on the new target.
3038 */
3039 dlist_foreach_modify(iter, &oldtarget->predicateLocks)
3040 {
3042 dlist_container(PREDICATELOCK, targetLink, iter.cur);
3046
3047 /*
3048 * Remove the old lock first. This avoids the chance of running
3049 * out of lock structure entries for the hash table.
3050 */
3052 oldXact = oldpredlock->tag.myXact;
3053
3054 dlist_delete(&(oldpredlock->xactLink));
3055
3056 /*
3057 * No need for retail delete from oldtarget list, we're removing
3058 * the whole target anyway.
3059 */
3061 &oldpredlock->tag,
3062 HASH_REMOVE, &found);
3063 Assert(found);
3064
3065 if (transfer)
3066 {
3068
3070 newpredlocktag.myXact = oldXact;
3076 HASH_ENTER,
3077 &found);
3078 if (!found)
3079 {
3080 dlist_push_tail(&(heaptarget->predicateLocks),
3081 &(newpredlock->targetLink));
3082 dlist_push_tail(&(newpredlocktag.myXact->predicateLocks),
3083 &(newpredlock->xactLink));
3084 newpredlock->commitSeqNo = oldCommitSeqNo;
3085 }
3086 else
3087 {
3088 if (newpredlock->commitSeqNo < oldCommitSeqNo)
3089 newpredlock->commitSeqNo = oldCommitSeqNo;
3090 }
3091
3092 Assert(newpredlock->commitSeqNo != 0);
3093 Assert((newpredlock->commitSeqNo == InvalidSerCommitSeqNo)
3094 || (newpredlock->tag.myXact == OldCommittedSxact));
3095 }
3096 }
3097
3099 &found);
3100 Assert(found);
3101 }
3102
3103 /* Put the scratch entry back */
3104 if (transfer)
3106
3107 /* Release locks in reverse order */
3109 for (i = NUM_PREDICATELOCK_PARTITIONS - 1; i >= 0; i--)
3112}
3113
3114/*
3115 * TransferPredicateLocksToHeapRelation
3116 * For all transactions, transfer all predicate locks for the given
3117 * relation to a single relation lock on the heap.
3118 */
3119void
3121{
3122 DropAllPredicateLocksFromTable(relation, true);
3123}
3124
3125
3126/*
3127 * PredicateLockPageSplit
3128 *
3129 * Copies any predicate locks for the old page to the new page.
3130 * Skip if this is a temporary table or toast table.
3131 *
3132 * NOTE: A page split (or overflow) affects all serializable transactions,
3133 * even if it occurs in the context of another transaction isolation level.
3134 *
3135 * NOTE: This currently leaves the local copy of the locks without
3136 * information on the new lock which is in shared memory. This could cause
3137 * problems if enough page splits occur on locked pages without the processes
3138 * which hold the locks getting in and noticing.
3139 */
3140void
3143{
3146 bool success;
3147
3148 /*
3149 * Bail out quickly if there are no serializable transactions running.
3150 *
3151 * It's safe to do this check without taking any additional locks. Even if
3152 * a serializable transaction starts concurrently, we know it can't take
3153 * any SIREAD locks on the page being split because the caller is holding
3154 * the associated buffer page lock. Memory reordering isn't an issue; the
3155 * memory barrier in the LWLock acquisition guarantees that this read
3156 * occurs while the buffer page lock is held.
3157 */
3159 return;
3160
3161 if (!PredicateLockingNeededForRelation(relation))
3162 return;
3163
3167
3169 relation->rd_locator.dbOid,
3170 relation->rd_id,
3171 oldblkno);
3173 relation->rd_locator.dbOid,
3174 relation->rd_id,
3175 newblkno);
3176
3178
3179 /*
3180 * Try copying the locks over to the new page's tag, creating it if
3181 * necessary.
3182 */
3185 false);
3186
3187 if (!success)
3188 {
3189 /*
3190 * No more predicate lock entries are available. Failure isn't an
3191 * option here, so promote the page lock to a relation lock.
3192 */
3193
3194 /* Get the parent relation lock's lock tag */
3196 &newtargettag);
3197 Assert(success);
3198
3199 /*
3200 * Move the locks to the parent. This shouldn't fail.
3201 *
3202 * Note that here we are removing locks held by other backends,
3203 * leading to a possible inconsistency in their local lock hash table.
3204 * This is OK because we're replacing it with a lock that covers the
3205 * old one.
3206 */
3209 true);
3210 Assert(success);
3211 }
3212
3214}
3215
3216/*
3217 * PredicateLockPageCombine
3218 *
3219 * Combines predicate locks for two existing pages.
3220 * Skip if this is a temporary table or toast table.
3221 *
3222 * NOTE: A page combine affects all serializable transactions, even if it
3223 * occurs in the context of another transaction isolation level.
3224 */
3225void
3228{
3229 /*
3230 * Page combines differ from page splits in that we ought to be able to
3231 * remove the locks on the old page after transferring them to the new
3232 * page, instead of duplicating them. However, because we can't edit other
3233 * backends' local lock tables, removing the old lock would leave them
3234 * with an entry in their LocalPredicateLockHash for a lock they're not
3235 * holding, which isn't acceptable. So we wind up having to do the same
3236 * work as a page split, acquiring a lock on the new page and keeping the
3237 * old page locked too. That can lead to some false positives, but should
3238 * be rare in practice.
3239 */
3241}
3242
3243/*
3244 * Walk the list of in-progress serializable transactions and find the new
3245 * xmin.
3246 */
3247static void
3249{
3250 dlist_iter iter;
3251
3253
3256
3258 {
3260 dlist_container(SERIALIZABLEXACT, xactLink, iter.cur);
3261
3265 {
3270 {
3273 }
3274 else if (TransactionIdEquals(sxact->xmin,
3277 }
3278 }
3279
3281}
3282
3283/*
3284 * ReleasePredicateLocks
3285 *
3286 * Releases predicate locks based on completion of the current transaction,
3287 * whether committed or rolled back. It can also be called for a read only
3288 * transaction when it becomes impossible for the transaction to become
3289 * part of a dangerous structure.
3290 *
3291 * We do nothing unless this is a serializable transaction.
3292 *
3293 * This method must ensure that shared memory hash tables are cleaned
3294 * up in some relatively timely fashion.
3295 *
3296 * If this transaction is committing and is holding any predicate locks,
3297 * it must be added to a list of completed serializable transactions still
3298 * holding locks.
3299 *
3300 * If isReadOnlySafe is true, then predicate locks are being released before
3301 * the end of the transaction because MySerializableXact has been determined
3302 * to be RO_SAFE. In non-parallel mode we can release it completely, but it
3303 * in parallel mode we partially release the SERIALIZABLEXACT and keep it
3304 * around until the end of the transaction, allowing each backend to clear its
3305 * MySerializableXact variable and benefit from the optimization in its own
3306 * time.
3307 */
3308void
3310{
3311 bool partiallyReleasing = false;
3312 bool needToClear;
3314 dlist_mutable_iter iter;
3315
3316 /*
3317 * We can't trust XactReadOnly here, because a transaction which started
3318 * as READ WRITE can show as READ ONLY later, e.g., within
3319 * subtransactions. We want to flag a transaction as READ ONLY if it
3320 * commits without writing so that de facto READ ONLY transactions get the
3321 * benefit of some RO optimizations, so we will use this local variable to
3322 * get some cleanup logic right which is based on whether the transaction
3323 * was declared READ ONLY at the top level.
3324 */
3326
3327 /* We can't be both committing and releasing early due to RO_SAFE. */
3329
3330 /* Are we at the end of a transaction, that is, a commit or abort? */
3331 if (!isReadOnlySafe)
3332 {
3333 /*
3334 * Parallel workers mustn't release predicate locks at the end of
3335 * their transaction. The leader will do that at the end of its
3336 * transaction.
3337 */
3338 if (IsParallelWorker())
3339 {
3341 return;
3342 }
3343
3344 /*
3345 * By the time the leader in a parallel query reaches end of
3346 * transaction, it has waited for all workers to exit.
3347 */
3349
3350 /*
3351 * If the leader in a parallel query earlier stashed a partially
3352 * released SERIALIZABLEXACT for final clean-up at end of transaction
3353 * (because workers might still have been accessing it), then it's
3354 * time to restore it.
3355 */
3357 {
3362 }
3363 }
3364
3366 {
3368 return;
3369 }
3370
3372
3373 /*
3374 * If the transaction is committing, but it has been partially released
3375 * already, then treat this as a roll back. It was marked as rolled back.
3376 */
3378 isCommit = false;
3379
3380 /*
3381 * If we're called in the middle of a transaction because we discovered
3382 * that the SXACT_FLAG_RO_SAFE flag was set, then we'll partially release
3383 * it (that is, release the predicate locks and conflicts, but not the
3384 * SERIALIZABLEXACT itself) if we're the first backend to have noticed.
3385 */
3387 {
3388 /*
3389 * The leader needs to stash a pointer to it, so that it can
3390 * completely release it at end-of-transaction.
3391 */
3392 if (!IsParallelWorker())
3394
3395 /*
3396 * The first backend to reach this condition will partially release
3397 * the SERIALIZABLEXACT. All others will just clear their
3398 * backend-local state so that they stop doing SSI checks for the rest
3399 * of the transaction.
3400 */
3402 {
3405 return;
3406 }
3407 else
3408 {
3410 partiallyReleasing = true;
3411 /* ... and proceed to perform the partial release below. */
3412 }
3413 }
3419
3420 /* may not be serializable during COMMIT/ROLLBACK PREPARED */
3422
3423 /* We'd better not already be on the cleanup list. */
3425
3427
3428 /*
3429 * We don't hold XidGenLock lock here, assuming that TransactionId is
3430 * atomic!
3431 *
3432 * If this value is changing, we don't care that much whether we get the
3433 * old or new value -- it is just used to determine how far
3434 * SxactGlobalXmin must advance before this transaction can be fully
3435 * cleaned up. The worst that could happen is we wait for one more
3436 * transaction to complete before freeing some RAM; correctness of visible
3437 * behavior is not affected.
3438 */
3440
3441 /*
3442 * If it's not a commit it's either a rollback or a read-only transaction
3443 * flagged SXACT_FLAG_RO_SAFE, and we can clear our locks immediately.
3444 */
3445 if (isCommit)
3446 {
3449 /* Recognize implicit read-only transaction (commit without write). */
3450 if (!MyXactDidWrite)
3452 }
3453 else
3454 {
3455 /*
3456 * The DOOMED flag indicates that we intend to roll back this
3457 * transaction and so it should not cause serialization failures for
3458 * other transactions that conflict with it. Note that this flag might
3459 * already be set, if another backend marked this transaction for
3460 * abort.
3461 *
3462 * The ROLLED_BACK flag further indicates that ReleasePredicateLocks
3463 * has been called, and so the SerializableXact is eligible for
3464 * cleanup. This means it should not be considered when calculating
3465 * SxactGlobalXmin.
3466 */
3469
3470 /*
3471 * If the transaction was previously prepared, but is now failing due
3472 * to a ROLLBACK PREPARED or (hopefully very rare) error after the
3473 * prepare, clear the prepared flag. This simplifies conflict
3474 * checking.
3475 */
3477 }
3478
3480 {
3482 if (--(PredXact->WritableSxactCount) == 0)
3483 {
3484 /*
3485 * Release predicate locks and rw-conflicts in for all committed
3486 * transactions. There are no longer any transactions which might
3487 * conflict with the locks and no chance for new transactions to
3488 * overlap. Similarly, existing conflicts in can't cause pivots,
3489 * and any conflicts in which could have completed a dangerous
3490 * structure would already have caused a rollback, so any
3491 * remaining ones must be benign.
3492 */
3494 }
3495 }
3496 else
3497 {
3498 /*
3499 * Read-only transactions: clear the list of transactions that might
3500 * make us unsafe. Note that we use 'inLink' for the iteration as
3501 * opposed to 'outLink' for the r/w xacts.
3502 */
3504 {
3506 dlist_container(RWConflictData, inLink, iter.cur);
3507
3510
3512 }
3513 }
3514
3515 /* Check for conflict out to old committed transactions. */
3516 if (isCommit
3519 {
3520 /*
3521 * we don't know which old committed transaction we conflicted with,
3522 * so be conservative and use FirstNormalSerCommitSeqNo here
3523 */
3527 }
3528
3529 /*
3530 * Release all outConflicts to committed transactions. If we're rolling
3531 * back clear them all. Set SXACT_FLAG_CONFLICT_OUT if any point to
3532 * previously committed transactions.
3533 */
3535 {
3537 dlist_container(RWConflictData, outLink, iter.cur);
3538
3539 if (isCommit
3541 && SxactIsCommitted(conflict->sxactIn))
3542 {
3544 || conflict->sxactIn->prepareSeqNo < MySerializableXact->SeqNo.earliestOutConflictCommit)
3547 }
3548
3549 if (!isCommit
3550 || SxactIsCommitted(conflict->sxactIn)
3551 || (conflict->sxactIn->SeqNo.lastCommitBeforeSnapshot >= PredXact->LastSxactCommitSeqNo))
3553 }
3554
3555 /*
3556 * Release all inConflicts from committed and read-only transactions. If
3557 * we're rolling back, clear them all.
3558 */
3560 {
3562 dlist_container(RWConflictData, inLink, iter.cur);
3563
3564 if (!isCommit
3565 || SxactIsCommitted(conflict->sxactOut)
3566 || SxactIsReadOnly(conflict->sxactOut))
3568 }
3569
3571 {
3572 /*
3573 * Remove ourselves from the list of possible conflicts for concurrent
3574 * READ ONLY transactions, flagging them as unsafe if we have a
3575 * conflict out. If any are waiting DEFERRABLE transactions, wake them
3576 * up if they are known safe or known unsafe.
3577 */
3579 {
3581 dlist_container(RWConflictData, outLink, iter.cur);
3582
3583 roXact = possibleUnsafeConflict->sxactIn;
3586
3587 /* Mark conflicted if necessary. */
3588 if (isCommit
3592 <= roXact->SeqNo.lastCommitBeforeSnapshot))
3593 {
3594 /*
3595 * This releases possibleUnsafeConflict (as well as all other
3596 * possible conflicts for roXact)
3597 */
3599 }
3600 else
3601 {
3603
3604 /*
3605 * If we were the last possible conflict, flag it safe. The
3606 * transaction can now safely release its predicate locks (but
3607 * that transaction's backend has to do that itself).
3608 */
3609 if (dlist_is_empty(&roXact->possibleUnsafeConflicts))
3610 roXact->flags |= SXACT_FLAG_RO_SAFE;
3611 }
3612
3613 /*
3614 * Wake up the process for a waiting DEFERRABLE transaction if we
3615 * now know it's either safe or conflicted.
3616 */
3619 ProcSendSignal(roXact->pgprocno);
3620 }
3621 }
3622
3623 /*
3624 * Check whether it's time to clean up old transactions. This can only be
3625 * done when the last serializable transaction with the oldest xmin among
3626 * serializable transactions completes. We then find the "new oldest"
3627 * xmin and purge any transactions which finished before this transaction
3628 * was launched.
3629 *
3630 * For parallel queries in read-only transactions, it might run twice. We
3631 * only release the reference on the first call.
3632 */
3633 needToClear = false;
3634 if ((partiallyReleasing ||
3638 {
3640 if (--(PredXact->SxactGlobalXminCount) == 0)
3641 {
3643 needToClear = true;
3644 }
3645 }
3646
3648
3650
3651 /* Add this to the list of transactions to check for later cleanup. */
3652 if (isCommit)
3655
3656 /*
3657 * If we're releasing a RO_SAFE transaction in parallel mode, we'll only
3658 * partially release it. That's necessary because other backends may have
3659 * a reference to it. The leader will release the SERIALIZABLEXACT itself
3660 * at the end of the transaction after workers have stopped running.
3661 */
3662 if (!isCommit)
3665 false);
3666
3668
3669 if (needToClear)
3671
3673}
3674
3675static void
3677{
3679 MyXactDidWrite = false;
3680
3681 /* Delete per-transaction lock table */
3683 {
3686 }
3687}
3688
3689/*
3690 * Clear old predicate locks, belonging to committed transactions that are no
3691 * longer interesting to any in-progress transaction.
3692 */
3693static void
3695{
3696 dlist_mutable_iter iter;
3697
3698 /*
3699 * Loop through finished transactions. They are in commit order, so we can
3700 * stop as soon as we find one that's still interesting.
3701 */
3705 {
3707 dlist_container(SERIALIZABLEXACT, finishedLink, iter.cur);
3708
3712 {
3713 /*
3714 * This transaction committed before any in-progress transaction
3715 * took its snapshot. It's no longer interesting.
3716 */
3718 dlist_delete_thoroughly(&finishedSxact->finishedLink);
3721 }
3722 else if (finishedSxact->commitSeqNo > PredXact->HavePartialClearedThrough
3723 && finishedSxact->commitSeqNo <= PredXact->CanPartialClearThrough)
3724 {
3725 /*
3726 * Any active transactions that took their snapshot before this
3727 * transaction committed are read-only, so we can clear part of
3728 * its state.
3729 */
3731
3733 {
3734 /* A read-only transaction can be removed entirely */
3735 dlist_delete_thoroughly(&(finishedSxact->finishedLink));
3737 }
3738 else
3739 {
3740 /*
3741 * A read-write transaction can only be partially cleared. We
3742 * need to keep the SERIALIZABLEXACT but can release the
3743 * SIREAD locks and conflicts in.
3744 */
3746 }
3747
3750 }
3751 else
3752 {
3753 /* Still interesting. */
3754 break;
3755 }
3756 }
3758
3759 /*
3760 * Loop through predicate locks on dummy transaction for summarized data.
3761 */
3764 {
3766 dlist_container(PREDICATELOCK, xactLink, iter.cur);
3768
3770 Assert(predlock->commitSeqNo != 0);
3771 Assert(predlock->commitSeqNo != InvalidSerCommitSeqNo);
3774
3775 /*
3776 * If this lock originally belonged to an old enough transaction, we
3777 * can release it.
3778 */
3780 {
3781 PREDICATELOCKTAG tag;
3782 PREDICATELOCKTARGET *target;
3786
3787 tag = predlock->tag;
3788 target = tag.myTarget;
3789 targettag = target->tag;
3792
3794
3795 dlist_delete(&(predlock->targetLink));
3796 dlist_delete(&(predlock->xactLink));
3797
3801 HASH_REMOVE, NULL);
3803
3805 }
3806 }
3807
3810}
3811
3812/*
3813 * This is the normal way to delete anything from any of the predicate
3814 * locking hash tables. Given a transaction which we know can be deleted:
3815 * delete all predicate locks held by that transaction and any predicate
3816 * lock targets which are now unreferenced by a lock; delete all conflicts
3817 * for the transaction; delete all xid values for the transaction; then
3818 * delete the transaction.
3819 *
3820 * When the partial flag is set, we can release all predicate locks and
3821 * in-conflict information -- we've established that there are no longer
3822 * any overlapping read write transactions for which this transaction could
3823 * matter -- but keep the transaction entry itself and any outConflicts.
3824 *
3825 * When the summarize flag is set, we've run short of room for sxact data
3826 * and must summarize to the SLRU. Predicate locks are transferred to a
3827 * dummy "old" transaction, with duplicate locks on a single target
3828 * collapsing to a single lock with the "latest" commitSeqNo from among
3829 * the conflicting locks..
3830 */
3831static void
3833 bool summarize)
3834{
3836 dlist_mutable_iter iter;
3837
3838 Assert(sxact != NULL);
3840 Assert(partial || !SxactIsOnFinishedList(sxact));
3842
3843 /*
3844 * First release all the predicate locks held by this xact (or transfer
3845 * them to OldCommittedSxact if summarize is true)
3846 */
3848 if (IsInParallelMode())
3849 LWLockAcquire(&sxact->perXactPredicateListLock, LW_EXCLUSIVE);
3850 dlist_foreach_modify(iter, &sxact->predicateLocks)
3851 {
3853 dlist_container(PREDICATELOCK, xactLink, iter.cur);
3854 PREDICATELOCKTAG tag;
3855 PREDICATELOCKTARGET *target;
3859
3860 tag = predlock->tag;
3861 target = tag.myTarget;
3862 targettag = target->tag;
3865
3867
3868 dlist_delete(&predlock->targetLink);
3869
3873 HASH_REMOVE, NULL);
3874 if (summarize)
3875 {
3876 bool found;
3877
3878 /* Fold into dummy transaction list. */
3883 HASH_ENTER_NULL, &found);
3884 if (!predlock)
3885 ereport(ERROR,
3887 errmsg("out of shared memory"),
3888 errhint("You might need to increase \"%s\".", "max_pred_locks_per_transaction")));
3889 if (found)
3890 {
3891 Assert(predlock->commitSeqNo != 0);
3892 Assert(predlock->commitSeqNo != InvalidSerCommitSeqNo);
3893 if (predlock->commitSeqNo < sxact->commitSeqNo)
3894 predlock->commitSeqNo = sxact->commitSeqNo;
3895 }
3896 else
3897 {
3899 &predlock->targetLink);
3901 &predlock->xactLink);
3902 predlock->commitSeqNo = sxact->commitSeqNo;
3903 }
3904 }
3905 else
3907
3909 }
3910
3911 /*
3912 * Rather than retail removal, just re-init the head after we've run
3913 * through the list.
3914 */
3915 dlist_init(&sxact->predicateLocks);
3916
3917 if (IsInParallelMode())
3918 LWLockRelease(&sxact->perXactPredicateListLock);
3920
3921 sxidtag.xid = sxact->topXid;
3923
3924 /* Release all outConflicts (unless 'partial' is true) */
3925 if (!partial)
3926 {
3927 dlist_foreach_modify(iter, &sxact->outConflicts)
3928 {
3930 dlist_container(RWConflictData, outLink, iter.cur);
3931
3932 if (summarize)
3933 conflict->sxactIn->flags |= SXACT_FLAG_SUMMARY_CONFLICT_IN;
3935 }
3936 }
3937
3938 /* Release all inConflicts. */
3939 dlist_foreach_modify(iter, &sxact->inConflicts)
3940 {
3942 dlist_container(RWConflictData, inLink, iter.cur);
3943
3944 if (summarize)
3945 conflict->sxactOut->flags |= SXACT_FLAG_SUMMARY_CONFLICT_OUT;
3947 }
3948
3949 /* Finally, get rid of the xid and the record of the transaction itself. */
3950 if (!partial)
3951 {
3952 if (sxidtag.xid != InvalidTransactionId)
3955 }
3956
3958}
3959
3960/*
3961 * Tests whether the given top level transaction is concurrent with
3962 * (overlaps) our current transaction.
3963 *
3964 * We need to identify the top level transaction for SSI, anyway, so pass
3965 * that to this function to save the overhead of checking the snapshot's
3966 * subxip array.
3967 */
3968static bool
3970{
3971 Snapshot snap;
3972
3975
3977
3978 if (TransactionIdPrecedes(xid, snap->xmin))
3979 return false;
3980
3981 if (TransactionIdFollowsOrEquals(xid, snap->xmax))
3982 return true;
3983
3984 return pg_lfind32(xid, snap->xip, snap->xcnt);
3985}
3986
3987bool
3989{
3990 if (!SerializationNeededForRead(relation, snapshot))
3991 return false;
3992
3993 /* Check if someone else has already decided that we need to die */
3995 {
3996 ereport(ERROR,
3998 errmsg("could not serialize access due to read/write dependencies among transactions"),
3999 errdetail_internal("Reason code: Canceled on identification as a pivot, during conflict out checking."),
4000 errhint("The transaction might succeed if retried.")));
4001 }
4002
4003 return true;
4004}
4005
4006/*
4007 * CheckForSerializableConflictOut
4008 * A table AM is reading a tuple that has been modified. If it determines
4009 * that the tuple version it is reading is not visible to us, it should
4010 * pass in the top level xid of the transaction that created it.
4011 * Otherwise, if it determines that it is visible to us but it has been
4012 * deleted or there is a newer version available due to an update, it
4013 * should pass in the top level xid of the modifying transaction.
4014 *
4015 * This function will check for overlap with our own transaction. If the given
4016 * xid is also serializable and the transactions overlap (i.e., they cannot see
4017 * each other's writes), then we have a conflict out.
4018 */
4019void
4021{
4025
4026 if (!SerializationNeededForRead(relation, snapshot))
4027 return;
4028
4029 /* Check if someone else has already decided that we need to die */
4031 {
4032 ereport(ERROR,
4034 errmsg("could not serialize access due to read/write dependencies among transactions"),
4035 errdetail_internal("Reason code: Canceled on identification as a pivot, during conflict out checking."),
4036 errhint("The transaction might succeed if retried.")));
4037 }
4039
4041 return;
4042
4043 /*
4044 * Find sxact or summarized info for the top level xid.
4045 */
4046 sxidtag.xid = xid;
4048 sxid = (SERIALIZABLEXID *)
4050 if (!sxid)
4051 {
4052 /*
4053 * Transaction not found in "normal" SSI structures. Check whether it
4054 * got pushed out to SLRU storage for "old committed" transactions.
4055 */
4057
4059 if (conflictCommitSeqNo != 0)
4060 {
4065 ereport(ERROR,
4067 errmsg("could not serialize access due to read/write dependencies among transactions"),
4068 errdetail_internal("Reason code: Canceled on conflict out to old pivot %u.", xid),
4069 errhint("The transaction might succeed if retried.")));
4070
4073 ereport(ERROR,
4075 errmsg("could not serialize access due to read/write dependencies among transactions"),
4076 errdetail_internal("Reason code: Canceled on identification as a pivot, with conflict out to old committed transaction %u.", xid),
4077 errhint("The transaction might succeed if retried.")));
4078
4080 }
4081
4082 /* It's not serializable or otherwise not important. */
4084 return;
4085 }
4086 sxact = sxid->myXact;
4087 Assert(TransactionIdEquals(sxact->topXid, xid));
4089 {
4090 /* Can't conflict with ourself or a transaction that will roll back. */
4092 return;
4093 }
4094
4095 /*
4096 * We have a conflict out to a transaction which has a conflict out to a
4097 * summarized transaction. That summarized transaction must have
4098 * committed first, and we can't tell when it committed in relation to our
4099 * snapshot acquisition, so something needs to be canceled.
4100 */
4102 {
4103 if (!SxactIsPrepared(sxact))
4104 {
4105 sxact->flags |= SXACT_FLAG_DOOMED;
4107 return;
4108 }
4109 else
4110 {
4112 ereport(ERROR,
4114 errmsg("could not serialize access due to read/write dependencies among transactions"),
4115 errdetail_internal("Reason code: Canceled on conflict out to old pivot."),
4116 errhint("The transaction might succeed if retried.")));
4117 }
4118 }
4119
4120 /*
4121 * If this is a read-only transaction and the writing transaction has
4122 * committed, and it doesn't have a rw-conflict to a transaction which
4123 * committed before it, no conflict.
4124 */
4129 || MySerializableXact->SeqNo.lastCommitBeforeSnapshot < sxact->SeqNo.earliestOutConflictCommit))
4130 {
4131 /* Read-only transaction will appear to run first. No conflict. */
4133 return;
4134 }
4135
4136 if (!XidIsConcurrent(xid))
4137 {
4138 /* This write was already in our snapshot; no conflict. */
4140 return;
4141 }
4142
4144 {
4145 /* We don't want duplicate conflict records in the list. */
4147 return;
4148 }
4149
4150 /*
4151 * Flag the conflict. But first, if this conflict creates a dangerous
4152 * structure, ereport an error.
4153 */
4156}
4157
4158/*
4159 * Check a particular target for rw-dependency conflict in. A subroutine of
4160 * CheckForSerializableConflictIn().
4161 */
4162static void
4164{
4167 PREDICATELOCKTARGET *target;
4170 dlist_mutable_iter iter;
4171
4173
4174 /*
4175 * The same hash and LW lock apply to the lock target and the lock itself.
4176 */
4180 target = (PREDICATELOCKTARGET *)
4183 HASH_FIND, NULL);
4184 if (!target)
4185 {
4186 /* Nothing has this target locked; we're done here. */
4188 return;
4189 }
4190
4191 /*
4192 * Each lock for an overlapping transaction represents a conflict: a
4193 * rw-dependency in to this transaction.
4194 */
4196
4197 dlist_foreach_modify(iter, &target->predicateLocks)
4198 {
4200 dlist_container(PREDICATELOCK, targetLink, iter.cur);
4201 SERIALIZABLEXACT *sxact = predlock->tag.myXact;
4202
4204 {
4205 /*
4206 * If we're getting a write lock on a tuple, we don't need a
4207 * predicate (SIREAD) lock on the same tuple. We can safely remove
4208 * our SIREAD lock, but we'll defer doing so until after the loop
4209 * because that requires upgrading to an exclusive partition lock.
4210 *
4211 * We can't use this optimization within a subtransaction because
4212 * the subtransaction could roll back, and we would be left
4213 * without any lock at the top level.
4214 */
4215 if (!IsSubTransaction()
4217 {
4219 mypredlocktag = predlock->tag;
4220 }
4221 }
4222 else if (!SxactIsDoomed(sxact)
4225 sxact->finishedBefore))
4227 {
4230
4231 /*
4232 * Re-check after getting exclusive lock because the other
4233 * transaction may have flagged a conflict.
4234 */
4235 if (!SxactIsDoomed(sxact)
4238 sxact->finishedBefore))
4240 {
4242 }
4243
4246 }
4247 }
4250
4251 /*
4252 * If we found one of our own SIREAD locks to remove, remove it now.
4253 *
4254 * At this point our transaction already has a RowExclusiveLock on the
4255 * relation, so we are OK to drop the predicate lock on the tuple, if
4256 * found, without fearing that another write against the tuple will occur
4257 * before the MVCC information makes it to the buffer.
4258 */
4259 if (mypredlock != NULL)
4260 {
4263
4265 if (IsInParallelMode())
4269
4270 /*
4271 * Remove the predicate lock from shared memory, if it wasn't removed
4272 * while the locks were released. One way that could happen is from
4273 * autovacuum cleaning up an index.
4274 */
4281 HASH_FIND, NULL);
4282 if (rmpredlock != NULL)
4283 {
4285
4286 dlist_delete(&(mypredlock->targetLink));
4287 dlist_delete(&(mypredlock->xactLink));
4288
4293 HASH_REMOVE, NULL);
4295
4297 }
4298
4301 if (IsInParallelMode())
4304
4305 if (rmpredlock != NULL)
4306 {
4307 /*
4308 * Remove entry in local lock table if it exists. It's OK if it
4309 * doesn't exist; that means the lock was transferred to a new
4310 * target by a different backend.
4311 */
4314 HASH_REMOVE, NULL);
4315
4317 }
4318 }
4319}
4320
4321/*
4322 * CheckForSerializableConflictIn
4323 * We are writing the given tuple. If that indicates a rw-conflict
4324 * in from another serializable transaction, take appropriate action.
4325 *
4326 * Skip checking for any granularity for which a parameter is missing.
4327 *
4328 * A tuple update or delete is in conflict if we have a predicate lock
4329 * against the relation or page in which the tuple exists, or against the
4330 * tuple itself.
4331 */
4332void
4334{
4336
4337 if (!SerializationNeededForWrite(relation))
4338 return;
4339
4340 /* Check if someone else has already decided that we need to die */
4342 ereport(ERROR,
4344 errmsg("could not serialize access due to read/write dependencies among transactions"),
4345 errdetail_internal("Reason code: Canceled on identification as a pivot, during conflict in checking."),
4346 errhint("The transaction might succeed if retried.")));
4347
4348 /*
4349 * We're doing a write which might cause rw-conflicts now or later.
4350 * Memorize that fact.
4351 */
4352 MyXactDidWrite = true;
4353
4354 /*
4355 * It is important that we check for locks from the finest granularity to
4356 * the coarsest granularity, so that granularity promotion doesn't cause
4357 * us to miss a lock. The new (coarser) lock will be acquired before the
4358 * old (finer) locks are released.
4359 *
4360 * It is not possible to take and hold a lock across the checks for all
4361 * granularities because each target could be in a separate partition.
4362 */
4363 if (tid != NULL)
4364 {
4366 relation->rd_locator.dbOid,
4367 relation->rd_id,
4371 }
4372
4373 if (blkno != InvalidBlockNumber)
4374 {
4376 relation->rd_locator.dbOid,
4377 relation->rd_id,
4378 blkno);
4380 }
4381
4383 relation->rd_locator.dbOid,
4384 relation->rd_id);
4386}
4387
4388/*
4389 * CheckTableForSerializableConflictIn
4390 * The entire table is going through a DDL-style logical mass delete
4391 * like TRUNCATE or DROP TABLE. If that causes a rw-conflict in from
4392 * another serializable transaction, take appropriate action.
4393 *
4394 * While these operations do not operate entirely within the bounds of
4395 * snapshot isolation, they can occur inside a serializable transaction, and
4396 * will logically occur after any reads which saw rows which were destroyed
4397 * by these operations, so we do what we can to serialize properly under
4398 * SSI.
4399 *
4400 * The relation passed in must be a heap relation. Any predicate lock of any
4401 * granularity on the heap will cause a rw-conflict in to this transaction.
4402 * Predicate locks on indexes do not matter because they only exist to guard
4403 * against conflicting inserts into the index, and this is a mass *delete*.
4404 * When a table is truncated or dropped, the index will also be truncated
4405 * or dropped, and we'll deal with locks on the index when that happens.
4406 *
4407 * Dropping or truncating a table also needs to drop any existing predicate
4408 * locks on heap tuples or pages, because they're about to go away. This
4409 * should be done before altering the predicate locks because the transaction
4410 * could be rolled back because of a conflict, in which case the lock changes
4411 * are not needed. (At the moment, we don't actually bother to drop the
4412 * existing locks on a dropped or truncated table at the moment. That might
4413 * lead to some false positives, but it doesn't seem worth the trouble.)
4414 */
4415void
4417{
4419 PREDICATELOCKTARGET *target;
4420 Oid dbId;
4421 Oid heapId;
4422 int i;
4423
4424 /*
4425 * Bail out quickly if there are no serializable transactions running.
4426 * It's safe to check this without taking locks because the caller is
4427 * holding an ACCESS EXCLUSIVE lock on the relation. No new locks which
4428 * would matter here can be acquired while that is held.
4429 */
4431 return;
4432
4433 if (!SerializationNeededForWrite(relation))
4434 return;
4435
4436 /*
4437 * We're doing a write which might cause rw-conflicts now or later.
4438 * Memorize that fact.
4439 */
4440 MyXactDidWrite = true;
4441
4442 Assert(relation->rd_index == NULL); /* not an index relation */
4443
4444 dbId = relation->rd_locator.dbOid;
4445 heapId = relation->rd_id;
4446
4448 for (i = 0; i < NUM_PREDICATELOCK_PARTITIONS; i++)
4451
4452 /* Scan through target list */
4454
4455 while ((target = (PREDICATELOCKTARGET *) hash_seq_search(&seqstat)))
4456 {
4457 dlist_mutable_iter iter;
4458
4459 /*
4460 * Check whether this is a target which needs attention.
4461 */
4463 continue; /* wrong relation id */
4464 if (GET_PREDICATELOCKTARGETTAG_DB(target->tag) != dbId)
4465 continue; /* wrong database id */
4466
4467 /*
4468 * Loop through locks for this target and flag conflicts.
4469 */
4470 dlist_foreach_modify(iter, &target->predicateLocks)
4471 {
4473 dlist_container(PREDICATELOCK, targetLink, iter.cur);
4474
4475 if (predlock->tag.myXact != MySerializableXact
4477 {
4479 }
4480 }
4481 }
4482
4483 /* Release locks in reverse order */
4485 for (i = NUM_PREDICATELOCK_PARTITIONS - 1; i >= 0; i--)
4488}
4489
4490
4491/*
4492 * Flag a rw-dependency between two serializable transactions.
4493 *
4494 * The caller is responsible for ensuring that we have a LW lock on
4495 * the transaction hash table.
4496 */
4497static void
4499{
4500 Assert(reader != writer);
4501
4502 /* First, see if this conflict causes failure. */
4504
4505 /* Actually do the conflict flagging. */
4506 if (reader == OldCommittedSxact)
4508 else if (writer == OldCommittedSxact)
4510 else
4511 SetRWConflict(reader, writer);
4512}
4513
4514/*----------------------------------------------------------------------------
4515 * We are about to add a RW-edge to the dependency graph - check that we don't
4516 * introduce a dangerous structure by doing so, and abort one of the
4517 * transactions if so.
4518 *
4519 * A serialization failure can only occur if there is a dangerous structure
4520 * in the dependency graph:
4521 *
4522 * Tin ------> Tpivot ------> Tout
4523 * rw rw
4524 *
4525 * Furthermore, Tout must commit first.
4526 *
4527 * One more optimization is that if Tin is declared READ ONLY (or commits
4528 * without writing), we can only have a problem if Tout committed before Tin
4529 * acquired its snapshot.
4530 *----------------------------------------------------------------------------
4531 */
4532static void
4535{
4536 bool failure;
4537
4539
4540 failure = false;
4541
4542 /*------------------------------------------------------------------------
4543 * Check for already-committed writer with rw-conflict out flagged
4544 * (conflict-flag on W means that T2 committed before W):
4545 *
4546 * R ------> W ------> T2
4547 * rw rw
4548 *
4549 * That is a dangerous structure, so we must abort. (Since the writer
4550 * has already committed, we must be the reader)
4551 *------------------------------------------------------------------------
4552 */
4555 failure = true;
4556
4557 /*------------------------------------------------------------------------
4558 * Check whether the writer has become a pivot with an out-conflict
4559 * committed transaction (T2), and T2 committed first:
4560 *
4561 * R ------> W ------> T2
4562 * rw rw
4563 *
4564 * Because T2 must've committed first, there is no anomaly if:
4565 * - the reader committed before T2
4566 * - the writer committed before T2
4567 * - the reader is a READ ONLY transaction and the reader was concurrent
4568 * with T2 (= reader acquired its snapshot before T2 committed)
4569 *
4570 * We also handle the case that T2 is prepared but not yet committed
4571 * here. In that case T2 has already checked for conflicts, so if it
4572 * commits first, making the above conflict real, it's too late for it
4573 * to abort.
4574 *------------------------------------------------------------------------
4575 */
4577 failure = true;
4578 else if (!failure)
4579 {
4580 dlist_iter iter;
4581
4582 dlist_foreach(iter, &writer->outConflicts)
4583 {
4585 dlist_container(RWConflictData, outLink, iter.cur);
4586 SERIALIZABLEXACT *t2 = conflict->sxactIn;
4587
4588 if (SxactIsPrepared(t2)
4589 && (!SxactIsCommitted(reader)
4590 || t2->prepareSeqNo <= reader->commitSeqNo)
4592 || t2->prepareSeqNo <= writer->commitSeqNo)
4593 && (!SxactIsReadOnly(reader)
4594 || t2->prepareSeqNo <= reader->SeqNo.lastCommitBeforeSnapshot))
4595 {
4596 failure = true;
4597 break;
4598 }
4599 }
4600 }
4601
4602 /*------------------------------------------------------------------------
4603 * Check whether the reader has become a pivot with a writer
4604 * that's committed (or prepared):
4605 *
4606 * T0 ------> R ------> W
4607 * rw rw
4608 *
4609 * Because W must've committed first for an anomaly to occur, there is no
4610 * anomaly if:
4611 * - T0 committed before the writer
4612 * - T0 is READ ONLY, and overlaps the writer
4613 *------------------------------------------------------------------------
4614 */
4615 if (!failure && SxactIsPrepared(writer) && !SxactIsReadOnly(reader))
4616 {
4617 if (SxactHasSummaryConflictIn(reader))
4618 {
4619 failure = true;
4620 }
4621 else
4622 {
4623 dlist_iter iter;
4624
4625 /*
4626 * The unconstify is needed as we have no const version of
4627 * dlist_foreach().
4628 */
4629 dlist_foreach(iter, &unconstify(SERIALIZABLEXACT *, reader)->inConflicts)
4630 {
4631 const RWConflict conflict =
4632 dlist_container(RWConflictData, inLink, iter.cur);
4633 const SERIALIZABLEXACT *t0 = conflict->sxactOut;
4634
4635 if (!SxactIsDoomed(t0)
4636 && (!SxactIsCommitted(t0)
4637 || t0->commitSeqNo >= writer->prepareSeqNo)
4638 && (!SxactIsReadOnly(t0)
4639 || t0->SeqNo.lastCommitBeforeSnapshot >= writer->prepareSeqNo))
4640 {
4641 failure = true;
4642 break;
4643 }
4644 }
4645 }
4646 }
4647
4648 if (failure)
4649 {
4650 /*
4651 * We have to kill a transaction to avoid a possible anomaly from
4652 * occurring. If the writer is us, we can just ereport() to cause a
4653 * transaction abort. Otherwise we flag the writer for termination,
4654 * causing it to abort when it tries to commit. However, if the writer
4655 * is a prepared transaction, already prepared, we can't abort it
4656 * anymore, so we have to kill the reader instead.
4657 */
4659 {
4661 ereport(ERROR,
4663 errmsg("could not serialize access due to read/write dependencies among transactions"),
4664 errdetail_internal("Reason code: Canceled on identification as a pivot, during write."),
4665 errhint("The transaction might succeed if retried.")));
4666 }
4667 else if (SxactIsPrepared(writer))
4668 {
4670
4671 /* if we're not the writer, we have to be the reader */
4672 Assert(MySerializableXact == reader);
4673 ereport(ERROR,
4675 errmsg("could not serialize access due to read/write dependencies among transactions"),
4676 errdetail_internal("Reason code: Canceled on conflict out to pivot %u, during read.", writer->topXid),
4677 errhint("The transaction might succeed if retried.")));
4678 }
4679 writer->flags |= SXACT_FLAG_DOOMED;
4680 }
4681}
4682
4683/*
4684 * PreCommit_CheckForSerializationFailure
4685 * Check for dangerous structures in a serializable transaction
4686 * at commit.
4687 *
4688 * We're checking for a dangerous structure as each conflict is recorded.
4689 * The only way we could have a problem at commit is if this is the "out"
4690 * side of a pivot, and neither the "in" side nor the pivot has yet
4691 * committed.
4692 *
4693 * If a dangerous structure is found, the pivot (the near conflict) is
4694 * marked for death, because rolling back another transaction might mean
4695 * that we fail without ever making progress. This transaction is
4696 * committing writes, so letting it commit ensures progress. If we
4697 * canceled the far conflict, it might immediately fail again on retry.
4698 */
4699void
4701{
4703
4705 return;
4706
4708
4710
4711 /*
4712 * Check if someone else has already decided that we need to die. Since
4713 * we set our own DOOMED flag when partially releasing, ignore in that
4714 * case.
4715 */
4718 {
4720 ereport(ERROR,
4722 errmsg("could not serialize access due to read/write dependencies among transactions"),
4723 errdetail_internal("Reason code: Canceled on identification as a pivot, during commit attempt."),
4724 errhint("The transaction might succeed if retried.")));
4725 }
4726
4728 {
4731
4732 if (!SxactIsCommitted(nearConflict->sxactOut)
4733 && !SxactIsDoomed(nearConflict->sxactOut))
4734 {
4736
4737 dlist_foreach(far_iter, &nearConflict->sxactOut->inConflicts)
4738 {
4741
4742 if (farConflict->sxactOut == MySerializableXact
4743 || (!SxactIsCommitted(farConflict->sxactOut)
4744 && !SxactIsReadOnly(farConflict->sxactOut)
4745 && !SxactIsDoomed(farConflict->sxactOut)))
4746 {
4747 /*
4748 * Normally, we kill the pivot transaction to make sure we
4749 * make progress if the failing transaction is retried.
4750 * However, we can't kill it if it's already prepared, so
4751 * in that case we commit suicide instead.
4752 */
4753 if (SxactIsPrepared(nearConflict->sxactOut))
4754 {
4756 ereport(ERROR,
4758 errmsg("could not serialize access due to read/write dependencies among transactions"),
4759 errdetail_internal("Reason code: Canceled on commit attempt with conflict in from prepared pivot."),
4760 errhint("The transaction might succeed if retried.")));
4761 }
4762 nearConflict->sxactOut->flags |= SXACT_FLAG_DOOMED;
4763 break;
4764 }
4765 }
4766 }
4767 }
4768
4771
4773}
4774
4775/*------------------------------------------------------------------------*/
4776
4777/*
4778 * Two-phase commit support
4779 */
4780
4781/*
4782 * AtPrepare_Locks
4783 * Do the preparatory work for a PREPARE: make 2PC state file
4784 * records for all predicate locks currently held.
4785 */
4786void
4788{
4791 TwoPhasePredicateXactRecord *xactRecord;
4792 TwoPhasePredicateLockRecord *lockRecord;
4793 dlist_iter iter;
4794
4796 xactRecord = &(record.data.xactRecord);
4797 lockRecord = &(record.data.lockRecord);
4798
4800 return;
4801
4802 /* Generate an xact record for our SERIALIZABLEXACT */
4804 xactRecord->xmin = MySerializableXact->xmin;
4805 xactRecord->flags = MySerializableXact->flags;
4806
4807 /*
4808 * Note that we don't include the list of conflicts in our out in the
4809 * statefile, because new conflicts can be added even after the
4810 * transaction prepares. We'll just make a conservative assumption during
4811 * recovery instead.
4812 */
4813
4815 &record, sizeof(record));
4816
4817 /*
4818 * Generate a lock record for each lock.
4819 *
4820 * To do this, we need to walk the predicate lock list in our sxact rather
4821 * than using the local predicate lock table because the latter is not
4822 * guaranteed to be accurate.
4823 */
4825
4826 /*
4827 * No need to take sxact->perXactPredicateListLock in parallel mode
4828 * because there cannot be any parallel workers running while we are
4829 * preparing a transaction.
4830 */
4832
4833 dlist_foreach(iter, &sxact->predicateLocks)
4834 {
4836 dlist_container(PREDICATELOCK, xactLink, iter.cur);
4837
4839 lockRecord->target = predlock->tag.myTarget->tag;
4840
4842 &record, sizeof(record));
4843 }
4844
4846}
4847
4848/*
4849 * PostPrepare_Locks
4850 * Clean up after successful PREPARE. Unlike the non-predicate
4851 * lock manager, we do not need to transfer locks to a dummy
4852 * PGPROC because our SERIALIZABLEXACT will stay around
4853 * anyway. We only need to clean up our local state.
4854 */
4855void
4857{
4859 return;
4860
4862
4865
4868
4870 MyXactDidWrite = false;
4871}
4872
4873/*
4874 * PredicateLockTwoPhaseFinish
4875 * Release a prepared transaction's predicate locks once it
4876 * commits or aborts.
4877 */
4878void
4880{
4883
4885
4887 sxid = (SERIALIZABLEXID *)
4890
4891 /* xid will not be found if it wasn't a serializable transaction */
4892 if (sxid == NULL)
4893 return;
4894
4895 /* Release its locks */
4896 MySerializableXact = sxid->myXact;
4897 MyXactDidWrite = true; /* conservatively assume that we wrote
4898 * something */
4900}
4901
4902/*
4903 * Re-acquire a predicate lock belonging to a transaction that was prepared.
4904 */
4905void
4907 void *recdata, uint32 len)
4908{
4911
4913
4914 record = (TwoPhasePredicateRecord *) recdata;
4915
4917 (record->type == TWOPHASEPREDICATERECORD_LOCK));
4918
4919 if (record->type == TWOPHASEPREDICATERECORD_XACT)
4920 {
4921 /* Per-transaction record. Set up a SERIALIZABLEXACT. */
4922 TwoPhasePredicateXactRecord *xactRecord;
4926 bool found;
4927
4928 xactRecord = (TwoPhasePredicateXactRecord *) &record->data.xactRecord;
4929
4932 if (!sxact)
4933 ereport(ERROR,
4935 errmsg("out of shared memory")));
4936
4937 /* vxid for a prepared xact is INVALID_PROC_NUMBER/xid; no pid */
4938 sxact->vxid.procNumber = INVALID_PROC_NUMBER;
4939 sxact->vxid.localTransactionId = (LocalTransactionId) xid;
4940 sxact->pid = 0;
4941 sxact->pgprocno = INVALID_PROC_NUMBER;
4942
4943 /* a prepared xact hasn't committed yet */
4944 sxact->prepareSeqNo = RecoverySerCommitSeqNo;
4945 sxact->commitSeqNo = InvalidSerCommitSeqNo;
4946 sxact->finishedBefore = InvalidTransactionId;
4947
4948 sxact->SeqNo.lastCommitBeforeSnapshot = RecoverySerCommitSeqNo;
4949
4950 /*
4951 * Don't need to track this; no transactions running at the time the
4952 * recovered xact started are still active, except possibly other
4953 * prepared xacts and we don't care whether those are RO_SAFE or not.
4954 */
4955 dlist_init(&(sxact->possibleUnsafeConflicts));
4956
4957 dlist_init(&(sxact->predicateLocks));
4958 dlist_node_init(&sxact->finishedLink);
4959
4960 sxact->topXid = xid;
4961 sxact->xmin = xactRecord->xmin;
4962 sxact->flags = xactRecord->flags;
4964 if (!SxactIsReadOnly(sxact))
4965 {
4969 }
4970
4971 /*
4972 * We don't know whether the transaction had any conflicts or not, so
4973 * we'll conservatively assume that it had both a conflict in and a
4974 * conflict out, and represent that with the summary conflict flags.
4975 */
4976 dlist_init(&(sxact->outConflicts));
4977 dlist_init(&(sxact->inConflicts));
4980
4981 /* Register the transaction's xid */
4982 sxidtag.xid = xid;
4984 &sxidtag,
4985 HASH_ENTER, &found);
4986 Assert(sxid != NULL);
4987 Assert(!found);
4988 sxid->myXact = sxact;
4989
4990 /*
4991 * Update global xmin. Note that this is a special case compared to
4992 * registering a normal transaction, because the global xmin might go
4993 * backwards. That's OK, because until recovery is over we're not
4994 * going to complete any transactions or create any non-prepared
4995 * transactions, so there's no danger of throwing away.
4996 */
4999 {
5003 }
5005 {
5008 }
5009
5011 }
5012 else if (record->type == TWOPHASEPREDICATERECORD_LOCK)
5013 {
5014 /* Lock record. Recreate the PREDICATELOCK */
5015 TwoPhasePredicateLockRecord *lockRecord;
5020
5021 lockRecord = (TwoPhasePredicateLockRecord *) &record->data.lockRecord;
5023
5025 sxidtag.xid = xid;
5026 sxid = (SERIALIZABLEXID *)
5029
5030 Assert(sxid != NULL);
5031 sxact = sxid->myXact;
5033
5035 }
5036}
5037
5038/*
5039 * Prepare to share the current SERIALIZABLEXACT with parallel workers.
5040 * Return a handle object that can be used by AttachSerializableXact() in a
5041 * parallel worker.
5042 */
5045{
5046 return MySerializableXact;
5047}
5048
5049/*
5050 * Allow parallel workers to import the leader's SERIALIZABLEXACT.
5051 */
5052void
5054{
5055
5057
5061}
bool ParallelContextActive(void)
Definition parallel.c:1031
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:1234
#define PG_USED_FOR_ASSERTS_ONLY
Definition c.h:223
#define Assert(condition)
Definition c.h:873
int64_t int64
Definition c.h:543
uint16_t uint16
Definition c.h:545
uint32_t uint32
Definition c.h:546
uint32 LocalTransactionId
Definition c.h:668
uint32 TransactionId
Definition c.h:666
size_t Size
Definition c.h:619
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 errmsg_internal(const char *fmt,...)
Definition elog.c:1170
int errdetail_internal(const char *fmt,...)
Definition elog.c:1243
int errdetail(const char *fmt,...)
Definition elog.c:1216
int errhint(const char *fmt,...)
Definition elog.c:1330
int errcode(int sqlerrcode)
Definition elog.c:863
int errmsg(const char *fmt,...)
Definition elog.c:1080
#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:60
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:1911
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition lwlock.c:1176
bool LWLockHeldByMeInMode(LWLock *lock, LWLockMode mode)
Definition lwlock.c:1955
void LWLockRelease(LWLock *lock)
Definition lwlock.c:1793
void LWLockInitialize(LWLock *lock, int tranche_id)
Definition lwlock.c:698
@ 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
#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:1445
void CheckPointPredicate(void)
Definition predicate.c:1041
void PredicateLockPageSplit(Relation relation, BlockNumber oldblkno, BlockNumber newblkno)
Definition predicate.c:3142
static void DecrementParentLocks(const PREDICATELOCKTARGETTAG *targettag)
Definition predicate.c:2389
static HTAB * PredicateLockHash
Definition predicate.c:398
static void SetPossibleUnsafeConflict(SERIALIZABLEXACT *roXact, SERIALIZABLEXACT *activeXact)
Definition predicate.c:666
#define PredicateLockTargetTagHashCode(predicatelocktargettag)
Definition predicate.c:303
static void SetNewSxactGlobalXmin(void)
Definition predicate.c:3249
void CheckForSerializableConflictIn(Relation relation, const ItemPointerData *tid, BlockNumber blkno)
Definition predicate.c:4334
#define SerialPage(xid)
Definition predicate.c:343
static void ReleasePredXact(SERIALIZABLEXACT *sxact)
Definition predicate.c:596
void SetSerializableTransactionSnapshot(Snapshot snapshot, VirtualTransactionId *sourcevxid, int sourcepid)
Definition predicate.c:1720
static bool RWConflictExists(const SERIALIZABLEXACT *reader, const SERIALIZABLEXACT *writer)
Definition predicate.c:610
static bool PredicateLockingNeededForRelation(Relation relation)
Definition predicate.c:498
static bool SerializationNeededForRead(Relation relation, Snapshot snapshot)
Definition predicate.c:516
static Snapshot GetSafeSnapshot(Snapshot origSnapshot)
Definition predicate.c:1556
#define SxactIsCommitted(sxact)
Definition predicate.c:277
static SerialControl serialControl
Definition predicate.c:354
void PredicateLockPage(Relation relation, BlockNumber blkno, Snapshot snapshot)
Definition predicate.c:2597
#define SxactIsROUnsafe(sxact)
Definition predicate.c:292
static Snapshot GetSerializableTransactionSnapshotInt(Snapshot snapshot, VirtualTransactionId *sourcevxid, int sourcepid)
Definition predicate.c:1762
static LWLock * ScratchPartitionLock
Definition predicate.c:408
static void PredicateLockAcquire(const PREDICATELOCKTARGETTAG *targettag)
Definition predicate.c:2515
#define SxactIsDeferrableWaiting(sxact)
Definition predicate.c:290
static void ReleasePredicateLocksLocal(void)
Definition predicate.c:3677
static HTAB * LocalPredicateLockHash
Definition predicate.c:414
int max_predicate_locks_per_page
Definition predicate.c:373
struct SerialControlData * SerialControl
Definition predicate.c:352
static PredXactList PredXact
Definition predicate.c:384
static void SetRWConflict(SERIALIZABLEXACT *reader, SERIALIZABLEXACT *writer)
Definition predicate.c:643
int GetSafeSnapshotBlockingPids(int blocked_pid, int *output, int output_size)
Definition predicate.c:1626
static uint32 ScratchTargetTagHash
Definition predicate.c:407
static void RemoveTargetIfNoLongerUsed(PREDICATELOCKTARGET *target, uint32 targettaghash)
Definition predicate.c:2181
static uint32 predicatelock_hash(const void *key, Size keysize)
Definition predicate.c:1419
void CheckForSerializableConflictOut(Relation relation, TransactionId xid, Snapshot snapshot)
Definition predicate.c:4021
#define SxactIsReadOnly(sxact)
Definition predicate.c:281
#define SerialNextPage(page)
Definition predicate.c:337
static void DropAllPredicateLocksFromTable(Relation relation, bool transfer)
Definition predicate.c:2935
bool PageIsPredicateLocked(Relation relation, BlockNumber blkno)
Definition predicate.c:2006
static void CreatePredicateLock(const PREDICATELOCKTARGETTAG *targettag, uint32 targettaghash, SERIALIZABLEXACT *sxact)
Definition predicate.c:2451
static void SerialAdd(TransactionId xid, SerCommitSeqNo minConflictCommitSeqNo)
Definition predicate.c:858
static void ClearOldPredicateLocks(void)
Definition predicate.c:3695
#define SxactHasSummaryConflictIn(sxact)
Definition predicate.c:282
static SERIALIZABLEXACT * CreatePredXact(void)
Definition predicate.c:582
static bool GetParentPredicateLockTag(const PREDICATELOCKTARGETTAG *tag, PREDICATELOCKTARGETTAG *parent)
Definition predicate.c:2070
#define PredicateLockHashCodeFromTargetHashCode(predicatelocktag, targethash)
Definition predicate.c:316
static void RestoreScratchTarget(bool lockheld)
Definition predicate.c:2159
#define SerialValue(slotno, xid)
Definition predicate.c:339
static void DeleteChildTargetLocks(const PREDICATELOCKTARGETTAG *newtargettag)
Definition predicate.c:2212
static void DeleteLockTarget(PREDICATELOCKTARGET *target, uint32 targettaghash)
Definition predicate.c:2667
void PredicateLockTwoPhaseFinish(FullTransactionId fxid, bool isCommit)
Definition predicate.c:4880
void predicatelock_twophase_recover(FullTransactionId fxid, uint16 info, void *recdata, uint32 len)
Definition predicate.c:4907
static SERIALIZABLEXACT * OldCommittedSxact
Definition predicate.c:362
#define SxactHasConflictOut(sxact)
Definition predicate.c:289
static bool MyXactDidWrite
Definition predicate.c:422
static int MaxPredicateChildLocks(const PREDICATELOCKTARGETTAG *tag)
Definition predicate.c:2287
static void FlagSxactUnsafe(SERIALIZABLEXACT *sxact)
Definition predicate.c:699
static void SerialInit(void)
Definition predicate.c:806
void CheckTableForSerializableConflictIn(Relation relation)
Definition predicate.c:4417
#define SxactIsPrepared(sxact)
Definition predicate.c:278
void AttachSerializableXact(SerializableXactHandle handle)
Definition predicate.c:5054
SerializableXactHandle ShareSerializableXact(void)
Definition predicate.c:5045
static bool PredicateLockExists(const PREDICATELOCKTARGETTAG *targettag)
Definition predicate.c:2043
static void RemoveScratchTarget(bool lockheld)
Definition predicate.c:2138
#define SxactIsOnFinishedList(sxact)
Definition predicate.c:267
#define SxactIsPartiallyReleased(sxact)
Definition predicate.c:293
static void SerialSetActiveSerXmin(TransactionId xid)
Definition predicate.c:990
static dlist_head * FinishedSerializableTransactions
Definition predicate.c:399
static bool SerializationNeededForWrite(Relation relation)
Definition predicate.c:560
static HTAB * SerializableXidHash
Definition predicate.c:396
static bool CheckAndPromotePredicateLockRequest(const PREDICATELOCKTARGETTAG *reqtag)
Definition predicate.c:2324
void PredicateLockPageCombine(Relation relation, BlockNumber oldblkno, BlockNumber newblkno)
Definition predicate.c:3227
static bool SerialPagePrecedesLogically(int64 page1, int64 page2)
Definition predicate.c:731
static void CheckTargetForConflictsIn(PREDICATELOCKTARGETTAG *targettag)
Definition predicate.c:4164
int max_predicate_locks_per_relation
Definition predicate.c:372
#define SxactIsROSafe(sxact)
Definition predicate.c:291
void PreCommit_CheckForSerializationFailure(void)
Definition predicate.c:4701
void ReleasePredicateLocks(bool isCommit, bool isReadOnlySafe)
Definition predicate.c:3310
static void FlagRWConflict(SERIALIZABLEXACT *reader, SERIALIZABLEXACT *writer)
Definition predicate.c:4499
static const PREDICATELOCKTARGETTAG ScratchTargetTag
Definition predicate.c:406
#define PredicateLockHashPartitionLockByIndex(i)
Definition predicate.c:261
static void OnConflict_CheckForSerializationFailure(const SERIALIZABLEXACT *reader, SERIALIZABLEXACT *writer)
Definition predicate.c:4534
static bool CoarserLockCovers(const PREDICATELOCKTARGETTAG *newtargettag)
Definition predicate.c:2109
void PredicateLockRelation(Relation relation, Snapshot snapshot)
Definition predicate.c:2574
static SERIALIZABLEXACT * MySerializableXact
Definition predicate.c:421
void PredicateLockShmemInit(void)
Definition predicate.c:1145
void PredicateLockTID(Relation relation, const ItemPointerData *tid, Snapshot snapshot, TransactionId tuple_xid)
Definition predicate.c:2619
Size PredicateLockShmemSize(void)
Definition predicate.c:1357
#define SxactIsDoomed(sxact)
Definition predicate.c:280
#define NPREDICATELOCKTARGETENTS()
Definition predicate.c:264
static SerCommitSeqNo SerialGetMinConflictCommitSeqNo(TransactionId xid)
Definition predicate.c:949
static void SummarizeOldestCommittedSxact(void)
Definition predicate.c:1501
bool check_serial_buffers(int *newval, void **extra, GucSource source)
Definition predicate.c:847
void PostPrepare_PredicateLocks(FullTransactionId fxid)
Definition predicate.c:4857
#define TargetTagIsCoveredBy(covered_target, covering_target)
Definition predicate.c:233
static RWConflictPoolHeader RWConflictPool
Definition predicate.c:390
static void ReleaseRWConflict(RWConflict conflict)
Definition predicate.c:691
static bool TransferPredicateLocksToNewTarget(PREDICATELOCKTARGETTAG oldtargettag, PREDICATELOCKTARGETTAG newtargettag, bool removeOld)
Definition predicate.c:2728
void AtPrepare_PredicateLocks(void)
Definition predicate.c:4788
void RegisterPredicateLockingXid(TransactionId xid)
Definition predicate.c:1957
#define PredicateLockHashPartitionLock(hashcode)
Definition predicate.c:258
#define SERIAL_ENTRIESPERPAGE
Definition predicate.c:330
static bool XidIsConcurrent(TransactionId xid)
Definition predicate.c:3970
static void ReleaseOneSerializableXact(SERIALIZABLEXACT *sxact, bool partial, bool summarize)
Definition predicate.c:3833
static HTAB * PredicateLockTargetHash
Definition predicate.c:397
bool CheckForSerializableConflictOutNeeded(Relation relation, Snapshot snapshot)
Definition predicate.c:3989
#define SxactIsRolledBack(sxact)
Definition predicate.c:279
static SERIALIZABLEXACT * SavedSerializableXact
Definition predicate.c:431
#define SxactHasSummaryConflictOut(sxact)
Definition predicate.c:283
void TransferPredicateLocksToHeapRelation(Relation relation)
Definition predicate.c:3121
static void CreateLocalPredicateLockHash(void)
Definition predicate.c:1938
#define SerialSlruCtl
Definition predicate.c:326
int max_predicate_locks_per_xact
Definition predicate.c:371
Snapshot GetSerializableTransactionSnapshot(Snapshot snapshot)
Definition predicate.c:1680
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:2125
bool ProcArrayInstallImportedXmin(TransactionId xmin, VirtualTransactionId *sourcevxid)
Definition procarray.c:2482
#define INVALID_PROC_NUMBER
Definition procnumber.h:26
#define RelationUsesLocalBuffers(relation)
Definition rel.h:646
bool ShmemAddrIsValid(const void *addr)
Definition shmem.c:276
Size add_size(Size s1, Size s2)
Definition shmem.c:495
Size mul_size(Size s1, Size s2)
Definition shmem.c:510
HTAB * ShmemInitHash(const char *name, int64 init_size, int64 max_size, HASHCTL *infoP, int hash_flags)
Definition shmem.c:334
void * ShmemInitStruct(const char *name, Size size, bool *foundPtr)
Definition shmem.c:389
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:252
int SimpleLruReadPage_ReadOnly(SlruCtl ctl, int64 pageno, TransactionId xid)
Definition slru.c:630
void SimpleLruWriteAll(SlruCtl ctl, bool allow_redirtied)
Definition slru.c:1347
int SimpleLruReadPage(SlruCtl ctl, int64 pageno, bool write_ok, TransactionId xid)
Definition slru.c:527
int SimpleLruZeroPage(SlruCtl ctl, int64 pageno)
Definition slru.c:375
void SimpleLruTruncate(SlruCtl ctl, int64 cutoffPage)
Definition slru.c:1433
Size SimpleLruShmemSize(int nslots, int nlsns)
Definition slru.c:198
bool check_slru_buffers(const char *name, int *newval)
Definition slru.c:355
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:1992
PGPROC * MyProc
Definition proc.c:67
void ProcWaitForSignal(uint32 wait_event_info)
Definition proc.c:1980
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:179
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
union SERIALIZABLEXACT::@129 SeqNo
SerCommitSeqNo prepareSeqNo
SerCommitSeqNo commitSeqNo
TransactionId finishedBefore
SerCommitSeqNo earliestOutConflictCommit
TransactionId headXid
Definition predicate.c:348
TransactionId tailXid
Definition predicate.c:349
TransactionId xmin
Definition snapshot.h:153
FullTransactionId nextXid
Definition transam.h:220
PREDICATELOCKTARGETTAG target
TwoPhasePredicateRecordType type
union TwoPhasePredicateRecord::@130 data
TwoPhasePredicateLockRecord lockRecord
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:1271
int max_prepared_xacts
Definition twophase.c:116
#define TWOPHASE_RM_PREDICATELOCK_ID
TransamVariablesData * TransamVariables
Definition varsup.c:34
bool XactDeferrable
Definition xact.c:86
bool XactReadOnly
Definition xact.c:83
TransactionId GetTopTransactionIdIfAny(void)
Definition xact.c:442
bool IsSubTransaction(void)
Definition xact.c:5066
bool TransactionIdIsCurrentTransactionId(TransactionId xid)
Definition xact.c:942
bool IsInParallelMode(void)
Definition xact.c:1090
#define IsolationIsSerializable()
Definition xact.h:53
bool RecoveryInProgress(void)
Definition xlog.c:6460

◆ 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 316 of file predicate.c.

◆ PredicateLockHashPartition

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

Definition at line 256 of file predicate.c.

◆ PredicateLockHashPartitionLock

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

Definition at line 258 of file predicate.c.

◆ PredicateLockHashPartitionLockByIndex

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

Definition at line 261 of file predicate.c.

◆ PredicateLockTargetTagHashCode

Definition at line 303 of file predicate.c.

◆ SERIAL_ENTRIESPERPAGE

#define SERIAL_ENTRIESPERPAGE   (SERIAL_PAGESIZE / SERIAL_ENTRYSIZE)

Definition at line 330 of file predicate.c.

◆ SERIAL_ENTRYSIZE

#define SERIAL_ENTRYSIZE   sizeof(SerCommitSeqNo)

Definition at line 329 of file predicate.c.

◆ SERIAL_MAX_PAGE

#define SERIAL_MAX_PAGE   (MaxTransactionId / SERIAL_ENTRIESPERPAGE)

Definition at line 335 of file predicate.c.

◆ SERIAL_PAGESIZE

#define SERIAL_PAGESIZE   BLCKSZ

Definition at line 328 of file predicate.c.

◆ SerialNextPage

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

Definition at line 337 of file predicate.c.

◆ SerialPage

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

Definition at line 343 of file predicate.c.

◆ SerialSlruCtl

#define SerialSlruCtl   (&SerialSlruCtlData)

Definition at line 326 of file predicate.c.

◆ SerialValue

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

Definition at line 339 of file predicate.c.

◆ SxactHasConflictOut

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

Definition at line 289 of file predicate.c.

◆ SxactHasSummaryConflictIn

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

Definition at line 282 of file predicate.c.

◆ SxactHasSummaryConflictOut

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

Definition at line 283 of file predicate.c.

◆ SxactIsCommitted

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

Definition at line 277 of file predicate.c.

◆ SxactIsDeferrableWaiting

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

Definition at line 290 of file predicate.c.

◆ SxactIsDoomed

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

Definition at line 280 of file predicate.c.

◆ SxactIsOnFinishedList

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

Definition at line 267 of file predicate.c.

◆ SxactIsPartiallyReleased

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

Definition at line 293 of file predicate.c.

◆ SxactIsPrepared

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

Definition at line 278 of file predicate.c.

◆ SxactIsReadOnly

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

Definition at line 281 of file predicate.c.

◆ SxactIsRolledBack

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

Definition at line 279 of file predicate.c.

◆ SxactIsROSafe

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

Definition at line 291 of file predicate.c.

◆ SxactIsROUnsafe

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

Definition at line 292 of file predicate.c.

◆ TargetTagIsCoveredBy

Typedef Documentation

◆ SerialControl

◆ SerialControlData

Function Documentation

◆ AtPrepare_PredicateLocks()

void AtPrepare_PredicateLocks ( void  )

Definition at line 4788 of file predicate.c.

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}

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 847 of file predicate.c.

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

References check_slru_buffers(), and newval.

◆ CheckAndPromotePredicateLockRequest()

static bool CheckAndPromotePredicateLockRequest ( const PREDICATELOCKTARGETTAG reqtag)
static

Definition at line 2324 of file predicate.c.

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}

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 4334 of file predicate.c.

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}

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 4021 of file predicate.c.

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}

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 3989 of file predicate.c.

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}

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 1041 of file predicate.c.

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}

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 4417 of file predicate.c.

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}

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 4164 of file predicate.c.

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}

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 3695 of file predicate.c.

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}

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 2109 of file predicate.c.

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}

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

Referenced by PredicateLockAcquire().

◆ CreateLocalPredicateLockHash()

static void CreateLocalPredicateLockHash ( void  )
static

Definition at line 1938 of file predicate.c.

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}

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 2451 of file predicate.c.

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}

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 2389 of file predicate.c.

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}

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 2212 of file predicate.c.

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}

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 2935 of file predicate.c.

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}

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 4499 of file predicate.c.

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}

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 699 of file predicate.c.

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}

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 2070 of file predicate.c.

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}

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 1445 of file predicate.c.

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}

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 1556 of file predicate.c.

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}

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 1626 of file predicate.c.

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}

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 1680 of file predicate.c.

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}

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 1762 of file predicate.c.

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}

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 2287 of file predicate.c.

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}

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 4534 of file predicate.c.

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}

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 4701 of file predicate.c.

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}

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 1419 of file predicate.c.

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}

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 4907 of file predicate.c.

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;
5023 targettaghash = PredicateLockTargetTagHashCode(&lockRecord->target);
5024
5026 sxidtag.xid = xid;
5027 sxid = (SERIALIZABLEXID *)
5030
5031 Assert(sxid != NULL);
5032 sxact = sxid->myXact;
5034
5035 CreatePredicateLock(&lockRecord->target, targettaghash, sxact);
5036 }
5037}

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 2515 of file predicate.c.

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}

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 2043 of file predicate.c.

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}

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 3227 of file predicate.c.

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}

References fb(), and PredicateLockPageSplit().

Referenced by _bt_mark_page_halfdead(), and ginDeletePage().

◆ PredicateLockPageSplit()

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

Definition at line 3142 of file predicate.c.

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}

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 1145 of file predicate.c.

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}

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 1357 of file predicate.c.

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}

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 2619 of file predicate.c.

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}

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 4880 of file predicate.c.

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}

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 1957 of file predicate.c.

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}

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 3833 of file predicate.c.

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}

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 3310 of file predicate.c.

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}

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 3677 of file predicate.c.

3678{
3680 MyXactDidWrite = false;
3681
3682 /* Delete per-transaction lock table */
3684 {
3687 }
3688}

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 610 of file predicate.c.

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}

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 858 of file predicate.c.

859{
860 TransactionId tailXid;
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 */
885 tailXid = serialControl->tailXid;
886 if (!TransactionIdIsValid(tailXid) || TransactionIdPrecedes(xid, tailXid))
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 {
900 firstZeroPage = SerialPage(tailXid);
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}

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 949 of file predicate.c.

950{
951 TransactionId headXid;
952 TransactionId tailXid;
954 int slotno;
955
957
959 headXid = serialControl->headXid;
960 tailXid = serialControl->tailXid;
962
963 if (!TransactionIdIsValid(headXid))
964 return 0;
965
967
968 if (TransactionIdPrecedes(xid, tailXid)
969 || TransactionIdFollows(xid, headXid))
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}

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 806 of file predicate.c.

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}

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 516 of file predicate.c.

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}

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 560 of file predicate.c.

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}

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 990 of file predicate.c.

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}

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 666 of file predicate.c.

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}

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 643 of file predicate.c.

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}

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 1720 of file predicate.c.

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}

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

Referenced by SetTransactionSnapshot().

◆ ShareSerializableXact()

SerializableXactHandle ShareSerializableXact ( void  )

Definition at line 5045 of file predicate.c.

5046{
5047 return MySerializableXact;
5048}

References MySerializableXact.

Referenced by InitializeParallelDSM().

◆ SummarizeOldestCommittedSxact()

static void SummarizeOldestCommittedSxact ( void  )
static

Definition at line 1501 of file predicate.c.

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}

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 2728 of file predicate.c.

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}

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 3970 of file predicate.c.

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}

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 373 of file predicate.c.

Referenced by MaxPredicateChildLocks().

◆ max_predicate_locks_per_relation

int max_predicate_locks_per_relation

Definition at line 372 of file predicate.c.

Referenced by MaxPredicateChildLocks().

◆ max_predicate_locks_per_xact

int max_predicate_locks_per_xact

Definition at line 371 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 431 of file predicate.c.

Referenced by ReleasePredicateLocks().

◆ ScratchPartitionLock

LWLock* ScratchPartitionLock
static

Definition at line 408 of file predicate.c.

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

◆ ScratchTargetTag

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

Definition at line 406 of file predicate.c.

406{0, 0, 0, 0};

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

◆ ScratchTargetTagHash

uint32 ScratchTargetTagHash
static

Definition at line 407 of file predicate.c.

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

◆ serialControl

◆ SerializableXidHash

◆ SerialSlruCtlData

SlruCtlData SerialSlruCtlData
static

Definition at line 324 of file predicate.c.