Age Owner TLA Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * predicate.c
4 : * POSTGRES predicate locking
5 : * to support full serializable transaction isolation
6 : *
7 : *
8 : * The approach taken is to implement Serializable Snapshot Isolation (SSI)
9 : * as initially described in this paper:
10 : *
11 : * Michael J. Cahill, Uwe Röhm, and Alan D. Fekete. 2008.
12 : * Serializable isolation for snapshot databases.
13 : * In SIGMOD '08: Proceedings of the 2008 ACM SIGMOD
14 : * international conference on Management of data,
15 : * pages 729-738, New York, NY, USA. ACM.
16 : * http://doi.acm.org/10.1145/1376616.1376690
17 : *
18 : * and further elaborated in Cahill's doctoral thesis:
19 : *
20 : * Michael James Cahill. 2009.
21 : * Serializable Isolation for Snapshot Databases.
22 : * Sydney Digital Theses.
23 : * University of Sydney, School of Information Technologies.
24 : * http://hdl.handle.net/2123/5353
25 : *
26 : *
27 : * Predicate locks for Serializable Snapshot Isolation (SSI) are SIREAD
28 : * locks, which are so different from normal locks that a distinct set of
29 : * structures is required to handle them. They are needed to detect
30 : * rw-conflicts when the read happens before the write. (When the write
31 : * occurs first, the reading transaction can check for a conflict by
32 : * examining the MVCC data.)
33 : *
34 : * (1) Besides tuples actually read, they must cover ranges of tuples
35 : * which would have been read based on the predicate. This will
36 : * require modelling the predicates through locks against database
37 : * objects such as pages, index ranges, or entire tables.
38 : *
39 : * (2) They must be kept in RAM for quick access. Because of this, it
40 : * isn't possible to always maintain tuple-level granularity -- when
41 : * the space allocated to store these approaches exhaustion, a
42 : * request for a lock may need to scan for situations where a single
43 : * transaction holds many fine-grained locks which can be coalesced
44 : * into a single coarser-grained lock.
45 : *
46 : * (3) They never block anything; they are more like flags than locks
47 : * in that regard; although they refer to database objects and are
48 : * used to identify rw-conflicts with normal write locks.
49 : *
50 : * (4) While they are associated with a transaction, they must survive
51 : * a successful COMMIT of that transaction, and remain until all
52 : * overlapping transactions complete. This even means that they
53 : * must survive termination of the transaction's process. If a
54 : * top level transaction is rolled back, however, it is immediately
55 : * flagged so that it can be ignored, and its SIREAD locks can be
56 : * released any time after that.
57 : *
58 : * (5) The only transactions which create SIREAD locks or check for
59 : * conflicts with them are serializable transactions.
60 : *
61 : * (6) When a write lock for a top level transaction is found to cover
62 : * an existing SIREAD lock for the same transaction, the SIREAD lock
63 : * can be deleted.
64 : *
65 : * (7) A write from a serializable transaction must ensure that an xact
66 : * record exists for the transaction, with the same lifespan (until
67 : * all concurrent transaction complete or the transaction is rolled
68 : * back) so that rw-dependencies to that transaction can be
69 : * detected.
70 : *
71 : * We use an optimization for read-only transactions. Under certain
72 : * circumstances, a read-only transaction's snapshot can be shown to
73 : * never have conflicts with other transactions. This is referred to
74 : * as a "safe" snapshot (and one known not to be is "unsafe").
75 : * However, it can't be determined whether a snapshot is safe until
76 : * all concurrent read/write transactions complete.
77 : *
78 : * Once a read-only transaction is known to have a safe snapshot, it
79 : * can release its predicate locks and exempt itself from further
80 : * predicate lock tracking. READ ONLY DEFERRABLE transactions run only
81 : * on safe snapshots, waiting as necessary for one to be available.
82 : *
83 : *
84 : * Lightweight locks to manage access to the predicate locking shared
85 : * memory objects must be taken in this order, and should be released in
86 : * reverse order:
87 : *
88 : * SerializableFinishedListLock
89 : * - Protects the list of transactions which have completed but which
90 : * may yet matter because they overlap still-active transactions.
91 : *
92 : * SerializablePredicateListLock
93 : * - Protects the linked list of locks held by a transaction. Note
94 : * that the locks themselves are also covered by the partition
95 : * locks of their respective lock targets; this lock only affects
96 : * the linked list connecting the locks related to a transaction.
97 : * - All transactions share this single lock (with no partitioning).
98 : * - There is never a need for a process other than the one running
99 : * an active transaction to walk the list of locks held by that
100 : * transaction, except parallel query workers sharing the leader's
101 : * transaction. In the parallel case, an extra per-sxact lock is
102 : * taken; see below.
103 : * - It is relatively infrequent that another process needs to
104 : * modify the list for a transaction, but it does happen for such
105 : * things as index page splits for pages with predicate locks and
106 : * freeing of predicate locked pages by a vacuum process. When
107 : * removing a lock in such cases, the lock itself contains the
108 : * pointers needed to remove it from the list. When adding a
109 : * lock in such cases, the lock can be added using the anchor in
110 : * the transaction structure. Neither requires walking the list.
111 : * - Cleaning up the list for a terminated transaction is sometimes
112 : * not done on a retail basis, in which case no lock is required.
113 : * - Due to the above, a process accessing its active transaction's
114 : * list always uses a shared lock, regardless of whether it is
115 : * walking or maintaining the list. This improves concurrency
116 : * for the common access patterns.
117 : * - A process which needs to alter the list of a transaction other
118 : * than its own active transaction must acquire an exclusive
119 : * lock.
120 : *
121 : * SERIALIZABLEXACT's member 'perXactPredicateListLock'
122 : * - Protects the linked list of predicate locks held by a transaction.
123 : * Only needed for parallel mode, where multiple backends share the
124 : * same SERIALIZABLEXACT object. Not needed if
125 : * SerializablePredicateListLock is held exclusively.
126 : *
127 : * PredicateLockHashPartitionLock(hashcode)
128 : * - The same lock protects a target, all locks on that target, and
129 : * the linked list of locks on the target.
130 : * - When more than one is needed, acquire in ascending address order.
131 : * - When all are needed (rare), acquire in ascending index order with
132 : * PredicateLockHashPartitionLockByIndex(index).
133 : *
134 : * SerializableXactHashLock
135 : * - Protects both PredXact and SerializableXidHash.
136 : *
137 : *
138 : * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
139 : * Portions Copyright (c) 1994, Regents of the University of California
140 : *
141 : *
142 : * IDENTIFICATION
143 : * src/backend/storage/lmgr/predicate.c
144 : *
145 : *-------------------------------------------------------------------------
146 : */
147 : /*
148 : * INTERFACE ROUTINES
149 : *
150 : * housekeeping for setting up shared memory predicate lock structures
151 : * InitPredicateLocks(void)
152 : * PredicateLockShmemSize(void)
153 : *
154 : * predicate lock reporting
155 : * GetPredicateLockStatusData(void)
156 : * PageIsPredicateLocked(Relation relation, BlockNumber blkno)
157 : *
158 : * predicate lock maintenance
159 : * GetSerializableTransactionSnapshot(Snapshot snapshot)
160 : * SetSerializableTransactionSnapshot(Snapshot snapshot,
161 : * VirtualTransactionId *sourcevxid)
162 : * RegisterPredicateLockingXid(void)
163 : * PredicateLockRelation(Relation relation, Snapshot snapshot)
164 : * PredicateLockPage(Relation relation, BlockNumber blkno,
165 : * Snapshot snapshot)
166 : * PredicateLockTID(Relation relation, ItemPointer tid, Snapshot snapshot,
167 : * TransactionId insert_xid)
168 : * PredicateLockPageSplit(Relation relation, BlockNumber oldblkno,
169 : * BlockNumber newblkno)
170 : * PredicateLockPageCombine(Relation relation, BlockNumber oldblkno,
171 : * BlockNumber newblkno)
172 : * TransferPredicateLocksToHeapRelation(Relation relation)
173 : * ReleasePredicateLocks(bool isCommit, bool isReadOnlySafe)
174 : *
175 : * conflict detection (may also trigger rollback)
176 : * CheckForSerializableConflictOut(Relation relation, TransactionId xid,
177 : * Snapshot snapshot)
178 : * CheckForSerializableConflictIn(Relation relation, ItemPointer tid,
179 : * BlockNumber blkno)
180 : * CheckTableForSerializableConflictIn(Relation relation)
181 : *
182 : * final rollback checking
183 : * PreCommit_CheckForSerializationFailure(void)
184 : *
185 : * two-phase commit support
186 : * AtPrepare_PredicateLocks(void);
187 : * PostPrepare_PredicateLocks(TransactionId xid);
188 : * PredicateLockTwoPhaseFinish(TransactionId xid, bool isCommit);
189 : * predicatelock_twophase_recover(TransactionId xid, uint16 info,
190 : * void *recdata, uint32 len);
191 : */
192 :
193 : #include "postgres.h"
194 :
195 : #include "access/parallel.h"
196 : #include "access/slru.h"
197 : #include "access/subtrans.h"
198 : #include "access/transam.h"
199 : #include "access/twophase.h"
200 : #include "access/twophase_rmgr.h"
201 : #include "access/xact.h"
202 : #include "access/xlog.h"
203 : #include "miscadmin.h"
204 : #include "pgstat.h"
205 : #include "port/pg_lfind.h"
206 : #include "storage/bufmgr.h"
207 : #include "storage/predicate.h"
208 : #include "storage/predicate_internals.h"
209 : #include "storage/proc.h"
210 : #include "storage/procarray.h"
211 : #include "utils/rel.h"
212 : #include "utils/snapmgr.h"
213 :
214 : /* Uncomment the next line to test the graceful degradation code. */
215 : /* #define TEST_SUMMARIZE_SERIAL */
216 :
217 : /*
218 : * Test the most selective fields first, for performance.
219 : *
220 : * a is covered by b if all of the following hold:
221 : * 1) a.database = b.database
222 : * 2) a.relation = b.relation
223 : * 3) b.offset is invalid (b is page-granularity or higher)
224 : * 4) either of the following:
225 : * 4a) a.offset is valid (a is tuple-granularity) and a.page = b.page
226 : * or 4b) a.offset is invalid and b.page is invalid (a is
227 : * page-granularity and b is relation-granularity
228 : */
229 : #define TargetTagIsCoveredBy(covered_target, covering_target) \
230 : ((GET_PREDICATELOCKTARGETTAG_RELATION(covered_target) == /* (2) */ \
231 : GET_PREDICATELOCKTARGETTAG_RELATION(covering_target)) \
232 : && (GET_PREDICATELOCKTARGETTAG_OFFSET(covering_target) == \
233 : InvalidOffsetNumber) /* (3) */ \
234 : && (((GET_PREDICATELOCKTARGETTAG_OFFSET(covered_target) != \
235 : InvalidOffsetNumber) /* (4a) */ \
236 : && (GET_PREDICATELOCKTARGETTAG_PAGE(covering_target) == \
237 : GET_PREDICATELOCKTARGETTAG_PAGE(covered_target))) \
238 : || ((GET_PREDICATELOCKTARGETTAG_PAGE(covering_target) == \
239 : InvalidBlockNumber) /* (4b) */ \
240 : && (GET_PREDICATELOCKTARGETTAG_PAGE(covered_target) \
241 : != InvalidBlockNumber))) \
242 : && (GET_PREDICATELOCKTARGETTAG_DB(covered_target) == /* (1) */ \
243 : GET_PREDICATELOCKTARGETTAG_DB(covering_target)))
244 :
245 : /*
246 : * The predicate locking target and lock shared hash tables are partitioned to
247 : * reduce contention. To determine which partition a given target belongs to,
248 : * compute the tag's hash code with PredicateLockTargetTagHashCode(), then
249 : * apply one of these macros.
250 : * NB: NUM_PREDICATELOCK_PARTITIONS must be a power of 2!
251 : */
252 : #define PredicateLockHashPartition(hashcode) \
253 : ((hashcode) % NUM_PREDICATELOCK_PARTITIONS)
254 : #define PredicateLockHashPartitionLock(hashcode) \
255 : (&MainLWLockArray[PREDICATELOCK_MANAGER_LWLOCK_OFFSET + \
256 : PredicateLockHashPartition(hashcode)].lock)
257 : #define PredicateLockHashPartitionLockByIndex(i) \
258 : (&MainLWLockArray[PREDICATELOCK_MANAGER_LWLOCK_OFFSET + (i)].lock)
259 :
260 : #define NPREDICATELOCKTARGETENTS() \
261 : mul_size(max_predicate_locks_per_xact, add_size(MaxBackends, max_prepared_xacts))
262 :
263 : #define SxactIsOnFinishedList(sxact) (!dlist_node_is_detached(&(sxact)->finishedLink))
264 :
265 : /*
266 : * Note that a sxact is marked "prepared" once it has passed
267 : * PreCommit_CheckForSerializationFailure, even if it isn't using
268 : * 2PC. This is the point at which it can no longer be aborted.
269 : *
270 : * The PREPARED flag remains set after commit, so SxactIsCommitted
271 : * implies SxactIsPrepared.
272 : */
273 : #define SxactIsCommitted(sxact) (((sxact)->flags & SXACT_FLAG_COMMITTED) != 0)
274 : #define SxactIsPrepared(sxact) (((sxact)->flags & SXACT_FLAG_PREPARED) != 0)
275 : #define SxactIsRolledBack(sxact) (((sxact)->flags & SXACT_FLAG_ROLLED_BACK) != 0)
276 : #define SxactIsDoomed(sxact) (((sxact)->flags & SXACT_FLAG_DOOMED) != 0)
277 : #define SxactIsReadOnly(sxact) (((sxact)->flags & SXACT_FLAG_READ_ONLY) != 0)
278 : #define SxactHasSummaryConflictIn(sxact) (((sxact)->flags & SXACT_FLAG_SUMMARY_CONFLICT_IN) != 0)
279 : #define SxactHasSummaryConflictOut(sxact) (((sxact)->flags & SXACT_FLAG_SUMMARY_CONFLICT_OUT) != 0)
280 : /*
281 : * The following macro actually means that the specified transaction has a
282 : * conflict out *to a transaction which committed ahead of it*. It's hard
283 : * to get that into a name of a reasonable length.
284 : */
285 : #define SxactHasConflictOut(sxact) (((sxact)->flags & SXACT_FLAG_CONFLICT_OUT) != 0)
286 : #define SxactIsDeferrableWaiting(sxact) (((sxact)->flags & SXACT_FLAG_DEFERRABLE_WAITING) != 0)
287 : #define SxactIsROSafe(sxact) (((sxact)->flags & SXACT_FLAG_RO_SAFE) != 0)
288 : #define SxactIsROUnsafe(sxact) (((sxact)->flags & SXACT_FLAG_RO_UNSAFE) != 0)
289 : #define SxactIsPartiallyReleased(sxact) (((sxact)->flags & SXACT_FLAG_PARTIALLY_RELEASED) != 0)
290 :
291 : /*
292 : * Compute the hash code associated with a PREDICATELOCKTARGETTAG.
293 : *
294 : * To avoid unnecessary recomputations of the hash code, we try to do this
295 : * just once per function, and then pass it around as needed. Aside from
296 : * passing the hashcode to hash_search_with_hash_value(), we can extract
297 : * the lock partition number from the hashcode.
298 : */
299 : #define PredicateLockTargetTagHashCode(predicatelocktargettag) \
300 : get_hash_value(PredicateLockTargetHash, predicatelocktargettag)
301 :
302 : /*
303 : * Given a predicate lock tag, and the hash for its target,
304 : * compute the lock hash.
305 : *
306 : * To make the hash code also depend on the transaction, we xor the sxid
307 : * struct's address into the hash code, left-shifted so that the
308 : * partition-number bits don't change. Since this is only a hash, we
309 : * don't care if we lose high-order bits of the address; use an
310 : * intermediate variable to suppress cast-pointer-to-int warnings.
311 : */
312 : #define PredicateLockHashCodeFromTargetHashCode(predicatelocktag, targethash) \
313 : ((targethash) ^ ((uint32) PointerGetDatum((predicatelocktag)->myXact)) \
314 : << LOG2_NUM_PREDICATELOCK_PARTITIONS)
315 :
316 :
317 : /*
318 : * The SLRU buffer area through which we access the old xids.
319 : */
320 : static SlruCtlData SerialSlruCtlData;
321 :
322 : #define SerialSlruCtl (&SerialSlruCtlData)
323 :
324 : #define SERIAL_PAGESIZE BLCKSZ
325 : #define SERIAL_ENTRYSIZE sizeof(SerCommitSeqNo)
326 : #define SERIAL_ENTRIESPERPAGE (SERIAL_PAGESIZE / SERIAL_ENTRYSIZE)
327 :
328 : /*
329 : * Set maximum pages based on the number needed to track all transactions.
330 : */
331 : #define SERIAL_MAX_PAGE (MaxTransactionId / SERIAL_ENTRIESPERPAGE)
332 :
333 : #define SerialNextPage(page) (((page) >= SERIAL_MAX_PAGE) ? 0 : (page) + 1)
334 :
335 : #define SerialValue(slotno, xid) (*((SerCommitSeqNo *) \
336 : (SerialSlruCtl->shared->page_buffer[slotno] + \
337 : ((((uint32) (xid)) % SERIAL_ENTRIESPERPAGE) * SERIAL_ENTRYSIZE))))
338 :
339 : #define SerialPage(xid) (((uint32) (xid)) / SERIAL_ENTRIESPERPAGE)
340 :
341 : typedef struct SerialControlData
342 : {
343 : int headPage; /* newest initialized page */
344 : TransactionId headXid; /* newest valid Xid in the SLRU */
345 : TransactionId tailXid; /* oldest xmin we might be interested in */
346 : } SerialControlData;
347 :
348 : typedef struct SerialControlData *SerialControl;
349 :
350 : static SerialControl serialControl;
351 :
352 : /*
353 : * When the oldest committed transaction on the "finished" list is moved to
354 : * SLRU, its predicate locks will be moved to this "dummy" transaction,
355 : * collapsing duplicate targets. When a duplicate is found, the later
356 : * commitSeqNo is used.
357 : */
358 : static SERIALIZABLEXACT *OldCommittedSxact;
359 :
360 :
361 : /*
362 : * These configuration variables are used to set the predicate lock table size
363 : * and to control promotion of predicate locks to coarser granularity in an
364 : * attempt to degrade performance (mostly as false positive serialization
365 : * failure) gracefully in the face of memory pressure.
366 : */
367 : int max_predicate_locks_per_xact; /* in guc_tables.c */
368 : int max_predicate_locks_per_relation; /* in guc_tables.c */
369 : int max_predicate_locks_per_page; /* in guc_tables.c */
370 :
371 : /*
372 : * This provides a list of objects in order to track transactions
373 : * participating in predicate locking. Entries in the list are fixed size,
374 : * and reside in shared memory. The memory address of an entry must remain
375 : * fixed during its lifetime. The list will be protected from concurrent
376 : * update externally; no provision is made in this code to manage that. The
377 : * number of entries in the list, and the size allowed for each entry is
378 : * fixed upon creation.
379 : */
380 : static PredXactList PredXact;
381 :
382 : /*
383 : * This provides a pool of RWConflict data elements to use in conflict lists
384 : * between transactions.
385 : */
386 : static RWConflictPoolHeader RWConflictPool;
387 :
388 : /*
389 : * The predicate locking hash tables are in shared memory.
390 : * Each backend keeps pointers to them.
391 : */
392 : static HTAB *SerializableXidHash;
393 : static HTAB *PredicateLockTargetHash;
394 : static HTAB *PredicateLockHash;
395 : static dlist_head *FinishedSerializableTransactions;
396 :
397 : /*
398 : * Tag for a dummy entry in PredicateLockTargetHash. By temporarily removing
399 : * this entry, you can ensure that there's enough scratch space available for
400 : * inserting one entry in the hash table. This is an otherwise-invalid tag.
401 : */
402 : static const PREDICATELOCKTARGETTAG ScratchTargetTag = {0, 0, 0, 0};
403 : static uint32 ScratchTargetTagHash;
404 : static LWLock *ScratchPartitionLock;
405 :
406 : /*
407 : * The local hash table used to determine when to combine multiple fine-
408 : * grained locks into a single courser-grained lock.
409 : */
410 : static HTAB *LocalPredicateLockHash = NULL;
411 :
412 : /*
413 : * Keep a pointer to the currently-running serializable transaction (if any)
414 : * for quick reference. Also, remember if we have written anything that could
415 : * cause a rw-conflict.
416 : */
417 : static SERIALIZABLEXACT *MySerializableXact = InvalidSerializableXact;
418 : static bool MyXactDidWrite = false;
419 :
420 : /*
421 : * The SXACT_FLAG_RO_UNSAFE optimization might lead us to release
422 : * MySerializableXact early. If that happens in a parallel query, the leader
423 : * needs to defer the destruction of the SERIALIZABLEXACT until end of
424 : * transaction, because the workers still have a reference to it. In that
425 : * case, the leader stores it here.
426 : */
427 : static SERIALIZABLEXACT *SavedSerializableXact = InvalidSerializableXact;
428 :
429 : /* local functions */
430 :
431 : static SERIALIZABLEXACT *CreatePredXact(void);
432 : static void ReleasePredXact(SERIALIZABLEXACT *sxact);
433 :
434 : static bool RWConflictExists(const SERIALIZABLEXACT *reader, const SERIALIZABLEXACT *writer);
435 : static void SetRWConflict(SERIALIZABLEXACT *reader, SERIALIZABLEXACT *writer);
436 : static void SetPossibleUnsafeConflict(SERIALIZABLEXACT *roXact, SERIALIZABLEXACT *activeXact);
437 : static void ReleaseRWConflict(RWConflict conflict);
438 : static void FlagSxactUnsafe(SERIALIZABLEXACT *sxact);
439 :
440 : static bool SerialPagePrecedesLogically(int page1, int page2);
441 : static void SerialInit(void);
442 : static void SerialAdd(TransactionId xid, SerCommitSeqNo minConflictCommitSeqNo);
443 : static SerCommitSeqNo SerialGetMinConflictCommitSeqNo(TransactionId xid);
444 : static void SerialSetActiveSerXmin(TransactionId xid);
445 :
446 : static uint32 predicatelock_hash(const void *key, Size keysize);
447 : static void SummarizeOldestCommittedSxact(void);
448 : static Snapshot GetSafeSnapshot(Snapshot origSnapshot);
449 : static Snapshot GetSerializableTransactionSnapshotInt(Snapshot snapshot,
450 : VirtualTransactionId *sourcevxid,
451 : int sourcepid);
452 : static bool PredicateLockExists(const PREDICATELOCKTARGETTAG *targettag);
453 : static bool GetParentPredicateLockTag(const PREDICATELOCKTARGETTAG *tag,
454 : PREDICATELOCKTARGETTAG *parent);
455 : static bool CoarserLockCovers(const PREDICATELOCKTARGETTAG *newtargettag);
456 : static void RemoveScratchTarget(bool lockheld);
457 : static void RestoreScratchTarget(bool lockheld);
458 : static void RemoveTargetIfNoLongerUsed(PREDICATELOCKTARGET *target,
459 : uint32 targettaghash);
460 : static void DeleteChildTargetLocks(const PREDICATELOCKTARGETTAG *newtargettag);
461 : static int MaxPredicateChildLocks(const PREDICATELOCKTARGETTAG *tag);
462 : static bool CheckAndPromotePredicateLockRequest(const PREDICATELOCKTARGETTAG *reqtag);
463 : static void DecrementParentLocks(const PREDICATELOCKTARGETTAG *targettag);
464 : static void CreatePredicateLock(const PREDICATELOCKTARGETTAG *targettag,
465 : uint32 targettaghash,
466 : SERIALIZABLEXACT *sxact);
467 : static void DeleteLockTarget(PREDICATELOCKTARGET *target, uint32 targettaghash);
468 : static bool TransferPredicateLocksToNewTarget(PREDICATELOCKTARGETTAG oldtargettag,
469 : PREDICATELOCKTARGETTAG newtargettag,
470 : bool removeOld);
471 : static void PredicateLockAcquire(const PREDICATELOCKTARGETTAG *targettag);
472 : static void DropAllPredicateLocksFromTable(Relation relation,
473 : bool transfer);
474 : static void SetNewSxactGlobalXmin(void);
475 : static void ClearOldPredicateLocks(void);
476 : static void ReleaseOneSerializableXact(SERIALIZABLEXACT *sxact, bool partial,
477 : bool summarize);
478 : static bool XidIsConcurrent(TransactionId xid);
479 : static void CheckTargetForConflictsIn(PREDICATELOCKTARGETTAG *targettag);
480 : static void FlagRWConflict(SERIALIZABLEXACT *reader, SERIALIZABLEXACT *writer);
481 : static void OnConflict_CheckForSerializationFailure(const SERIALIZABLEXACT *reader,
482 : SERIALIZABLEXACT *writer);
483 : static void CreateLocalPredicateLockHash(void);
484 : static void ReleasePredicateLocksLocal(void);
485 :
486 :
487 : /*------------------------------------------------------------------------*/
488 :
489 : /*
490 : * Does this relation participate in predicate locking? Temporary and system
491 : * relations are exempt.
492 : */
4316 heikki.linnakangas 493 ECB : static inline bool
4316 heikki.linnakangas 494 GIC 144322 : PredicateLockingNeededForRelation(Relation relation)
4316 heikki.linnakangas 495 ECB : {
633 tgl 496 CBC 200781 : return !(relation->rd_id < FirstUnpinnedObjectId ||
129 michael 497 GNC 56459 : RelationUsesLocalBuffers(relation));
498 : }
499 :
500 : /*
501 : * When a public interface method is called for a read, this is the test to
502 : * see if we should do a quick return.
503 : *
504 : * Note: this function has side-effects! If this transaction has been flagged
505 : * as RO-safe since the last call, we release all predicate locks and reset
506 : * MySerializableXact. That makes subsequent calls to return quickly.
507 : *
508 : * This is marked as 'inline' to eliminate the function call overhead in the
509 : * common case that serialization is not needed.
4316 heikki.linnakangas 510 ECB : */
511 : static inline bool
4316 heikki.linnakangas 512 GIC 271976780 : SerializationNeededForRead(Relation relation, Snapshot snapshot)
4316 heikki.linnakangas 513 ECB : {
514 : /* Nothing to do if this is not a serializable transaction */
4316 heikki.linnakangas 515 GIC 271976780 : if (MySerializableXact == InvalidSerializableXact)
516 271838078 : return false;
517 :
518 : /*
519 : * Don't acquire locks or conflict when scanning with a special snapshot.
520 : * This excludes things like CLUSTER and REINDEX. They use the wholesale
521 : * functions TransferPredicateLocksToHeapRelation() and
522 : * CheckTableForSerializableConflictIn() to participate in serialization,
2564 noah 523 ECB : * but the scans involved don't need serialization.
4316 heikki.linnakangas 524 : */
4316 heikki.linnakangas 525 GIC 138702 : if (!IsMVCCSnapshot(snapshot))
526 1450 : return false;
527 :
528 : /*
529 : * Check if we have just become "RO-safe". If we have, immediately release
530 : * all locks as they're not needed anymore. This also resets
531 : * MySerializableXact, so that subsequent calls to this function can exit
532 : * quickly.
533 : *
534 : * A transaction is flagged as RO_SAFE if all concurrent R/W transactions
535 : * commit without having conflicts out to an earlier snapshot, thus
4315 heikki.linnakangas 536 ECB : * ensuring that no conflicts are possible for this transaction.
537 : */
4316 heikki.linnakangas 538 CBC 137252 : if (SxactIsROSafe(MySerializableXact))
4316 heikki.linnakangas 539 ECB : {
1486 tmunro 540 GIC 33 : ReleasePredicateLocks(false, true);
4316 heikki.linnakangas 541 33 : return false;
542 : }
4316 heikki.linnakangas 543 ECB :
544 : /* Check if the relation doesn't participate in predicate locking */
4316 heikki.linnakangas 545 GIC 137219 : if (!PredicateLockingNeededForRelation(relation))
4316 heikki.linnakangas 546 CBC 85415 : return false;
547 :
4315 heikki.linnakangas 548 GIC 51804 : return true; /* no excuse to skip predicate locking */
549 : }
550 :
551 : /*
552 : * Like SerializationNeededForRead(), but called on writes.
553 : * The logic is the same, but there is no snapshot and we can't be RO-safe.
4316 heikki.linnakangas 554 ECB : */
555 : static inline bool
4316 heikki.linnakangas 556 GIC 24295083 : SerializationNeededForWrite(Relation relation)
4316 heikki.linnakangas 557 ECB : {
558 : /* Nothing to do if this is not a serializable transaction */
4316 heikki.linnakangas 559 GIC 24295083 : if (MySerializableXact == InvalidSerializableXact)
560 24288026 : return false;
4316 heikki.linnakangas 561 ECB :
562 : /* Check if the relation doesn't participate in predicate locking */
4316 heikki.linnakangas 563 GIC 7057 : if (!PredicateLockingNeededForRelation(relation))
4316 heikki.linnakangas 564 CBC 2629 : return false;
565 :
4315 heikki.linnakangas 566 GIC 4428 : return true; /* no excuse to skip predicate locking */
567 : }
568 :
569 :
570 : /*------------------------------------------------------------------------*/
571 :
572 : /*
573 : * These functions are a simple implementation of a list for this specific
574 : * type of struct. If there is ever a generalized shared memory list, we
575 : * should probably switch to that.
4444 heikki.linnakangas 576 ECB : */
577 : static SERIALIZABLEXACT *
4444 heikki.linnakangas 578 GIC 3467 : CreatePredXact(void)
579 : {
580 : SERIALIZABLEXACT *sxact;
4444 heikki.linnakangas 581 EUB :
80 andres 582 GNC 3467 : if (dlist_is_empty(&PredXact->availableList))
4444 heikki.linnakangas 583 UIC 0 : return NULL;
584 :
80 andres 585 GNC 3467 : sxact = dlist_container(SERIALIZABLEXACT, xactLink,
586 : dlist_pop_head_node(&PredXact->availableList));
587 3467 : dlist_push_tail(&PredXact->activeList, &sxact->xactLink);
588 3467 : return sxact;
4444 heikki.linnakangas 589 ECB : }
590 :
591 : static void
4444 heikki.linnakangas 592 CBC 1641 : ReleasePredXact(SERIALIZABLEXACT *sxact)
4444 heikki.linnakangas 593 ECB : {
4444 heikki.linnakangas 594 GIC 1641 : Assert(ShmemAddrIsValid(sxact));
595 :
80 andres 596 GNC 1641 : dlist_delete(&sxact->xactLink);
597 1641 : dlist_push_tail(&PredXact->availableList, &sxact->xactLink);
4444 heikki.linnakangas 598 GIC 1641 : }
4444 heikki.linnakangas 599 ECB :
4444 heikki.linnakangas 600 EUB : /*------------------------------------------------------------------------*/
601 :
602 : /*
603 : * These functions manage primitive access to the RWConflict pool and lists.
604 : */
4444 heikki.linnakangas 605 ECB : static bool
4309 tgl 606 CBC 2648 : RWConflictExists(const SERIALIZABLEXACT *reader, const SERIALIZABLEXACT *writer)
607 : {
608 : dlist_iter iter;
4444 heikki.linnakangas 609 ECB :
4444 heikki.linnakangas 610 CBC 2648 : Assert(reader != writer);
4444 heikki.linnakangas 611 ECB :
612 : /* Check the ends of the purported conflict first. */
4316 heikki.linnakangas 613 GIC 2648 : if (SxactIsDoomed(reader)
614 2648 : || SxactIsDoomed(writer)
80 andres 615 GNC 2640 : || dlist_is_empty(&reader->outConflicts)
616 607 : || dlist_is_empty(&writer->inConflicts))
4444 heikki.linnakangas 617 GIC 2113 : return false;
618 :
619 : /*
620 : * A conflict is possible; walk the list to find out.
621 : *
622 : * The unconstify is needed as we have no const version of
623 : * dlist_foreach().
624 : */
80 andres 625 GNC 559 : dlist_foreach(iter, &unconstify(SERIALIZABLEXACT *, reader)->outConflicts)
4444 heikki.linnakangas 626 EUB : {
80 andres 627 GNC 535 : RWConflict conflict =
628 535 : dlist_container(RWConflictData, outLink, iter.cur);
629 :
4444 heikki.linnakangas 630 GIC 535 : if (conflict->sxactIn == writer)
631 511 : return true;
632 : }
4444 heikki.linnakangas 633 ECB :
634 : /* No conflict found. */
4444 heikki.linnakangas 635 CBC 24 : return false;
4444 heikki.linnakangas 636 ECB : }
637 :
638 : static void
4444 heikki.linnakangas 639 GIC 780 : SetRWConflict(SERIALIZABLEXACT *reader, SERIALIZABLEXACT *writer)
4444 heikki.linnakangas 640 ECB : {
641 : RWConflict conflict;
642 :
4444 heikki.linnakangas 643 CBC 780 : Assert(reader != writer);
644 780 : Assert(!RWConflictExists(reader, writer));
4444 heikki.linnakangas 645 ECB :
80 andres 646 GNC 780 : if (dlist_is_empty(&RWConflictPool->availableList))
4444 heikki.linnakangas 647 UIC 0 : ereport(ERROR,
4444 heikki.linnakangas 648 ECB : (errcode(ERRCODE_OUT_OF_MEMORY),
4274 peter_e 649 : errmsg("not enough elements in RWConflictPool to record a read/write conflict"),
650 : errhint("You might need to run fewer transactions at a time or increase max_connections.")));
4444 heikki.linnakangas 651 :
80 andres 652 GNC 780 : conflict = dlist_head_element(RWConflictData, outLink, &RWConflictPool->availableList);
653 780 : dlist_delete(&conflict->outLink);
654 :
4444 heikki.linnakangas 655 GIC 780 : conflict->sxactOut = reader;
656 780 : conflict->sxactIn = writer;
80 andres 657 GNC 780 : dlist_push_tail(&reader->outConflicts, &conflict->outLink);
658 780 : dlist_push_tail(&writer->inConflicts, &conflict->inLink);
4444 heikki.linnakangas 659 GIC 780 : }
4444 heikki.linnakangas 660 ECB :
661 : static void
4444 heikki.linnakangas 662 GIC 132 : SetPossibleUnsafeConflict(SERIALIZABLEXACT *roXact,
4444 heikki.linnakangas 663 ECB : SERIALIZABLEXACT *activeXact)
664 : {
665 : RWConflict conflict;
666 :
4444 heikki.linnakangas 667 GIC 132 : Assert(roXact != activeXact);
4444 heikki.linnakangas 668 CBC 132 : Assert(SxactIsReadOnly(roXact));
4444 heikki.linnakangas 669 GIC 132 : Assert(!SxactIsReadOnly(activeXact));
670 :
80 andres 671 GNC 132 : if (dlist_is_empty(&RWConflictPool->availableList))
4444 heikki.linnakangas 672 UIC 0 : ereport(ERROR,
4444 heikki.linnakangas 673 ECB : (errcode(ERRCODE_OUT_OF_MEMORY),
674 : errmsg("not enough elements in RWConflictPool to record a potential read/write conflict"),
675 : errhint("You might need to run fewer transactions at a time or increase max_connections.")));
676 :
80 andres 677 GNC 132 : conflict = dlist_head_element(RWConflictData, outLink, &RWConflictPool->availableList);
678 132 : dlist_delete(&conflict->outLink);
4444 heikki.linnakangas 679 ECB :
4444 heikki.linnakangas 680 CBC 132 : conflict->sxactOut = activeXact;
681 132 : conflict->sxactIn = roXact;
80 andres 682 GNC 132 : dlist_push_tail(&activeXact->possibleUnsafeConflicts, &conflict->outLink);
683 132 : dlist_push_tail(&roXact->possibleUnsafeConflicts, &conflict->inLink);
4444 heikki.linnakangas 684 GIC 132 : }
685 :
686 : static void
687 912 : ReleaseRWConflict(RWConflict conflict)
4444 heikki.linnakangas 688 ECB : {
80 andres 689 GNC 912 : dlist_delete(&conflict->inLink);
690 912 : dlist_delete(&conflict->outLink);
691 912 : dlist_push_tail(&RWConflictPool->availableList, &conflict->outLink);
4444 heikki.linnakangas 692 GIC 912 : }
693 :
694 : static void
695 3 : FlagSxactUnsafe(SERIALIZABLEXACT *sxact)
696 : {
697 : dlist_mutable_iter iter;
698 :
4444 heikki.linnakangas 699 CBC 3 : Assert(SxactIsReadOnly(sxact));
700 3 : Assert(!SxactIsROSafe(sxact));
4444 heikki.linnakangas 701 ECB :
4444 heikki.linnakangas 702 CBC 3 : sxact->flags |= SXACT_FLAG_RO_UNSAFE;
4444 heikki.linnakangas 703 ECB :
704 : /*
705 : * We know this isn't a safe snapshot, so we can stop looking for other
706 : * potential conflicts.
707 : */
80 andres 708 GNC 6 : dlist_foreach_modify(iter, &sxact->possibleUnsafeConflicts)
709 : {
710 3 : RWConflict conflict =
711 3 : dlist_container(RWConflictData, inLink, iter.cur);
712 :
4444 heikki.linnakangas 713 GIC 3 : Assert(!SxactIsReadOnly(conflict->sxactOut));
714 3 : Assert(sxact == conflict->sxactIn);
715 :
716 3 : ReleaseRWConflict(conflict);
717 : }
718 3 : }
719 :
720 : /*------------------------------------------------------------------------*/
721 :
722 : /*
723 : * Decide whether a Serial page number is "older" for truncation purposes.
724 : * Analogous to CLOGPagePrecedes().
4444 heikki.linnakangas 725 ECB : */
726 : static bool
813 noah 727 CBC 74866 : SerialPagePrecedesLogically(int page1, int page2)
728 : {
729 : TransactionId xid1;
730 : TransactionId xid2;
813 noah 731 ECB :
813 noah 732 GIC 74866 : xid1 = ((TransactionId) page1) * SERIAL_ENTRIESPERPAGE;
733 74866 : xid1 += FirstNormalTransactionId + 1;
734 74866 : xid2 = ((TransactionId) page2) * SERIAL_ENTRIESPERPAGE;
735 74866 : xid2 += FirstNormalTransactionId + 1;
736 :
737 125994 : return (TransactionIdPrecedes(xid1, xid2) &&
813 noah 738 CBC 51128 : TransactionIdPrecedes(xid1, xid2 + SERIAL_ENTRIESPERPAGE - 1));
739 : }
740 :
741 : #ifdef USE_ASSERT_CHECKING
742 : static void
813 noah 743 GIC 1826 : SerialPagePrecedesLogicallyUnitTests(void)
744 : {
813 noah 745 CBC 1826 : int per_page = SERIAL_ENTRIESPERPAGE,
746 1826 : offset = per_page / 2;
813 noah 747 ECB : int newestPage,
748 : oldestPage,
749 : headPage,
750 : targetPage;
751 : TransactionId newestXact,
752 : oldestXact;
753 :
754 : /* GetNewTransactionId() has assigned the last XID it can safely use. */
813 noah 755 GIC 1826 : newestPage = 2 * SLRU_PAGES_PER_SEGMENT - 1; /* nothing special */
756 1826 : newestXact = newestPage * per_page + offset;
813 noah 757 CBC 1826 : Assert(newestXact / per_page == newestPage);
758 1826 : oldestXact = newestXact + 1;
813 noah 759 GIC 1826 : oldestXact -= 1U << 31;
813 noah 760 CBC 1826 : oldestPage = oldestXact / per_page;
4444 heikki.linnakangas 761 ECB :
762 : /*
763 : * In this scenario, the SLRU headPage pertains to the last ~1000 XIDs
764 : * assigned. oldestXact finishes, ~2B XIDs having elapsed since it
765 : * started. Further transactions cause us to summarize oldestXact to
813 noah 766 : * tailPage. Function must return false so SerialAdd() doesn't zero
767 : * tailPage (which may contain entries for other old, recently-finished
768 : * XIDs) and half the SLRU. Reaching this requires burning ~2B XIDs in
769 : * single-user mode, a negligible possibility.
4444 heikki.linnakangas 770 : */
813 noah 771 GIC 1826 : headPage = newestPage;
772 1826 : targetPage = oldestPage;
773 1826 : Assert(!SerialPagePrecedesLogically(headPage, targetPage));
774 :
775 : /*
776 : * In this scenario, the SLRU headPage pertains to oldestXact. We're
777 : * summarizing an XID near newestXact. (Assume few other XIDs used
813 noah 778 EUB : * SERIALIZABLE, hence the minimal headPage advancement. Assume
779 : * oldestXact was long-running and only recently reached the SLRU.)
780 : * Function must return true to make SerialAdd() create targetPage.
781 : *
782 : * Today's implementation mishandles this case, but it doesn't matter
783 : * enough to fix. Verify that the defect affects just one page by
784 : * asserting correct treatment of its prior page. Reaching this case
785 : * requires burning ~2B XIDs in single-user mode, a negligible
786 : * possibility. Moreover, if it does happen, the consequence would be
787 : * mild, namely a new transaction failing in SimpleLruReadPage().
788 : */
813 noah 789 GIC 1826 : headPage = oldestPage;
813 noah 790 GBC 1826 : targetPage = newestPage;
813 noah 791 GIC 1826 : Assert(SerialPagePrecedesLogically(headPage, targetPage - 1));
792 : #if 0
793 : Assert(SerialPagePrecedesLogically(headPage, targetPage));
794 : #endif
4444 heikki.linnakangas 795 1826 : }
796 : #endif
4444 heikki.linnakangas 797 EUB :
798 : /*
799 : * Initialize for the tracking of old serializable committed xids.
800 : */
801 : static void
1059 tgl 802 GIC 1826 : SerialInit(void)
803 : {
804 : bool found;
805 :
4444 heikki.linnakangas 806 EUB : /*
807 : * Set up SLRU management of the pg_serial data.
808 : */
1059 tgl 809 GBC 1826 : SerialSlruCtl->PagePrecedes = SerialPagePrecedesLogically;
1059 tgl 810 GIC 1826 : SimpleLruInit(SerialSlruCtl, "Serial",
811 1826 : NUM_SERIAL_BUFFERS, 0, SerialSLRULock, "pg_serial",
812 : LWTRANCHE_SERIAL_BUFFER, SYNC_HANDLER_NONE);
813 noah 813 EUB : #ifdef USE_ASSERT_CHECKING
813 noah 814 GBC 1826 : SerialPagePrecedesLogicallyUnitTests();
815 : #endif
813 noah 816 GIC 1826 : SlruPagePrecedesUnitTests(SerialSlruCtl, SERIAL_ENTRIESPERPAGE);
817 :
4444 heikki.linnakangas 818 EUB : /*
1059 tgl 819 : * Create or attach to the SerialControl structure.
4444 heikki.linnakangas 820 : */
1059 tgl 821 GBC 1826 : serialControl = (SerialControl)
822 1826 : ShmemInitStruct("SerialControlData", sizeof(SerialControlData), &found);
823 :
2085 824 1826 : Assert(found == IsUnderPostmaster);
4444 heikki.linnakangas 825 GIC 1826 : if (!found)
826 : {
4444 heikki.linnakangas 827 EUB : /*
828 : * Set control information to reflect empty SLRU.
829 : */
1059 tgl 830 GBC 1826 : serialControl->headPage = -1;
1059 tgl 831 GIC 1826 : serialControl->headXid = InvalidTransactionId;
1059 tgl 832 GBC 1826 : serialControl->tailXid = InvalidTransactionId;
833 : }
4444 heikki.linnakangas 834 GIC 1826 : }
4444 heikki.linnakangas 835 EUB :
836 : /*
837 : * Record a committed read write serializable xid and the minimum
838 : * commitSeqNo of any transactions to which this xid had a rw-conflict out.
839 : * An invalid commitSeqNo means that there were no conflicts out from xid.
840 : */
841 : static void
1059 tgl 842 UIC 0 : SerialAdd(TransactionId xid, SerCommitSeqNo minConflictCommitSeqNo)
843 : {
844 : TransactionId tailXid;
845 : int targetPage;
846 : int slotno;
847 : int firstZeroPage;
848 : bool isNewPage;
4444 heikki.linnakangas 849 ECB :
4444 heikki.linnakangas 850 UIC 0 : Assert(TransactionIdIsValid(xid));
851 :
1059 tgl 852 0 : targetPage = SerialPage(xid);
853 :
854 0 : LWLockAcquire(SerialSLRULock, LW_EXCLUSIVE);
855 :
4444 heikki.linnakangas 856 ECB : /*
857 : * If no serializable transactions are active, there shouldn't be anything
4415 858 : * to push out to the SLRU. Hitting this assert would mean there's
4444 859 : * something wrong with the earlier cleanup logic.
860 : */
1059 tgl 861 LBC 0 : tailXid = serialControl->tailXid;
4444 heikki.linnakangas 862 UIC 0 : Assert(TransactionIdIsValid(tailXid));
4444 heikki.linnakangas 863 ECB :
4415 864 : /*
865 : * If the SLRU is currently unused, zero out the whole active region from
4382 bruce 866 EUB : * tailXid to headXid before taking it into use. Otherwise zero out only
867 : * any new pages that enter the tailXid-headXid range as we advance
868 : * headXid.
4415 heikki.linnakangas 869 : */
1059 tgl 870 UBC 0 : if (serialControl->headPage < 0)
871 : {
1059 tgl 872 UIC 0 : firstZeroPage = SerialPage(tailXid);
4444 heikki.linnakangas 873 0 : isNewPage = true;
874 : }
875 : else
4444 heikki.linnakangas 876 EUB : {
1059 tgl 877 UIC 0 : firstZeroPage = SerialNextPage(serialControl->headPage);
1059 tgl 878 UBC 0 : isNewPage = SerialPagePrecedesLogically(serialControl->headPage,
1059 tgl 879 EUB : targetPage);
4444 heikki.linnakangas 880 : }
881 :
1059 tgl 882 UIC 0 : if (!TransactionIdIsValid(serialControl->headXid)
883 0 : || TransactionIdFollows(xid, serialControl->headXid))
884 0 : serialControl->headXid = xid;
4415 heikki.linnakangas 885 0 : if (isNewPage)
1059 tgl 886 0 : serialControl->headPage = targetPage;
887 :
4444 heikki.linnakangas 888 0 : if (isNewPage)
889 : {
4444 heikki.linnakangas 890 ECB : /* Initialize intervening pages. */
4415 heikki.linnakangas 891 UIC 0 : while (firstZeroPage != targetPage)
4444 heikki.linnakangas 892 ECB : {
1059 tgl 893 UIC 0 : (void) SimpleLruZeroPage(SerialSlruCtl, firstZeroPage);
894 0 : firstZeroPage = SerialNextPage(firstZeroPage);
895 : }
896 0 : slotno = SimpleLruZeroPage(SerialSlruCtl, targetPage);
897 : }
898 : else
899 0 : slotno = SimpleLruReadPage(SerialSlruCtl, targetPage, true, xid);
4444 heikki.linnakangas 900 ECB :
1059 tgl 901 UIC 0 : SerialValue(slotno, xid) = minConflictCommitSeqNo;
1059 tgl 902 LBC 0 : SerialSlruCtl->shared->page_dirty[slotno] = true;
4444 heikki.linnakangas 903 ECB :
1059 tgl 904 LBC 0 : LWLockRelease(SerialSLRULock);
4444 heikki.linnakangas 905 0 : }
906 :
907 : /*
908 : * Get the minimum commitSeqNo for any conflict out for the given xid. For
909 : * a transaction which exists but has no conflict out, InvalidSerCommitSeqNo
910 : * will be returned.
911 : */
912 : static SerCommitSeqNo
1059 tgl 913 GIC 25 : SerialGetMinConflictCommitSeqNo(TransactionId xid)
4444 heikki.linnakangas 914 ECB : {
915 : TransactionId headXid;
4444 heikki.linnakangas 916 EUB : TransactionId tailXid;
917 : SerCommitSeqNo val;
918 : int slotno;
919 :
4444 heikki.linnakangas 920 GBC 25 : Assert(TransactionIdIsValid(xid));
921 :
1059 tgl 922 25 : LWLockAcquire(SerialSLRULock, LW_SHARED);
923 25 : headXid = serialControl->headXid;
1059 tgl 924 GIC 25 : tailXid = serialControl->tailXid;
925 25 : LWLockRelease(SerialSLRULock);
4444 heikki.linnakangas 926 ECB :
4444 heikki.linnakangas 927 GIC 25 : if (!TransactionIdIsValid(headXid))
928 25 : return 0;
4444 heikki.linnakangas 929 ECB :
4444 heikki.linnakangas 930 UIC 0 : Assert(TransactionIdIsValid(tailXid));
4444 heikki.linnakangas 931 ECB :
4444 heikki.linnakangas 932 UIC 0 : if (TransactionIdPrecedes(xid, tailXid)
933 0 : || TransactionIdFollows(xid, headXid))
934 0 : return 0;
935 :
936 : /*
937 : * The following function must be called without holding SerialSLRULock,
938 : * but will return with that lock held, which must then be released.
939 : */
1059 tgl 940 0 : slotno = SimpleLruReadPage_ReadOnly(SerialSlruCtl,
1059 tgl 941 ECB : SerialPage(xid), xid);
1059 tgl 942 UIC 0 : val = SerialValue(slotno, xid);
943 0 : LWLockRelease(SerialSLRULock);
4444 heikki.linnakangas 944 0 : return val;
4444 heikki.linnakangas 945 ECB : }
946 :
947 : /*
948 : * Call this whenever there is a new xmin for active serializable
949 : * transactions. We don't need to keep information on transactions which
4415 950 : * precede that. InvalidTransactionId means none active, so everything in
951 : * the SLRU can be discarded.
952 : */
953 : static void
1059 tgl 954 GBC 1710 : SerialSetActiveSerXmin(TransactionId xid)
955 : {
1059 tgl 956 GIC 1710 : LWLockAcquire(SerialSLRULock, LW_EXCLUSIVE);
4444 heikki.linnakangas 957 EUB :
958 : /*
959 : * When no sxacts are active, nothing overlaps, set the xid values to
960 : * invalid to show that there are no valid entries. Don't clear headPage,
961 : * though. A new xmin might still land on that page, and we don't want to
962 : * repeatedly zero out the same page.
963 : */
4444 heikki.linnakangas 964 GIC 1710 : if (!TransactionIdIsValid(xid))
965 : {
1059 tgl 966 846 : serialControl->tailXid = InvalidTransactionId;
967 846 : serialControl->headXid = InvalidTransactionId;
968 846 : LWLockRelease(SerialSLRULock);
4444 heikki.linnakangas 969 846 : return;
970 : }
971 :
972 : /*
973 : * When we're recovering prepared transactions, the global xmin might move
974 : * backwards depending on the order they're recovered. Normally that's not
975 : * OK, but during recovery no serializable transactions will commit, so
976 : * the SLRU is empty and we can get away with it.
977 : */
978 864 : if (RecoveryInProgress())
979 : {
1059 tgl 980 UIC 0 : Assert(serialControl->headPage < 0);
981 0 : if (!TransactionIdIsValid(serialControl->tailXid)
982 0 : || TransactionIdPrecedes(xid, serialControl->tailXid))
983 : {
984 0 : serialControl->tailXid = xid;
985 : }
986 0 : LWLockRelease(SerialSLRULock);
4444 heikki.linnakangas 987 0 : return;
988 : }
989 :
1059 tgl 990 GBC 864 : Assert(!TransactionIdIsValid(serialControl->tailXid)
1059 tgl 991 EUB : || TransactionIdFollows(xid, serialControl->tailXid));
992 :
1059 tgl 993 GIC 864 : serialControl->tailXid = xid;
4444 heikki.linnakangas 994 EUB :
1059 tgl 995 GIC 864 : LWLockRelease(SerialSLRULock);
996 : }
4415 heikki.linnakangas 997 EUB :
998 : /*
999 : * Perform a checkpoint --- either during shutdown, or on-the-fly
1000 : *
1001 : * We don't have any data that needs to survive a restart, but this is a
1002 : * convenient place to truncate the SLRU.
1003 : */
1004 : void
4415 heikki.linnakangas 1005 GIC 2363 : CheckPointPredicate(void)
1006 : {
1007 : int tailPage;
1008 :
1059 tgl 1009 GBC 2363 : LWLockAcquire(SerialSLRULock, LW_EXCLUSIVE);
1010 :
1011 : /* Exit quickly if the SLRU is currently not in use. */
1059 tgl 1012 GIC 2363 : if (serialControl->headPage < 0)
1013 : {
1014 2363 : LWLockRelease(SerialSLRULock);
4444 heikki.linnakangas 1015 2363 : return;
1016 : }
1017 :
1059 tgl 1018 UIC 0 : if (TransactionIdIsValid(serialControl->tailXid))
1019 : {
1020 : /* We can truncate the SLRU up to the page containing tailXid */
1021 0 : tailPage = SerialPage(serialControl->tailXid);
1022 : }
1023 : else
1024 : {
813 noah 1025 ECB : /*----------
1026 : * The SLRU is no longer needed. Truncate to head before we set head
1027 : * invalid.
1028 : *
1029 : * XXX: It's possible that the SLRU is not needed again until XID
1030 : * wrap-around has happened, so that the segment containing headPage
1031 : * that we leave behind will appear to be new again. In that case it
1032 : * won't be removed until XID horizon advances enough to make it
4322 heikki.linnakangas 1033 : * current again.
1034 : *
1035 : * XXX: This should happen in vac_truncate_clog(), not in checkpoints.
1036 : * Consider this scenario, starting from a system with no in-progress
1037 : * transactions and VACUUM FREEZE having maximized oldestXact:
1038 : * - Start a SERIALIZABLE transaction.
1039 : * - Start, finish, and summarize a SERIALIZABLE transaction, creating
813 noah 1040 : * one SLRU page.
1041 : * - Consume XIDs to reach xidStopLimit.
1042 : * - Finish all transactions. Due to the long-running SERIALIZABLE
1043 : * transaction, earlier checkpoints did not touch headPage. The
1044 : * next checkpoint will change it, but that checkpoint happens after
1045 : * the end of the scenario.
1046 : * - VACUUM to advance XID limits.
1047 : * - Consume ~2M XIDs, crossing the former xidWrapLimit.
1048 : * - Start, finish, and summarize a SERIALIZABLE transaction.
1049 : * SerialAdd() declines to create the targetPage, because headPage
1050 : * is not regarded as in the past relative to that targetPage. The
1051 : * transaction instigating the summarize fails in
1052 : * SimpleLruReadPage().
1053 : */
1059 tgl 1054 UIC 0 : tailPage = serialControl->headPage;
1055 0 : serialControl->headPage = -1;
1056 : }
1057 :
1058 0 : LWLockRelease(SerialSLRULock);
1059 :
1060 : /* Truncate away pages that are no longer required */
1061 0 : SimpleLruTruncate(SerialSlruCtl, tailPage);
1062 :
4415 heikki.linnakangas 1063 ECB : /*
1064 : * Write dirty SLRU pages to disk
1065 : *
1066 : * This is not actually necessary from a correctness point of view. We do
1067 : * it merely as a debugging aid.
1068 : *
1069 : * We're doing this after the truncation to avoid writing pages right
1070 : * before deleting the file in which they sit, which would be completely
4384 rhaas 1071 : * pointless.
4415 heikki.linnakangas 1072 : */
926 tmunro 1073 UIC 0 : SimpleLruWriteAll(SerialSlruCtl, true);
1074 : }
1075 :
1076 : /*------------------------------------------------------------------------*/
1077 :
4444 heikki.linnakangas 1078 ECB : /*
1079 : * InitPredicateLocks -- Initialize the predicate locking data structures.
1080 : *
1081 : * This is called from CreateSharedMemoryAndSemaphores(), which see for
1082 : * more comments. In the normal postmaster case, the shared hash tables
1083 : * are created here. Backends inherit the pointers
1084 : * to the shared tables via fork(). In the EXEC_BACKEND case, each
1085 : * backend re-executes this code to obtain pointers to the already existing
1086 : * shared hash tables.
1087 : */
1088 : void
4444 heikki.linnakangas 1089 GIC 1826 : InitPredicateLocks(void)
1090 : {
1091 : HASHCTL info;
1092 : long max_table_size;
1093 : Size requestSize;
1094 : bool found;
1095 :
1096 : #ifndef EXEC_BACKEND
2085 tgl 1097 CBC 1826 : Assert(!IsUnderPostmaster);
1098 : #endif
1099 :
1100 : /*
1101 : * Compute size of predicate lock target hashtable. Note these
1102 : * calculations must agree with PredicateLockShmemSize!
1103 : */
4444 heikki.linnakangas 1104 GIC 1826 : max_table_size = NPREDICATELOCKTARGETENTS();
1105 :
1106 : /*
4444 heikki.linnakangas 1107 ECB : * Allocate hash table for PREDICATELOCKTARGET structs. This stores
1108 : * per-predicate-lock-target information.
1109 : */
4444 heikki.linnakangas 1110 GIC 1826 : info.keysize = sizeof(PREDICATELOCKTARGETTAG);
1111 1826 : info.entrysize = sizeof(PREDICATELOCKTARGET);
4444 heikki.linnakangas 1112 CBC 1826 : info.num_partitions = NUM_PREDICATELOCK_PARTITIONS;
4444 heikki.linnakangas 1113 ECB :
4444 heikki.linnakangas 1114 GIC 1826 : PredicateLockTargetHash = ShmemInitHash("PREDICATELOCKTARGET hash",
1115 : max_table_size,
1116 : max_table_size,
4444 heikki.linnakangas 1117 ECB : &info,
3034 tgl 1118 : HASH_ELEM | HASH_BLOBS |
1119 : HASH_PARTITION | HASH_FIXED_SIZE);
4444 heikki.linnakangas 1120 :
1121 : /*
4323 1122 : * Reserve a dummy entry in the hash table; we use it to make sure there's
4444 1123 : * always one entry available when we need to split or combine a page,
1124 : * because running out of space there could mean aborting a
1125 : * non-serializable transaction.
1126 : */
2085 tgl 1127 CBC 1826 : if (!IsUnderPostmaster)
1128 : {
1129 1826 : (void) hash_search(PredicateLockTargetHash, &ScratchTargetTag,
2085 tgl 1130 ECB : HASH_ENTER, &found);
2085 tgl 1131 GIC 1826 : Assert(!found);
2085 tgl 1132 ECB : }
1133 :
1134 : /* Pre-calculate the hash and partition lock of the scratch entry */
2085 tgl 1135 GIC 1826 : ScratchTargetTagHash = PredicateLockTargetTagHashCode(&ScratchTargetTag);
2085 tgl 1136 CBC 1826 : ScratchPartitionLock = PredicateLockHashPartitionLock(ScratchTargetTagHash);
4444 heikki.linnakangas 1137 ECB :
1138 : /*
1139 : * Allocate hash table for PREDICATELOCK structs. This stores per
1140 : * xact-lock-of-a-target information.
1141 : */
4444 heikki.linnakangas 1142 CBC 1826 : info.keysize = sizeof(PREDICATELOCKTAG);
1143 1826 : info.entrysize = sizeof(PREDICATELOCK);
1144 1826 : info.hash = predicatelock_hash;
1145 1826 : info.num_partitions = NUM_PREDICATELOCK_PARTITIONS;
4444 heikki.linnakangas 1146 ECB :
2085 tgl 1147 : /* Assume an average of 2 xacts per target */
2085 tgl 1148 CBC 1826 : max_table_size *= 2;
2085 tgl 1149 ECB :
4444 heikki.linnakangas 1150 CBC 1826 : PredicateLockHash = ShmemInitHash("PREDICATELOCK hash",
4381 heikki.linnakangas 1151 ECB : max_table_size,
1152 : max_table_size,
1153 : &info,
3034 tgl 1154 : HASH_ELEM | HASH_FUNCTION |
1155 : HASH_PARTITION | HASH_FIXED_SIZE);
1156 :
1157 : /*
1158 : * Compute size for serializable transaction hashtable. Note these
1159 : * calculations must agree with PredicateLockShmemSize!
4444 heikki.linnakangas 1160 : */
362 rhaas 1161 CBC 1826 : max_table_size = (MaxBackends + max_prepared_xacts);
1162 :
4444 heikki.linnakangas 1163 ECB : /*
1164 : * Allocate a list to hold information on transactions participating in
1165 : * predicate locking.
1166 : *
1167 : * Assume an average of 10 predicate locking transactions per backend.
1168 : * This allows aggressive cleanup while detail is present before data must
1169 : * be summarized for storage in SLRU and the "dummy" transaction.
1170 : */
4444 heikki.linnakangas 1171 GIC 1826 : max_table_size *= 10;
1172 :
1173 1826 : PredXact = ShmemInitStruct("PredXactList",
1174 : PredXactListDataSize,
1175 : &found);
2085 tgl 1176 1826 : Assert(found == IsUnderPostmaster);
4444 heikki.linnakangas 1177 1826 : if (!found)
1178 : {
1179 : int i;
1180 :
80 andres 1181 GNC 1826 : dlist_init(&PredXact->availableList);
1182 1826 : dlist_init(&PredXact->activeList);
4444 heikki.linnakangas 1183 CBC 1826 : PredXact->SxactGlobalXmin = InvalidTransactionId;
4444 heikki.linnakangas 1184 GIC 1826 : PredXact->SxactGlobalXminCount = 0;
1185 1826 : PredXact->WritableSxactCount = 0;
4444 heikki.linnakangas 1186 CBC 1826 : PredXact->LastSxactCommitSeqNo = FirstNormalSerCommitSeqNo - 1;
1187 1826 : PredXact->CanPartialClearThrough = 0;
4444 heikki.linnakangas 1188 GIC 1826 : PredXact->HavePartialClearedThrough = 0;
1189 1826 : requestSize = mul_size((Size) max_table_size,
1190 : sizeof(SERIALIZABLEXACT));
4444 heikki.linnakangas 1191 CBC 1826 : PredXact->element = ShmemAlloc(requestSize);
4444 heikki.linnakangas 1192 ECB : /* Add all elements to available list, clean. */
4444 heikki.linnakangas 1193 GIC 1826 : memset(PredXact->element, 0, requestSize);
4444 heikki.linnakangas 1194 CBC 1923246 : for (i = 0; i < max_table_size; i++)
1195 : {
80 andres 1196 GNC 1921420 : LWLockInitialize(&PredXact->element[i].perXactPredicateListLock,
1059 tgl 1197 ECB : LWTRANCHE_PER_XACT_PREDICATE_LIST);
80 andres 1198 GNC 1921420 : dlist_push_tail(&PredXact->availableList, &PredXact->element[i].xactLink);
4444 heikki.linnakangas 1199 ECB : }
4444 heikki.linnakangas 1200 GIC 1826 : PredXact->OldCommittedSxact = CreatePredXact();
1201 1826 : SetInvalidVirtualTransactionId(PredXact->OldCommittedSxact->vxid);
4294 1202 1826 : PredXact->OldCommittedSxact->prepareSeqNo = 0;
4444 1203 1826 : PredXact->OldCommittedSxact->commitSeqNo = 0;
1204 1826 : PredXact->OldCommittedSxact->SeqNo.lastCommitBeforeSnapshot = 0;
80 andres 1205 GNC 1826 : dlist_init(&PredXact->OldCommittedSxact->outConflicts);
1206 1826 : dlist_init(&PredXact->OldCommittedSxact->inConflicts);
1207 1826 : dlist_init(&PredXact->OldCommittedSxact->predicateLocks);
1208 1826 : dlist_node_init(&PredXact->OldCommittedSxact->finishedLink);
1209 1826 : dlist_init(&PredXact->OldCommittedSxact->possibleUnsafeConflicts);
4444 heikki.linnakangas 1210 GIC 1826 : PredXact->OldCommittedSxact->topXid = InvalidTransactionId;
4444 heikki.linnakangas 1211 CBC 1826 : PredXact->OldCommittedSxact->finishedBefore = InvalidTransactionId;
1212 1826 : PredXact->OldCommittedSxact->xmin = InvalidTransactionId;
1213 1826 : PredXact->OldCommittedSxact->flags = SXACT_FLAG_COMMITTED;
4444 heikki.linnakangas 1214 GIC 1826 : PredXact->OldCommittedSxact->pid = 0;
479 tmunro 1215 1826 : PredXact->OldCommittedSxact->pgprocno = INVALID_PGPROCNO;
1216 : }
1217 : /* This never changes, so let's keep a local copy. */
4444 heikki.linnakangas 1218 1826 : OldCommittedSxact = PredXact->OldCommittedSxact;
4444 heikki.linnakangas 1219 ECB :
1220 : /*
1221 : * Allocate hash table for SERIALIZABLEXID structs. This stores per-xid
1222 : * information for serializable transactions which have accessed data.
1223 : */
4444 heikki.linnakangas 1224 GIC 1826 : info.keysize = sizeof(SERIALIZABLEXIDTAG);
1225 1826 : info.entrysize = sizeof(SERIALIZABLEXID);
4444 heikki.linnakangas 1226 ECB :
4444 heikki.linnakangas 1227 GIC 1826 : SerializableXidHash = ShmemInitHash("SERIALIZABLEXID hash",
4441 heikki.linnakangas 1228 ECB : max_table_size,
1229 : max_table_size,
1230 : &info,
1231 : HASH_ELEM | HASH_BLOBS |
3034 tgl 1232 : HASH_FIXED_SIZE);
4444 heikki.linnakangas 1233 :
1234 : /*
1235 : * Allocate space for tracking rw-conflicts in lists attached to the
1236 : * transactions.
1237 : *
1238 : * Assume an average of 5 conflicts per transaction. Calculations suggest
1239 : * that this will prevent resource exhaustion in even the most pessimal
1240 : * loads up to max_connections = 200 with all 200 connections pounding the
1241 : * database with serializable transactions. Beyond that, there may be
1242 : * occasional transactions canceled when trying to flag conflicts. That's
1243 : * probably OK.
1244 : */
4444 heikki.linnakangas 1245 CBC 1826 : max_table_size *= 5;
1246 :
4444 heikki.linnakangas 1247 GIC 1826 : RWConflictPool = ShmemInitStruct("RWConflictPool",
4444 heikki.linnakangas 1248 ECB : RWConflictPoolHeaderDataSize,
1249 : &found);
2085 tgl 1250 CBC 1826 : Assert(found == IsUnderPostmaster);
4444 heikki.linnakangas 1251 1826 : if (!found)
1252 : {
1253 : int i;
1254 :
80 andres 1255 GNC 1826 : dlist_init(&RWConflictPool->availableList);
4444 heikki.linnakangas 1256 GIC 1826 : requestSize = mul_size((Size) max_table_size,
1257 : RWConflictDataSize);
1258 1826 : RWConflictPool->element = ShmemAlloc(requestSize);
4444 heikki.linnakangas 1259 ECB : /* Add all elements to available list, clean. */
4444 heikki.linnakangas 1260 CBC 1826 : memset(RWConflictPool->element, 0, requestSize);
1261 9608926 : for (i = 0; i < max_table_size; i++)
1262 : {
80 andres 1263 GNC 9607100 : dlist_push_tail(&RWConflictPool->availableList,
1264 9607100 : &RWConflictPool->element[i].outLink);
4444 heikki.linnakangas 1265 ECB : }
1266 : }
1267 :
1268 : /*
1269 : * Create or attach to the header for the list of finished serializable
1270 : * transactions.
1271 : */
80 andres 1272 GNC 1826 : FinishedSerializableTransactions = (dlist_head *)
4444 heikki.linnakangas 1273 GIC 1826 : ShmemInitStruct("FinishedSerializableTransactions",
1274 : sizeof(dlist_head),
1275 : &found);
2085 tgl 1276 1826 : Assert(found == IsUnderPostmaster);
4444 heikki.linnakangas 1277 1826 : if (!found)
80 andres 1278 GNC 1826 : dlist_init(FinishedSerializableTransactions);
1279 :
1280 : /*
1281 : * Initialize the SLRU storage for old committed serializable
1282 : * transactions.
1283 : */
1059 tgl 1284 GIC 1826 : SerialInit();
4444 heikki.linnakangas 1285 1826 : }
1286 :
1287 : /*
4444 heikki.linnakangas 1288 EUB : * Estimate shared-memory space used for predicate lock table
1289 : */
1290 : Size
4444 heikki.linnakangas 1291 GIC 2738 : PredicateLockShmemSize(void)
1292 : {
4444 heikki.linnakangas 1293 GBC 2738 : Size size = 0;
1294 : long max_table_size;
1295 :
4444 heikki.linnakangas 1296 EUB : /* predicate lock target hash table */
4444 heikki.linnakangas 1297 GIC 2738 : max_table_size = NPREDICATELOCKTARGETENTS();
4444 heikki.linnakangas 1298 GBC 2738 : size = add_size(size, hash_estimate_size(max_table_size,
1299 : sizeof(PREDICATELOCKTARGET)));
1300 :
1301 : /* predicate lock hash table */
4444 heikki.linnakangas 1302 GIC 2738 : max_table_size *= 2;
1303 2738 : size = add_size(size, hash_estimate_size(max_table_size,
1304 : sizeof(PREDICATELOCK)));
1305 :
1306 : /*
1307 : * Since NPREDICATELOCKTARGETENTS is only an estimate, add 10% safety
1308 : * margin.
1309 : */
1310 2738 : size = add_size(size, size / 10);
1311 :
1312 : /* transaction list */
362 rhaas 1313 2738 : max_table_size = MaxBackends + max_prepared_xacts;
4444 heikki.linnakangas 1314 CBC 2738 : max_table_size *= 10;
4444 heikki.linnakangas 1315 GIC 2738 : size = add_size(size, PredXactListDataSize);
1316 2738 : size = add_size(size, mul_size((Size) max_table_size,
1317 : sizeof(SERIALIZABLEXACT)));
1318 :
1319 : /* transaction xid table */
1320 2738 : size = add_size(size, hash_estimate_size(max_table_size,
1321 : sizeof(SERIALIZABLEXID)));
1322 :
4442 heikki.linnakangas 1323 ECB : /* rw-conflict pool */
4442 heikki.linnakangas 1324 GIC 2738 : max_table_size *= 5;
1325 2738 : size = add_size(size, RWConflictPoolHeaderDataSize);
1326 2738 : size = add_size(size, mul_size((Size) max_table_size,
1327 : RWConflictDataSize));
1328 :
4444 heikki.linnakangas 1329 ECB : /* Head for list of finished serializable transactions. */
80 andres 1330 GNC 2738 : size = add_size(size, sizeof(dlist_head));
4444 heikki.linnakangas 1331 ECB :
1332 : /* Shared memory structures for SLRU tracking of old committed xids. */
1059 tgl 1333 GIC 2738 : size = add_size(size, sizeof(SerialControlData));
1059 tgl 1334 CBC 2738 : size = add_size(size, SimpleLruShmemSize(NUM_SERIAL_BUFFERS, 0));
4444 heikki.linnakangas 1335 ECB :
4444 heikki.linnakangas 1336 CBC 2738 : return size;
4444 heikki.linnakangas 1337 ECB : }
1338 :
1339 :
1340 : /*
1341 : * Compute the hash code associated with a PREDICATELOCKTAG.
1342 : *
1343 : * Because we want to use just one set of partition locks for both the
1344 : * PREDICATELOCKTARGET and PREDICATELOCK hash tables, we have to make sure
1345 : * that PREDICATELOCKs fall into the same partition number as their
1346 : * associated PREDICATELOCKTARGETs. dynahash.c expects the partition number
1347 : * to be the low-order bits of the hash code, and therefore a
1348 : * PREDICATELOCKTAG's hash code must have the same low-order bits as the
1349 : * associated PREDICATELOCKTARGETTAG's hash code. We achieve this with this
1350 : * specialized hash function.
1351 : */
1352 : static uint32
4444 heikki.linnakangas 1353 UIC 0 : predicatelock_hash(const void *key, Size keysize)
4444 heikki.linnakangas 1354 ECB : {
4309 tgl 1355 UIC 0 : const PREDICATELOCKTAG *predicatelocktag = (const PREDICATELOCKTAG *) key;
1356 : uint32 targethash;
4444 heikki.linnakangas 1357 ECB :
4444 heikki.linnakangas 1358 LBC 0 : Assert(keysize == sizeof(PREDICATELOCKTAG));
4444 heikki.linnakangas 1359 ECB :
1360 : /* Look into the associated target object, and compute its hash code */
4444 heikki.linnakangas 1361 LBC 0 : targethash = PredicateLockTargetTagHashCode(&predicatelocktag->myTarget->tag);
1362 :
4444 heikki.linnakangas 1363 UIC 0 : return PredicateLockHashCodeFromTargetHashCode(predicatelocktag, targethash);
1364 : }
1365 :
1366 :
1367 : /*
1368 : * GetPredicateLockStatusData
1369 : * Return a table containing the internal state of the predicate
1370 : * lock manager for use in pg_lock_status.
1371 : *
4444 heikki.linnakangas 1372 EUB : * Like GetLockStatusData, this function tries to hold the partition LWLocks
1373 : * for as short a time as possible by returning two arrays that simply
1374 : * contain the PREDICATELOCKTARGETTAG and SERIALIZABLEXACT for each lock
1375 : * table entry. Multiple copies of the same PREDICATELOCKTARGETTAG and
1376 : * SERIALIZABLEXACT will likely appear.
1377 : */
1378 : PredicateLockData *
4444 heikki.linnakangas 1379 GIC 264 : GetPredicateLockStatusData(void)
1380 : {
1381 : PredicateLockData *data;
1382 : int i;
1383 : int els,
1384 : el;
1385 : HASH_SEQ_STATUS seqstat;
1386 : PREDICATELOCK *predlock;
1387 :
4444 heikki.linnakangas 1388 GBC 264 : data = (PredicateLockData *) palloc(sizeof(PredicateLockData));
1389 :
4444 heikki.linnakangas 1390 EUB : /*
1391 : * To ensure consistency, take simultaneous locks on all partition locks
1392 : * in ascending order, then SerializableXactHashLock.
1393 : */
4444 heikki.linnakangas 1394 GIC 4488 : for (i = 0; i < NUM_PREDICATELOCK_PARTITIONS; i++)
3359 rhaas 1395 4224 : LWLockAcquire(PredicateLockHashPartitionLockByIndex(i), LW_SHARED);
4444 heikki.linnakangas 1396 264 : LWLockAcquire(SerializableXactHashLock, LW_SHARED);
1397 :
4444 heikki.linnakangas 1398 EUB : /* Get number of locks and allocate appropriately-sized arrays. */
4444 heikki.linnakangas 1399 GIC 264 : els = hash_get_num_entries(PredicateLockHash);
4444 heikki.linnakangas 1400 GBC 264 : data->nelements = els;
4444 heikki.linnakangas 1401 GIC 264 : data->locktags = (PREDICATELOCKTARGETTAG *)
1402 264 : palloc(sizeof(PREDICATELOCKTARGETTAG) * els);
4444 heikki.linnakangas 1403 GBC 264 : data->xacts = (SERIALIZABLEXACT *)
1404 264 : palloc(sizeof(SERIALIZABLEXACT) * els);
1405 :
1406 :
1407 : /* Scan through PredicateLockHash and copy contents */
1408 264 : hash_seq_init(&seqstat, PredicateLockHash);
1409 :
1410 264 : el = 0;
1411 :
4444 heikki.linnakangas 1412 GIC 267 : while ((predlock = (PREDICATELOCK *) hash_seq_search(&seqstat)))
1413 : {
1414 3 : data->locktags[el] = predlock->tag.myTarget->tag;
1415 3 : data->xacts[el] = *predlock->tag.myXact;
1416 3 : el++;
1417 : }
1418 :
1419 264 : Assert(el == els);
1420 :
1421 : /* Release locks in reverse order */
1422 264 : LWLockRelease(SerializableXactHashLock);
1423 4488 : for (i = NUM_PREDICATELOCK_PARTITIONS - 1; i >= 0; i--)
3359 rhaas 1424 4224 : LWLockRelease(PredicateLockHashPartitionLockByIndex(i));
1425 :
4444 heikki.linnakangas 1426 264 : return data;
4444 heikki.linnakangas 1427 ECB : }
1428 :
1429 : /*
1430 : * Free up shared memory structures by pushing the oldest sxact (the one at
1431 : * the front of the SummarizeOldestCommittedSxact queue) into summary form.
1432 : * Each call will free exactly one SERIALIZABLEXACT structure and may also
1433 : * free one or more of these structures: SERIALIZABLEXID, PREDICATELOCK,
1434 : * PREDICATELOCKTARGET, RWConflictData.
1435 : */
1436 : static void
4444 heikki.linnakangas 1437 UIC 0 : SummarizeOldestCommittedSxact(void)
1438 : {
1439 : SERIALIZABLEXACT *sxact;
1440 :
4444 heikki.linnakangas 1441 LBC 0 : LWLockAcquire(SerializableFinishedListLock, LW_EXCLUSIVE);
1442 :
1443 : /*
4415 heikki.linnakangas 1444 ECB : * This function is only called if there are no sxact slots available.
1445 : * Some of them must belong to old, already-finished transactions, so
1446 : * there should be something in FinishedSerializableTransactions list that
4382 bruce 1447 : * we can summarize. However, there's a race condition: while we were not
1448 : * holding any locks, a transaction might have ended and cleaned up all
1449 : * the finished sxact entries already, freeing up their sxact slots. In
1450 : * that case, we have nothing to do here. The caller will find one of the
1451 : * slots released by the other backend when it retries.
1452 : */
80 andres 1453 UNC 0 : if (dlist_is_empty(FinishedSerializableTransactions))
4444 heikki.linnakangas 1454 ECB : {
4444 heikki.linnakangas 1455 LBC 0 : LWLockRelease(SerializableFinishedListLock);
4444 heikki.linnakangas 1456 UIC 0 : return;
4444 heikki.linnakangas 1457 ECB : }
1458 :
1459 : /*
1460 : * Grab the first sxact off the finished list -- this will be the earliest
3260 bruce 1461 : * commit. Remove it from the list.
1462 : */
80 andres 1463 UNC 0 : sxact = dlist_head_element(SERIALIZABLEXACT, finishedLink,
1464 : FinishedSerializableTransactions);
1465 0 : dlist_delete_thoroughly(&sxact->finishedLink);
1466 :
4444 heikki.linnakangas 1467 ECB : /* Add to SLRU summary information. */
4444 heikki.linnakangas 1468 UIC 0 : if (TransactionIdIsValid(sxact->topXid) && !SxactIsReadOnly(sxact))
1059 tgl 1469 0 : SerialAdd(sxact->topXid, SxactHasConflictOut(sxact)
1059 tgl 1470 ECB : ? sxact->SeqNo.earliestOutConflictCommit : InvalidSerCommitSeqNo);
1471 :
1472 : /* Summarize and release the detail. */
4444 heikki.linnakangas 1473 LBC 0 : ReleaseOneSerializableXact(sxact, false, true);
1474 :
4444 heikki.linnakangas 1475 UIC 0 : LWLockRelease(SerializableFinishedListLock);
1476 : }
1477 :
1478 : /*
4444 heikki.linnakangas 1479 EUB : * GetSafeSnapshot
1480 : * Obtain and register a snapshot for a READ ONLY DEFERRABLE
1481 : * transaction. Ensures that the snapshot is "safe", i.e. a
1482 : * read-only transaction running on it can execute serializably
1483 : * without further checks. This requires waiting for concurrent
1484 : * transactions to complete, and retrying with a new snapshot if
1485 : * one of them could possibly create a conflict.
1486 : *
1487 : * As with GetSerializableTransactionSnapshot (which this is a subroutine
1488 : * for), the passed-in Snapshot pointer should reference a static data
1489 : * area that can safely be passed to GetSnapshotData.
1490 : */
1491 : static Snapshot
4444 heikki.linnakangas 1492 GIC 4 : GetSafeSnapshot(Snapshot origSnapshot)
1493 : {
1494 : Snapshot snapshot;
4444 heikki.linnakangas 1495 ECB :
4444 heikki.linnakangas 1496 GIC 4 : Assert(XactReadOnly && XactDeferrable);
4444 heikki.linnakangas 1497 ECB :
1498 : while (true)
1499 : {
1500 : /*
4213 tgl 1501 : * GetSerializableTransactionSnapshotInt is going to call
1502 : * GetSnapshotData, so we need to provide it the static snapshot area
1503 : * our caller passed to us. The pointer returned is actually the same
1504 : * one passed to it, but we avoid assuming that here.
1505 : */
4187 tgl 1506 CBC 5 : snapshot = GetSerializableTransactionSnapshotInt(origSnapshot,
2125 andres 1507 ECB : NULL, InvalidPid);
1508 :
4444 heikki.linnakangas 1509 CBC 5 : if (MySerializableXact == InvalidSerializableXact)
4444 heikki.linnakangas 1510 GIC 4 : return snapshot; /* no concurrent r/w xacts; it's safe */
4444 heikki.linnakangas 1511 ECB :
4321 heikki.linnakangas 1512 CBC 1 : LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
1513 :
1514 : /*
1515 : * Wait for concurrent transactions to finish. Stop early if one of
1516 : * them marked us as conflicted.
4444 heikki.linnakangas 1517 ECB : */
4321 heikki.linnakangas 1518 GIC 1 : MySerializableXact->flags |= SXACT_FLAG_DEFERRABLE_WAITING;
80 andres 1519 GNC 2 : while (!(dlist_is_empty(&MySerializableXact->possibleUnsafeConflicts) ||
4444 heikki.linnakangas 1520 CBC 1 : SxactIsROUnsafe(MySerializableXact)))
1521 : {
4321 1522 1 : LWLockRelease(SerializableXactHashLock);
2378 rhaas 1523 1 : ProcWaitForSignal(WAIT_EVENT_SAFE_SNAPSHOT);
4321 heikki.linnakangas 1524 GIC 1 : LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
4321 heikki.linnakangas 1525 ECB : }
4444 heikki.linnakangas 1526 GIC 1 : MySerializableXact->flags &= ~SXACT_FLAG_DEFERRABLE_WAITING;
4321 heikki.linnakangas 1527 ECB :
4444 heikki.linnakangas 1528 CBC 1 : if (!SxactIsROUnsafe(MySerializableXact))
1529 : {
4321 heikki.linnakangas 1530 UIC 0 : LWLockRelease(SerializableXactHashLock);
4444 1531 0 : break; /* success */
4321 heikki.linnakangas 1532 ECB : }
1533 :
4321 heikki.linnakangas 1534 CBC 1 : LWLockRelease(SerializableXactHashLock);
1535 :
1536 : /* else, need to retry... */
4444 heikki.linnakangas 1537 GIC 1 : ereport(DEBUG2,
1538 : (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
1539 : errmsg_internal("deferrable snapshot was unsafe; trying a new one")));
1486 tmunro 1540 1 : ReleasePredicateLocks(false, false);
1541 : }
1542 :
1543 : /*
1544 : * Now we have a safe snapshot, so we don't need to do any further checks.
1545 : */
4444 heikki.linnakangas 1546 UIC 0 : Assert(SxactIsROSafe(MySerializableXact));
1486 tmunro 1547 0 : ReleasePredicateLocks(false, true);
1548 :
4444 heikki.linnakangas 1549 LBC 0 : return snapshot;
1550 : }
4444 heikki.linnakangas 1551 ECB :
1552 : /*
1553 : * GetSafeSnapshotBlockingPids
1554 : * If the specified process is currently blocked in GetSafeSnapshot,
1555 : * write the process IDs of all processes that it is blocked by
1556 : * into the caller-supplied buffer output[]. The list is truncated at
1557 : * output_size, and the number of PIDs written into the buffer is
1558 : * returned. Returns zero if the given PID is not currently blocked
2190 tgl 1559 : * in GetSafeSnapshot.
2190 tgl 1560 EUB : */
1561 : int
2190 tgl 1562 GIC 2103 : GetSafeSnapshotBlockingPids(int blocked_pid, int *output, int output_size)
1563 : {
1564 2103 : int num_written = 0;
1565 : dlist_iter iter;
60 andres 1566 GNC 2103 : SERIALIZABLEXACT *blocking_sxact = NULL;
1567 :
2190 tgl 1568 GIC 2103 : LWLockAcquire(SerializableXactHashLock, LW_SHARED);
1569 :
1570 : /* Find blocked_pid's SERIALIZABLEXACT by linear search. */
80 andres 1571 GNC 4400 : dlist_foreach(iter, &PredXact->activeList)
2190 tgl 1572 ECB : {
60 andres 1573 GNC 2463 : SERIALIZABLEXACT *sxact =
1574 2463 : dlist_container(SERIALIZABLEXACT, xactLink, iter.cur);
1575 :
2190 tgl 1576 CBC 2463 : if (sxact->pid == blocked_pid)
1577 : {
60 andres 1578 GNC 166 : blocking_sxact = sxact;
2190 tgl 1579 GIC 166 : break;
1580 : }
2190 tgl 1581 ECB : }
1582 :
1583 : /* Did we find it, and is it currently waiting in GetSafeSnapshot? */
60 andres 1584 GNC 2103 : if (blocking_sxact != NULL && SxactIsDeferrableWaiting(blocking_sxact))
1585 : {
1586 : /* Traverse the list of possible unsafe conflicts collecting PIDs. */
1587 2 : dlist_foreach(iter, &blocking_sxact->possibleUnsafeConflicts)
1588 : {
80 1589 2 : RWConflict possibleUnsafeConflict =
1590 2 : dlist_container(RWConflictData, inLink, iter.cur);
1591 :
2190 tgl 1592 CBC 2 : output[num_written++] = possibleUnsafeConflict->sxactOut->pid;
1593 :
60 andres 1594 GNC 2 : if (num_written >= output_size)
1595 2 : break;
1596 : }
1597 : }
1598 :
2190 tgl 1599 GIC 2103 : LWLockRelease(SerializableXactHashLock);
1600 :
1601 2103 : return num_written;
1602 : }
1603 :
1604 : /*
4213 tgl 1605 ECB : * Acquire a snapshot that can be used for the current transaction.
1606 : *
1607 : * Make sure we have a SERIALIZABLEXACT reference in MySerializableXact.
1608 : * It should be current for this process and be contained in PredXact.
1609 : *
1610 : * The passed-in Snapshot pointer should reference a static data area that
1611 : * can safely be passed to GetSnapshotData. The return value is actually
1612 : * always this same pointer; no new snapshot data structure is allocated
1613 : * within this function.
4444 heikki.linnakangas 1614 EUB : */
1615 : Snapshot
4213 tgl 1616 GIC 1640 : GetSerializableTransactionSnapshot(Snapshot snapshot)
1617 : {
4444 heikki.linnakangas 1618 1640 : Assert(IsolationIsSerializable());
4444 heikki.linnakangas 1619 EUB :
1620 : /*
1621 : * Can't use serializable mode while recovery is still active, as it is,
1622 : * for example, on a hot standby. We could get here despite the check in
1623 : * check_transaction_isolation() if default_transaction_isolation is set
1624 : * to serializable, so phrase the hint accordingly.
1625 : */
3880 tgl 1626 GIC 1640 : if (RecoveryInProgress())
3880 tgl 1627 UIC 0 : ereport(ERROR,
1628 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1629 : errmsg("cannot use serializable mode in a hot standby"),
1630 : errdetail("\"default_transaction_isolation\" is set to \"serializable\"."),
1631 : errhint("You can use \"SET default_transaction_isolation = 'repeatable read'\" to change the default.")));
1632 :
4444 heikki.linnakangas 1633 ECB : /*
1634 : * A special optimization is available for SERIALIZABLE READ ONLY
1635 : * DEFERRABLE transactions -- we can wait for a suitable snapshot and
1636 : * thereby avoid all SSI overhead once it's running.
1637 : */
4444 heikki.linnakangas 1638 GIC 1640 : if (XactReadOnly && XactDeferrable)
1639 4 : return GetSafeSnapshot(snapshot);
1640 :
4187 tgl 1641 1636 : return GetSerializableTransactionSnapshotInt(snapshot,
1642 : NULL, InvalidPid);
4444 heikki.linnakangas 1643 ECB : }
1644 :
4187 tgl 1645 : /*
1646 : * Import a snapshot to be used for the current transaction.
1647 : *
1648 : * This is nearly the same as GetSerializableTransactionSnapshot, except that
1649 : * we don't take a new snapshot, but rather use the data we're handed.
1650 : *
1651 : * The caller must have verified that the snapshot came from a serializable
1652 : * transaction; and if we're read-write, the source transaction must not be
4187 tgl 1653 EUB : * read-only.
1654 : */
4187 tgl 1655 ECB : void
4187 tgl 1656 CBC 13 : SetSerializableTransactionSnapshot(Snapshot snapshot,
2125 andres 1657 ECB : VirtualTransactionId *sourcevxid,
1658 : int sourcepid)
1659 : {
4187 tgl 1660 GIC 13 : Assert(IsolationIsSerializable());
1661 :
1662 : /*
1663 : * If this is called by parallel.c in a parallel worker, we don't want to
1664 : * create a SERIALIZABLEXACT just yet because the leader's
1665 : * SERIALIZABLEXACT will be installed with AttachSerializableXact(). We
1666 : * also don't want to reject SERIALIZABLE READ ONLY DEFERRABLE in this
1667 : * case, because the leader has already determined that the snapshot it
1668 : * has passed us is safe. So there is nothing for us to do.
1669 : */
1486 tmunro 1670 13 : if (IsParallelWorker())
1671 13 : return;
1672 :
1673 : /*
4187 tgl 1674 ECB : * We do not allow SERIALIZABLE READ ONLY DEFERRABLE transactions to
1675 : * import snapshots, since there's no way to wait for a safe snapshot when
1676 : * we're using the snap we're told to. (XXX instead of throwing an error,
3955 bruce 1677 : * we could just ignore the XactDeferrable flag?)
1678 : */
4187 tgl 1679 LBC 0 : if (XactReadOnly && XactDeferrable)
4187 tgl 1680 UIC 0 : ereport(ERROR,
4187 tgl 1681 EUB : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1682 : errmsg("a snapshot-importing transaction must not be READ ONLY DEFERRABLE")));
1683 :
2125 andres 1684 UIC 0 : (void) GetSerializableTransactionSnapshotInt(snapshot, sourcevxid,
2125 andres 1685 ECB : sourcepid);
1686 : }
1687 :
4187 tgl 1688 : /*
1689 : * Guts of GetSerializableTransactionSnapshot
4187 tgl 1690 EUB : *
1691 : * If sourcevxid is valid, this is actually an import operation and we should
1692 : * skip calling GetSnapshotData, because the snapshot contents are already
1693 : * loaded up. HOWEVER: to avoid race conditions, we must check that the
1694 : * source xact is still running after we acquire SerializableXactHashLock.
1695 : * We do that by calling ProcArrayInstallImportedXmin.
1696 : */
1697 : static Snapshot
4187 tgl 1698 GIC 1641 : GetSerializableTransactionSnapshotInt(Snapshot snapshot,
1699 : VirtualTransactionId *sourcevxid,
1700 : int sourcepid)
1701 : {
1702 : PGPROC *proc;
1703 : VirtualTransactionId vxid;
1704 : SERIALIZABLEXACT *sxact,
1705 : *othersxact;
1706 :
1707 : /* We only do this for serializable transactions. Once. */
4444 heikki.linnakangas 1708 1641 : Assert(MySerializableXact == InvalidSerializableXact);
1709 :
1710 1641 : Assert(!RecoveryInProgress());
1711 :
1712 : /*
2901 rhaas 1713 ECB : * Since all parts of a serializable transaction must use the same
1714 : * snapshot, it is too late to establish one after a parallel operation
1715 : * has begun.
1716 : */
2901 rhaas 1717 CBC 1641 : if (IsInParallelMode())
2901 rhaas 1718 UIC 0 : elog(ERROR, "cannot establish serializable snapshot during a parallel operation");
1719 :
4444 heikki.linnakangas 1720 GIC 1641 : proc = MyProc;
4444 heikki.linnakangas 1721 CBC 1641 : Assert(proc != NULL);
1722 1641 : GET_VXID_FROM_PGPROC(vxid, *proc);
4444 heikki.linnakangas 1723 ECB :
1724 : /*
1725 : * First we get the sxact structure, which may involve looping and access
1726 : * to the "finished" list to free a structure for use.
4187 tgl 1727 : *
1728 : * We must hold SerializableXactHashLock when taking/checking the snapshot
1729 : * to avoid race conditions, for much the same reasons that
3955 bruce 1730 : * GetSnapshotData takes the ProcArrayLock. Since we might have to
1731 : * release SerializableXactHashLock to call SummarizeOldestCommittedSxact,
1732 : * this means we have to create the sxact first, which is a bit annoying
1733 : * (in particular, an elog(ERROR) in procarray.c would cause us to leak
3260 1734 : * the sxact). Consider refactoring to avoid this.
4444 heikki.linnakangas 1735 : */
1059 tgl 1736 : #ifdef TEST_SUMMARIZE_SERIAL
1737 : SummarizeOldestCommittedSxact();
1738 : #endif
4444 heikki.linnakangas 1739 GIC 1641 : LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
4444 heikki.linnakangas 1740 ECB : do
1741 : {
4444 heikki.linnakangas 1742 GIC 1641 : sxact = CreatePredXact();
1743 : /* If null, push out committed sxact to SLRU summary & retry. */
1744 1641 : if (!sxact)
1745 : {
4444 heikki.linnakangas 1746 UIC 0 : LWLockRelease(SerializableXactHashLock);
1747 0 : SummarizeOldestCommittedSxact();
4444 heikki.linnakangas 1748 LBC 0 : LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
1749 : }
4444 heikki.linnakangas 1750 CBC 1641 : } while (!sxact);
1751 :
4187 tgl 1752 ECB : /* Get the snapshot, or check that it's safe to use */
2125 andres 1753 CBC 1641 : if (!sourcevxid)
4187 tgl 1754 1641 : snapshot = GetSnapshotData(snapshot);
2125 andres 1755 UIC 0 : else if (!ProcArrayInstallImportedXmin(snapshot->xmin, sourcevxid))
4187 tgl 1756 ECB : {
4187 tgl 1757 UIC 0 : ReleasePredXact(sxact);
1758 0 : LWLockRelease(SerializableXactHashLock);
1759 0 : ereport(ERROR,
1760 : (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
1761 : errmsg("could not import the requested snapshot"),
1762 : errdetail("The source process with PID %d is not running anymore.",
1763 : sourcepid)));
1764 : }
1765 :
4444 heikki.linnakangas 1766 ECB : /*
1767 : * If there are no serializable transactions which are not read-only, we
4444 heikki.linnakangas 1768 EUB : * can "opt out" of predicate locking and conflict checking for a
1769 : * read-only transaction.
1770 : *
1771 : * The reason this is safe is that a read-only transaction can only become
1772 : * part of a dangerous structure if it overlaps a writable transaction
1773 : * which in turn overlaps a writable transaction which committed before
1774 : * the read-only transaction started. A new writable transaction can
4444 heikki.linnakangas 1775 ECB : * overlap this one, but it can't meet the other condition of overlapping
1776 : * a transaction which committed before this one started.
1777 : */
4444 heikki.linnakangas 1778 GIC 1641 : if (XactReadOnly && PredXact->WritableSxactCount == 0)
1779 : {
1780 112 : ReleasePredXact(sxact);
4444 heikki.linnakangas 1781 CBC 112 : LWLockRelease(SerializableXactHashLock);
4444 heikki.linnakangas 1782 GIC 112 : return snapshot;
4444 heikki.linnakangas 1783 ECB : }
1784 :
1785 : /* Initialize the structure. */
4444 heikki.linnakangas 1786 CBC 1529 : sxact->vxid = vxid;
4444 heikki.linnakangas 1787 GIC 1529 : sxact->SeqNo.lastCommitBeforeSnapshot = PredXact->LastSxactCommitSeqNo;
4294 heikki.linnakangas 1788 CBC 1529 : sxact->prepareSeqNo = InvalidSerCommitSeqNo;
4444 heikki.linnakangas 1789 GIC 1529 : sxact->commitSeqNo = InvalidSerCommitSeqNo;
80 andres 1790 GNC 1529 : dlist_init(&(sxact->outConflicts));
1791 1529 : dlist_init(&(sxact->inConflicts));
1792 1529 : dlist_init(&(sxact->possibleUnsafeConflicts));
4444 heikki.linnakangas 1793 GIC 1529 : sxact->topXid = GetTopTransactionIdIfAny();
1794 1529 : sxact->finishedBefore = InvalidTransactionId;
4444 heikki.linnakangas 1795 CBC 1529 : sxact->xmin = snapshot->xmin;
4444 heikki.linnakangas 1796 GIC 1529 : sxact->pid = MyProcPid;
479 tmunro 1797 1529 : sxact->pgprocno = MyProc->pgprocno;
80 andres 1798 GNC 1529 : dlist_init(&sxact->predicateLocks);
1799 1529 : dlist_node_init(&sxact->finishedLink);
4444 heikki.linnakangas 1800 GIC 1529 : sxact->flags = 0;
4444 heikki.linnakangas 1801 CBC 1529 : if (XactReadOnly)
1802 : {
1803 : dlist_iter iter;
1804 :
1805 106 : sxact->flags |= SXACT_FLAG_READ_ONLY;
1806 :
4444 heikki.linnakangas 1807 ECB : /*
1808 : * Register all concurrent r/w transactions as possible conflicts; if
1809 : * all of them commit without any outgoing conflicts to earlier
1810 : * transactions then this snapshot can be deemed safe (and we can run
1811 : * without tracking predicate locks).
1812 : */
80 andres 1813 GNC 464 : dlist_foreach(iter, &PredXact->activeList)
4444 heikki.linnakangas 1814 ECB : {
80 andres 1815 GNC 358 : othersxact = dlist_container(SERIALIZABLEXACT, xactLink, iter.cur);
1816 :
4293 heikki.linnakangas 1817 CBC 358 : if (!SxactIsCommitted(othersxact)
1818 239 : && !SxactIsDoomed(othersxact)
1819 239 : && !SxactIsReadOnly(othersxact))
1820 : {
4444 heikki.linnakangas 1821 GIC 132 : SetPossibleUnsafeConflict(sxact, othersxact);
1822 : }
4444 heikki.linnakangas 1823 ECB : }
1824 :
1825 : /*
1826 : * If we didn't find any possibly unsafe conflicts because every
1827 : * uncommitted writable transaction turned out to be doomed, then we
1828 : * can "opt out" immediately. See comments above the earlier check for
1829 : * PredXact->WritableSxactCount == 0.
31 tmunro 1830 : */
31 tmunro 1831 GNC 106 : if (dlist_is_empty(&sxact->possibleUnsafeConflicts))
1832 : {
31 tmunro 1833 UIC 0 : ReleasePredXact(sxact);
1834 0 : LWLockRelease(SerializableXactHashLock);
1835 0 : return snapshot;
1836 : }
1837 : }
1838 : else
1839 : {
4444 heikki.linnakangas 1840 CBC 1423 : ++(PredXact->WritableSxactCount);
1841 1423 : Assert(PredXact->WritableSxactCount <=
1842 : (MaxBackends + max_prepared_xacts));
1843 : }
4444 heikki.linnakangas 1844 ECB :
1845 : /* Maintain serializable global xmin info. */
31 tmunro 1846 CBC 1529 : if (!TransactionIdIsValid(PredXact->SxactGlobalXmin))
1847 : {
31 tmunro 1848 GIC 846 : Assert(PredXact->SxactGlobalXminCount == 0);
31 tmunro 1849 CBC 846 : PredXact->SxactGlobalXmin = snapshot->xmin;
31 tmunro 1850 GIC 846 : PredXact->SxactGlobalXminCount = 1;
31 tmunro 1851 CBC 846 : SerialSetActiveSerXmin(snapshot->xmin);
1852 : }
1853 683 : else if (TransactionIdEquals(snapshot->xmin, PredXact->SxactGlobalXmin))
31 tmunro 1854 ECB : {
31 tmunro 1855 GIC 649 : Assert(PredXact->SxactGlobalXminCount > 0);
1856 649 : PredXact->SxactGlobalXminCount++;
31 tmunro 1857 ECB : }
1858 : else
1859 : {
31 tmunro 1860 CBC 34 : Assert(TransactionIdFollows(snapshot->xmin, PredXact->SxactGlobalXmin));
31 tmunro 1861 ECB : }
1862 :
4444 heikki.linnakangas 1863 GIC 1529 : MySerializableXact = sxact;
4321 1864 1529 : MyXactDidWrite = false; /* haven't written anything yet */
1865 :
4444 1866 1529 : LWLockRelease(SerializableXactHashLock);
1867 :
1486 tmunro 1868 1529 : CreateLocalPredicateLockHash();
1869 :
1870 1529 : return snapshot;
1871 : }
1872 :
1873 : static void
1874 1542 : CreateLocalPredicateLockHash(void)
1875 : {
1876 : HASHCTL hash_ctl;
1877 :
1878 : /* Initialize the backend-local hash table of parent locks */
4444 heikki.linnakangas 1879 GBC 1542 : Assert(LocalPredicateLockHash == NULL);
4444 heikki.linnakangas 1880 GIC 1542 : hash_ctl.keysize = sizeof(PREDICATELOCKTARGETTAG);
1881 1542 : hash_ctl.entrysize = sizeof(LOCALPREDICATELOCK);
1882 1542 : LocalPredicateLockHash = hash_create("Local predicate lock",
1883 : max_predicate_locks_per_xact,
1884 : &hash_ctl,
1885 : HASH_ELEM | HASH_BLOBS);
4444 heikki.linnakangas 1886 GBC 1542 : }
1887 :
1888 : /*
1889 : * Register the top level XID in SerializableXidHash.
1890 : * Also store it for easy reference in MySerializableXact.
4444 heikki.linnakangas 1891 EUB : */
1892 : void
4309 heikki.linnakangas 1893 GBC 298065 : RegisterPredicateLockingXid(TransactionId xid)
1894 : {
4444 heikki.linnakangas 1895 EUB : SERIALIZABLEXIDTAG sxidtag;
1896 : SERIALIZABLEXID *sxid;
1897 : bool found;
1898 :
1899 : /*
1900 : * If we're not tracking predicate lock data for this transaction, we
1901 : * should ignore the request and return quickly.
1902 : */
4444 heikki.linnakangas 1903 GIC 298065 : if (MySerializableXact == InvalidSerializableXact)
1904 296802 : return;
1905 :
1906 : /* We should have a valid XID and be at the top level. */
1907 1263 : Assert(TransactionIdIsValid(xid));
1908 :
4321 1909 1263 : LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
1910 :
1911 : /* This should only be done once per transaction. */
1912 1263 : Assert(MySerializableXact->topXid == InvalidTransactionId);
1913 :
4444 1914 1263 : MySerializableXact->topXid = xid;
1915 :
4444 heikki.linnakangas 1916 CBC 1263 : sxidtag.xid = xid;
4444 heikki.linnakangas 1917 GIC 1263 : sxid = (SERIALIZABLEXID *) hash_search(SerializableXidHash,
1918 : &sxidtag,
1919 : HASH_ENTER, &found);
1920 1263 : Assert(!found);
4444 heikki.linnakangas 1921 ECB :
1922 : /* Initialize the structure. */
4321 heikki.linnakangas 1923 GIC 1263 : sxid->myXact = MySerializableXact;
4444 1924 1263 : LWLockRelease(SerializableXactHashLock);
4444 heikki.linnakangas 1925 ECB : }
1926 :
1927 :
1928 : /*
1929 : * Check whether there are any predicate locks held by any transaction
1930 : * for the page at the given block number.
1931 : *
1932 : * Note that the transaction may be completed but not yet subject to
1933 : * cleanup due to overlapping serializable transactions. This must
1934 : * return valid information regardless of transaction isolation level.
1935 : *
1936 : * Also note that this doesn't check for a conflicting relation lock,
1937 : * just a lock specifically on the given page.
1938 : *
1939 : * One use is to support proper behavior during GiST index vacuum.
1940 : */
1941 : bool
4309 heikki.linnakangas 1942 UIC 0 : PageIsPredicateLocked(Relation relation, BlockNumber blkno)
4444 heikki.linnakangas 1943 ECB : {
1944 : PREDICATELOCKTARGETTAG targettag;
1945 : uint32 targettaghash;
3359 rhaas 1946 : LWLock *partitionLock;
1947 : PREDICATELOCKTARGET *target;
4444 heikki.linnakangas 1948 :
4444 heikki.linnakangas 1949 UIC 0 : SET_PREDICATELOCKTARGETTAG_PAGE(targettag,
1950 : relation->rd_locator.dbOid,
1951 : relation->rd_id,
4444 heikki.linnakangas 1952 ECB : blkno);
1953 :
4444 heikki.linnakangas 1954 LBC 0 : targettaghash = PredicateLockTargetTagHashCode(&targettag);
4444 heikki.linnakangas 1955 UIC 0 : partitionLock = PredicateLockHashPartitionLock(targettaghash);
1956 0 : LWLockAcquire(partitionLock, LW_SHARED);
1957 : target = (PREDICATELOCKTARGET *)
4444 heikki.linnakangas 1958 LBC 0 : hash_search_with_hash_value(PredicateLockTargetHash,
1959 : &targettag, targettaghash,
4444 heikki.linnakangas 1960 ECB : HASH_FIND, NULL);
4444 heikki.linnakangas 1961 UIC 0 : LWLockRelease(partitionLock);
4444 heikki.linnakangas 1962 ECB :
4444 heikki.linnakangas 1963 UIC 0 : return (target != NULL);
1964 : }
1965 :
4444 heikki.linnakangas 1966 ECB :
1967 : /*
1968 : * Check whether a particular lock is held by this transaction.
1969 : *
4444 heikki.linnakangas 1970 EUB : * Important note: this function may return false even if the lock is
1971 : * being held, because it uses the local lock table which is not
1972 : * updated if another transaction modifies our lock list (e.g. to
1973 : * split an index page). It can also return true when a coarser
1974 : * granularity lock that covers this target is being held. Be careful
1975 : * to only use this function in circumstances where such errors are
1976 : * acceptable!
1977 : */
1978 : static bool
4309 tgl 1979 GIC 77194 : PredicateLockExists(const PREDICATELOCKTARGETTAG *targettag)
1980 : {
1981 : LOCALPREDICATELOCK *lock;
4444 heikki.linnakangas 1982 ECB :
1983 : /* check local hash table */
4444 heikki.linnakangas 1984 GIC 77194 : lock = (LOCALPREDICATELOCK *) hash_search(LocalPredicateLockHash,
1985 : targettag,
1986 : HASH_FIND, NULL);
4444 heikki.linnakangas 1987 ECB :
4444 heikki.linnakangas 1988 GIC 77194 : if (!lock)
1989 30089 : return false;
4444 heikki.linnakangas 1990 ECB :
1991 : /*
1992 : * Found entry in the table, but still need to check whether it's actually
1993 : * held -- it could just be a parent of some held lock.
1994 : */
4444 heikki.linnakangas 1995 GIC 47105 : return lock->held;
1996 : }
1997 :
4444 heikki.linnakangas 1998 ECB : /*
1999 : * Return the parent lock tag in the lock hierarchy: the next coarser
2000 : * lock that covers the provided tag.
2001 : *
2002 : * Returns true and sets *parent to the parent tag if one exists,
2003 : * returns false if none exists.
2004 : */
2005 : static bool
4309 tgl 2006 GIC 45149 : GetParentPredicateLockTag(const PREDICATELOCKTARGETTAG *tag,
2007 : PREDICATELOCKTARGETTAG *parent)
2008 : {
4444 heikki.linnakangas 2009 45149 : switch (GET_PREDICATELOCKTARGETTAG_TYPE(*tag))
2010 : {
4444 heikki.linnakangas 2011 CBC 9800 : case PREDLOCKTAG_RELATION:
2012 : /* relation locks have no parent lock */
4444 heikki.linnakangas 2013 GIC 9800 : return false;
2014 :
4444 heikki.linnakangas 2015 CBC 8416 : case PREDLOCKTAG_PAGE:
2016 : /* parent lock is relation lock */
2017 8416 : SET_PREDICATELOCKTARGETTAG_RELATION(*parent,
2118 tgl 2018 EUB : GET_PREDICATELOCKTARGETTAG_DB(*tag),
2118 tgl 2019 ECB : GET_PREDICATELOCKTARGETTAG_RELATION(*tag));
2020 :
4444 heikki.linnakangas 2021 GIC 8416 : return true;
2022 :
4444 heikki.linnakangas 2023 CBC 26933 : case PREDLOCKTAG_TUPLE:
4444 heikki.linnakangas 2024 ECB : /* parent lock is page lock */
4444 heikki.linnakangas 2025 GBC 26933 : SET_PREDICATELOCKTARGETTAG_PAGE(*parent,
2118 tgl 2026 ECB : GET_PREDICATELOCKTARGETTAG_DB(*tag),
2027 : GET_PREDICATELOCKTARGETTAG_RELATION(*tag),
2028 : GET_PREDICATELOCKTARGETTAG_PAGE(*tag));
4444 heikki.linnakangas 2029 GIC 26933 : return true;
2030 : }
2031 :
4444 heikki.linnakangas 2032 ECB : /* not reachable */
4444 heikki.linnakangas 2033 UIC 0 : Assert(false);
2034 : return false;
2035 : }
4444 heikki.linnakangas 2036 ECB :
2037 : /*
2038 : * Check whether the lock we are considering is already covered by a
4444 heikki.linnakangas 2039 EUB : * coarser lock for our transaction.
4422 heikki.linnakangas 2040 ECB : *
2041 : * Like PredicateLockExists, this function might return a false
2042 : * negative, but it will never return a false positive.
2043 : */
4444 2044 : static bool
4309 tgl 2045 CBC 26031 : CoarserLockCovers(const PREDICATELOCKTARGETTAG *newtargettag)
4444 heikki.linnakangas 2046 EUB : {
4444 heikki.linnakangas 2047 ECB : PREDICATELOCKTARGETTAG targettag,
2048 : parenttag;
2049 :
4444 heikki.linnakangas 2050 GIC 26031 : targettag = *newtargettag;
2051 :
2052 : /* check parents iteratively until no more */
2053 31415 : while (GetParentPredicateLockTag(&targettag, &parenttag))
4444 heikki.linnakangas 2054 ECB : {
4444 heikki.linnakangas 2055 GIC 27205 : targettag = parenttag;
2056 27205 : if (PredicateLockExists(&targettag))
2057 21821 : return true;
4444 heikki.linnakangas 2058 ECB : }
2059 :
2060 : /* no more parents to check; lock is not covered */
4444 heikki.linnakangas 2061 CBC 4210 : return false;
4444 heikki.linnakangas 2062 ECB : }
2063 :
2064 : /*
4323 2065 : * Remove the dummy entry from the predicate lock target hash, to free up some
1059 tgl 2066 : * scratch space. The caller must be holding SerializablePredicateListLock,
2067 : * and must restore the entry with RestoreScratchTarget() before releasing the
2068 : * lock.
4323 heikki.linnakangas 2069 : *
2070 : * If lockheld is true, the caller is already holding the partition lock
2071 : * of the partition containing the scratch entry.
2072 : */
2073 : static void
4323 heikki.linnakangas 2074 GIC 19 : RemoveScratchTarget(bool lockheld)
2075 : {
2076 : bool found;
2077 :
1059 tgl 2078 19 : Assert(LWLockHeldByMe(SerializablePredicateListLock));
2079 :
4323 heikki.linnakangas 2080 19 : if (!lockheld)
4323 heikki.linnakangas 2081 UIC 0 : LWLockAcquire(ScratchPartitionLock, LW_EXCLUSIVE);
4323 heikki.linnakangas 2082 GIC 19 : hash_search_with_hash_value(PredicateLockTargetHash,
2083 : &ScratchTargetTag,
2084 : ScratchTargetTagHash,
4323 heikki.linnakangas 2085 ECB : HASH_REMOVE, &found);
4323 heikki.linnakangas 2086 GIC 19 : Assert(found);
2087 19 : if (!lockheld)
4323 heikki.linnakangas 2088 UIC 0 : LWLockRelease(ScratchPartitionLock);
4323 heikki.linnakangas 2089 GIC 19 : }
2090 :
4323 heikki.linnakangas 2091 ECB : /*
2092 : * Re-insert the dummy entry in predicate lock target hash.
2093 : */
2094 : static void
4323 heikki.linnakangas 2095 GIC 19 : RestoreScratchTarget(bool lockheld)
4323 heikki.linnakangas 2096 ECB : {
2097 : bool found;
2098 :
1059 tgl 2099 GIC 19 : Assert(LWLockHeldByMe(SerializablePredicateListLock));
2100 :
4323 heikki.linnakangas 2101 19 : if (!lockheld)
4323 heikki.linnakangas 2102 LBC 0 : LWLockAcquire(ScratchPartitionLock, LW_EXCLUSIVE);
4323 heikki.linnakangas 2103 GIC 19 : hash_search_with_hash_value(PredicateLockTargetHash,
4323 heikki.linnakangas 2104 ECB : &ScratchTargetTag,
2105 : ScratchTargetTagHash,
2106 : HASH_ENTER, &found);
4323 heikki.linnakangas 2107 CBC 19 : Assert(!found);
4323 heikki.linnakangas 2108 GIC 19 : if (!lockheld)
4323 heikki.linnakangas 2109 LBC 0 : LWLockRelease(ScratchPartitionLock);
4323 heikki.linnakangas 2110 GIC 19 : }
2111 :
2112 : /*
2113 : * Check whether the list of related predicate locks is empty for a
2114 : * predicate lock target, and remove the target if it is.
4444 heikki.linnakangas 2115 ECB : */
2116 : static void
4444 heikki.linnakangas 2117 GIC 4204 : RemoveTargetIfNoLongerUsed(PREDICATELOCKTARGET *target, uint32 targettaghash)
4444 heikki.linnakangas 2118 ECB : {
2119 : PREDICATELOCKTARGET *rmtarget PG_USED_FOR_ASSERTS_ONLY;
2120 :
1059 tgl 2121 CBC 4204 : Assert(LWLockHeldByMe(SerializablePredicateListLock));
4444 heikki.linnakangas 2122 ECB :
2123 : /* Can't remove it until no locks at this target. */
80 andres 2124 GNC 4204 : if (!dlist_is_empty(&target->predicateLocks))
4444 heikki.linnakangas 2125 CBC 961 : return;
2126 :
2127 : /* Actually remove the target. */
2128 3243 : rmtarget = hash_search_with_hash_value(PredicateLockTargetHash,
4444 heikki.linnakangas 2129 GIC 3243 : &target->tag,
4444 heikki.linnakangas 2130 ECB : targettaghash,
2131 : HASH_REMOVE, NULL);
4444 heikki.linnakangas 2132 CBC 3243 : Assert(rmtarget == target);
2133 : }
4444 heikki.linnakangas 2134 ECB :
2135 : /*
2136 : * Delete child target locks owned by this process.
2137 : * This implementation is assuming that the usage of each target tag field
3260 bruce 2138 : * is uniform. No need to make this hard if we don't have to.
4444 heikki.linnakangas 2139 : *
1486 tmunro 2140 : * We acquire an LWLock in the case of parallel mode, because worker
2141 : * backends have access to the leader's SERIALIZABLEXACT. Otherwise,
2142 : * we aren't acquiring LWLocks for the predicate lock or lock
2143 : * target structures associated with this transaction unless we're going
2144 : * to modify them, because no other process is permitted to modify our
2145 : * locks.
2146 : */
2147 : static void
4309 tgl 2148 GIC 2344 : DeleteChildTargetLocks(const PREDICATELOCKTARGETTAG *newtargettag)
2149 : {
2150 : SERIALIZABLEXACT *sxact;
2151 : PREDICATELOCK *predlock;
2152 : dlist_mutable_iter iter;
2153 :
1059 2154 2344 : LWLockAcquire(SerializablePredicateListLock, LW_SHARED);
4321 heikki.linnakangas 2155 2344 : sxact = MySerializableXact;
1486 tmunro 2156 2344 : if (IsInParallelMode())
1059 tgl 2157 11 : LWLockAcquire(&sxact->perXactPredicateListLock, LW_EXCLUSIVE);
2158 :
80 andres 2159 GNC 7766 : dlist_foreach_modify(iter, &sxact->predicateLocks)
4444 heikki.linnakangas 2160 ECB : {
2161 : PREDICATELOCKTAG oldlocktag;
2162 : PREDICATELOCKTARGET *oldtarget;
2163 : PREDICATELOCKTARGETTAG oldtargettag;
2164 :
80 andres 2165 GNC 5422 : predlock = dlist_container(PREDICATELOCK, xactLink, iter.cur);
2166 :
4444 heikki.linnakangas 2167 GIC 5422 : oldlocktag = predlock->tag;
2168 5422 : Assert(oldlocktag.myXact == sxact);
2169 5422 : oldtarget = oldlocktag.myTarget;
2170 5422 : oldtargettag = oldtarget->tag;
4444 heikki.linnakangas 2171 EUB :
4444 heikki.linnakangas 2172 GIC 5422 : if (TargetTagIsCoveredBy(oldtargettag, *newtargettag))
2173 : {
2174 : uint32 oldtargettaghash;
2175 : LWLock *partitionLock;
4036 peter_e 2176 EUB : PREDICATELOCK *rmpredlock PG_USED_FOR_ASSERTS_ONLY;
2177 :
4444 heikki.linnakangas 2178 GIC 999 : oldtargettaghash = PredicateLockTargetTagHashCode(&oldtargettag);
2179 999 : partitionLock = PredicateLockHashPartitionLock(oldtargettaghash);
2180 :
2181 999 : LWLockAcquire(partitionLock, LW_EXCLUSIVE);
2182 :
80 andres 2183 GNC 999 : dlist_delete(&predlock->xactLink);
2184 999 : dlist_delete(&predlock->targetLink);
4444 heikki.linnakangas 2185 GIC 999 : rmpredlock = hash_search_with_hash_value
2186 : (PredicateLockHash,
2187 : &oldlocktag,
2188 999 : PredicateLockHashCodeFromTargetHashCode(&oldlocktag,
4444 heikki.linnakangas 2189 ECB : oldtargettaghash),
2190 : HASH_REMOVE, NULL);
4444 heikki.linnakangas 2191 GIC 999 : Assert(rmpredlock == predlock);
2192 :
2193 999 : RemoveTargetIfNoLongerUsed(oldtarget, oldtargettaghash);
2194 :
2195 999 : LWLockRelease(partitionLock);
2196 :
2197 999 : DecrementParentLocks(&oldtargettag);
4444 heikki.linnakangas 2198 ECB : }
2199 : }
1486 tmunro 2200 GIC 2344 : if (IsInParallelMode())
1059 tgl 2201 CBC 11 : LWLockRelease(&sxact->perXactPredicateListLock);
1059 tgl 2202 GIC 2344 : LWLockRelease(SerializablePredicateListLock);
4444 heikki.linnakangas 2203 CBC 2344 : }
4444 heikki.linnakangas 2204 ECB :
2205 : /*
2206 : * Returns the promotion limit for a given predicate lock target. This is the
2207 : * max number of descendant locks allowed before promoting to the specified
2193 kgrittn 2208 : * tag. Note that the limit includes non-direct descendants (e.g., both tuples
2209 : * and pages for a relation lock).
2210 : *
2211 : * Currently the default limit is 2 for a page lock, and half of the value of
2212 : * max_pred_locks_per_transaction - 1 for a relation lock, to match behavior
2213 : * of earlier releases when upgrading.
4444 heikki.linnakangas 2214 : *
2215 : * TODO SSI: We should probably add additional GUCs to allow a maximum ratio
2193 kgrittn 2216 : * of page and tuple locks based on the pages in a relation, and the maximum
2217 : * ratio of tuple locks to tuples in a page. This would provide more
2218 : * generally "balanced" allocation of locks to where they are most useful,
2219 : * while still allowing the absolute numbers to prevent one relation from
2220 : * tying up all predicate lock resources.
2221 : */
2222 : static int
2193 kgrittn 2223 GIC 5384 : MaxPredicateChildLocks(const PREDICATELOCKTARGETTAG *tag)
2224 : {
4444 heikki.linnakangas 2225 CBC 5384 : switch (GET_PREDICATELOCKTARGETTAG_TYPE(*tag))
4444 heikki.linnakangas 2226 ECB : {
4444 heikki.linnakangas 2227 GIC 3518 : case PREDLOCKTAG_RELATION:
2193 kgrittn 2228 3518 : return max_predicate_locks_per_relation < 0
2229 : ? (max_predicate_locks_per_xact
2193 kgrittn 2230 CBC 3518 : / (-max_predicate_locks_per_relation)) - 1
2193 kgrittn 2231 GIC 3518 : : max_predicate_locks_per_relation;
2232 :
4444 heikki.linnakangas 2233 CBC 1866 : case PREDLOCKTAG_PAGE:
2193 kgrittn 2234 1866 : return max_predicate_locks_per_page;
2235 :
4444 heikki.linnakangas 2236 UIC 0 : case PREDLOCKTAG_TUPLE:
4444 heikki.linnakangas 2237 ECB :
2238 : /*
2239 : * not reachable: nothing is finer-granularity than a tuple, so we
2240 : * should never try to promote to it.
2241 : */
4444 heikki.linnakangas 2242 UIC 0 : Assert(false);
2243 : return 0;
2244 : }
2245 :
2246 : /* not reachable */
2247 0 : Assert(false);
2248 : return 0;
2249 : }
2250 :
2251 : /*
4444 heikki.linnakangas 2252 ECB : * For all ancestors of a newly-acquired predicate lock, increment
2253 : * their child count in the parent hash table. If any of them have
2254 : * more descendants than their promotion threshold, acquire the
2255 : * coarsest such lock.
2256 : *
2257 : * Returns true if a parent lock was acquired and false otherwise.
2258 : */
2259 : static bool
4309 tgl 2260 GIC 4210 : CheckAndPromotePredicateLockRequest(const PREDICATELOCKTARGETTAG *reqtag)
2261 : {
2262 : PREDICATELOCKTARGETTAG targettag,
2263 : nexttag,
2264 : promotiontag;
4444 heikki.linnakangas 2265 ECB : LOCALPREDICATELOCK *parentlock;
2266 : bool found,
2267 : promote;
2268 :
4444 heikki.linnakangas 2269 GIC 4210 : promote = false;
2270 :
2271 4210 : targettag = *reqtag;
2272 :
2273 : /* check parents iteratively */
2274 13804 : while (GetParentPredicateLockTag(&targettag, &nexttag))
2275 : {
2276 5384 : targettag = nexttag;
4444 heikki.linnakangas 2277 CBC 5384 : parentlock = (LOCALPREDICATELOCK *) hash_search(LocalPredicateLockHash,
4444 heikki.linnakangas 2278 EUB : &targettag,
2279 : HASH_ENTER,
4444 heikki.linnakangas 2280 ECB : &found);
4444 heikki.linnakangas 2281 GIC 5384 : if (!found)
2282 : {
2283 3323 : parentlock->held = false;
2284 3323 : parentlock->childLocks = 1;
2285 : }
2286 : else
4444 heikki.linnakangas 2287 CBC 2061 : parentlock->childLocks++;
2288 :
2193 kgrittn 2289 GBC 5384 : if (parentlock->childLocks >
2290 5384 : MaxPredicateChildLocks(&targettag))
2291 : {
2292 : /*
4444 heikki.linnakangas 2293 ECB : * We should promote to this parent lock. Continue to check its
2294 : * ancestors, however, both to get their child counts right and to
2295 : * check whether we should just go ahead and promote to one of
2296 : * them.
2297 : */
4444 heikki.linnakangas 2298 GIC 333 : promotiontag = targettag;
4444 heikki.linnakangas 2299 CBC 333 : promote = true;
2300 : }
2301 : }
4444 heikki.linnakangas 2302 ECB :
4444 heikki.linnakangas 2303 GIC 4210 : if (promote)
2304 : {
2305 : /* acquire coarsest ancestor eligible for promotion */
2306 333 : PredicateLockAcquire(&promotiontag);
2307 333 : return true;
2308 : }
2309 : else
2310 3877 : return false;
2311 : }
2312 :
2313 : /*
4444 heikki.linnakangas 2314 ECB : * When releasing a lock, decrement the child count on all ancestor
2315 : * locks.
2316 : *
2317 : * This is called only when releasing a lock via
2318 : * DeleteChildTargetLocks (i.e. when a lock becomes redundant because
2319 : * we've acquired its parent, possibly due to promotion) or when a new
2320 : * MVCC write lock makes the predicate lock unnecessary. There's no
2321 : * point in calling it when locks are released at transaction end, as
2322 : * this information is no longer needed.
2323 : */
2324 : static void
4309 tgl 2325 GIC 1380 : DecrementParentLocks(const PREDICATELOCKTARGETTAG *targettag)
4444 heikki.linnakangas 2326 ECB : {
2327 : PREDICATELOCKTARGETTAG parenttag,
2328 : nexttag;
2329 :
4444 heikki.linnakangas 2330 GIC 1380 : parenttag = *targettag;
2331 :
2332 4140 : while (GetParentPredicateLockTag(&parenttag, &nexttag))
4444 heikki.linnakangas 2333 ECB : {
2334 : uint32 targettaghash;
2335 : LOCALPREDICATELOCK *parentlock,
4036 peter_e 2336 : *rmlock PG_USED_FOR_ASSERTS_ONLY;
4444 heikki.linnakangas 2337 EUB :
4444 heikki.linnakangas 2338 GIC 2760 : parenttag = nexttag;
2339 2760 : targettaghash = PredicateLockTargetTagHashCode(&parenttag);
2340 : parentlock = (LOCALPREDICATELOCK *)
4444 heikki.linnakangas 2341 CBC 2760 : hash_search_with_hash_value(LocalPredicateLockHash,
4444 heikki.linnakangas 2342 ECB : &parenttag, targettaghash,
2343 : HASH_FIND, NULL);
2344 :
2345 : /*
2346 : * There's a small chance the parent lock doesn't exist in the lock
2347 : * table. This can happen if we prematurely removed it because an
2348 : * index split caused the child refcount to be off.
2349 : */
4444 heikki.linnakangas 2350 GIC 2760 : if (parentlock == NULL)
4444 heikki.linnakangas 2351 LBC 0 : continue;
4444 heikki.linnakangas 2352 EUB :
4444 heikki.linnakangas 2353 GIC 2760 : parentlock->childLocks--;
2354 :
2355 : /*
2356 : * Under similar circumstances the parent lock's refcount might be
4444 heikki.linnakangas 2357 ECB : * zero. This only happens if we're holding that lock (otherwise we
2358 : * would have removed the entry).
2359 : */
4444 heikki.linnakangas 2360 CBC 2760 : if (parentlock->childLocks < 0)
4444 heikki.linnakangas 2361 ECB : {
4444 heikki.linnakangas 2362 UIC 0 : Assert(parentlock->held);
2363 0 : parentlock->childLocks = 0;
4444 heikki.linnakangas 2364 ECB : }
2365 :
4444 heikki.linnakangas 2366 CBC 2760 : if ((parentlock->childLocks == 0) && (!parentlock->held))
4444 heikki.linnakangas 2367 ECB : {
2368 : rmlock = (LOCALPREDICATELOCK *)
4444 heikki.linnakangas 2369 GIC 750 : hash_search_with_hash_value(LocalPredicateLockHash,
2370 : &parenttag, targettaghash,
2371 : HASH_REMOVE, NULL);
2372 750 : Assert(rmlock == parentlock);
2373 : }
2374 : }
2375 1380 : }
2376 :
2377 : /*
4444 heikki.linnakangas 2378 ECB : * Indicate that a predicate lock on the given target is held by the
2379 : * specified transaction. Has no effect if the lock is already held.
2380 : *
2381 : * This updates the lock table and the sxact's lock list, and creates
2382 : * the lock target if necessary, but does *not* do anything related to
2383 : * granularity promotion or the local lock table. See
2384 : * PredicateLockAcquire for that.
2385 : */
2386 : static void
4309 tgl 2387 GIC 4210 : CreatePredicateLock(const PREDICATELOCKTARGETTAG *targettag,
4444 heikki.linnakangas 2388 ECB : uint32 targettaghash,
2389 : SERIALIZABLEXACT *sxact)
2390 : {
2391 : PREDICATELOCKTARGET *target;
2392 : PREDICATELOCKTAG locktag;
2393 : PREDICATELOCK *lock;
2394 : LWLock *partitionLock;
2395 : bool found;
2396 :
4444 heikki.linnakangas 2397 GIC 4210 : partitionLock = PredicateLockHashPartitionLock(targettaghash);
2398 :
1059 tgl 2399 CBC 4210 : LWLockAcquire(SerializablePredicateListLock, LW_SHARED);
1486 tmunro 2400 4210 : if (IsInParallelMode())
1059 tgl 2401 16 : LWLockAcquire(&sxact->perXactPredicateListLock, LW_EXCLUSIVE);
4444 heikki.linnakangas 2402 GIC 4210 : LWLockAcquire(partitionLock, LW_EXCLUSIVE);
2403 :
4444 heikki.linnakangas 2404 ECB : /* Make sure that the target is represented. */
2405 : target = (PREDICATELOCKTARGET *)
4444 heikki.linnakangas 2406 GIC 4210 : hash_search_with_hash_value(PredicateLockTargetHash,
2407 : targettag, targettaghash,
2408 : HASH_ENTER_NULL, &found);
2409 4210 : if (!target)
4444 heikki.linnakangas 2410 UIC 0 : ereport(ERROR,
4444 heikki.linnakangas 2411 ECB : (errcode(ERRCODE_OUT_OF_MEMORY),
2412 : errmsg("out of shared memory"),
2413 : errhint("You might need to increase max_pred_locks_per_transaction.")));
4444 heikki.linnakangas 2414 GIC 4210 : if (!found)
80 andres 2415 GNC 3243 : dlist_init(&target->predicateLocks);
2416 :
2417 : /* We've got the sxact and target, make sure they're joined. */
4444 heikki.linnakangas 2418 GIC 4210 : locktag.myTarget = target;
2419 4210 : locktag.myXact = sxact;
2420 : lock = (PREDICATELOCK *)
2421 4210 : hash_search_with_hash_value(PredicateLockHash, &locktag,
2118 tgl 2422 CBC 4210 : PredicateLockHashCodeFromTargetHashCode(&locktag, targettaghash),
4385 rhaas 2423 ECB : HASH_ENTER_NULL, &found);
4444 heikki.linnakangas 2424 GIC 4210 : if (!lock)
4444 heikki.linnakangas 2425 UIC 0 : ereport(ERROR,
2426 : (errcode(ERRCODE_OUT_OF_MEMORY),
2427 : errmsg("out of shared memory"),
2428 : errhint("You might need to increase max_pred_locks_per_transaction.")));
2429 :
4444 heikki.linnakangas 2430 GIC 4210 : if (!found)
2431 : {
80 andres 2432 GNC 4204 : dlist_push_tail(&target->predicateLocks, &lock->targetLink);
2433 4204 : dlist_push_tail(&sxact->predicateLocks, &lock->xactLink);
4381 heikki.linnakangas 2434 GIC 4204 : lock->commitSeqNo = InvalidSerCommitSeqNo;
2435 : }
4444 heikki.linnakangas 2436 ECB :
4444 heikki.linnakangas 2437 GIC 4210 : LWLockRelease(partitionLock);
1486 tmunro 2438 4210 : if (IsInParallelMode())
1059 tgl 2439 16 : LWLockRelease(&sxact->perXactPredicateListLock);
1059 tgl 2440 CBC 4210 : LWLockRelease(SerializablePredicateListLock);
4444 heikki.linnakangas 2441 4210 : }
2442 :
4444 heikki.linnakangas 2443 ECB : /*
2444 : * Acquire a predicate lock on the specified target for the current
2445 : * connection if not already held. This updates the local lock table
2446 : * and uses it to implement granularity promotion. It will consolidate
2447 : * multiple locks into a coarser lock if warranted, and will release
2448 : * any finer-grained locks covered by the new one.
2449 : */
2450 : static void
4309 tgl 2451 GIC 26235 : PredicateLockAcquire(const PREDICATELOCKTARGETTAG *targettag)
2452 : {
2453 : uint32 targettaghash;
2454 : bool found;
2455 : LOCALPREDICATELOCK *locallock;
2456 :
2457 : /* Do we have the lock already, or a covering lock? */
4444 heikki.linnakangas 2458 26235 : if (PredicateLockExists(targettag))
4444 heikki.linnakangas 2459 CBC 22025 : return;
2460 :
4444 heikki.linnakangas 2461 GIC 26031 : if (CoarserLockCovers(targettag))
2462 21821 : return;
4444 heikki.linnakangas 2463 ECB :
2464 : /* the same hash and LW lock apply to the lock target and the local lock. */
4444 heikki.linnakangas 2465 GIC 4210 : targettaghash = PredicateLockTargetTagHashCode(targettag);
4444 heikki.linnakangas 2466 ECB :
2467 : /* Acquire lock in local table */
2468 : locallock = (LOCALPREDICATELOCK *)
4444 heikki.linnakangas 2469 GIC 4210 : hash_search_with_hash_value(LocalPredicateLockHash,
4444 heikki.linnakangas 2470 ECB : targettag, targettaghash,
2471 : HASH_ENTER, &found);
4444 heikki.linnakangas 2472 GIC 4210 : locallock->held = true;
2473 4210 : if (!found)
2474 3877 : locallock->childLocks = 0;
2475 :
2476 : /* Actually create the lock */
4321 2477 4210 : CreatePredicateLock(targettag, targettaghash, MySerializableXact);
2478 :
2479 : /*
2480 : * Lock has been acquired. Check whether it should be promoted to a
4444 heikki.linnakangas 2481 ECB : * coarser granularity, or whether there are finer-granularity locks to
2482 : * clean up.
2483 : */
4444 heikki.linnakangas 2484 GIC 4210 : if (CheckAndPromotePredicateLockRequest(targettag))
2485 : {
4444 heikki.linnakangas 2486 ECB : /*
2487 : * Lock request was promoted to a coarser-granularity lock, and that
2488 : * lock was acquired. It will delete this lock and any of its
2489 : * children, so we're done.
2490 : */
2491 : }
2492 : else
2493 : {
2494 : /* Clean up any finer-granularity locks */
4444 heikki.linnakangas 2495 CBC 3877 : if (GET_PREDICATELOCKTARGETTAG_TYPE(*targettag) != PREDLOCKTAG_TUPLE)
4444 heikki.linnakangas 2496 GBC 2344 : DeleteChildTargetLocks(targettag);
2497 : }
2498 : }
2499 :
2500 :
2501 : /*
2502 : * PredicateLockRelation
2503 : *
2504 : * Gets a predicate lock at the relation level.
4444 heikki.linnakangas 2505 ECB : * Skip if not in full serializable transaction isolation level.
2506 : * Skip if this is a temporary table.
2507 : * Clear any finer-grained predicate locks this session has on the relation.
2508 : */
4444 heikki.linnakangas 2509 EUB : void
4309 heikki.linnakangas 2510 GIC 1194493 : PredicateLockRelation(Relation relation, Snapshot snapshot)
4444 heikki.linnakangas 2511 ECB : {
2512 : PREDICATELOCKTARGETTAG tag;
2513 :
4316 heikki.linnakangas 2514 GIC 1194493 : if (!SerializationNeededForRead(relation, snapshot))
4444 2515 1193780 : return;
4444 heikki.linnakangas 2516 ECB :
4444 heikki.linnakangas 2517 GIC 713 : SET_PREDICATELOCKTARGETTAG_RELATION(tag,
2518 : relation->rd_locator.dbOid,
2519 : relation->rd_id);
2520 713 : PredicateLockAcquire(&tag);
2521 : }
2522 :
2523 : /*
2524 : * PredicateLockPage
2525 : *
2526 : * Gets a predicate lock at the page level.
2527 : * Skip if not in full serializable transaction isolation level.
2528 : * Skip if this is a temporary table.
4444 heikki.linnakangas 2529 EUB : * Skip if a coarser predicate lock already covers this page.
2530 : * Clear any finer-grained predicate locks this session has on the relation.
2531 : */
2532 : void
4309 heikki.linnakangas 2533 GBC 10333049 : PredicateLockPage(Relation relation, BlockNumber blkno, Snapshot snapshot)
2534 : {
4444 heikki.linnakangas 2535 EUB : PREDICATELOCKTARGETTAG tag;
2536 :
4316 heikki.linnakangas 2537 GBC 10333049 : if (!SerializationNeededForRead(relation, snapshot))
4444 heikki.linnakangas 2538 GIC 10331614 : return;
4444 heikki.linnakangas 2539 EUB :
4444 heikki.linnakangas 2540 GIC 1435 : SET_PREDICATELOCKTARGETTAG_PAGE(tag,
2541 : relation->rd_locator.dbOid,
4444 heikki.linnakangas 2542 EUB : relation->rd_id,
2543 : blkno);
4444 heikki.linnakangas 2544 GIC 1435 : PredicateLockAcquire(&tag);
4444 heikki.linnakangas 2545 EUB : }
2546 :
2547 : /*
1167 tmunro 2548 : * PredicateLockTID
2549 : *
4444 heikki.linnakangas 2550 : * Gets a predicate lock at the tuple level.
2551 : * Skip if not in full serializable transaction isolation level.
2552 : * Skip if this is a temporary table.
2553 : */
2554 : void
1167 tmunro 2555 GIC 19026793 : PredicateLockTID(Relation relation, ItemPointer tid, Snapshot snapshot,
1167 tmunro 2556 EUB : TransactionId tuple_xid)
2557 : {
2558 : PREDICATELOCKTARGETTAG tag;
4444 heikki.linnakangas 2559 :
4316 heikki.linnakangas 2560 GBC 19026793 : if (!SerializationNeededForRead(relation, snapshot))
4444 heikki.linnakangas 2561 GIC 19003039 : return;
2562 :
2563 : /*
2564 : * Return if this xact wrote it.
2565 : */
2566 23754 : if (relation->rd_index == NULL)
2567 : {
2568 : /* If we wrote it; we already have a write lock. */
1167 tmunro 2569 23754 : if (TransactionIdIsCurrentTransactionId(tuple_xid))
1245 tmunro 2570 UIC 0 : return;
2571 : }
2572 :
2573 : /*
2574 : * Do quick-but-not-definitive test for a relation lock first. This will
2575 : * never cause a return when the relation is *not* locked, but will
2576 : * occasionally let the check continue when there really *is* a relation
2577 : * level lock.
2578 : */
4444 heikki.linnakangas 2579 GIC 23754 : SET_PREDICATELOCKTARGETTAG_RELATION(tag,
2580 : relation->rd_locator.dbOid,
2581 : relation->rd_id);
2582 23754 : if (PredicateLockExists(&tag))
4444 heikki.linnakangas 2583 UIC 0 : return;
2584 :
4444 heikki.linnakangas 2585 GIC 23754 : SET_PREDICATELOCKTARGETTAG_TUPLE(tag,
2586 : relation->rd_locator.dbOid,
2587 : relation->rd_id,
2588 : ItemPointerGetBlockNumber(tid),
2589 : ItemPointerGetOffsetNumber(tid));
4444 heikki.linnakangas 2590 GBC 23754 : PredicateLockAcquire(&tag);
2591 : }
2592 :
2593 :
2594 : /*
2595 : * DeleteLockTarget
2596 : *
2597 : * Remove a predicate lock target along with any locks held for it.
2598 : *
2599 : * Caller must hold SerializablePredicateListLock and the
4444 heikki.linnakangas 2600 EUB : * appropriate hash partition lock for the target.
2601 : */
2602 : static void
4444 heikki.linnakangas 2603 UIC 0 : DeleteLockTarget(PREDICATELOCKTARGET *target, uint32 targettaghash)
2604 : {
2605 : dlist_mutable_iter iter;
2606 :
1059 tgl 2607 UBC 0 : Assert(LWLockHeldByMeInMode(SerializablePredicateListLock,
2608 : LW_EXCLUSIVE));
4444 heikki.linnakangas 2609 UIC 0 : Assert(LWLockHeldByMe(PredicateLockHashPartitionLock(targettaghash)));
2610 :
2611 0 : LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
80 andres 2612 EUB :
80 andres 2613 UNC 0 : dlist_foreach_modify(iter, &target->predicateLocks)
2614 : {
2615 0 : PREDICATELOCK *predlock =
2616 0 : dlist_container(PREDICATELOCK, targetLink, iter.cur);
2617 : bool found;
2618 :
2619 0 : dlist_delete(&(predlock->xactLink));
2620 0 : dlist_delete(&(predlock->targetLink));
2621 :
4444 heikki.linnakangas 2622 UBC 0 : hash_search_with_hash_value
2623 : (PredicateLockHash,
2624 0 : &predlock->tag,
2625 0 : PredicateLockHashCodeFromTargetHashCode(&predlock->tag,
4444 heikki.linnakangas 2626 EUB : targettaghash),
2627 : HASH_REMOVE, &found);
4444 heikki.linnakangas 2628 UIC 0 : Assert(found);
2629 : }
2630 0 : LWLockRelease(SerializableXactHashLock);
2631 :
2632 : /* Remove the target itself, if possible. */
2633 0 : RemoveTargetIfNoLongerUsed(target, targettaghash);
2634 0 : }
4444 heikki.linnakangas 2635 EUB :
2636 :
2637 : /*
2638 : * TransferPredicateLocksToNewTarget
2639 : *
2640 : * Move or copy all the predicate locks for a lock target, for use by
2641 : * index page splits/combines and other things that create or replace
2642 : * lock targets. If 'removeOld' is true, the old locks and the target
2643 : * will be removed.
2644 : *
2645 : * Returns true on success, or false if we ran out of shared memory to
2646 : * allocate the new target or locks. Guaranteed to always succeed if
2647 : * removeOld is set (by using the scratch entry in PredicateLockTargetHash
2648 : * for scratch space).
2649 : *
2650 : * Warning: the "removeOld" option should be used only with care,
4422 2651 : * because this function does not (indeed, can not) update other
2652 : * backends' LocalPredicateLockHash. If we are only adding new
2653 : * entries, this is not a problem: the local lock table is used only
2654 : * as a hint, so missing entries for locks that are held are
2655 : * OK. Having entries for locks that are no longer held, as can happen
2656 : * when using "removeOld", is not in general OK. We can only use it
2657 : * safely when replacing a lock with a coarser-granularity lock that
2658 : * covers it, or if we are absolutely certain that no one will need to
2659 : * refer to that lock in the future.
2660 : *
2661 : * Caller must hold SerializablePredicateListLock exclusively.
4444 2662 : */
2663 : static bool
4309 heikki.linnakangas 2664 UIC 0 : TransferPredicateLocksToNewTarget(PREDICATELOCKTARGETTAG oldtargettag,
2665 : PREDICATELOCKTARGETTAG newtargettag,
2666 : bool removeOld)
2667 : {
4444 heikki.linnakangas 2668 EUB : uint32 oldtargettaghash;
2669 : LWLock *oldpartitionLock;
2670 : PREDICATELOCKTARGET *oldtarget;
2671 : uint32 newtargettaghash;
3359 rhaas 2672 : LWLock *newpartitionLock;
4444 heikki.linnakangas 2673 : bool found;
4444 heikki.linnakangas 2674 UIC 0 : bool outOfShmem = false;
4444 heikki.linnakangas 2675 EUB :
1059 tgl 2676 UIC 0 : Assert(LWLockHeldByMeInMode(SerializablePredicateListLock,
1486 tmunro 2677 EUB : LW_EXCLUSIVE));
2678 :
4444 heikki.linnakangas 2679 UBC 0 : oldtargettaghash = PredicateLockTargetTagHashCode(&oldtargettag);
4444 heikki.linnakangas 2680 UIC 0 : newtargettaghash = PredicateLockTargetTagHashCode(&newtargettag);
4444 heikki.linnakangas 2681 UBC 0 : oldpartitionLock = PredicateLockHashPartitionLock(oldtargettaghash);
2682 0 : newpartitionLock = PredicateLockHashPartitionLock(newtargettaghash);
2683 :
2684 0 : if (removeOld)
2685 : {
4444 heikki.linnakangas 2686 EUB : /*
4323 2687 : * Remove the dummy entry to give us scratch space, so we know we'll
2688 : * be able to create the new lock target.
2689 : */
4323 heikki.linnakangas 2690 UBC 0 : RemoveScratchTarget(false);
2691 : }
2692 :
2693 : /*
4444 heikki.linnakangas 2694 EUB : * We must get the partition locks in ascending sequence to avoid
2695 : * deadlocks. If old and new partitions are the same, we must request the
2696 : * lock only once.
2697 : */
4444 heikki.linnakangas 2698 UIC 0 : if (oldpartitionLock < newpartitionLock)
2699 : {
4444 heikki.linnakangas 2700 UBC 0 : LWLockAcquire(oldpartitionLock,
4444 heikki.linnakangas 2701 UIC 0 : (removeOld ? LW_EXCLUSIVE : LW_SHARED));
2702 0 : LWLockAcquire(newpartitionLock, LW_EXCLUSIVE);
4444 heikki.linnakangas 2703 EUB : }
4444 heikki.linnakangas 2704 UBC 0 : else if (oldpartitionLock > newpartitionLock)
4444 heikki.linnakangas 2705 EUB : {
4444 heikki.linnakangas 2706 UBC 0 : LWLockAcquire(newpartitionLock, LW_EXCLUSIVE);
4444 heikki.linnakangas 2707 UIC 0 : LWLockAcquire(oldpartitionLock,
4444 heikki.linnakangas 2708 UBC 0 : (removeOld ? LW_EXCLUSIVE : LW_SHARED));
2709 : }
4444 heikki.linnakangas 2710 EUB : else
4444 heikki.linnakangas 2711 UIC 0 : LWLockAcquire(newpartitionLock, LW_EXCLUSIVE);
4444 heikki.linnakangas 2712 EUB :
2713 : /*
2714 : * Look for the old target. If not found, that's OK; no predicate locks
2715 : * are affected, so we can just clean up and return. If it does exist,
2716 : * walk its list of predicate locks and move or copy them to the new
2717 : * target.
2718 : */
4444 heikki.linnakangas 2719 UBC 0 : oldtarget = hash_search_with_hash_value(PredicateLockTargetHash,
2720 : &oldtargettag,
2721 : oldtargettaghash,
4444 heikki.linnakangas 2722 EUB : HASH_FIND, NULL);
2723 :
4444 heikki.linnakangas 2724 UIC 0 : if (oldtarget)
2725 : {
4444 heikki.linnakangas 2726 EUB : PREDICATELOCKTARGET *newtarget;
2727 : PREDICATELOCKTAG newpredlocktag;
2728 : dlist_mutable_iter iter;
2729 :
4444 heikki.linnakangas 2730 UBC 0 : newtarget = hash_search_with_hash_value(PredicateLockTargetHash,
4444 heikki.linnakangas 2731 EUB : &newtargettag,
2732 : newtargettaghash,
2733 : HASH_ENTER_NULL, &found);
2734 :
4444 heikki.linnakangas 2735 UIC 0 : if (!newtarget)
4444 heikki.linnakangas 2736 EUB : {
2737 : /* Failed to allocate due to insufficient shmem */
4444 heikki.linnakangas 2738 UBC 0 : outOfShmem = true;
4444 heikki.linnakangas 2739 UIC 0 : goto exit;
4444 heikki.linnakangas 2740 EUB : }
2741 :
2742 : /* If we created a new entry, initialize it */
4444 heikki.linnakangas 2743 UBC 0 : if (!found)
80 andres 2744 UNC 0 : dlist_init(&newtarget->predicateLocks);
4444 heikki.linnakangas 2745 EUB :
4433 magnus 2746 UBC 0 : newpredlocktag.myTarget = newtarget;
2747 :
2748 : /*
4323 heikki.linnakangas 2749 EUB : * Loop through all the locks on the old target, replacing them with
2750 : * locks on the new target.
2751 : */
4444 heikki.linnakangas 2752 UIC 0 : LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
2753 :
80 andres 2754 UNC 0 : dlist_foreach_modify(iter, &oldtarget->predicateLocks)
2755 : {
2756 0 : PREDICATELOCK *oldpredlock =
2757 0 : dlist_container(PREDICATELOCK, targetLink, iter.cur);
2758 : PREDICATELOCK *newpredlock;
4381 heikki.linnakangas 2759 UIC 0 : SerCommitSeqNo oldCommitSeqNo = oldpredlock->commitSeqNo;
2760 :
4444 2761 0 : newpredlocktag.myXact = oldpredlock->tag.myXact;
2762 :
2763 0 : if (removeOld)
2764 : {
80 andres 2765 UNC 0 : dlist_delete(&(oldpredlock->xactLink));
2766 0 : dlist_delete(&(oldpredlock->targetLink));
2767 :
4444 heikki.linnakangas 2768 UIC 0 : hash_search_with_hash_value
2769 : (PredicateLockHash,
2770 0 : &oldpredlock->tag,
2118 tgl 2771 0 : PredicateLockHashCodeFromTargetHashCode(&oldpredlock->tag,
2772 : oldtargettaghash),
2773 : HASH_REMOVE, &found);
4444 heikki.linnakangas 2774 0 : Assert(found);
2775 : }
2776 :
2777 : newpredlock = (PREDICATELOCK *)
4309 tgl 2778 0 : hash_search_with_hash_value(PredicateLockHash,
4309 tgl 2779 ECB : &newpredlocktag,
2118 tgl 2780 UIC 0 : PredicateLockHashCodeFromTargetHashCode(&newpredlocktag,
2781 : newtargettaghash),
2782 : HASH_ENTER_NULL,
2783 : &found);
4444 heikki.linnakangas 2784 0 : if (!newpredlock)
2785 : {
2786 : /* Out of shared memory. Undo what we've done so far. */
2787 0 : LWLockRelease(SerializableXactHashLock);
2788 0 : DeleteLockTarget(newtarget, newtargettaghash);
2789 0 : outOfShmem = true;
2790 0 : goto exit;
2791 : }
4433 magnus 2792 0 : if (!found)
2793 : {
80 andres 2794 UNC 0 : dlist_push_tail(&(newtarget->predicateLocks),
2795 : &(newpredlock->targetLink));
2796 0 : dlist_push_tail(&(newpredlocktag.myXact->predicateLocks),
2797 : &(newpredlock->xactLink));
4381 heikki.linnakangas 2798 LBC 0 : newpredlock->commitSeqNo = oldCommitSeqNo;
4433 magnus 2799 ECB : }
2800 : else
4381 heikki.linnakangas 2801 : {
4381 heikki.linnakangas 2802 LBC 0 : if (newpredlock->commitSeqNo < oldCommitSeqNo)
4381 heikki.linnakangas 2803 UIC 0 : newpredlock->commitSeqNo = oldCommitSeqNo;
4381 heikki.linnakangas 2804 ECB : }
2805 :
4381 heikki.linnakangas 2806 LBC 0 : Assert(newpredlock->commitSeqNo != 0);
4381 heikki.linnakangas 2807 UIC 0 : Assert((newpredlock->commitSeqNo == InvalidSerCommitSeqNo)
4381 heikki.linnakangas 2808 EUB : || (newpredlock->tag.myXact == OldCommittedSxact));
2809 : }
4444 heikki.linnakangas 2810 UIC 0 : LWLockRelease(SerializableXactHashLock);
4444 heikki.linnakangas 2811 ECB :
4444 heikki.linnakangas 2812 LBC 0 : if (removeOld)
2813 : {
80 andres 2814 UNC 0 : Assert(dlist_is_empty(&oldtarget->predicateLocks));
4444 heikki.linnakangas 2815 LBC 0 : RemoveTargetIfNoLongerUsed(oldtarget, oldtargettaghash);
2816 : }
2817 : }
2818 :
4444 heikki.linnakangas 2819 ECB :
4444 heikki.linnakangas 2820 LBC 0 : exit:
2821 : /* Release partition locks in reverse order of acquisition. */
4444 heikki.linnakangas 2822 UIC 0 : if (oldpartitionLock < newpartitionLock)
4444 heikki.linnakangas 2823 ECB : {
4444 heikki.linnakangas 2824 LBC 0 : LWLockRelease(newpartitionLock);
2825 0 : LWLockRelease(oldpartitionLock);
4444 heikki.linnakangas 2826 ECB : }
4444 heikki.linnakangas 2827 UIC 0 : else if (oldpartitionLock > newpartitionLock)
2828 : {
2829 0 : LWLockRelease(oldpartitionLock);
2830 0 : LWLockRelease(newpartitionLock);
2831 : }
4444 heikki.linnakangas 2832 ECB : else
4444 heikki.linnakangas 2833 LBC 0 : LWLockRelease(newpartitionLock);
2834 :
4444 heikki.linnakangas 2835 UIC 0 : if (removeOld)
4444 heikki.linnakangas 2836 ECB : {
2837 : /* We shouldn't run out of memory if we're moving locks */
4444 heikki.linnakangas 2838 LBC 0 : Assert(!outOfShmem);
2839 :
2840 : /* Put the scratch entry back */
4323 heikki.linnakangas 2841 UIC 0 : RestoreScratchTarget(false);
2842 : }
2843 :
4444 2844 0 : return !outOfShmem;
4444 heikki.linnakangas 2845 ECB : }
2846 :
4323 heikki.linnakangas 2847 EUB : /*
2848 : * Drop all predicate locks of any granularity from the specified relation,
2849 : * which can be a heap relation or an index relation. If 'transfer' is true,
2850 : * acquire a relation lock on the heap for any transactions with any lock(s)
2851 : * on the specified relation.
2852 : *
2853 : * This requires grabbing a lot of LW locks and scanning the entire lock
2854 : * target table for matches. That makes this more expensive than most
2855 : * predicate lock management functions, but it will only be called for DDL
2856 : * type commands that are expensive anyway, and there are fast returns when
2857 : * no serializable transactions are active or the relation is temporary.
2858 : *
2859 : * We don't use the TransferPredicateLocksToNewTarget function because it
2860 : * acquires its own locks on the partitions of the two targets involved,
2861 : * and we'll already be holding all partition locks.
2862 : *
2863 : * We can't throw an error from here, because the call could be from a
2864 : * transaction which is not serializable.
2865 : *
2866 : * NOTE: This is currently only called with transfer set to true, but that may
2867 : * change. If we decide to clean up the locks from a table on commit of a
2868 : * transaction which executed DROP TABLE, the false condition will be useful.
2869 : */
2870 : static void
4309 heikki.linnakangas 2871 GIC 13605 : DropAllPredicateLocksFromTable(Relation relation, bool transfer)
2872 : {
2873 : HASH_SEQ_STATUS seqstat;
4323 heikki.linnakangas 2874 EUB : PREDICATELOCKTARGET *oldtarget;
2875 : PREDICATELOCKTARGET *heaptarget;
2876 : Oid dbId;
2877 : Oid relId;
2878 : Oid heapId;
2879 : int i;
2880 : bool isIndex;
2881 : bool found;
2882 : uint32 heaptargettaghash;
2883 :
2884 : /*
2885 : * Bail out quickly if there are no serializable transactions running.
2886 : * It's safe to check this without taking locks because the caller is
2887 : * holding an ACCESS EXCLUSIVE lock on the relation. No new locks which
2888 : * would matter here can be acquired while that is held.
2889 : */
4323 heikki.linnakangas 2890 GIC 13605 : if (!TransactionIdIsValid(PredXact->SxactGlobalXmin))
2891 13586 : return;
2892 :
4316 2893 35 : if (!PredicateLockingNeededForRelation(relation))
4323 heikki.linnakangas 2894 GBC 16 : return;
4323 heikki.linnakangas 2895 EUB :
277 rhaas 2896 GNC 19 : dbId = relation->rd_locator.dbOid;
4323 heikki.linnakangas 2897 GBC 19 : relId = relation->rd_id;
4323 heikki.linnakangas 2898 GIC 19 : if (relation->rd_index == NULL)
2899 : {
4323 heikki.linnakangas 2900 UIC 0 : isIndex = false;
2901 0 : heapId = relId;
2902 : }
4323 heikki.linnakangas 2903 EUB : else
2904 : {
4323 heikki.linnakangas 2905 GIC 19 : isIndex = true;
4323 heikki.linnakangas 2906 GBC 19 : heapId = relation->rd_index->indrelid;
2907 : }
2908 19 : Assert(heapId != InvalidOid);
2118 tgl 2909 GIC 19 : Assert(transfer || !isIndex); /* index OID only makes sense with
2910 : * transfer */
2911 :
4323 heikki.linnakangas 2912 EUB : /* Retrieve first time needed, then keep. */
4323 heikki.linnakangas 2913 GBC 19 : heaptargettaghash = 0;
4323 heikki.linnakangas 2914 GIC 19 : heaptarget = NULL;
4323 heikki.linnakangas 2915 EUB :
2916 : /* Acquire locks on all lock partitions */
1059 tgl 2917 GBC 19 : LWLockAcquire(SerializablePredicateListLock, LW_EXCLUSIVE);
4323 heikki.linnakangas 2918 GIC 323 : for (i = 0; i < NUM_PREDICATELOCK_PARTITIONS; i++)
3359 rhaas 2919 304 : LWLockAcquire(PredicateLockHashPartitionLockByIndex(i), LW_EXCLUSIVE);
4323 heikki.linnakangas 2920 19 : LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
4323 heikki.linnakangas 2921 EUB :
2922 : /*
2923 : * Remove the dummy entry to give us scratch space, so we know we'll be
2924 : * able to create the new lock target.
2925 : */
4323 heikki.linnakangas 2926 GIC 19 : if (transfer)
4323 heikki.linnakangas 2927 GBC 19 : RemoveScratchTarget(true);
2928 :
2929 : /* Scan through target map */
4323 heikki.linnakangas 2930 GIC 19 : hash_seq_init(&seqstat, PredicateLockTargetHash);
4323 heikki.linnakangas 2931 EUB :
4323 heikki.linnakangas 2932 GBC 36 : while ((oldtarget = (PREDICATELOCKTARGET *) hash_seq_search(&seqstat)))
2933 : {
2934 : dlist_mutable_iter iter;
4323 heikki.linnakangas 2935 EUB :
2936 : /*
2937 : * Check whether this is a target which needs attention.
2938 : */
4323 heikki.linnakangas 2939 GIC 17 : if (GET_PREDICATELOCKTARGETTAG_RELATION(oldtarget->tag) != relId)
2940 17 : continue; /* wrong relation id */
4323 heikki.linnakangas 2941 UBC 0 : if (GET_PREDICATELOCKTARGETTAG_DB(oldtarget->tag) != dbId)
4323 heikki.linnakangas 2942 UIC 0 : continue; /* wrong database id */
4323 heikki.linnakangas 2943 UBC 0 : if (transfer && !isIndex
4323 heikki.linnakangas 2944 UIC 0 : && GET_PREDICATELOCKTARGETTAG_TYPE(oldtarget->tag) == PREDLOCKTAG_RELATION)
2945 0 : continue; /* already the right lock */
2946 :
4323 heikki.linnakangas 2947 ECB : /*
3260 bruce 2948 : * If we made it here, we have work to do. We make sure the heap
2949 : * relation lock exists, then we walk the list of predicate locks for
2950 : * the old target we found, moving all locks to the heap relation lock
4323 heikki.linnakangas 2951 : * -- unless they already hold that.
2952 : */
2953 :
2954 : /*
2955 : * First make sure we have the heap relation target. We only need to
2956 : * do this once.
2957 : */
4323 heikki.linnakangas 2958 UIC 0 : if (transfer && heaptarget == NULL)
2959 : {
2960 : PREDICATELOCKTARGETTAG heaptargettag;
2961 :
2962 0 : SET_PREDICATELOCKTARGETTAG_RELATION(heaptargettag, dbId, heapId);
4323 heikki.linnakangas 2963 LBC 0 : heaptargettaghash = PredicateLockTargetTagHashCode(&heaptargettag);
4323 heikki.linnakangas 2964 UIC 0 : heaptarget = hash_search_with_hash_value(PredicateLockTargetHash,
4323 heikki.linnakangas 2965 ECB : &heaptargettag,
2966 : heaptargettaghash,
2967 : HASH_ENTER, &found);
4323 heikki.linnakangas 2968 UIC 0 : if (!found)
80 andres 2969 UNC 0 : dlist_init(&heaptarget->predicateLocks);
2970 : }
2971 :
2972 : /*
2973 : * Loop through all the locks on the old target, replacing them with
2974 : * locks on the new target.
2975 : */
2976 0 : dlist_foreach_modify(iter, &oldtarget->predicateLocks)
2977 : {
2978 0 : PREDICATELOCK *oldpredlock =
2979 0 : dlist_container(PREDICATELOCK, targetLink, iter.cur);
2980 : PREDICATELOCK *newpredlock;
4323 heikki.linnakangas 2981 ECB : SerCommitSeqNo oldCommitSeqNo;
2982 : SERIALIZABLEXACT *oldXact;
2983 :
2984 : /*
2985 : * Remove the old lock first. This avoids the chance of running
2986 : * out of lock structure entries for the hash table.
2987 : */
4323 heikki.linnakangas 2988 UIC 0 : oldCommitSeqNo = oldpredlock->commitSeqNo;
2989 0 : oldXact = oldpredlock->tag.myXact;
2990 :
80 andres 2991 UNC 0 : dlist_delete(&(oldpredlock->xactLink));
2992 :
4323 heikki.linnakangas 2993 ECB : /*
2994 : * No need for retail delete from oldtarget list, we're removing
2995 : * the whole target anyway.
2996 : */
4323 heikki.linnakangas 2997 LBC 0 : hash_search(PredicateLockHash,
4323 heikki.linnakangas 2998 UIC 0 : &oldpredlock->tag,
4323 heikki.linnakangas 2999 EUB : HASH_REMOVE, &found);
4323 heikki.linnakangas 3000 UBC 0 : Assert(found);
4323 heikki.linnakangas 3001 EUB :
4323 heikki.linnakangas 3002 UIC 0 : if (transfer)
4323 heikki.linnakangas 3003 EUB : {
3004 : PREDICATELOCKTAG newpredlocktag;
3005 :
4323 heikki.linnakangas 3006 UIC 0 : newpredlocktag.myTarget = heaptarget;
4323 heikki.linnakangas 3007 UBC 0 : newpredlocktag.myXact = oldXact;
3008 : newpredlock = (PREDICATELOCK *)
4309 tgl 3009 UIC 0 : hash_search_with_hash_value(PredicateLockHash,
3010 : &newpredlocktag,
2118 3011 0 : PredicateLockHashCodeFromTargetHashCode(&newpredlocktag,
2118 tgl 3012 EUB : heaptargettaghash),
3013 : HASH_ENTER,
3014 : &found);
4323 heikki.linnakangas 3015 UIC 0 : if (!found)
3016 : {
80 andres 3017 UNC 0 : dlist_push_tail(&(heaptarget->predicateLocks),
3018 : &(newpredlock->targetLink));
3019 0 : dlist_push_tail(&(newpredlocktag.myXact->predicateLocks),
3020 : &(newpredlock->xactLink));
4323 heikki.linnakangas 3021 UIC 0 : newpredlock->commitSeqNo = oldCommitSeqNo;
4323 heikki.linnakangas 3022 EUB : }
3023 : else
3024 : {
4323 heikki.linnakangas 3025 UIC 0 : if (newpredlock->commitSeqNo < oldCommitSeqNo)
3026 0 : newpredlock->commitSeqNo = oldCommitSeqNo;
3027 : }
3028 :
3029 0 : Assert(newpredlock->commitSeqNo != 0);
4323 heikki.linnakangas 3030 UBC 0 : Assert((newpredlock->commitSeqNo == InvalidSerCommitSeqNo)
3031 : || (newpredlock->tag.myXact == OldCommittedSxact));
4323 heikki.linnakangas 3032 EUB : }
3033 : }
3034 :
4323 heikki.linnakangas 3035 UIC 0 : hash_search(PredicateLockTargetHash, &oldtarget->tag, HASH_REMOVE,
3036 : &found);
3037 0 : Assert(found);
3038 : }
3039 :
4323 heikki.linnakangas 3040 EUB : /* Put the scratch entry back */
4323 heikki.linnakangas 3041 GIC 19 : if (transfer)
3042 19 : RestoreScratchTarget(true);
4323 heikki.linnakangas 3043 EUB :
3044 : /* Release locks in reverse order */
4323 heikki.linnakangas 3045 GIC 19 : LWLockRelease(SerializableXactHashLock);
4323 heikki.linnakangas 3046 GBC 323 : for (i = NUM_PREDICATELOCK_PARTITIONS - 1; i >= 0; i--)
3359 rhaas 3047 GIC 304 : LWLockRelease(PredicateLockHashPartitionLockByIndex(i));
1059 tgl 3048 19 : LWLockRelease(SerializablePredicateListLock);
3049 : }
3050 :
3051 : /*
3052 : * TransferPredicateLocksToHeapRelation
3053 : * For all transactions, transfer all predicate locks for the given
3054 : * relation to a single relation lock on the heap.
3055 : */
3056 : void
4309 heikki.linnakangas 3057 13605 : TransferPredicateLocksToHeapRelation(Relation relation)
3058 : {
4323 heikki.linnakangas 3059 CBC 13605 : DropAllPredicateLocksFromTable(relation, true);
4323 heikki.linnakangas 3060 GIC 13605 : }
3061 :
3062 :
3063 : /*
3064 : * PredicateLockPageSplit
3065 : *
3066 : * Copies any predicate locks for the old page to the new page.
3067 : * Skip if this is a temporary table or toast table.
3068 : *
3069 : * NOTE: A page split (or overflow) affects all serializable transactions,
3070 : * even if it occurs in the context of another transaction isolation level.
3071 : *
3072 : * NOTE: This currently leaves the local copy of the locks without
4444 heikki.linnakangas 3073 ECB : * information on the new lock which is in shared memory. This could cause
3074 : * problems if enough page splits occur on locked pages without the processes
3075 : * which hold the locks getting in and noticing.
3076 : */
3077 : void
4309 heikki.linnakangas 3078 GIC 41358 : PredicateLockPageSplit(Relation relation, BlockNumber oldblkno,
3079 : BlockNumber newblkno)
3080 : {
4444 heikki.linnakangas 3081 ECB : PREDICATELOCKTARGETTAG oldtargettag;
3082 : PREDICATELOCKTARGETTAG newtargettag;
3083 : bool success;
3084 :
4367 rhaas 3085 : /*
3086 : * Bail out quickly if there are no serializable transactions running.
4332 heikki.linnakangas 3087 : *
4323 3088 : * It's safe to do this check without taking any additional locks. Even if
3089 : * a serializable transaction starts concurrently, we know it can't take
3090 : * any SIREAD locks on the page being split because the caller is holding
3091 : * the associated buffer page lock. Memory reordering isn't an issue; the
3092 : * memory barrier in the LWLock acquisition guarantees that this read
3093 : * occurs while the buffer page lock is held.
3094 : */
4367 rhaas 3095 CBC 41358 : if (!TransactionIdIsValid(PredXact->SxactGlobalXmin))
3096 41358 : return;
4367 rhaas 3097 ECB :
4316 heikki.linnakangas 3098 GIC 11 : if (!PredicateLockingNeededForRelation(relation))
4444 heikki.linnakangas 3099 CBC 11 : return;
4444 heikki.linnakangas 3100 ECB :
4444 heikki.linnakangas 3101 UBC 0 : Assert(oldblkno != newblkno);
3102 0 : Assert(BlockNumberIsValid(oldblkno));
4444 heikki.linnakangas 3103 UIC 0 : Assert(BlockNumberIsValid(newblkno));
4444 heikki.linnakangas 3104 ECB :
4444 heikki.linnakangas 3105 LBC 0 : SET_PREDICATELOCKTARGETTAG_PAGE(oldtargettag,
3106 : relation->rd_locator.dbOid,
4444 heikki.linnakangas 3107 EUB : relation->rd_id,
3108 : oldblkno);
4444 heikki.linnakangas 3109 UBC 0 : SET_PREDICATELOCKTARGETTAG_PAGE(newtargettag,
3110 : relation->rd_locator.dbOid,
3111 : relation->rd_id,
3112 : newblkno);
4444 heikki.linnakangas 3113 ECB :
1059 tgl 3114 LBC 0 : LWLockAcquire(SerializablePredicateListLock, LW_EXCLUSIVE);
3115 :
3116 : /*
3117 : * Try copying the locks over to the new page's tag, creating it if
3118 : * necessary.
3119 : */
4444 heikki.linnakangas 3120 UIC 0 : success = TransferPredicateLocksToNewTarget(oldtargettag,
3121 : newtargettag,
3122 : false);
3123 :
3124 0 : if (!success)
3125 : {
3126 : /*
3127 : * No more predicate lock entries are available. Failure isn't an
3128 : * option here, so promote the page lock to a relation lock.
3129 : */
3130 :
3131 : /* Get the parent relation lock's lock tag */
3132 0 : success = GetParentPredicateLockTag(&oldtargettag,
3133 : &newtargettag);
3134 0 : Assert(success);
3135 :
3136 : /*
3137 : * Move the locks to the parent. This shouldn't fail.
3138 : *
3139 : * Note that here we are removing locks held by other backends,
3140 : * leading to a possible inconsistency in their local lock hash table.
3141 : * This is OK because we're replacing it with a lock that covers the
4382 bruce 3142 ECB : * old one.
3143 : */
4444 heikki.linnakangas 3144 LBC 0 : success = TransferPredicateLocksToNewTarget(oldtargettag,
3145 : newtargettag,
3146 : true);
4444 heikki.linnakangas 3147 UIC 0 : Assert(success);
3148 : }
3149 :
1059 tgl 3150 0 : LWLockRelease(SerializablePredicateListLock);
3151 : }
3152 :
3153 : /*
3154 : * PredicateLockPageCombine
3155 : *
3156 : * Combines predicate locks for two existing pages.
3157 : * Skip if this is a temporary table or toast table.
3158 : *
3159 : * NOTE: A page combine affects all serializable transactions, even if it
3160 : * occurs in the context of another transaction isolation level.
4444 heikki.linnakangas 3161 ECB : */
3162 : void
4309 heikki.linnakangas 3163 GIC 2675 : PredicateLockPageCombine(Relation relation, BlockNumber oldblkno,
4309 heikki.linnakangas 3164 ECB : BlockNumber newblkno)
3165 : {
3166 : /*
3167 : * Page combines differ from page splits in that we ought to be able to
3168 : * remove the locks on the old page after transferring them to the new
3169 : * page, instead of duplicating them. However, because we can't edit other
3170 : * backends' local lock tables, removing the old lock would leave them
4382 bruce 3171 : * with an entry in their LocalPredicateLockHash for a lock they're not
3172 : * holding, which isn't acceptable. So we wind up having to do the same
3173 : * work as a page split, acquiring a lock on the new page and keeping the
3174 : * old page locked too. That can lead to some false positives, but should
3175 : * be rare in practice.
3176 : */
4422 heikki.linnakangas 3177 GIC 2675 : PredicateLockPageSplit(relation, oldblkno, newblkno);
4444 3178 2675 : }
3179 :
3180 : /*
4321 heikki.linnakangas 3181 ECB : * Walk the list of in-progress serializable transactions and find the new
3182 : * xmin.
3183 : */
3184 : static void
4444 heikki.linnakangas 3185 GIC 864 : SetNewSxactGlobalXmin(void)
3186 : {
3187 : dlist_iter iter;
3188 :
4444 heikki.linnakangas 3189 CBC 864 : Assert(LWLockHeldByMe(SerializableXactHashLock));
3190 :
3191 864 : PredXact->SxactGlobalXmin = InvalidTransactionId;
3192 864 : PredXact->SxactGlobalXminCount = 0;
4444 heikki.linnakangas 3193 ECB :
80 andres 3194 GNC 3272 : dlist_foreach(iter, &PredXact->activeList)
3195 : {
3196 2408 : SERIALIZABLEXACT *sxact =
3197 2408 : dlist_container(SERIALIZABLEXACT, xactLink, iter.cur);
3198 :
4310 heikki.linnakangas 3199 GIC 2408 : if (!SxactIsRolledBack(sxact)
4444 3200 2110 : && !SxactIsCommitted(sxact)
4444 heikki.linnakangas 3201 CBC 18 : && sxact != OldCommittedSxact)
3202 : {
3203 18 : Assert(sxact->xmin != InvalidTransactionId);
3204 18 : if (!TransactionIdIsValid(PredXact->SxactGlobalXmin)
4444 heikki.linnakangas 3205 UIC 0 : || TransactionIdPrecedes(sxact->xmin,
3206 0 : PredXact->SxactGlobalXmin))
4444 heikki.linnakangas 3207 ECB : {
4444 heikki.linnakangas 3208 GIC 18 : PredXact->SxactGlobalXmin = sxact->xmin;
3209 18 : PredXact->SxactGlobalXminCount = 1;
3210 : }
4444 heikki.linnakangas 3211 UIC 0 : else if (TransactionIdEquals(sxact->xmin,
3212 : PredXact->SxactGlobalXmin))
4444 heikki.linnakangas 3213 LBC 0 : PredXact->SxactGlobalXminCount++;
4444 heikki.linnakangas 3214 ECB : }
3215 : }
3216 :
1059 tgl 3217 GIC 864 : SerialSetActiveSerXmin(PredXact->SxactGlobalXmin);
4444 heikki.linnakangas 3218 864 : }
3219 :
3220 : /*
3221 : * ReleasePredicateLocks
4444 heikki.linnakangas 3222 ECB : *
3223 : * Releases predicate locks based on completion of the current transaction,
3224 : * whether committed or rolled back. It can also be called for a read only
3225 : * transaction when it becomes impossible for the transaction to become
3226 : * part of a dangerous structure.
3227 : *
3228 : * We do nothing unless this is a serializable transaction.
3229 : *
3230 : * This method must ensure that shared memory hash tables are cleaned
3231 : * up in some relatively timely fashion.
3232 : *
3233 : * If this transaction is committing and is holding any predicate locks,
3234 : * it must be added to a list of completed serializable transactions still
3235 : * holding locks.
3236 : *
1486 tmunro 3237 : * If isReadOnlySafe is true, then predicate locks are being released before
3238 : * the end of the transaction because MySerializableXact has been determined
3239 : * to be RO_SAFE. In non-parallel mode we can release it completely, but it
3240 : * in parallel mode we partially release the SERIALIZABLEXACT and keep it
3241 : * around until the end of the transaction, allowing each backend to clear its
3242 : * MySerializableXact variable and benefit from the optimization in its own
3243 : * time.
3244 : */
4444 heikki.linnakangas 3245 : void
1486 tmunro 3246 CBC 486218 : ReleasePredicateLocks(bool isCommit, bool isReadOnlySafe)
3247 : {
34 tmunro 3248 GIC 486218 : bool partiallyReleasing = false;
3249 : bool needToClear;
4444 heikki.linnakangas 3250 ECB : SERIALIZABLEXACT *roXact;
3251 : dlist_mutable_iter iter;
3252 :
3253 : /*
3254 : * We can't trust XactReadOnly here, because a transaction which started
3255 : * as READ WRITE can show as READ ONLY later, e.g., within
3256 : * subtransactions. We want to flag a transaction as READ ONLY if it
3257 : * commits without writing so that de facto READ ONLY transactions get the
3258 : * benefit of some RO optimizations, so we will use this local variable to
3259 : * get some cleanup logic right which is based on whether the transaction
3260 : * was declared READ ONLY at the top level.
3261 : */
3262 : bool topLevelIsDeclaredReadOnly;
3263 :
3264 : /* We can't be both committing and releasing early due to RO_SAFE. */
1486 tmunro 3265 GIC 486218 : Assert(!(isCommit && isReadOnlySafe));
3266 :
3267 : /* Are we at the end of a transaction, that is, a commit or abort? */
3268 486218 : if (!isReadOnlySafe)
3269 : {
3270 : /*
3271 : * Parallel workers mustn't release predicate locks at the end of
3272 : * their transaction. The leader will do that at the end of its
1486 tmunro 3273 ECB : * transaction.
3274 : */
1486 tmunro 3275 GIC 486185 : if (IsParallelWorker())
3276 : {
3277 3894 : ReleasePredicateLocksLocal();
3278 484687 : return;
1486 tmunro 3279 ECB : }
3280 :
3281 : /*
3282 : * By the time the leader in a parallel query reaches end of
3283 : * transaction, it has waited for all workers to exit.
3284 : */
1486 tmunro 3285 CBC 482291 : Assert(!ParallelContextActive());
3286 :
3287 : /*
3288 : * If the leader in a parallel query earlier stashed a partially
3289 : * released SERIALIZABLEXACT for final clean-up at end of transaction
3290 : * (because workers might still have been accessing it), then it's
3291 : * time to restore it.
3292 : */
1486 tmunro 3293 GIC 482291 : if (SavedSerializableXact != InvalidSerializableXact)
3294 : {
3295 1 : Assert(MySerializableXact == InvalidSerializableXact);
3296 1 : MySerializableXact = SavedSerializableXact;
3297 1 : SavedSerializableXact = InvalidSerializableXact;
3298 1 : Assert(SxactIsPartiallyReleased(MySerializableXact));
3299 : }
3300 : }
1486 tmunro 3301 ECB :
4444 heikki.linnakangas 3302 CBC 482324 : if (MySerializableXact == InvalidSerializableXact)
3303 : {
4444 heikki.linnakangas 3304 GIC 480790 : Assert(LocalPredicateLockHash == NULL);
3305 480790 : return;
3306 : }
3307 :
2717 kgrittn 3308 1534 : LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
3309 :
1486 tmunro 3310 ECB : /*
3311 : * If the transaction is committing, but it has been partially released
3312 : * already, then treat this as a roll back. It was marked as rolled back.
3313 : */
1486 tmunro 3314 GIC 1534 : if (isCommit && SxactIsPartiallyReleased(MySerializableXact))
1486 tmunro 3315 CBC 2 : isCommit = false;
1486 tmunro 3316 ECB :
3317 : /*
3318 : * If we're called in the middle of a transaction because we discovered
3319 : * that the SXACT_FLAG_RO_SAFE flag was set, then we'll partially release
3320 : * it (that is, release the predicate locks and conflicts, but not the
3321 : * SERIALIZABLEXACT itself) if we're the first backend to have noticed.
3322 : */
1486 tmunro 3323 GIC 1534 : if (isReadOnlySafe && IsInParallelMode())
3324 : {
3325 : /*
3326 : * The leader needs to stash a pointer to it, so that it can
1486 tmunro 3327 ECB : * completely release it at end-of-transaction.
3328 : */
1486 tmunro 3329 GIC 5 : if (!IsParallelWorker())
3330 1 : SavedSerializableXact = MySerializableXact;
3331 :
3332 : /*
3333 : * The first backend to reach this condition will partially release
3334 : * the SERIALIZABLEXACT. All others will just clear their
3335 : * backend-local state so that they stop doing SSI checks for the rest
3336 : * of the transaction.
1486 tmunro 3337 ECB : */
1486 tmunro 3338 GIC 5 : if (SxactIsPartiallyReleased(MySerializableXact))
1486 tmunro 3339 ECB : {
1486 tmunro 3340 CBC 3 : LWLockRelease(SerializableXactHashLock);
1486 tmunro 3341 GIC 3 : ReleasePredicateLocksLocal();
1486 tmunro 3342 CBC 3 : return;
1486 tmunro 3343 ECB : }
3344 : else
3345 : {
1486 tmunro 3346 GIC 2 : MySerializableXact->flags |= SXACT_FLAG_PARTIALLY_RELEASED;
34 3347 2 : partiallyReleasing = true;
3348 : /* ... and proceed to perform the partial release below. */
3349 : }
1486 tmunro 3350 ECB : }
4444 heikki.linnakangas 3351 CBC 1531 : Assert(!isCommit || SxactIsPrepared(MySerializableXact));
4316 3352 1531 : Assert(!isCommit || !SxactIsDoomed(MySerializableXact));
4444 heikki.linnakangas 3353 GIC 1531 : Assert(!SxactIsCommitted(MySerializableXact));
1486 tmunro 3354 1531 : Assert(SxactIsPartiallyReleased(MySerializableXact)
3355 : || !SxactIsRolledBack(MySerializableXact));
3356 :
3357 : /* may not be serializable during COMMIT/ROLLBACK PREPARED */
2717 kgrittn 3358 GBC 1531 : Assert(MySerializableXact->pid == 0 || IsolationIsSerializable());
3359 :
4444 heikki.linnakangas 3360 EUB : /* We'd better not already be on the cleanup list. */
4321 heikki.linnakangas 3361 GIC 1531 : Assert(!SxactIsOnFinishedList(MySerializableXact));
3362 :
4444 3363 1531 : topLevelIsDeclaredReadOnly = SxactIsReadOnly(MySerializableXact);
3364 :
3365 : /*
3366 : * We don't hold XidGenLock lock here, assuming that TransactionId is
3367 : * atomic!
4444 heikki.linnakangas 3368 ECB : *
3369 : * If this value is changing, we don't care that much whether we get the
3370 : * old or new value -- it is just used to determine how far
1363 michael 3371 : * SxactGlobalXmin must advance before this transaction can be fully
3372 : * cleaned up. The worst that could happen is we wait for one more
4444 heikki.linnakangas 3373 : * transaction to complete before freeing some RAM; correctness of visible
3374 : * behavior is not affected.
3375 : */
971 andres 3376 GIC 1531 : MySerializableXact->finishedBefore = XidFromFullTransactionId(ShmemVariableCache->nextXid);
4444 heikki.linnakangas 3377 ECB :
4444 heikki.linnakangas 3378 EUB : /*
1486 tmunro 3379 ECB : * If it's not a commit it's either a rollback or a read-only transaction
3380 : * flagged SXACT_FLAG_RO_SAFE, and we can clear our locks immediately.
3381 : */
4444 heikki.linnakangas 3382 GIC 1531 : if (isCommit)
4444 heikki.linnakangas 3383 ECB : {
4444 heikki.linnakangas 3384 CBC 1210 : MySerializableXact->flags |= SXACT_FLAG_COMMITTED;
3385 1210 : MySerializableXact->commitSeqNo = ++(PredXact->LastSxactCommitSeqNo);
4444 heikki.linnakangas 3386 ECB : /* Recognize implicit read-only transaction (commit without write). */
4321 heikki.linnakangas 3387 GIC 1210 : if (!MyXactDidWrite)
4444 3388 233 : MySerializableXact->flags |= SXACT_FLAG_READ_ONLY;
3389 : }
3390 : else
3391 : {
3392 : /*
4310 heikki.linnakangas 3393 ECB : * The DOOMED flag indicates that we intend to roll back this
3394 : * transaction and so it should not cause serialization failures for
3395 : * other transactions that conflict with it. Note that this flag might
3396 : * already be set, if another backend marked this transaction for
3397 : * abort.
3398 : *
3399 : * The ROLLED_BACK flag further indicates that ReleasePredicateLocks
3400 : * has been called, and so the SerializableXact is eligible for
3401 : * cleanup. This means it should not be considered when calculating
3402 : * SxactGlobalXmin.
3403 : */
1431 tmunro 3404 CBC 321 : MySerializableXact->flags |= SXACT_FLAG_DOOMED;
4310 heikki.linnakangas 3405 GIC 321 : MySerializableXact->flags |= SXACT_FLAG_ROLLED_BACK;
3406 :
3407 : /*
3408 : * If the transaction was previously prepared, but is now failing due
3409 : * to a ROLLBACK PREPARED or (hopefully very rare) error after the
3410 : * prepare, clear the prepared flag. This simplifies conflict
3411 : * checking.
4294 heikki.linnakangas 3412 ECB : */
4294 heikki.linnakangas 3413 GIC 321 : MySerializableXact->flags &= ~SXACT_FLAG_PREPARED;
4310 heikki.linnakangas 3414 ECB : }
4444 3415 :
4444 heikki.linnakangas 3416 GIC 1531 : if (!topLevelIsDeclaredReadOnly)
4444 heikki.linnakangas 3417 ECB : {
4444 heikki.linnakangas 3418 CBC 1423 : Assert(PredXact->WritableSxactCount > 0);
3419 1423 : if (--(PredXact->WritableSxactCount) == 0)
3420 : {
3421 : /*
4444 heikki.linnakangas 3422 ECB : * Release predicate locks and rw-conflicts in for all committed
3423 : * transactions. There are no longer any transactions which might
3424 : * conflict with the locks and no chance for new transactions to
3425 : * overlap. Similarly, existing conflicts in can't cause pivots,
3426 : * and any conflicts in which could have completed a dangerous
3427 : * structure would already have caused a rollback, so any
3428 : * remaining ones must be benign.
3429 : */
4444 heikki.linnakangas 3430 GIC 856 : PredXact->CanPartialClearThrough = PredXact->LastSxactCommitSeqNo;
3431 : }
4444 heikki.linnakangas 3432 ECB : }
3433 : else
3434 : {
3435 : /*
3436 : * Read-only transactions: clear the list of transactions that might
3437 : * make us unsafe. Note that we use 'inLink' for the iteration as
3438 : * opposed to 'outLink' for the r/w xacts.
3439 : */
80 andres 3440 GNC 150 : dlist_foreach_modify(iter, &MySerializableXact->possibleUnsafeConflicts)
3441 : {
3442 42 : RWConflict possibleUnsafeConflict =
3443 42 : dlist_container(RWConflictData, inLink, iter.cur);
3444 :
4444 heikki.linnakangas 3445 CBC 42 : Assert(!SxactIsReadOnly(possibleUnsafeConflict->sxactOut));
3446 42 : Assert(MySerializableXact == possibleUnsafeConflict->sxactIn);
4444 heikki.linnakangas 3447 ECB :
4444 heikki.linnakangas 3448 GIC 42 : ReleaseRWConflict(possibleUnsafeConflict);
3449 : }
3450 : }
3451 :
3452 : /* Check for conflict out to old committed transactions. */
3453 1531 : if (isCommit
3454 1210 : && !SxactIsReadOnly(MySerializableXact)
3455 977 : && SxactHasSummaryConflictOut(MySerializableXact))
3456 : {
3457 : /*
3458 : * we don't know which old committed transaction we conflicted with,
4321 heikki.linnakangas 3459 ECB : * so be conservative and use FirstNormalSerCommitSeqNo here
3460 : */
4444 heikki.linnakangas 3461 LBC 0 : MySerializableXact->SeqNo.earliestOutConflictCommit =
4444 heikki.linnakangas 3462 ECB : FirstNormalSerCommitSeqNo;
4444 heikki.linnakangas 3463 UIC 0 : MySerializableXact->flags |= SXACT_FLAG_CONFLICT_OUT;
3464 : }
4444 heikki.linnakangas 3465 ECB :
3466 : /*
3467 : * Release all outConflicts to committed transactions. If we're rolling
3468 : * back clear them all. Set SXACT_FLAG_CONFLICT_OUT if any point to
3469 : * previously committed transactions.
3470 : */
80 andres 3471 GNC 2210 : dlist_foreach_modify(iter, &MySerializableXact->outConflicts)
3472 : {
3473 679 : RWConflict conflict =
3474 679 : dlist_container(RWConflictData, outLink, iter.cur);
3475 :
4444 heikki.linnakangas 3476 GIC 679 : if (isCommit
3477 451 : && !SxactIsReadOnly(MySerializableXact)
3478 343 : && SxactIsCommitted(conflict->sxactIn))
3479 : {
3480 96 : if ((MySerializableXact->flags & SXACT_FLAG_CONFLICT_OUT) == 0
4294 heikki.linnakangas 3481 UIC 0 : || conflict->sxactIn->prepareSeqNo < MySerializableXact->SeqNo.earliestOutConflictCommit)
4294 heikki.linnakangas 3482 CBC 96 : MySerializableXact->SeqNo.earliestOutConflictCommit = conflict->sxactIn->prepareSeqNo;
4444 3483 96 : MySerializableXact->flags |= SXACT_FLAG_CONFLICT_OUT;
4444 heikki.linnakangas 3484 ECB : }
3485 :
4444 heikki.linnakangas 3486 GIC 679 : if (!isCommit
4444 heikki.linnakangas 3487 CBC 451 : || SxactIsCommitted(conflict->sxactIn)
4444 heikki.linnakangas 3488 GIC 333 : || (conflict->sxactIn->SeqNo.lastCommitBeforeSnapshot >= PredXact->LastSxactCommitSeqNo))
4444 heikki.linnakangas 3489 CBC 346 : ReleaseRWConflict(conflict);
4444 heikki.linnakangas 3490 ECB : }
3491 :
3492 : /*
3493 : * Release all inConflicts from committed and read-only transactions. If
3494 : * we're rolling back, clear them all.
3495 : */
80 andres 3496 GNC 2300 : dlist_foreach_modify(iter, &MySerializableXact->inConflicts)
3497 : {
3498 769 : RWConflict conflict =
3499 769 : dlist_container(RWConflictData, inLink, iter.cur);
3500 :
4444 heikki.linnakangas 3501 GIC 769 : if (!isCommit
3502 599 : || SxactIsCommitted(conflict->sxactOut)
3503 415 : || SxactIsReadOnly(conflict->sxactOut))
3504 434 : ReleaseRWConflict(conflict);
3505 : }
3506 :
3507 1531 : if (!topLevelIsDeclaredReadOnly)
3508 : {
3509 : /*
3510 : * Remove ourselves from the list of possible conflicts for concurrent
3511 : * READ ONLY transactions, flagging them as unsafe if we have a
4444 heikki.linnakangas 3512 ECB : * conflict out. If any are waiting DEFERRABLE transactions, wake them
3513 : * up if they are known safe or known unsafe.
3514 : */
80 andres 3515 GNC 1513 : dlist_foreach_modify(iter, &MySerializableXact->possibleUnsafeConflicts)
4444 heikki.linnakangas 3516 ECB : {
80 andres 3517 GNC 90 : RWConflict possibleUnsafeConflict =
3518 90 : dlist_container(RWConflictData, outLink, iter.cur);
3519 :
4444 heikki.linnakangas 3520 GIC 90 : roXact = possibleUnsafeConflict->sxactIn;
4444 heikki.linnakangas 3521 CBC 90 : Assert(MySerializableXact == possibleUnsafeConflict->sxactOut);
3522 90 : Assert(SxactIsReadOnly(roXact));
4444 heikki.linnakangas 3523 ECB :
3524 : /* Mark conflicted if necessary. */
4444 heikki.linnakangas 3525 GIC 90 : if (isCommit
4321 heikki.linnakangas 3526 CBC 88 : && MyXactDidWrite
4444 3527 83 : && SxactHasConflictOut(MySerializableXact)
4444 heikki.linnakangas 3528 GIC 13 : && (MySerializableXact->SeqNo.earliestOutConflictCommit
3529 13 : <= roXact->SeqNo.lastCommitBeforeSnapshot))
3530 : {
3531 : /*
3532 : * This releases possibleUnsafeConflict (as well as all other
3533 : * possible conflicts for roXact)
4444 heikki.linnakangas 3534 ECB : */
4444 heikki.linnakangas 3535 GIC 3 : FlagSxactUnsafe(roXact);
4444 heikki.linnakangas 3536 ECB : }
3537 : else
3538 : {
4444 heikki.linnakangas 3539 GBC 87 : ReleaseRWConflict(possibleUnsafeConflict);
4444 heikki.linnakangas 3540 EUB :
3541 : /*
3542 : * If we were the last possible conflict, flag it safe. The
3543 : * transaction can now safely release its predicate locks (but
3544 : * that transaction's backend has to do that itself).
3545 : */
80 andres 3546 GNC 87 : if (dlist_is_empty(&roXact->possibleUnsafeConflicts))
4444 heikki.linnakangas 3547 GIC 65 : roXact->flags |= SXACT_FLAG_RO_SAFE;
3548 : }
4444 heikki.linnakangas 3549 ECB :
3550 : /*
3551 : * Wake up the process for a waiting DEFERRABLE transaction if we
3552 : * now know it's either safe or conflicted.
3553 : */
4444 heikki.linnakangas 3554 GIC 90 : if (SxactIsDeferrableWaiting(roXact) &&
3555 1 : (SxactIsROUnsafe(roXact) || SxactIsROSafe(roXact)))
479 tmunro 3556 1 : ProcSendSignal(roXact->pgprocno);
3557 : }
3558 : }
4444 heikki.linnakangas 3559 ECB :
3560 : /*
3561 : * Check whether it's time to clean up old transactions. This can only be
3562 : * done when the last serializable transaction with the oldest xmin among
3563 : * serializable transactions completes. We then find the "new oldest"
3564 : * xmin and purge any transactions which finished before this transaction
3565 : * was launched.
3566 : *
34 tmunro 3567 EUB : * For parallel queries in read-only transactions, it might run twice.
3568 : * We only release the reference on the first call.
3569 : */
4444 heikki.linnakangas 3570 GIC 1531 : needToClear = false;
34 tmunro 3571 GBC 1531 : if ((partiallyReleasing ||
3572 1529 : !SxactIsPartiallyReleased(MySerializableXact)) &&
3573 1529 : TransactionIdEquals(MySerializableXact->xmin,
34 tmunro 3574 EUB : PredXact->SxactGlobalXmin))
4444 heikki.linnakangas 3575 : {
4444 heikki.linnakangas 3576 GIC 1513 : Assert(PredXact->SxactGlobalXminCount > 0);
3577 1513 : if (--(PredXact->SxactGlobalXminCount) == 0)
3578 : {
3579 864 : SetNewSxactGlobalXmin();
3580 864 : needToClear = true;
4444 heikki.linnakangas 3581 EUB : }
3582 : }
3583 :
4444 heikki.linnakangas 3584 GIC 1531 : LWLockRelease(SerializableXactHashLock);
3585 :
3586 1531 : LWLockAcquire(SerializableFinishedListLock, LW_EXCLUSIVE);
3587 :
3588 : /* Add this to the list of transactions to check for later cleanup. */
4444 heikki.linnakangas 3589 GBC 1531 : if (isCommit)
80 andres 3590 GNC 1210 : dlist_push_tail(FinishedSerializableTransactions,
3591 1210 : &MySerializableXact->finishedLink);
4444 heikki.linnakangas 3592 EUB :
1486 tmunro 3593 : /*
3594 : * If we're releasing a RO_SAFE transaction in parallel mode, we'll only
3595 : * partially release it. That's necessary because other backends may have
3596 : * a reference to it. The leader will release the SERIALIZABLEXACT itself
3597 : * at the end of the transaction after workers have stopped running.
3598 : */
4444 heikki.linnakangas 3599 GIC 1531 : if (!isCommit)
1486 tmunro 3600 GBC 321 : ReleaseOneSerializableXact(MySerializableXact,
3601 321 : isReadOnlySafe && IsInParallelMode(),
3602 : false);
3603 :
4444 heikki.linnakangas 3604 1531 : LWLockRelease(SerializableFinishedListLock);
3605 :
3606 1531 : if (needToClear)
4444 heikki.linnakangas 3607 GIC 864 : ClearOldPredicateLocks();
3608 :
1486 tmunro 3609 1531 : ReleasePredicateLocksLocal();
1486 tmunro 3610 ECB : }
3611 :
3612 : static void
1486 tmunro 3613 GIC 5428 : ReleasePredicateLocksLocal(void)
3614 : {
4444 heikki.linnakangas 3615 5428 : MySerializableXact = InvalidSerializableXact;
4321 3616 5428 : MyXactDidWrite = false;
3617 :
3618 : /* Delete per-transaction lock table */
4444 3619 5428 : if (LocalPredicateLockHash != NULL)
3620 : {
3621 1530 : hash_destroy(LocalPredicateLockHash);
3622 1530 : LocalPredicateLockHash = NULL;
3623 : }
3624 5428 : }
3625 :
3626 : /*
3627 : * Clear old predicate locks, belonging to committed transactions that are no
3628 : * longer interesting to any in-progress transaction.
3629 : */
3630 : static void
3631 864 : ClearOldPredicateLocks(void)
3632 : {
3633 : dlist_mutable_iter iter;
3634 :
3635 : /*
3636 : * Loop through finished transactions. They are in commit order, so we can
3637 : * stop as soon as we find one that's still interesting.
3638 : */
4444 heikki.linnakangas 3639 CBC 864 : LWLockAcquire(SerializableFinishedListLock, LW_EXCLUSIVE);
4444 heikki.linnakangas 3640 GIC 864 : LWLockAcquire(SerializableXactHashLock, LW_SHARED);
80 andres 3641 GNC 2082 : dlist_foreach_modify(iter, FinishedSerializableTransactions)
3642 : {
3643 1227 : SERIALIZABLEXACT *finishedSxact =
3644 1227 : dlist_container(SERIALIZABLEXACT, finishedLink, iter.cur);
4444 heikki.linnakangas 3645 ECB :
4444 heikki.linnakangas 3646 CBC 1227 : if (!TransactionIdIsValid(PredXact->SxactGlobalXmin)
3647 28 : || TransactionIdPrecedesOrEquals(finishedSxact->finishedBefore,
4444 heikki.linnakangas 3648 GIC 28 : PredXact->SxactGlobalXmin))
3649 : {
3650 : /*
3651 : * This transaction committed before any in-progress transaction
3652 : * took its snapshot. It's no longer interesting.
3653 : */
4444 heikki.linnakangas 3654 CBC 1210 : LWLockRelease(SerializableXactHashLock);
80 andres 3655 GNC 1210 : dlist_delete_thoroughly(&finishedSxact->finishedLink);
4444 heikki.linnakangas 3656 CBC 1210 : ReleaseOneSerializableXact(finishedSxact, false, false);
3657 1210 : LWLockAcquire(SerializableXactHashLock, LW_SHARED);
4444 heikki.linnakangas 3658 ECB : }
4444 heikki.linnakangas 3659 GIC 17 : else if (finishedSxact->commitSeqNo > PredXact->HavePartialClearedThrough
2118 tgl 3660 CBC 17 : && finishedSxact->commitSeqNo <= PredXact->CanPartialClearThrough)
3661 : {
4099 heikki.linnakangas 3662 ECB : /*
3663 : * Any active transactions that took their snapshot before this
3664 : * transaction committed are read-only, so we can clear part of
3665 : * its state.
3666 : */
4444 heikki.linnakangas 3667 GIC 8 : LWLockRelease(SerializableXactHashLock);
4099 heikki.linnakangas 3668 ECB :
4099 heikki.linnakangas 3669 GIC 8 : if (SxactIsReadOnly(finishedSxact))
3670 : {
3671 : /* A read-only transaction can be removed entirely */
80 andres 3672 UNC 0 : dlist_delete_thoroughly(&(finishedSxact->finishedLink));
4099 heikki.linnakangas 3673 UBC 0 : ReleaseOneSerializableXact(finishedSxact, false, false);
4099 heikki.linnakangas 3674 EUB : }
3675 : else
3676 : {
3677 : /*
3955 bruce 3678 : * A read-write transaction can only be partially cleared. We
3679 : * need to keep the SERIALIZABLEXACT but can release the
3680 : * SIREAD locks and conflicts in.
3681 : */
4099 heikki.linnakangas 3682 GIC 8 : ReleaseOneSerializableXact(finishedSxact, true, false);
4099 heikki.linnakangas 3683 EUB : }
3684 :
4444 heikki.linnakangas 3685 GBC 8 : PredXact->HavePartialClearedThrough = finishedSxact->commitSeqNo;
3686 8 : LWLockAcquire(SerializableXactHashLock, LW_SHARED);
4444 heikki.linnakangas 3687 EUB : }
3688 : else
3689 : {
3690 : /* Still interesting. */
3691 : break;
4321 3692 : }
4444 3693 : }
4444 heikki.linnakangas 3694 GIC 864 : LWLockRelease(SerializableXactHashLock);
4444 heikki.linnakangas 3695 EUB :
3696 : /*
3697 : * Loop through predicate locks on dummy transaction for summarized data.
3698 : */
1059 tgl 3699 CBC 864 : LWLockAcquire(SerializablePredicateListLock, LW_SHARED);
80 andres 3700 GNC 864 : dlist_foreach_modify(iter, &OldCommittedSxact->predicateLocks)
3701 : {
80 andres 3702 UNC 0 : PREDICATELOCK *predlock =
3703 0 : dlist_container(PREDICATELOCK, xactLink, iter.cur);
3704 : bool canDoPartialCleanup;
4444 heikki.linnakangas 3705 ECB :
4444 heikki.linnakangas 3706 LBC 0 : LWLockAcquire(SerializableXactHashLock, LW_SHARED);
4381 3707 0 : Assert(predlock->commitSeqNo != 0);
4381 heikki.linnakangas 3708 UIC 0 : Assert(predlock->commitSeqNo != InvalidSerCommitSeqNo);
4444 3709 0 : canDoPartialCleanup = (predlock->commitSeqNo <= PredXact->CanPartialClearThrough);
4444 heikki.linnakangas 3710 LBC 0 : LWLockRelease(SerializableXactHashLock);
3711 :
4321 heikki.linnakangas 3712 ECB : /*
3713 : * If this lock originally belonged to an old enough transaction, we
4321 heikki.linnakangas 3714 EUB : * can release it.
3715 : */
4444 heikki.linnakangas 3716 UIC 0 : if (canDoPartialCleanup)
4444 heikki.linnakangas 3717 EUB : {
3718 : PREDICATELOCKTAG tag;
3719 : PREDICATELOCKTARGET *target;
3720 : PREDICATELOCKTARGETTAG targettag;
3721 : uint32 targettaghash;
3722 : LWLock *partitionLock;
3723 :
4444 heikki.linnakangas 3724 LBC 0 : tag = predlock->tag;
4444 heikki.linnakangas 3725 UIC 0 : target = tag.myTarget;
4444 heikki.linnakangas 3726 UBC 0 : targettag = target->tag;
3727 0 : targettaghash = PredicateLockTargetTagHashCode(&targettag);
4444 heikki.linnakangas 3728 UIC 0 : partitionLock = PredicateLockHashPartitionLock(targettaghash);
4444 heikki.linnakangas 3729 EUB :
4444 heikki.linnakangas 3730 UBC 0 : LWLockAcquire(partitionLock, LW_EXCLUSIVE);
4444 heikki.linnakangas 3731 EUB :
80 andres 3732 UNC 0 : dlist_delete(&(predlock->targetLink));
3733 0 : dlist_delete(&(predlock->xactLink));
3734 :
4444 heikki.linnakangas 3735 LBC 0 : hash_search_with_hash_value(PredicateLockHash, &tag,
2118 tgl 3736 UIC 0 : PredicateLockHashCodeFromTargetHashCode(&tag,
2118 tgl 3737 ECB : targettaghash),
4444 heikki.linnakangas 3738 : HASH_REMOVE, NULL);
4444 heikki.linnakangas 3739 LBC 0 : RemoveTargetIfNoLongerUsed(target, targettaghash);
3740 :
4444 heikki.linnakangas 3741 UIC 0 : LWLockRelease(partitionLock);
4444 heikki.linnakangas 3742 ECB : }
3743 : }
3744 :
1059 tgl 3745 GIC 864 : LWLockRelease(SerializablePredicateListLock);
4444 heikki.linnakangas 3746 864 : LWLockRelease(SerializableFinishedListLock);
3747 864 : }
3748 :
3749 : /*
3750 : * This is the normal way to delete anything from any of the predicate
3751 : * locking hash tables. Given a transaction which we know can be deleted:
4444 heikki.linnakangas 3752 ECB : * delete all predicate locks held by that transaction and any predicate
3753 : * lock targets which are now unreferenced by a lock; delete all conflicts
3754 : * for the transaction; delete all xid values for the transaction; then
3755 : * delete the transaction.
3756 : *
3757 : * When the partial flag is set, we can release all predicate locks and
3758 : * in-conflict information -- we've established that there are no longer
3759 : * any overlapping read write transactions for which this transaction could
3760 : * matter -- but keep the transaction entry itself and any outConflicts.
3761 : *
4444 heikki.linnakangas 3762 EUB : * When the summarize flag is set, we've run short of room for sxact data
3763 : * and must summarize to the SLRU. Predicate locks are transferred to a
4444 heikki.linnakangas 3764 ECB : * dummy "old" transaction, with duplicate locks on a single target
3765 : * collapsing to a single lock with the "latest" commitSeqNo from among
3766 : * the conflicting locks..
3767 : */
3768 : static void
4444 heikki.linnakangas 3769 GIC 1539 : ReleaseOneSerializableXact(SERIALIZABLEXACT *sxact, bool partial,
3770 : bool summarize)
4444 heikki.linnakangas 3771 ECB : {
3772 : SERIALIZABLEXIDTAG sxidtag;
3773 : dlist_mutable_iter iter;
3774 :
4444 heikki.linnakangas 3775 CBC 1539 : Assert(sxact != NULL);
4310 heikki.linnakangas 3776 GIC 1539 : Assert(SxactIsRolledBack(sxact) || SxactIsCommitted(sxact));
4099 heikki.linnakangas 3777 GBC 1539 : Assert(partial || !SxactIsOnFinishedList(sxact));
4444 heikki.linnakangas 3778 GIC 1539 : Assert(LWLockHeldByMe(SerializableFinishedListLock));
3779 :
3780 : /*
3781 : * First release all the predicate locks held by this xact (or transfer
3782 : * them to OldCommittedSxact if summarize is true)
3783 : */
1059 tgl 3784 CBC 1539 : LWLockAcquire(SerializablePredicateListLock, LW_SHARED);
1486 tmunro 3785 GIC 1539 : if (IsInParallelMode())
1059 tgl 3786 3 : LWLockAcquire(&sxact->perXactPredicateListLock, LW_EXCLUSIVE);
80 andres 3787 GNC 4363 : dlist_foreach_modify(iter, &sxact->predicateLocks)
3788 : {
3789 2824 : PREDICATELOCK *predlock =
3790 2824 : dlist_container(PREDICATELOCK, xactLink, iter.cur);
3791 : PREDICATELOCKTAG tag;
3792 : PREDICATELOCKTARGET *target;
3793 : PREDICATELOCKTARGETTAG targettag;
3794 : uint32 targettaghash;
3795 : LWLock *partitionLock;
3796 :
4444 heikki.linnakangas 3797 GIC 2824 : tag = predlock->tag;
4444 heikki.linnakangas 3798 CBC 2824 : target = tag.myTarget;
4444 heikki.linnakangas 3799 GIC 2824 : targettag = target->tag;
3800 2824 : targettaghash = PredicateLockTargetTagHashCode(&targettag);
4444 heikki.linnakangas 3801 CBC 2824 : partitionLock = PredicateLockHashPartitionLock(targettaghash);
3802 :
4444 heikki.linnakangas 3803 GBC 2824 : LWLockAcquire(partitionLock, LW_EXCLUSIVE);
3804 :
80 andres 3805 GNC 2824 : dlist_delete(&predlock->targetLink);
3806 :
4444 heikki.linnakangas 3807 GIC 2824 : hash_search_with_hash_value(PredicateLockHash, &tag,
2118 tgl 3808 2824 : PredicateLockHashCodeFromTargetHashCode(&tag,
2118 tgl 3809 ECB : targettaghash),
3810 : HASH_REMOVE, NULL);
4444 heikki.linnakangas 3811 CBC 2824 : if (summarize)
4444 heikki.linnakangas 3812 EUB : {
3813 : bool found;
3814 :
3815 : /* Fold into dummy transaction list. */
4444 heikki.linnakangas 3816 UIC 0 : tag.myXact = OldCommittedSxact;
4444 heikki.linnakangas 3817 LBC 0 : predlock = hash_search_with_hash_value(PredicateLockHash, &tag,
2118 tgl 3818 0 : PredicateLockHashCodeFromTargetHashCode(&tag,
3819 : targettaghash),
4385 rhaas 3820 ECB : HASH_ENTER_NULL, &found);
4444 heikki.linnakangas 3821 LBC 0 : if (!predlock)
4444 heikki.linnakangas 3822 UIC 0 : ereport(ERROR,
3823 : (errcode(ERRCODE_OUT_OF_MEMORY),
3824 : errmsg("out of shared memory"),
3825 : errhint("You might need to increase max_pred_locks_per_transaction.")));
3826 0 : if (found)
3827 : {
4381 3828 0 : Assert(predlock->commitSeqNo != 0);
4381 heikki.linnakangas 3829 LBC 0 : Assert(predlock->commitSeqNo != InvalidSerCommitSeqNo);
4444 3830 0 : if (predlock->commitSeqNo < sxact->commitSeqNo)
4444 heikki.linnakangas 3831 UIC 0 : predlock->commitSeqNo = sxact->commitSeqNo;
4444 heikki.linnakangas 3832 EUB : }
3833 : else
3834 : {
80 andres 3835 UNC 0 : dlist_push_tail(&target->predicateLocks,
3836 : &predlock->targetLink);
3837 0 : dlist_push_tail(&OldCommittedSxact->predicateLocks,
3838 : &predlock->xactLink);
4444 heikki.linnakangas 3839 UIC 0 : predlock->commitSeqNo = sxact->commitSeqNo;
3840 : }
3841 : }
4444 heikki.linnakangas 3842 EUB : else
4444 heikki.linnakangas 3843 GBC 2824 : RemoveTargetIfNoLongerUsed(target, targettaghash);
4444 heikki.linnakangas 3844 EUB :
4444 heikki.linnakangas 3845 GIC 2824 : LWLockRelease(partitionLock);
3846 : }
3847 :
4444 heikki.linnakangas 3848 EUB : /*
3849 : * Rather than retail removal, just re-init the head after we've run
3850 : * through the list.
3851 : */
80 andres 3852 GNC 1539 : dlist_init(&sxact->predicateLocks);
4444 heikki.linnakangas 3853 ECB :
1486 tmunro 3854 GIC 1539 : if (IsInParallelMode())
1059 tgl 3855 CBC 3 : LWLockRelease(&sxact->perXactPredicateListLock);
3856 1539 : LWLockRelease(SerializablePredicateListLock);
4444 heikki.linnakangas 3857 ECB :
4444 heikki.linnakangas 3858 GIC 1539 : sxidtag.xid = sxact->topXid;
3859 1539 : LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
4444 heikki.linnakangas 3860 ECB :
4321 3861 : /* Release all outConflicts (unless 'partial' is true) */
4444 heikki.linnakangas 3862 GIC 1539 : if (!partial)
3863 : {
80 andres 3864 GNC 1529 : dlist_foreach_modify(iter, &sxact->outConflicts)
3865 : {
80 andres 3866 UNC 0 : RWConflict conflict =
3867 0 : dlist_container(RWConflictData, outLink, iter.cur);
3868 :
4444 heikki.linnakangas 3869 UBC 0 : if (summarize)
3870 0 : conflict->sxactIn->flags |= SXACT_FLAG_SUMMARY_CONFLICT_IN;
3871 0 : ReleaseRWConflict(conflict);
3872 : }
3873 : }
4444 heikki.linnakangas 3874 EUB :
3875 : /* Release all inConflicts. */
80 andres 3876 GNC 1539 : dlist_foreach_modify(iter, &sxact->inConflicts)
3877 : {
80 andres 3878 UNC 0 : RWConflict conflict =
3879 0 : dlist_container(RWConflictData, inLink, iter.cur);
3880 :
4444 heikki.linnakangas 3881 UIC 0 : if (summarize)
3882 0 : conflict->sxactOut->flags |= SXACT_FLAG_SUMMARY_CONFLICT_OUT;
4444 heikki.linnakangas 3883 LBC 0 : ReleaseRWConflict(conflict);
4444 heikki.linnakangas 3884 ECB : }
3885 :
4321 3886 : /* Finally, get rid of the xid and the record of the transaction itself. */
4444 heikki.linnakangas 3887 GIC 1539 : if (!partial)
3888 : {
4444 heikki.linnakangas 3889 CBC 1529 : if (sxidtag.xid != InvalidTransactionId)
3890 1263 : hash_search(SerializableXidHash, &sxidtag, HASH_REMOVE, NULL);
4444 heikki.linnakangas 3891 GIC 1529 : ReleasePredXact(sxact);
3892 : }
4444 heikki.linnakangas 3893 ECB :
4444 heikki.linnakangas 3894 GIC 1539 : LWLockRelease(SerializableXactHashLock);
3895 1539 : }
4444 heikki.linnakangas 3896 EUB :
3897 : /*
3898 : * Tests whether the given top level transaction is concurrent with
3899 : * (overlaps) our current transaction.
4444 heikki.linnakangas 3900 ECB : *
3901 : * We need to identify the top level transaction for SSI, anyway, so pass
3902 : * that to this function to save the overhead of checking the snapshot's
3903 : * subxip array.
3904 : */
3905 : static bool
4444 heikki.linnakangas 3906 GIC 532 : XidIsConcurrent(TransactionId xid)
3907 : {
3908 : Snapshot snap;
3909 :
4444 heikki.linnakangas 3910 CBC 532 : Assert(TransactionIdIsValid(xid));
3911 532 : Assert(!TransactionIdEquals(xid, GetTopTransactionIdIfAny()));
3912 :
4444 heikki.linnakangas 3913 GIC 532 : snap = GetTransactionSnapshot();
3914 :
3915 532 : if (TransactionIdPrecedes(xid, snap->xmin))
4444 heikki.linnakangas 3916 UIC 0 : return false;
3917 :
4444 heikki.linnakangas 3918 GIC 532 : if (TransactionIdFollowsOrEquals(xid, snap->xmax))
4444 heikki.linnakangas 3919 CBC 522 : return true;
3920 :
199 michael 3921 GNC 10 : return pg_lfind32(xid, snap->xip, snap->xcnt);
4444 heikki.linnakangas 3922 ECB : }
3923 :
3924 : bool
1167 tmunro 3925 GIC 241421878 : CheckForSerializableConflictOutNeeded(Relation relation, Snapshot snapshot)
3926 : {
1167 tmunro 3927 CBC 241421878 : if (!SerializationNeededForRead(relation, snapshot))
3928 241396543 : return false;
1167 tmunro 3929 ECB :
3930 : /* Check if someone else has already decided that we need to die */
1167 tmunro 3931 CBC 25335 : if (SxactIsDoomed(MySerializableXact))
3932 : {
1167 tmunro 3933 UIC 0 : ereport(ERROR,
1167 tmunro 3934 ECB : (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
3935 : errmsg("could not serialize access due to read/write dependencies among transactions"),
3936 : errdetail_internal("Reason code: Canceled on identification as a pivot, during conflict out checking."),
3937 : errhint("The transaction might succeed if retried.")));
3938 : }
3939 :
1167 tmunro 3940 GIC 25335 : return true;
3941 : }
3942 :
3943 : /*
3944 : * CheckForSerializableConflictOut
1031 tmunro 3945 ECB : * A table AM is reading a tuple that has been modified. If it determines
3946 : * that the tuple version it is reading is not visible to us, it should
3947 : * pass in the top level xid of the transaction that created it.
3948 : * Otherwise, if it determines that it is visible to us but it has been
3949 : * deleted or there is a newer version available due to an update, it
3950 : * should pass in the top level xid of the modifying transaction.
3951 : *
3952 : * This function will check for overlap with our own transaction. If the given
3953 : * xid is also serializable and the transactions overlap (i.e., they cannot see
3954 : * each other's writes), then we have a conflict out.
3955 : */
3956 : void
1167 tmunro 3957 GIC 567 : CheckForSerializableConflictOut(Relation relation, TransactionId xid, Snapshot snapshot)
3958 : {
3959 : SERIALIZABLEXIDTAG sxidtag;
3960 : SERIALIZABLEXID *sxid;
3961 : SERIALIZABLEXACT *sxact;
3962 :
4316 heikki.linnakangas 3963 567 : if (!SerializationNeededForRead(relation, snapshot))
4444 3964 204 : return;
4444 heikki.linnakangas 3965 ECB :
4316 3966 : /* Check if someone else has already decided that we need to die */
4316 heikki.linnakangas 3967 GIC 567 : if (SxactIsDoomed(MySerializableXact))
4444 heikki.linnakangas 3968 ECB : {
4444 heikki.linnakangas 3969 LBC 0 : ereport(ERROR,
3970 : (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
3971 : errmsg("could not serialize access due to read/write dependencies among transactions"),
4255 peter_e 3972 ECB : errdetail_internal("Reason code: Canceled on identification as a pivot, during conflict out checking."),
4444 heikki.linnakangas 3973 : errhint("The transaction might succeed if retried.")));
3974 : }
4444 heikki.linnakangas 3975 GIC 567 : Assert(TransactionIdIsValid(xid));
4444 heikki.linnakangas 3976 ECB :
4444 heikki.linnakangas 3977 GIC 567 : if (TransactionIdEquals(xid, GetTopTransactionIdIfAny()))
4444 heikki.linnakangas 3978 LBC 0 : return;
4444 heikki.linnakangas 3979 ECB :
3980 : /*
3981 : * Find sxact or summarized info for the top level xid.
3982 : */
4444 heikki.linnakangas 3983 GIC 567 : sxidtag.xid = xid;
3984 567 : LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
4444 heikki.linnakangas 3985 ECB : sxid = (SERIALIZABLEXID *)
4444 heikki.linnakangas 3986 CBC 567 : hash_search(SerializableXidHash, &sxidtag, HASH_FIND, NULL);
3987 567 : if (!sxid)
3988 : {
4444 heikki.linnakangas 3989 ECB : /*
3990 : * Transaction not found in "normal" SSI structures. Check whether it
3991 : * got pushed out to SLRU storage for "old committed" transactions.
3992 : */
3993 : SerCommitSeqNo conflictCommitSeqNo;
3994 :
1059 tgl 3995 CBC 25 : conflictCommitSeqNo = SerialGetMinConflictCommitSeqNo(xid);
4444 heikki.linnakangas 3996 GIC 25 : if (conflictCommitSeqNo != 0)
3997 : {
4444 heikki.linnakangas 3998 LBC 0 : if (conflictCommitSeqNo != InvalidSerCommitSeqNo
3999 0 : && (!SxactIsReadOnly(MySerializableXact)
4444 heikki.linnakangas 4000 UIC 0 : || conflictCommitSeqNo
4001 0 : <= MySerializableXact->SeqNo.lastCommitBeforeSnapshot))
4002 0 : ereport(ERROR,
4003 : (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
4004 : errmsg("could not serialize access due to read/write dependencies among transactions"),
4005 : errdetail_internal("Reason code: Canceled on conflict out to old pivot %u.", xid),
4006 : errhint("The transaction might succeed if retried.")));
4007 :
4008 0 : if (SxactHasSummaryConflictIn(MySerializableXact)
80 andres 4009 UNC 0 : || !dlist_is_empty(&MySerializableXact->inConflicts))
4444 heikki.linnakangas 4010 UIC 0 : ereport(ERROR,
4011 : (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
4012 : errmsg("could not serialize access due to read/write dependencies among transactions"),
4013 : errdetail_internal("Reason code: Canceled on identification as a pivot, with conflict out to old committed transaction %u.", xid),
2118 tgl 4014 ECB : errhint("The transaction might succeed if retried.")));
4444 heikki.linnakangas 4015 :
4444 heikki.linnakangas 4016 UBC 0 : MySerializableXact->flags |= SXACT_FLAG_SUMMARY_CONFLICT_OUT;
4444 heikki.linnakangas 4017 ECB : }
4018 :
4019 : /* It's not serializable or otherwise not important. */
4444 heikki.linnakangas 4020 GIC 25 : LWLockRelease(SerializableXactHashLock);
4021 25 : return;
4022 : }
4023 542 : sxact = sxid->myXact;
4024 542 : Assert(TransactionIdEquals(sxact->topXid, xid));
4316 heikki.linnakangas 4025 CBC 542 : if (sxact == MySerializableXact || SxactIsDoomed(sxact))
4026 : {
4027 : /* Can't conflict with ourself or a transaction that will roll back. */
4444 4028 4 : LWLockRelease(SerializableXactHashLock);
4444 heikki.linnakangas 4029 GIC 4 : return;
4030 : }
4031 :
4444 heikki.linnakangas 4032 ECB : /*
4033 : * We have a conflict out to a transaction which has a conflict out to a
3260 bruce 4034 : * summarized transaction. That summarized transaction must have
4035 : * committed first, and we can't tell when it committed in relation to our
4302 peter_e 4036 : * snapshot acquisition, so something needs to be canceled.
4444 heikki.linnakangas 4037 : */
4444 heikki.linnakangas 4038 GIC 538 : if (SxactHasSummaryConflictOut(sxact))
4039 : {
4444 heikki.linnakangas 4040 LBC 0 : if (!SxactIsPrepared(sxact))
4041 : {
4316 heikki.linnakangas 4042 UIC 0 : sxact->flags |= SXACT_FLAG_DOOMED;
4444 4043 0 : LWLockRelease(SerializableXactHashLock);
4444 heikki.linnakangas 4044 LBC 0 : return;
4045 : }
4444 heikki.linnakangas 4046 ECB : else
4047 : {
4444 heikki.linnakangas 4048 UIC 0 : LWLockRelease(SerializableXactHashLock);
4444 heikki.linnakangas 4049 LBC 0 : ereport(ERROR,
4444 heikki.linnakangas 4050 ECB : (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
4051 : errmsg("could not serialize access due to read/write dependencies among transactions"),
3955 bruce 4052 EUB : errdetail_internal("Reason code: Canceled on conflict out to old pivot."),
4444 heikki.linnakangas 4053 ECB : errhint("The transaction might succeed if retried.")));
4054 : }
4055 : }
4056 :
4057 : /*
4058 : * If this is a read-only transaction and the writing transaction has
4059 : * committed, and it doesn't have a rw-conflict to a transaction which
4060 : * committed before it, no conflict.
4061 : */
4444 heikki.linnakangas 4062 CBC 538 : if (SxactIsReadOnly(MySerializableXact)
4444 heikki.linnakangas 4063 GIC 119 : && SxactIsCommitted(sxact)
4064 8 : && !SxactHasSummaryConflictOut(sxact)
4065 8 : && (!SxactHasConflictOut(sxact)
4444 heikki.linnakangas 4066 CBC 2 : || MySerializableXact->SeqNo.lastCommitBeforeSnapshot < sxact->SeqNo.earliestOutConflictCommit))
4067 : {
4068 : /* Read-only transaction will appear to run first. No conflict. */
4444 heikki.linnakangas 4069 GIC 6 : LWLockRelease(SerializableXactHashLock);
4070 6 : return;
4071 : }
4072 :
4073 532 : if (!XidIsConcurrent(xid))
4074 : {
4075 : /* This write was already in our snapshot; no conflict. */
4444 heikki.linnakangas 4076 UIC 0 : LWLockRelease(SerializableXactHashLock);
4077 0 : return;
4078 : }
4079 :
4321 heikki.linnakangas 4080 GIC 532 : if (RWConflictExists(MySerializableXact, sxact))
4081 : {
4082 : /* We don't want duplicate conflict records in the list. */
4444 heikki.linnakangas 4083 CBC 169 : LWLockRelease(SerializableXactHashLock);
4444 heikki.linnakangas 4084 GIC 169 : return;
4085 : }
4086 :
4444 heikki.linnakangas 4087 ECB : /*
4088 : * Flag the conflict. But first, if this conflict creates a dangerous
4089 : * structure, ereport an error.
4090 : */
4321 heikki.linnakangas 4091 CBC 363 : FlagRWConflict(MySerializableXact, sxact);
4444 4092 350 : LWLockRelease(SerializableXactHashLock);
4093 : }
4094 :
4095 : /*
4096 : * Check a particular target for rw-dependency conflict in. A subroutine of
4097 : * CheckForSerializableConflictIn().
4098 : */
4099 : static void
4444 heikki.linnakangas 4100 GIC 7478 : CheckTargetForConflictsIn(PREDICATELOCKTARGETTAG *targettag)
4101 : {
4444 heikki.linnakangas 4102 ECB : uint32 targettaghash;
4103 : LWLock *partitionLock;
4104 : PREDICATELOCKTARGET *target;
4343 rhaas 4105 GIC 7478 : PREDICATELOCK *mypredlock = NULL;
4106 : PREDICATELOCKTAG mypredlocktag;
4107 : dlist_mutable_iter iter;
4108 :
4444 heikki.linnakangas 4109 7478 : Assert(MySerializableXact != InvalidSerializableXact);
4110 :
4111 : /*
4112 : * The same hash and LW lock apply to the lock target and the lock itself.
4444 heikki.linnakangas 4113 ECB : */
4444 heikki.linnakangas 4114 GIC 7478 : targettaghash = PredicateLockTargetTagHashCode(targettag);
4444 heikki.linnakangas 4115 CBC 7478 : partitionLock = PredicateLockHashPartitionLock(targettaghash);
4444 heikki.linnakangas 4116 GIC 7478 : LWLockAcquire(partitionLock, LW_SHARED);
4117 : target = (PREDICATELOCKTARGET *)
4118 7478 : hash_search_with_hash_value(PredicateLockTargetHash,
4119 : targettag, targettaghash,
4444 heikki.linnakangas 4120 ECB : HASH_FIND, NULL);
4444 heikki.linnakangas 4121 GIC 7478 : if (!target)
4122 : {
4444 heikki.linnakangas 4123 ECB : /* Nothing has this target locked; we're done here. */
4444 heikki.linnakangas 4124 GIC 5607 : LWLockRelease(partitionLock);
4422 heikki.linnakangas 4125 CBC 5607 : return;
4126 : }
4127 :
4128 : /*
4444 heikki.linnakangas 4129 ECB : * Each lock for an overlapping transaction represents a conflict: a
4130 : * rw-dependency in to this transaction.
4131 : */
4444 heikki.linnakangas 4132 GIC 1871 : LWLockAcquire(SerializableXactHashLock, LW_SHARED);
4133 :
80 andres 4134 GNC 4216 : dlist_foreach_modify(iter, &target->predicateLocks)
4135 : {
4136 2412 : PREDICATELOCK *predlock =
4137 2412 : dlist_container(PREDICATELOCK, targetLink, iter.cur);
4138 2412 : SERIALIZABLEXACT *sxact = predlock->tag.myXact;
4139 :
4444 heikki.linnakangas 4140 GIC 2412 : if (sxact == MySerializableXact)
4141 : {
4142 : /*
4143 : * If we're getting a write lock on a tuple, we don't need a
4144 : * predicate (SIREAD) lock on the same tuple. We can safely remove
4145 : * our SIREAD lock, but we'll defer doing so until after the loop
4146 : * because that requires upgrading to an exclusive partition lock.
4147 : *
4148 : * We can't use this optimization within a subtransaction because
4149 : * the subtransaction could roll back, and we would be left
4150 : * without any lock at the top level.
4151 : */
4384 rhaas 4152 1564 : if (!IsSubTransaction()
4153 1564 : && GET_PREDICATELOCKTARGETTAG_OFFSET(*targettag))
4154 : {
4343 4155 388 : mypredlock = predlock;
4343 rhaas 4156 CBC 388 : mypredlocktag = predlock->tag;
4157 : }
4158 : }
4316 heikki.linnakangas 4159 GIC 848 : else if (!SxactIsDoomed(sxact)
4444 4160 848 : && (!SxactIsCommitted(sxact)
4161 83 : || TransactionIdPrecedes(GetTransactionSnapshot()->xmin,
4162 : sxact->finishedBefore))
4321 4163 839 : && !RWConflictExists(sxact, MySerializableXact))
4164 : {
4444 4165 497 : LWLockRelease(SerializableXactHashLock);
4166 497 : LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
4167 :
4168 : /*
4169 : * Re-check after getting exclusive lock because the other
4387 rhaas 4170 ECB : * transaction may have flagged a conflict.
4171 : */
4316 heikki.linnakangas 4172 GIC 497 : if (!SxactIsDoomed(sxact)
4387 rhaas 4173 CBC 497 : && (!SxactIsCommitted(sxact)
4174 74 : || TransactionIdPrecedes(GetTransactionSnapshot()->xmin,
4175 : sxact->finishedBefore))
4321 heikki.linnakangas 4176 GIC 497 : && !RWConflictExists(sxact, MySerializableXact))
4177 : {
4178 497 : FlagRWConflict(sxact, MySerializableXact);
4179 : }
4444 heikki.linnakangas 4180 ECB :
4444 heikki.linnakangas 4181 GIC 430 : LWLockRelease(SerializableXactHashLock);
4444 heikki.linnakangas 4182 CBC 430 : LWLockAcquire(SerializableXactHashLock, LW_SHARED);
4183 : }
4184 : }
4185 1804 : LWLockRelease(SerializableXactHashLock);
4186 1804 : LWLockRelease(partitionLock);
4343 rhaas 4187 ECB :
4188 : /*
4189 : * If we found one of our own SIREAD locks to remove, remove it now.
4190 : *
1371 michael 4191 : * At this point our transaction already has a RowExclusiveLock on the
4192 : * relation, so we are OK to drop the predicate lock on the tuple, if
4323 heikki.linnakangas 4193 : * found, without fearing that another write against the tuple will occur
4194 : * before the MVCC information makes it to the buffer.
4195 : */
4343 rhaas 4196 GIC 1804 : if (mypredlock != NULL)
4197 : {
4198 : uint32 predlockhashcode;
4199 : PREDICATELOCK *rmpredlock;
4343 rhaas 4200 ECB :
1059 tgl 4201 CBC 381 : LWLockAcquire(SerializablePredicateListLock, LW_SHARED);
1486 tmunro 4202 GBC 381 : if (IsInParallelMode())
1059 tgl 4203 UBC 0 : LWLockAcquire(&MySerializableXact->perXactPredicateListLock, LW_EXCLUSIVE);
4343 rhaas 4204 GIC 381 : LWLockAcquire(partitionLock, LW_EXCLUSIVE);
4205 381 : LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
4206 :
4207 : /*
4323 heikki.linnakangas 4208 EUB : * Remove the predicate lock from shared memory, if it wasn't removed
4209 : * while the locks were released. One way that could happen is from
4210 : * autovacuum cleaning up an index.
4343 rhaas 4211 : */
4343 rhaas 4212 GIC 381 : predlockhashcode = PredicateLockHashCodeFromTargetHashCode
4343 rhaas 4213 EUB : (&mypredlocktag, targettaghash);
4214 : rmpredlock = (PREDICATELOCK *)
4343 rhaas 4215 GIC 381 : hash_search_with_hash_value(PredicateLockHash,
4343 rhaas 4216 EUB : &mypredlocktag,
4217 : predlockhashcode,
4218 : HASH_FIND, NULL);
4343 rhaas 4219 GIC 381 : if (rmpredlock != NULL)
4220 : {
4221 381 : Assert(rmpredlock == mypredlock);
4343 rhaas 4222 ECB :
80 andres 4223 GNC 381 : dlist_delete(&(mypredlock->targetLink));
4224 381 : dlist_delete(&(mypredlock->xactLink));
4343 rhaas 4225 ECB :
4226 : rmpredlock = (PREDICATELOCK *)
4343 rhaas 4227 GIC 381 : hash_search_with_hash_value(PredicateLockHash,
4228 : &mypredlocktag,
4229 : predlockhashcode,
4230 : HASH_REMOVE, NULL);
4231 381 : Assert(rmpredlock == mypredlock);
4232 :
4233 381 : RemoveTargetIfNoLongerUsed(target, targettaghash);
4234 : }
4235 :
4343 rhaas 4236 CBC 381 : LWLockRelease(SerializableXactHashLock);
4343 rhaas 4237 GIC 381 : LWLockRelease(partitionLock);
1486 tmunro 4238 CBC 381 : if (IsInParallelMode())
1059 tgl 4239 UIC 0 : LWLockRelease(&MySerializableXact->perXactPredicateListLock);
1059 tgl 4240 GIC 381 : LWLockRelease(SerializablePredicateListLock);
4323 heikki.linnakangas 4241 ECB :
4343 rhaas 4242 GIC 381 : if (rmpredlock != NULL)
4243 : {
4343 rhaas 4244 ECB : /*
4323 heikki.linnakangas 4245 EUB : * Remove entry in local lock table if it exists. It's OK if it
4323 heikki.linnakangas 4246 ECB : * doesn't exist; that means the lock was transferred to a new
4323 heikki.linnakangas 4247 EUB : * target by a different backend.
4248 : */
4343 rhaas 4249 CBC 381 : hash_search_with_hash_value(LocalPredicateLockHash,
4343 rhaas 4250 ECB : targettag, targettaghash,
4251 : HASH_REMOVE, NULL);
4252 :
4343 rhaas 4253 GIC 381 : DecrementParentLocks(targettag);
4254 : }
4255 : }
4256 : }
4257 :
4258 : /*
4259 : * CheckForSerializableConflictIn
4260 : * We are writing the given tuple. If that indicates a rw-conflict
4261 : * in from another serializable transaction, take appropriate action.
4262 : *
4263 : * Skip checking for any granularity for which a parameter is missing.
4264 : *
4265 : * A tuple update or delete is in conflict if we have a predicate lock
4266 : * against the relation or page in which the tuple exists, or against the
4267 : * tuple itself.
4268 : */
4269 : void
1167 tmunro 4270 24294998 : CheckForSerializableConflictIn(Relation relation, ItemPointer tid, BlockNumber blkno)
4444 heikki.linnakangas 4271 ECB : {
4272 : PREDICATELOCKTARGETTAG targettag;
4273 :
4316 heikki.linnakangas 4274 GIC 24294998 : if (!SerializationNeededForWrite(relation))
4444 4275 24290573 : return;
4444 heikki.linnakangas 4276 ECB :
4277 : /* Check if someone else has already decided that we need to die */
4316 heikki.linnakangas 4278 CBC 4425 : if (SxactIsDoomed(MySerializableXact))
4444 heikki.linnakangas 4279 GIC 1 : ereport(ERROR,
4280 : (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
4281 : errmsg("could not serialize access due to read/write dependencies among transactions"),
4282 : errdetail_internal("Reason code: Canceled on identification as a pivot, during conflict in checking."),
4283 : errhint("The transaction might succeed if retried.")));
4284 :
4285 : /*
4286 : * We're doing a write which might cause rw-conflicts now or later.
4287 : * Memorize that fact.
4288 : */
4321 4289 4424 : MyXactDidWrite = true;
4290 :
4444 heikki.linnakangas 4291 ECB : /*
4292 : * It is important that we check for locks from the finest granularity to
4293 : * the coarsest granularity, so that granularity promotion doesn't cause
4294 : * us to miss a lock. The new (coarser) lock will be acquired before the
4295 : * old (finer) locks are released.
4296 : *
4297 : * It is not possible to take and hold a lock across the checks for all
4298 : * granularities because each target could be in a separate partition.
4299 : */
1167 tmunro 4300 GIC 4424 : if (tid != NULL)
4301 : {
4444 heikki.linnakangas 4302 643 : SET_PREDICATELOCKTARGETTAG_TUPLE(targettag,
4303 : relation->rd_locator.dbOid,
4304 : relation->rd_id,
4305 : ItemPointerGetBlockNumber(tid),
4306 : ItemPointerGetOffsetNumber(tid));
4307 643 : CheckTargetForConflictsIn(&targettag);
4308 : }
4309 :
1167 tmunro 4310 4401 : if (blkno != InvalidBlockNumber)
4311 : {
4444 heikki.linnakangas 4312 2464 : SET_PREDICATELOCKTARGETTAG_PAGE(targettag,
4313 : relation->rd_locator.dbOid,
4444 heikki.linnakangas 4314 ECB : relation->rd_id,
1167 tmunro 4315 EUB : blkno);
4444 heikki.linnakangas 4316 CBC 2464 : CheckTargetForConflictsIn(&targettag);
4317 : }
4318 :
4444 heikki.linnakangas 4319 GIC 4371 : SET_PREDICATELOCKTARGETTAG_RELATION(targettag,
4320 : relation->rd_locator.dbOid,
4321 : relation->rd_id);
4444 heikki.linnakangas 4322 CBC 4371 : CheckTargetForConflictsIn(&targettag);
4444 heikki.linnakangas 4323 ECB : }
4324 :
4325 : /*
4323 4326 : * CheckTableForSerializableConflictIn
4327 : * The entire table is going through a DDL-style logical mass delete
4328 : * like TRUNCATE or DROP TABLE. If that causes a rw-conflict in from
4329 : * another serializable transaction, take appropriate action.
4323 heikki.linnakangas 4330 EUB : *
4323 heikki.linnakangas 4331 ECB : * While these operations do not operate entirely within the bounds of
4332 : * snapshot isolation, they can occur inside a serializable transaction, and
4333 : * will logically occur after any reads which saw rows which were destroyed
4334 : * by these operations, so we do what we can to serialize properly under
4335 : * SSI.
4336 : *
4337 : * The relation passed in must be a heap relation. Any predicate lock of any
4338 : * granularity on the heap will cause a rw-conflict in to this transaction.
4339 : * Predicate locks on indexes do not matter because they only exist to guard
4340 : * against conflicting inserts into the index, and this is a mass *delete*.
4341 : * When a table is truncated or dropped, the index will also be truncated
4342 : * or dropped, and we'll deal with locks on the index when that happens.
4343 : *
4344 : * Dropping or truncating a table also needs to drop any existing predicate
4345 : * locks on heap tuples or pages, because they're about to go away. This
4346 : * should be done before altering the predicate locks because the transaction
4347 : * could be rolled back because of a conflict, in which case the lock changes
4348 : * are not needed. (At the moment, we don't actually bother to drop the
4349 : * existing locks on a dropped or truncated table at the moment. That might
4350 : * lead to some false positives, but it doesn't seem worth the trouble.)
4351 : */
4352 : void
4309 heikki.linnakangas 4353 CBC 20343 : CheckTableForSerializableConflictIn(Relation relation)
4354 : {
4323 heikki.linnakangas 4355 ECB : HASH_SEQ_STATUS seqstat;
4356 : PREDICATELOCKTARGET *target;
4323 heikki.linnakangas 4357 EUB : Oid dbId;
4358 : Oid heapId;
4359 : int i;
4360 :
4361 : /*
4362 : * Bail out quickly if there are no serializable transactions running.
4363 : * It's safe to check this without taking locks because the caller is
4364 : * holding an ACCESS EXCLUSIVE lock on the relation. No new locks which
4365 : * would matter here can be acquired while that is held.
4366 : */
4323 heikki.linnakangas 4367 CBC 20343 : if (!TransactionIdIsValid(PredXact->SxactGlobalXmin))
4323 heikki.linnakangas 4368 GIC 20340 : return;
4323 heikki.linnakangas 4369 ECB :
4316 heikki.linnakangas 4370 CBC 85 : if (!SerializationNeededForWrite(relation))
4323 4371 82 : return;
4372 :
4321 heikki.linnakangas 4373 ECB : /*
4374 : * We're doing a write which might cause rw-conflicts now or later.
4375 : * Memorize that fact.
4376 : */
4321 heikki.linnakangas 4377 GBC 3 : MyXactDidWrite = true;
4378 :
4323 heikki.linnakangas 4379 CBC 3 : Assert(relation->rd_index == NULL); /* not an index relation */
4323 heikki.linnakangas 4380 ECB :
277 rhaas 4381 GNC 3 : dbId = relation->rd_locator.dbOid;
4323 heikki.linnakangas 4382 GIC 3 : heapId = relation->rd_id;
4383 :
1059 tgl 4384 3 : LWLockAcquire(SerializablePredicateListLock, LW_EXCLUSIVE);
4323 heikki.linnakangas 4385 51 : for (i = 0; i < NUM_PREDICATELOCK_PARTITIONS; i++)
3359 rhaas 4386 CBC 48 : LWLockAcquire(PredicateLockHashPartitionLockByIndex(i), LW_SHARED);
2717 kgrittn 4387 GIC 3 : LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
4388 :
4389 : /* Scan through target list */
4323 heikki.linnakangas 4390 3 : hash_seq_init(&seqstat, PredicateLockTargetHash);
4391 :
4392 6 : while ((target = (PREDICATELOCKTARGET *) hash_seq_search(&seqstat)))
4393 : {
4394 : dlist_mutable_iter iter;
4395 :
4323 heikki.linnakangas 4396 ECB : /*
4397 : * Check whether this is a target which needs attention.
4398 : */
4323 heikki.linnakangas 4399 CBC 3 : if (GET_PREDICATELOCKTARGETTAG_RELATION(target->tag) != heapId)
4323 heikki.linnakangas 4400 GIC 3 : continue; /* wrong relation id */
4323 heikki.linnakangas 4401 UIC 0 : if (GET_PREDICATELOCKTARGETTAG_DB(target->tag) != dbId)
4402 0 : continue; /* wrong database id */
4403 :
4404 : /*
4323 heikki.linnakangas 4405 ECB : * Loop through locks for this target and flag conflicts.
4406 : */
80 andres 4407 UNC 0 : dlist_foreach_modify(iter, &target->predicateLocks)
4408 : {
4409 0 : PREDICATELOCK *predlock =
4410 0 : dlist_container(PREDICATELOCK, targetLink, iter.cur);
4323 heikki.linnakangas 4411 ECB :
4323 heikki.linnakangas 4412 UIC 0 : if (predlock->tag.myXact != MySerializableXact
2118 tgl 4413 0 : && !RWConflictExists(predlock->tag.myXact, MySerializableXact))
4414 : {
4321 heikki.linnakangas 4415 0 : FlagRWConflict(predlock->tag.myXact, MySerializableXact);
4416 : }
4417 : }
4418 : }
4419 :
4420 : /* Release locks in reverse order */
4323 heikki.linnakangas 4421 GIC 3 : LWLockRelease(SerializableXactHashLock);
4422 51 : for (i = NUM_PREDICATELOCK_PARTITIONS - 1; i >= 0; i--)
3359 rhaas 4423 48 : LWLockRelease(PredicateLockHashPartitionLockByIndex(i));
1059 tgl 4424 3 : LWLockRelease(SerializablePredicateListLock);
4425 : }
4426 :
4427 :
4444 heikki.linnakangas 4428 ECB : /*
4429 : * Flag a rw-dependency between two serializable transactions.
4430 : *
4431 : * The caller is responsible for ensuring that we have a LW lock on
4432 : * the transaction hash table.
4433 : */
4434 : static void
4444 heikki.linnakangas 4435 CBC 860 : FlagRWConflict(SERIALIZABLEXACT *reader, SERIALIZABLEXACT *writer)
4436 : {
4437 860 : Assert(reader != writer);
4438 :
4439 : /* First, see if this conflict causes failure. */
4444 heikki.linnakangas 4440 GIC 860 : OnConflict_CheckForSerializationFailure(reader, writer);
4441 :
4442 : /* Actually do the conflict flagging. */
4443 780 : if (reader == OldCommittedSxact)
4444 heikki.linnakangas 4444 LBC 0 : writer->flags |= SXACT_FLAG_SUMMARY_CONFLICT_IN;
4444 heikki.linnakangas 4445 CBC 780 : else if (writer == OldCommittedSxact)
4444 heikki.linnakangas 4446 UIC 0 : reader->flags |= SXACT_FLAG_SUMMARY_CONFLICT_OUT;
4444 heikki.linnakangas 4447 ECB : else
4444 heikki.linnakangas 4448 CBC 780 : SetRWConflict(reader, writer);
4444 heikki.linnakangas 4449 GIC 780 : }
4450 :
4451 : /*----------------------------------------------------------------------------
4452 : * We are about to add a RW-edge to the dependency graph - check that we don't
4453 : * introduce a dangerous structure by doing so, and abort one of the
4454 : * transactions if so.
4332 heikki.linnakangas 4455 ECB : *
4456 : * A serialization failure can only occur if there is a dangerous structure
4457 : * in the dependency graph:
4458 : *
4459 : * Tin ------> Tpivot ------> Tout
4324 4460 : * rw rw
4332 4461 : *
4462 : * Furthermore, Tout must commit first.
4463 : *
4464 : * One more optimization is that if Tin is declared READ ONLY (or commits
4465 : * without writing), we can only have a problem if Tout committed before Tin
4466 : * acquired its snapshot.
4324 4467 : *----------------------------------------------------------------------------
4444 4468 : */
4469 : static void
4309 tgl 4470 CBC 860 : OnConflict_CheckForSerializationFailure(const SERIALIZABLEXACT *reader,
4444 heikki.linnakangas 4471 ECB : SERIALIZABLEXACT *writer)
4472 : {
4473 : bool failure;
4474 :
4444 heikki.linnakangas 4475 GIC 860 : Assert(LWLockHeldByMe(SerializableXactHashLock));
4476 :
4477 860 : failure = false;
4478 :
4479 : /*------------------------------------------------------------------------
4332 heikki.linnakangas 4480 ECB : * Check for already-committed writer with rw-conflict out flagged
4481 : * (conflict-flag on W means that T2 committed before W):
4332 heikki.linnakangas 4482 EUB : *
4483 : * R ------> W ------> T2
4484 : * rw rw
4485 : *
4486 : * That is a dangerous structure, so we must abort. (Since the writer
4487 : * has already committed, we must be the reader)
4488 : *------------------------------------------------------------------------
4444 heikki.linnakangas 4489 ECB : */
4444 heikki.linnakangas 4490 CBC 860 : if (SxactIsCommitted(writer)
2118 tgl 4491 GIC 18 : && (SxactHasConflictOut(writer) || SxactHasSummaryConflictOut(writer)))
4444 heikki.linnakangas 4492 2 : failure = true;
4493 :
4494 : /*------------------------------------------------------------------------
4495 : * Check whether the writer has become a pivot with an out-conflict
4332 heikki.linnakangas 4496 ECB : * committed transaction (T2), and T2 committed first:
4497 : *
4498 : * R ------> W ------> T2
4324 4499 : * rw rw
4500 : *
4501 : * Because T2 must've committed first, there is no anomaly if:
4502 : * - the reader committed before T2
4503 : * - the writer committed before T2
4504 : * - the reader is a READ ONLY transaction and the reader was concurrent
4505 : * with T2 (= reader acquired its snapshot before T2 committed)
4506 : *
4507 : * We also handle the case that T2 is prepared but not yet committed
4508 : * here. In that case T2 has already checked for conflicts, so if it
4509 : * commits first, making the above conflict real, it's too late for it
4510 : * to abort.
4511 : *------------------------------------------------------------------------
4512 : */
80 andres 4513 GNC 860 : if (!failure && SxactHasSummaryConflictOut(writer))
80 andres 4514 UNC 0 : failure = true;
80 andres 4515 GNC 860 : else if (!failure)
4444 heikki.linnakangas 4516 ECB : {
4517 : dlist_iter iter;
4518 :
80 andres 4519 GNC 1071 : dlist_foreach(iter, &writer->outConflicts)
4444 heikki.linnakangas 4520 ECB : {
80 andres 4521 GNC 288 : RWConflict conflict =
4522 288 : dlist_container(RWConflictData, outLink, iter.cur);
4332 heikki.linnakangas 4523 CBC 288 : SERIALIZABLEXACT *t2 = conflict->sxactIn;
4524 :
4294 heikki.linnakangas 4525 GIC 288 : if (SxactIsPrepared(t2)
4332 heikki.linnakangas 4526 CBC 81 : && (!SxactIsCommitted(reader)
4294 4527 65 : || t2->prepareSeqNo <= reader->commitSeqNo)
4332 4528 81 : && (!SxactIsCommitted(writer)
4294 heikki.linnakangas 4529 UIC 0 : || t2->prepareSeqNo <= writer->commitSeqNo)
4332 heikki.linnakangas 4530 GIC 81 : && (!SxactIsReadOnly(reader)
2118 tgl 4531 12 : || t2->prepareSeqNo <= reader->SeqNo.lastCommitBeforeSnapshot))
4532 : {
4444 heikki.linnakangas 4533 75 : failure = true;
4534 75 : break;
4535 : }
4536 : }
4537 : }
4538 :
4539 : /*------------------------------------------------------------------------
4540 : * Check whether the reader has become a pivot with a writer
4541 : * that's committed (or prepared):
4542 : *
4332 heikki.linnakangas 4543 ECB : * T0 ------> R ------> W
4544 : * rw rw
4545 : *
4546 : * Because W must've committed first for an anomaly to occur, there is no
4547 : * anomaly if:
4548 : * - T0 committed before the writer
4549 : * - T0 is READ ONLY, and overlaps the writer
4324 4550 : *------------------------------------------------------------------------
4551 : */
4294 heikki.linnakangas 4552 CBC 860 : if (!failure && SxactIsPrepared(writer) && !SxactIsReadOnly(reader))
4553 : {
4332 4554 18 : if (SxactHasSummaryConflictIn(reader))
4444 heikki.linnakangas 4555 ECB : {
4444 heikki.linnakangas 4556 UIC 0 : failure = true;
4444 heikki.linnakangas 4557 ECB : }
4558 : else
4559 : {
4560 : dlist_iter iter;
4561 :
4562 : /*
4563 : * The unconstify is needed as we have no const version of
4564 : * dlist_foreach().
4565 : */
80 andres 4566 GNC 18 : dlist_foreach(iter, &unconstify(SERIALIZABLEXACT *, reader)->inConflicts)
4567 : {
4568 11 : const RWConflict conflict =
4569 11 : dlist_container(RWConflictData, inLink, iter.cur);
4570 11 : const SERIALIZABLEXACT *t0 = conflict->sxactOut;
4571 :
4572 11 : if (!SxactIsDoomed(t0)
4573 11 : && (!SxactIsCommitted(t0)
4574 11 : || t0->commitSeqNo >= writer->prepareSeqNo)
4575 11 : && (!SxactIsReadOnly(t0)
80 andres 4576 UNC 0 : || t0->SeqNo.lastCommitBeforeSnapshot >= writer->prepareSeqNo))
4577 : {
80 andres 4578 GNC 11 : failure = true;
4579 11 : break;
4580 : }
4581 : }
4582 : }
4444 heikki.linnakangas 4583 ECB : }
4584 :
4444 heikki.linnakangas 4585 GIC 860 : if (failure)
4444 heikki.linnakangas 4586 ECB : {
4332 4587 : /*
4588 : * We have to kill a transaction to avoid a possible anomaly from
4324 4589 : * occurring. If the writer is us, we can just ereport() to cause a
4590 : * transaction abort. Otherwise we flag the writer for termination,
4591 : * causing it to abort when it tries to commit. However, if the writer
4592 : * is a prepared transaction, already prepared, we can't abort it
4593 : * anymore, so we have to kill the reader instead.
4594 : */
4444 heikki.linnakangas 4595 GIC 88 : if (MySerializableXact == writer)
4596 : {
4597 67 : LWLockRelease(SerializableXactHashLock);
4598 67 : ereport(ERROR,
4444 heikki.linnakangas 4599 ECB : (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
4600 : errmsg("could not serialize access due to read/write dependencies among transactions"),
4601 : errdetail_internal("Reason code: Canceled on identification as a pivot, during write."),
4602 : errhint("The transaction might succeed if retried.")));
4603 : }
4444 heikki.linnakangas 4604 CBC 21 : else if (SxactIsPrepared(writer))
4605 : {
4606 13 : LWLockRelease(SerializableXactHashLock);
4607 :
4332 heikki.linnakangas 4608 ECB : /* if we're not the writer, we have to be the reader */
4332 heikki.linnakangas 4609 CBC 13 : Assert(MySerializableXact == reader);
4444 heikki.linnakangas 4610 GIC 13 : ereport(ERROR,
4611 : (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
4444 heikki.linnakangas 4612 ECB : errmsg("could not serialize access due to read/write dependencies among transactions"),
4255 peter_e 4613 : errdetail_internal("Reason code: Canceled on conflict out to pivot %u, during read.", writer->topXid),
4614 : errhint("The transaction might succeed if retried.")));
4615 : }
4316 heikki.linnakangas 4616 CBC 8 : writer->flags |= SXACT_FLAG_DOOMED;
4444 heikki.linnakangas 4617 ECB : }
4444 heikki.linnakangas 4618 GIC 780 : }
4444 heikki.linnakangas 4619 ECB :
4620 : /*
4621 : * PreCommit_CheckForSerializationFailure
4622 : * Check for dangerous structures in a serializable transaction
4623 : * at commit.
4624 : *
4625 : * We're checking for a dangerous structure as each conflict is recorded.
4444 heikki.linnakangas 4626 EUB : * The only way we could have a problem at commit is if this is the "out"
4627 : * side of a pivot, and neither the "in" side nor the pivot has yet
4628 : * committed.
4629 : *
4630 : * If a dangerous structure is found, the pivot (the near conflict) is
4631 : * marked for death, because rolling back another transaction might mean
4632 : * that we fail without ever making progress. This transaction is
4633 : * committing writes, so letting it commit ensures progress. If we
4634 : * canceled the far conflict, it might immediately fail again on retry.
4635 : */
4636 : void
4444 heikki.linnakangas 4637 GIC 464952 : PreCommit_CheckForSerializationFailure(void)
4444 heikki.linnakangas 4638 EUB : {
4639 : dlist_iter near_iter;
4640 :
4444 heikki.linnakangas 4641 GIC 464952 : if (MySerializableXact == InvalidSerializableXact)
4642 463570 : return;
4643 :
4644 1382 : Assert(IsolationIsSerializable());
4645 :
4646 1382 : LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
4444 heikki.linnakangas 4647 EUB :
4648 : /*
34 tmunro 4649 : * Check if someone else has already decided that we need to die. Since
4650 : * we set our own DOOMED flag when partially releasing, ignore in that
4651 : * case.
4652 : */
34 tmunro 4653 GIC 1382 : if (SxactIsDoomed(MySerializableXact) &&
4654 156 : !SxactIsPartiallyReleased(MySerializableXact))
4655 : {
4444 heikki.linnakangas 4656 155 : LWLockRelease(SerializableXactHashLock);
4444 heikki.linnakangas 4657 GBC 155 : ereport(ERROR,
4444 heikki.linnakangas 4658 EUB : (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
4659 : errmsg("could not serialize access due to read/write dependencies among transactions"),
4255 peter_e 4660 : errdetail_internal("Reason code: Canceled on identification as a pivot, during commit attempt."),
4661 : errhint("The transaction might succeed if retried.")));
4662 : }
4444 heikki.linnakangas 4663 :
80 andres 4664 GNC 1828 : dlist_foreach(near_iter, &MySerializableXact->inConflicts)
4665 : {
4666 601 : RWConflict nearConflict =
4667 601 : dlist_container(RWConflictData, inLink, near_iter.cur);
4668 :
4444 heikki.linnakangas 4669 GIC 601 : if (!SxactIsCommitted(nearConflict->sxactOut)
4316 4670 417 : && !SxactIsDoomed(nearConflict->sxactOut))
4671 : {
4672 : dlist_iter far_iter;
4444 heikki.linnakangas 4673 EUB :
80 andres 4674 GNC 447 : dlist_foreach(far_iter, &nearConflict->sxactOut->inConflicts)
4444 heikki.linnakangas 4675 EUB : {
80 andres 4676 GNC 178 : RWConflict farConflict =
4677 178 : dlist_container(RWConflictData, inLink, far_iter.cur);
4678 :
4444 heikki.linnakangas 4679 GBC 178 : if (farConflict->sxactOut == MySerializableXact
4680 42 : || (!SxactIsCommitted(farConflict->sxactOut)
4681 24 : && !SxactIsReadOnly(farConflict->sxactOut)
4316 heikki.linnakangas 4682 GIC 12 : && !SxactIsDoomed(farConflict->sxactOut)))
4444 heikki.linnakangas 4683 EUB : {
4310 4684 : /*
4685 : * Normally, we kill the pivot transaction to make sure we
4686 : * make progress if the failing transaction is retried.
4687 : * However, we can't kill it if it's already prepared, so
4688 : * in that case we commit suicide instead.
4689 : */
4310 heikki.linnakangas 4690 GIC 148 : if (SxactIsPrepared(nearConflict->sxactOut))
4691 : {
4310 heikki.linnakangas 4692 UIC 0 : LWLockRelease(SerializableXactHashLock);
4310 heikki.linnakangas 4693 UBC 0 : ereport(ERROR,
4310 heikki.linnakangas 4694 EUB : (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
4695 : errmsg("could not serialize access due to read/write dependencies among transactions"),
4255 peter_e 4696 : errdetail_internal("Reason code: Canceled on commit attempt with conflict in from prepared pivot."),
4697 : errhint("The transaction might succeed if retried.")));
4698 : }
4316 heikki.linnakangas 4699 GBC 148 : nearConflict->sxactOut->flags |= SXACT_FLAG_DOOMED;
4444 4700 148 : break;
4701 : }
4702 : }
4703 : }
4704 : }
4444 heikki.linnakangas 4705 EUB :
4294 heikki.linnakangas 4706 GBC 1227 : MySerializableXact->prepareSeqNo = ++(PredXact->LastSxactCommitSeqNo);
4444 heikki.linnakangas 4707 GIC 1227 : MySerializableXact->flags |= SXACT_FLAG_PREPARED;
4444 heikki.linnakangas 4708 EUB :
4444 heikki.linnakangas 4709 GBC 1227 : LWLockRelease(SerializableXactHashLock);
4444 heikki.linnakangas 4710 EUB : }
4711 :
4712 : /*------------------------------------------------------------------------*/
4713 :
4714 : /*
4715 : * Two-phase commit support
4716 : */
4717 :
4718 : /*
4719 : * AtPrepare_Locks
4720 : * Do the preparatory work for a PREPARE: make 2PC state file
4721 : * records for all predicate locks currently held.
4722 : */
4723 : void
4444 heikki.linnakangas 4724 GIC 361 : AtPrepare_PredicateLocks(void)
4725 : {
4726 : SERIALIZABLEXACT *sxact;
4727 : TwoPhasePredicateRecord record;
4444 heikki.linnakangas 4728 EUB : TwoPhasePredicateXactRecord *xactRecord;
4729 : TwoPhasePredicateLockRecord *lockRecord;
4730 : dlist_iter iter;
4731 :
4321 heikki.linnakangas 4732 GBC 361 : sxact = MySerializableXact;
4444 4733 361 : xactRecord = &(record.data.xactRecord);
4444 heikki.linnakangas 4734 GIC 361 : lockRecord = &(record.data.lockRecord);
4444 heikki.linnakangas 4735 EUB :
4444 heikki.linnakangas 4736 GBC 361 : if (MySerializableXact == InvalidSerializableXact)
4444 heikki.linnakangas 4737 GIC 349 : return;
4444 heikki.linnakangas 4738 EUB :
2881 4739 : /* Generate an xact record for our SERIALIZABLEXACT */
4444 heikki.linnakangas 4740 GBC 12 : record.type = TWOPHASEPREDICATERECORD_XACT;
4444 heikki.linnakangas 4741 GIC 12 : xactRecord->xmin = MySerializableXact->xmin;
4444 heikki.linnakangas 4742 GBC 12 : xactRecord->flags = MySerializableXact->flags;
4743 :
4444 heikki.linnakangas 4744 EUB : /*
4745 : * Note that we don't include the list of conflicts in our out in the
4746 : * statefile, because new conflicts can be added even after the
4747 : * transaction prepares. We'll just make a conservative assumption during
4748 : * recovery instead.
4749 : */
4750 :
4444 heikki.linnakangas 4751 GIC 12 : RegisterTwoPhaseRecord(TWOPHASE_RM_PREDICATELOCK_ID, 0,
4444 heikki.linnakangas 4752 ECB : &record, sizeof(record));
4753 :
4754 : /*
4755 : * Generate a lock record for each lock.
4756 : *
4757 : * To do this, we need to walk the predicate lock list in our sxact rather
4758 : * than using the local predicate lock table because the latter is not
4759 : * guaranteed to be accurate.
4760 : */
1059 tgl 4761 CBC 12 : LWLockAcquire(SerializablePredicateListLock, LW_SHARED);
4762 :
4763 : /*
1059 tgl 4764 ECB : * No need to take sxact->perXactPredicateListLock in parallel mode
4765 : * because there cannot be any parallel workers running while we are
4766 : * preparing a transaction.
1486 tmunro 4767 : */
1486 tmunro 4768 CBC 12 : Assert(!IsParallelWorker() && !ParallelContextActive());
1486 tmunro 4769 ECB :
80 andres 4770 GNC 22 : dlist_foreach(iter, &sxact->predicateLocks)
4771 : {
4772 10 : PREDICATELOCK *predlock =
4773 10 : dlist_container(PREDICATELOCK, xactLink, iter.cur);
4774 :
4444 heikki.linnakangas 4775 GIC 10 : record.type = TWOPHASEPREDICATERECORD_LOCK;
4776 10 : lockRecord->target = predlock->tag.myTarget->tag;
4777 :
4778 10 : RegisterTwoPhaseRecord(TWOPHASE_RM_PREDICATELOCK_ID, 0,
4779 : &record, sizeof(record));
4780 : }
4781 :
1059 tgl 4782 12 : LWLockRelease(SerializablePredicateListLock);
4783 : }
4784 :
4785 : /*
4786 : * PostPrepare_Locks
4787 : * Clean up after successful PREPARE. Unlike the non-predicate
4788 : * lock manager, we do not need to transfer locks to a dummy
4789 : * PGPROC because our SERIALIZABLEXACT will stay around
4790 : * anyway. We only need to clean up our local state.
4791 : */
4792 : void
4444 heikki.linnakangas 4793 361 : PostPrepare_PredicateLocks(TransactionId xid)
4794 : {
4795 361 : if (MySerializableXact == InvalidSerializableXact)
4796 349 : return;
4797 :
4798 12 : Assert(SxactIsPrepared(MySerializableXact));
4799 :
4800 12 : MySerializableXact->pid = 0;
479 tmunro 4801 12 : MySerializableXact->pgprocno = INVALID_PGPROCNO;
4802 :
4444 heikki.linnakangas 4803 12 : hash_destroy(LocalPredicateLockHash);
4804 12 : LocalPredicateLockHash = NULL;
4805 :
4806 12 : MySerializableXact = InvalidSerializableXact;
4321 4807 12 : MyXactDidWrite = false;
4808 : }
4809 :
4810 : /*
4811 : * PredicateLockTwoPhaseFinish
4812 : * Release a prepared transaction's predicate locks once it
4813 : * commits or aborts.
4814 : */
4815 : void
4444 4816 365 : PredicateLockTwoPhaseFinish(TransactionId xid, bool isCommit)
4817 : {
4818 : SERIALIZABLEXID *sxid;
4819 : SERIALIZABLEXIDTAG sxidtag;
4820 :
4821 365 : sxidtag.xid = xid;
4822 :
4823 365 : LWLockAcquire(SerializableXactHashLock, LW_SHARED);
4824 : sxid = (SERIALIZABLEXID *)
4825 365 : hash_search(SerializableXidHash, &sxidtag, HASH_FIND, NULL);
4826 365 : LWLockRelease(SerializableXactHashLock);
4827 :
4828 : /* xid will not be found if it wasn't a serializable transaction */
4829 365 : if (sxid == NULL)
4830 353 : return;
4831 :
4832 : /* Release its locks */
4833 12 : MySerializableXact = sxid->myXact;
4321 4834 12 : MyXactDidWrite = true; /* conservatively assume that we wrote
4835 : * something */
1486 tmunro 4836 12 : ReleasePredicateLocks(isCommit, false);
4837 : }
4838 :
4839 : /*
4840 : * Re-acquire a predicate lock belonging to a transaction that was prepared.
4841 : */
4842 : void
4444 heikki.linnakangas 4843 UIC 0 : predicatelock_twophase_recover(TransactionId xid, uint16 info,
4844 : void *recdata, uint32 len)
4845 : {
4846 : TwoPhasePredicateRecord *record;
4847 :
4848 0 : Assert(len == sizeof(TwoPhasePredicateRecord));
4849 :
4850 0 : record = (TwoPhasePredicateRecord *) recdata;
4851 :
4852 0 : Assert((record->type == TWOPHASEPREDICATERECORD_XACT) ||
4853 : (record->type == TWOPHASEPREDICATERECORD_LOCK));
4854 :
4855 0 : if (record->type == TWOPHASEPREDICATERECORD_XACT)
4856 : {
4857 : /* Per-transaction record. Set up a SERIALIZABLEXACT. */
4858 : TwoPhasePredicateXactRecord *xactRecord;
4859 : SERIALIZABLEXACT *sxact;
4860 : SERIALIZABLEXID *sxid;
4861 : SERIALIZABLEXIDTAG sxidtag;
4862 : bool found;
4863 :
4864 0 : xactRecord = (TwoPhasePredicateXactRecord *) &record->data.xactRecord;
4865 :
4866 0 : LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
4867 0 : sxact = CreatePredXact();
4868 0 : if (!sxact)
4869 0 : ereport(ERROR,
4870 : (errcode(ERRCODE_OUT_OF_MEMORY),
4871 : errmsg("out of shared memory")));
4872 :
4873 : /* vxid for a prepared xact is InvalidBackendId/xid; no pid */
4874 0 : sxact->vxid.backendId = InvalidBackendId;
4875 0 : sxact->vxid.localTransactionId = (LocalTransactionId) xid;
4876 0 : sxact->pid = 0;
479 tmunro 4877 0 : sxact->pgprocno = INVALID_PGPROCNO;
4878 :
4879 : /* a prepared xact hasn't committed yet */
4294 heikki.linnakangas 4880 0 : sxact->prepareSeqNo = RecoverySerCommitSeqNo;
4444 4881 0 : sxact->commitSeqNo = InvalidSerCommitSeqNo;
4882 0 : sxact->finishedBefore = InvalidTransactionId;
4883 :
4884 0 : sxact->SeqNo.lastCommitBeforeSnapshot = RecoverySerCommitSeqNo;
4885 :
4886 : /*
4887 : * Don't need to track this; no transactions running at the time the
4888 : * recovered xact started are still active, except possibly other
4889 : * prepared xacts and we don't care whether those are RO_SAFE or not.
4890 : */
80 andres 4891 UNC 0 : dlist_init(&(sxact->possibleUnsafeConflicts));
4892 :
4893 0 : dlist_init(&(sxact->predicateLocks));
4894 0 : dlist_node_init(&sxact->finishedLink);
4895 :
4444 heikki.linnakangas 4896 UIC 0 : sxact->topXid = xid;
4897 0 : sxact->xmin = xactRecord->xmin;
4898 0 : sxact->flags = xactRecord->flags;
4899 0 : Assert(SxactIsPrepared(sxact));
4900 0 : if (!SxactIsReadOnly(sxact))
4901 : {
4902 0 : ++(PredXact->WritableSxactCount);
4903 0 : Assert(PredXact->WritableSxactCount <=
4904 : (MaxBackends + max_prepared_xacts));
4905 : }
4906 :
4907 : /*
4908 : * We don't know whether the transaction had any conflicts or not, so
4909 : * we'll conservatively assume that it had both a conflict in and a
4910 : * conflict out, and represent that with the summary conflict flags.
4911 : */
80 andres 4912 UNC 0 : dlist_init(&(sxact->outConflicts));
4913 0 : dlist_init(&(sxact->inConflicts));
4057 heikki.linnakangas 4914 UIC 0 : sxact->flags |= SXACT_FLAG_SUMMARY_CONFLICT_IN;
4915 0 : sxact->flags |= SXACT_FLAG_SUMMARY_CONFLICT_OUT;
4916 :
4917 : /* Register the transaction's xid */
4444 4918 0 : sxidtag.xid = xid;
4919 0 : sxid = (SERIALIZABLEXID *) hash_search(SerializableXidHash,
4920 : &sxidtag,
4921 : HASH_ENTER, &found);
4385 rhaas 4922 0 : Assert(sxid != NULL);
4444 heikki.linnakangas 4923 0 : Assert(!found);
4924 0 : sxid->myXact = (SERIALIZABLEXACT *) sxact;
4925 :
4926 : /*
4927 : * Update global xmin. Note that this is a special case compared to
4928 : * registering a normal transaction, because the global xmin might go
4929 : * backwards. That's OK, because until recovery is over we're not
4930 : * going to complete any transactions or create any non-prepared
4931 : * transactions, so there's no danger of throwing away.
4932 : */
4933 0 : if ((!TransactionIdIsValid(PredXact->SxactGlobalXmin)) ||
4934 0 : (TransactionIdFollows(PredXact->SxactGlobalXmin, sxact->xmin)))
4935 : {
4936 0 : PredXact->SxactGlobalXmin = sxact->xmin;
4937 0 : PredXact->SxactGlobalXminCount = 1;
1059 tgl 4938 0 : SerialSetActiveSerXmin(sxact->xmin);
4939 : }
4444 heikki.linnakangas 4940 0 : else if (TransactionIdEquals(sxact->xmin, PredXact->SxactGlobalXmin))
4941 : {
4942 0 : Assert(PredXact->SxactGlobalXminCount > 0);
4943 0 : PredXact->SxactGlobalXminCount++;
4944 : }
4945 :
4946 0 : LWLockRelease(SerializableXactHashLock);
4947 : }
4948 0 : else if (record->type == TWOPHASEPREDICATERECORD_LOCK)
4949 : {
4950 : /* Lock record. Recreate the PREDICATELOCK */
4951 : TwoPhasePredicateLockRecord *lockRecord;
4952 : SERIALIZABLEXID *sxid;
4953 : SERIALIZABLEXACT *sxact;
4954 : SERIALIZABLEXIDTAG sxidtag;
4955 : uint32 targettaghash;
4956 :
4957 0 : lockRecord = (TwoPhasePredicateLockRecord *) &record->data.lockRecord;
4958 0 : targettaghash = PredicateLockTargetTagHashCode(&lockRecord->target);
4959 :
4960 0 : LWLockAcquire(SerializableXactHashLock, LW_SHARED);
4961 0 : sxidtag.xid = xid;
4962 : sxid = (SERIALIZABLEXID *)
4963 0 : hash_search(SerializableXidHash, &sxidtag, HASH_FIND, NULL);
4964 0 : LWLockRelease(SerializableXactHashLock);
4965 :
4966 0 : Assert(sxid != NULL);
4967 0 : sxact = sxid->myXact;
4968 0 : Assert(sxact != InvalidSerializableXact);
4969 :
4970 0 : CreatePredicateLock(&lockRecord->target, targettaghash, sxact);
4971 : }
4972 0 : }
4973 :
4974 : /*
4975 : * Prepare to share the current SERIALIZABLEXACT with parallel workers.
4976 : * Return a handle object that can be used by AttachSerializableXact() in a
4977 : * parallel worker.
4978 : */
4979 : SerializableXactHandle
1486 tmunro 4980 GIC 403 : ShareSerializableXact(void)
4981 : {
4982 403 : return MySerializableXact;
4983 : }
4984 :
4985 : /*
4986 : * Allow parallel workers to import the leader's SERIALIZABLEXACT.
4987 : */
4988 : void
4989 1298 : AttachSerializableXact(SerializableXactHandle handle)
4990 : {
4991 :
4992 1298 : Assert(MySerializableXact == InvalidSerializableXact);
4993 :
4994 1298 : MySerializableXact = (SERIALIZABLEXACT *) handle;
4995 1298 : if (MySerializableXact != InvalidSerializableXact)
4996 13 : CreateLocalPredicateLockHash();
4997 1298 : }
|