PostgreSQL Source Code git master
Loading...
Searching...
No Matches
inval.c File Reference
#include "postgres.h"
#include <limits.h>
#include "access/htup_details.h"
#include "access/xact.h"
#include "access/xloginsert.h"
#include "catalog/catalog.h"
#include "catalog/pg_constraint.h"
#include "miscadmin.h"
#include "storage/procnumber.h"
#include "storage/sinval.h"
#include "storage/smgr.h"
#include "utils/catcache.h"
#include "utils/injection_point.h"
#include "utils/inval.h"
#include "utils/memdebug.h"
#include "utils/memutils.h"
#include "utils/rel.h"
#include "utils/relmapper.h"
#include "utils/snapmgr.h"
#include "utils/syscache.h"
Include dependency graph for inval.c:

Go to the source code of this file.

Data Structures

struct  InvalMessageArray
 
struct  InvalidationMsgsGroup
 
struct  InvalidationInfo
 
struct  TransInvalidationInfo
 
struct  SYSCACHECALLBACK
 
struct  RELCACHECALLBACK
 
struct  RELSYNCCALLBACK
 

Macros

#define CatCacheMsgs   0
 
#define RelCacheMsgs   1
 
#define SetSubGroupToFollow(targetgroup, priorgroup, subgroup)
 
#define SetGroupToFollow(targetgroup, priorgroup)
 
#define NumMessagesInSubGroup(group, subgroup)    ((group)->nextmsg[subgroup] - (group)->firstmsg[subgroup])
 
#define NumMessagesInGroup(group)
 
#define MAX_SYSCACHE_CALLBACKS   64
 
#define MAX_RELCACHE_CALLBACKS   10
 
#define MAX_RELSYNC_CALLBACKS   10
 
#define ProcessMessageSubGroup(group, subgroup, codeFragment)
 
#define ProcessMessageSubGroupMulti(group, subgroup, codeFragment)
 

Typedefs

typedef struct InvalMessageArray InvalMessageArray
 
typedef struct InvalidationMsgsGroup InvalidationMsgsGroup
 
typedef struct InvalidationInfo InvalidationInfo
 
typedef struct TransInvalidationInfo TransInvalidationInfo
 

Functions

static void AddInvalidationMessage (InvalidationMsgsGroup *group, int subgroup, const SharedInvalidationMessage *msg)
 
static void AppendInvalidationMessageSubGroup (InvalidationMsgsGroup *dest, InvalidationMsgsGroup *src, int subgroup)
 
static void AddCatcacheInvalidationMessage (InvalidationMsgsGroup *group, int id, uint32 hashValue, Oid dbId)
 
static void AddCatalogInvalidationMessage (InvalidationMsgsGroup *group, Oid dbId, Oid catId)
 
static void AddRelcacheInvalidationMessage (InvalidationMsgsGroup *group, Oid dbId, Oid relId)
 
static void AddRelsyncInvalidationMessage (InvalidationMsgsGroup *group, Oid dbId, Oid relId)
 
static void AddSnapshotInvalidationMessage (InvalidationMsgsGroup *group, Oid dbId, Oid relId)
 
static void AppendInvalidationMessages (InvalidationMsgsGroup *dest, InvalidationMsgsGroup *src)
 
static void ProcessInvalidationMessages (InvalidationMsgsGroup *group, void(*func)(SharedInvalidationMessage *msg))
 
static void ProcessInvalidationMessagesMulti (InvalidationMsgsGroup *group, void(*func)(const SharedInvalidationMessage *msgs, int n))
 
static void RegisterCatcacheInvalidation (int cacheId, uint32 hashValue, Oid dbId, void *context)
 
static void RegisterCatalogInvalidation (InvalidationInfo *info, Oid dbId, Oid catId)
 
static void RegisterRelcacheInvalidation (InvalidationInfo *info, Oid dbId, Oid relId)
 
static void RegisterRelsyncInvalidation (InvalidationInfo *info, Oid dbId, Oid relId)
 
static void RegisterSnapshotInvalidation (InvalidationInfo *info, Oid dbId, Oid relId)
 
static InvalidationInfoPrepareInvalidationState (void)
 
static InvalidationInfoPrepareInplaceInvalidationState (void)
 
void InvalidateSystemCachesExtended (bool debug_discard)
 
void LocalExecuteInvalidationMessage (SharedInvalidationMessage *msg)
 
void InvalidateSystemCaches (void)
 
void AcceptInvalidationMessages (void)
 
void PostPrepare_Inval (void)
 
int xactGetCommittedInvalidationMessages (SharedInvalidationMessage **msgs, bool *RelcacheInitFileInval)
 
int inplaceGetInvalidationMessages (SharedInvalidationMessage **msgs, bool *RelcacheInitFileInval)
 
void ProcessCommittedInvalidationMessages (SharedInvalidationMessage *msgs, int nmsgs, bool RelcacheInitFileInval, Oid dbid, Oid tsid)
 
void AtEOXact_Inval (bool isCommit)
 
void PreInplace_Inval (void)
 
void AtInplace_Inval (void)
 
void ForgetInplace_Inval (void)
 
void AtEOSubXact_Inval (bool isCommit)
 
void CommandEndInvalidationMessages (void)
 
static void CacheInvalidateHeapTupleCommon (Relation relation, HeapTuple tuple, HeapTuple newtuple, InvalidationInfo *(*prepare_callback)(void))
 
void CacheInvalidateHeapTuple (Relation relation, HeapTuple tuple, HeapTuple newtuple)
 
void CacheInvalidateHeapTupleInplace (Relation relation, HeapTuple key_equivalent_tuple)
 
void CacheInvalidateCatalog (Oid catalogId)
 
void CacheInvalidateRelcache (Relation relation)
 
void CacheInvalidateRelcacheAll (void)
 
void CacheInvalidateRelcacheByTuple (HeapTuple classTuple)
 
void CacheInvalidateRelcacheByRelid (Oid relid)
 
void CacheInvalidateRelSync (Oid relid)
 
void CacheInvalidateRelSyncAll (void)
 
void CacheInvalidateSmgr (RelFileLocatorBackend rlocator)
 
void CacheInvalidateRelmap (Oid databaseId)
 
void CacheRegisterSyscacheCallback (SysCacheIdentifier cacheid, SyscacheCallbackFunction func, Datum arg)
 
void CacheRegisterRelcacheCallback (RelcacheCallbackFunction func, Datum arg)
 
void CacheRegisterRelSyncCallback (RelSyncCallbackFunction func, Datum arg)
 
void CallSyscacheCallbacks (SysCacheIdentifier cacheid, uint32 hashvalue)
 
void CallRelSyncCallbacks (Oid relid)
 
void LogLogicalInvalidations (void)
 

Variables

static InvalMessageArray InvalMessageArrays [2]
 
static TransInvalidationInfotransInvalInfo = NULL
 
static InvalidationInfoinplaceInvalInfo = NULL
 
int debug_discard_caches = 0
 
static struct SYSCACHECALLBACK syscache_callback_list [MAX_SYSCACHE_CALLBACKS]
 
static int16 syscache_callback_links [SysCacheSize]
 
static int syscache_callback_count = 0
 
static struct RELCACHECALLBACK relcache_callback_list [MAX_RELCACHE_CALLBACKS]
 
static int relcache_callback_count = 0
 
static struct RELSYNCCALLBACK relsync_callback_list [MAX_RELSYNC_CALLBACKS]
 
static int relsync_callback_count = 0
 

Macro Definition Documentation

◆ CatCacheMsgs

#define CatCacheMsgs   0

Definition at line 171 of file inval.c.

◆ MAX_RELCACHE_CALLBACKS

#define MAX_RELCACHE_CALLBACKS   10

Definition at line 273 of file inval.c.

◆ MAX_RELSYNC_CALLBACKS

#define MAX_RELSYNC_CALLBACKS   10

Definition at line 274 of file inval.c.

◆ MAX_SYSCACHE_CALLBACKS

#define MAX_SYSCACHE_CALLBACKS   64

Definition at line 272 of file inval.c.

◆ NumMessagesInGroup

#define NumMessagesInGroup (   group)
Value:
#define CatCacheMsgs
Definition inval.c:171
#define NumMessagesInSubGroup(group, subgroup)
Definition inval.c:204
#define RelCacheMsgs
Definition inval.c:172
static int fb(int x)

Definition at line 207 of file inval.c.

230{
231 /* Events emitted by current command */
232 InvalidationMsgsGroup CurrentCmdInvalidMsgs;
233
234 /* init file must be invalidated? */
235 bool RelcacheInitFileInval;
237
238/* subclass adding fields specific to transactional invalidation */
239typedef struct TransInvalidationInfo
240{
241 /* Base class */
242 struct InvalidationInfo ii;
243
244 /* Events emitted by previous commands of this (sub)transaction */
246
247 /* Back link to parent transaction's info */
249
250 /* Subtransaction nesting depth */
251 int my_level;
253
255
257
258/* GUC storage */
260
261/*
262 * Dynamically-registered callback functions. Current implementation
263 * assumes there won't be enough of these to justify a dynamically resizable
264 * array; it'd be easy to improve that if needed.
265 *
266 * To avoid searching in CallSyscacheCallbacks, all callbacks for a given
267 * syscache are linked into a list pointed to by syscache_callback_links[id].
268 * The link values are syscache_callback_list[] index plus 1, or 0 for none.
269 */
270
271#define MAX_SYSCACHE_CALLBACKS 64
272#define MAX_RELCACHE_CALLBACKS 10
273#define MAX_RELSYNC_CALLBACKS 10
274
275static struct SYSCACHECALLBACK
276{
277 int16 id; /* cache number */
278 int16 link; /* next callback index+1 for same cache */
280 Datum arg;
282
284
285static int syscache_callback_count = 0;
286
287static struct RELCACHECALLBACK
288{
290 Datum arg;
292
293static int relcache_callback_count = 0;
294
295static struct RELSYNCCALLBACK
296{
298 Datum arg;
300
301static int relsync_callback_count = 0;
302
303
304/* ----------------------------------------------------------------
305 * Invalidation subgroup support functions
306 * ----------------------------------------------------------------
307 */
308
309/*
310 * AddInvalidationMessage
311 * Add an invalidation message to a (sub)group.
312 *
313 * The group must be the last active one, since we assume we can add to the
314 * end of the relevant InvalMessageArray.
315 *
316 * subgroup must be CatCacheMsgs or RelCacheMsgs.
317 */
318static void
320 const SharedInvalidationMessage *msg)
321{
323 int nextindex = group->nextmsg[subgroup];
324
325 if (nextindex >= ima->maxmsgs)
326 {
327 if (ima->msgs == NULL)
328 {
329 /* Create new storage array in TopTransactionContext */
330 int reqsize = 32; /* arbitrary */
331
335 ima->maxmsgs = reqsize;
336 Assert(nextindex == 0);
337 }
338 else
339 {
340 /* Enlarge storage array */
341 int reqsize = 2 * ima->maxmsgs;
342
344 repalloc(ima->msgs,
346 ima->maxmsgs = reqsize;
347 }
348 }
349 /* Okay, add message to current group */
350 ima->msgs[nextindex] = *msg;
351 group->nextmsg[subgroup]++;
352}
353
354/*
355 * Append one subgroup of invalidation messages to another, resetting
356 * the source subgroup to empty.
357 */
358static void
361 int subgroup)
362{
363 /* Messages must be adjacent in main array */
364 Assert(dest->nextmsg[subgroup] == src->firstmsg[subgroup]);
365
366 /* ... which makes this easy: */
367 dest->nextmsg[subgroup] = src->nextmsg[subgroup];
368
369 /*
370 * This is handy for some callers and irrelevant for others. But we do it
371 * always, reasoning that it's bad to leave different groups pointing at
372 * the same fragment of the message array.
373 */
374 SetSubGroupToFollow(src, dest, subgroup);
375}
376
377/*
378 * Process a subgroup of invalidation messages.
379 *
380 * This is a macro that executes the given code fragment for each message in
381 * a message subgroup. The fragment should refer to the message as *msg.
382 */
383#define ProcessMessageSubGroup(group, subgroup, codeFragment) \
384 do { \
385 int _msgindex = (group)->firstmsg[subgroup]; \
386 int _endmsg = (group)->nextmsg[subgroup]; \
387 for (; _msgindex < _endmsg; _msgindex++) \
388 { \
389 SharedInvalidationMessage *msg = \
390 &InvalMessageArrays[subgroup].msgs[_msgindex]; \
391 codeFragment; \
392 } \
393 } while (0)
394
395/*
396 * Process a subgroup of invalidation messages as an array.
397 *
398 * As above, but the code fragment can handle an array of messages.
399 * The fragment should refer to the messages as msgs[], with n entries.
400 */
401#define ProcessMessageSubGroupMulti(group, subgroup, codeFragment) \
402 do { \
403 int n = NumMessagesInSubGroup(group, subgroup); \
404 if (n > 0) { \
405 SharedInvalidationMessage *msgs = \
406 &InvalMessageArrays[subgroup].msgs[(group)->firstmsg[subgroup]]; \
407 codeFragment; \
408 } \
409 } while (0)
410
411
412/* ----------------------------------------------------------------
413 * Invalidation group support functions
414 *
415 * These routines understand about the division of a logical invalidation
416 * group into separate physical arrays for catcache and relcache entries.
417 * ----------------------------------------------------------------
418 */
419
420/*
421 * Add a catcache inval entry
422 */
423static void
425 int id, uint32 hashValue, Oid dbId)
426{
428
429 Assert(id < CHAR_MAX);
430 msg.cc.id = (int8) id;
431 msg.cc.dbId = dbId;
432 msg.cc.hashValue = hashValue;
433
434 /*
435 * Define padding bytes in SharedInvalidationMessage structs to be
436 * defined. Otherwise the sinvaladt.c ringbuffer, which is accessed by
437 * multiple processes, will cause spurious valgrind warnings about
438 * undefined memory being used. That's because valgrind remembers the
439 * undefined bytes from the last local process's store, not realizing that
440 * another process has written since, filling the previously uninitialized
441 * bytes
442 */
443 VALGRIND_MAKE_MEM_DEFINED(&msg, sizeof(msg));
444
446}
447
448/*
449 * Add a whole-catalog inval entry
450 */
451static void
453 Oid dbId, Oid catId)
454{
456
458 msg.cat.dbId = dbId;
459 msg.cat.catId = catId;
460 /* check AddCatcacheInvalidationMessage() for an explanation */
461 VALGRIND_MAKE_MEM_DEFINED(&msg, sizeof(msg));
462
464}
465
466/*
467 * Add a relcache inval entry
468 */
469static void
471 Oid dbId, Oid relId)
472{
474
475 /*
476 * Don't add a duplicate item. We assume dbId need not be checked because
477 * it will never change. InvalidOid for relId means all relations so we
478 * don't need to add individual ones when it is present.
479 */
481 if (msg->rc.id == SHAREDINVALRELCACHE_ID &&
482 (msg->rc.relId == relId ||
483 msg->rc.relId == InvalidOid))
484 return);
485
486 /* OK, add the item */
488 msg.rc.dbId = dbId;
489 msg.rc.relId = relId;
490 /* check AddCatcacheInvalidationMessage() for an explanation */
491 VALGRIND_MAKE_MEM_DEFINED(&msg, sizeof(msg));
492
494}
495
496/*
497 * Add a relsync inval entry
498 *
499 * We put these into the relcache subgroup for simplicity. This message is the
500 * same as AddRelcacheInvalidationMessage() except that it is for
501 * RelationSyncCache maintained by decoding plugin pgoutput.
502 */
503static void
505 Oid dbId, Oid relId)
506{
508
509 /* Don't add a duplicate item. */
511 if (msg->rc.id == SHAREDINVALRELSYNC_ID &&
512 (msg->rc.relId == relId ||
513 msg->rc.relId == InvalidOid))
514 return);
515
516 /* OK, add the item */
518 msg.rc.dbId = dbId;
519 msg.rc.relId = relId;
520 /* check AddCatcacheInvalidationMessage() for an explanation */
521 VALGRIND_MAKE_MEM_DEFINED(&msg, sizeof(msg));
522
524}
525
526/*
527 * Add a snapshot inval entry
528 *
529 * We put these into the relcache subgroup for simplicity.
530 */
531static void
533 Oid dbId, Oid relId)
534{
536
537 /* Don't add a duplicate item */
538 /* We assume dbId need not be checked because it will never change */
540 if (msg->sn.id == SHAREDINVALSNAPSHOT_ID &&
541 msg->sn.relId == relId)
542 return);
543
544 /* OK, add the item */
546 msg.sn.dbId = dbId;
547 msg.sn.relId = relId;
548 /* check AddCatcacheInvalidationMessage() for an explanation */
549 VALGRIND_MAKE_MEM_DEFINED(&msg, sizeof(msg));
550
552}
553
554/*
555 * Append one group of invalidation messages to another, resetting
556 * the source group to empty.
557 */
558static void
561{
564}
565
566/*
567 * Execute the given function for all the messages in an invalidation group.
568 * The group is not altered.
569 *
570 * catcache entries are processed first, for reasons mentioned above.
571 */
572static void
574 void (*func) (SharedInvalidationMessage *msg))
575{
576 ProcessMessageSubGroup(group, CatCacheMsgs, func(msg));
577 ProcessMessageSubGroup(group, RelCacheMsgs, func(msg));
578}
579
580/*
581 * As above, but the function is able to process an array of messages
582 * rather than just one at a time.
583 */
584static void
586 void (*func) (const SharedInvalidationMessage *msgs, int n))
587{
588 ProcessMessageSubGroupMulti(group, CatCacheMsgs, func(msgs, n));
589 ProcessMessageSubGroupMulti(group, RelCacheMsgs, func(msgs, n));
590}
591
592/* ----------------------------------------------------------------
593 * private support functions
594 * ----------------------------------------------------------------
595 */
596
597/*
598 * RegisterCatcacheInvalidation
599 *
600 * Register an invalidation event for a catcache tuple entry.
601 */
602static void
604 uint32 hashValue,
605 Oid dbId,
606 void *context)
607{
608 InvalidationInfo *info = (InvalidationInfo *) context;
609
611 cacheId, hashValue, dbId);
612}
613
614/*
615 * RegisterCatalogInvalidation
616 *
617 * Register an invalidation event for all catcache entries from a catalog.
618 */
619static void
621{
623}
624
625/*
626 * RegisterRelcacheInvalidation
627 *
628 * As above, but register a relcache invalidation event.
629 */
630static void
632{
634
635 /*
636 * Most of the time, relcache invalidation is associated with system
637 * catalog updates, but there are a few cases where it isn't. Quick hack
638 * to ensure that the next CommandCounterIncrement() will think that we
639 * need to do CommandEndInvalidationMessages().
640 */
642
643 /*
644 * If the relation being invalidated is one of those cached in a relcache
645 * init file, mark that we need to zap that file at commit. For simplicity
646 * invalidations for a specific database always invalidate the shared file
647 * as well. Also zap when we are invalidating whole relcache.
648 */
649 if (relId == InvalidOid || RelationIdIsInInitFile(relId))
650 info->RelcacheInitFileInval = true;
651}
652
653/*
654 * RegisterRelsyncInvalidation
655 *
656 * As above, but register a relsynccache invalidation event.
657 */
658static void
660{
662}
663
664/*
665 * RegisterSnapshotInvalidation
666 *
667 * Register an invalidation event for MVCC scans against a given catalog.
668 * Only needed for catalogs that don't have catcaches.
669 */
670static void
672{
674}
675
676/*
677 * PrepareInvalidationState
678 * Initialize inval data for the current (sub)transaction.
679 */
680static InvalidationInfo *
682{
684
685 /* PrepareToInvalidateCacheTuple() needs relcache */
687 /* Can't queue transactional message while collecting inplace messages. */
689
690 if (transInvalInfo != NULL &&
693
696 sizeof(TransInvalidationInfo));
699
700 /* Now, do we have a previous stack entry? */
701 if (transInvalInfo != NULL)
702 {
703 /* Yes; this one should be for a deeper nesting level. */
704 Assert(myInfo->my_level > transInvalInfo->my_level);
705
706 /*
707 * The parent (sub)transaction must not have any current (i.e.,
708 * not-yet-locally-processed) messages. If it did, we'd have a
709 * semantic problem: the new subtransaction presumably ought not be
710 * able to see those events yet, but since the CommandCounter is
711 * linear, that can't work once the subtransaction advances the
712 * counter. This is a convenient place to check for that, as well as
713 * being important to keep management of the message arrays simple.
714 */
716 elog(ERROR, "cannot start a subtransaction when there are unprocessed inval messages");
717
718 /*
719 * MemoryContextAllocZero set firstmsg = nextmsg = 0 in each group,
720 * which is fine for the first (sub)transaction, but otherwise we need
721 * to update them to follow whatever is already in the arrays.
722 */
723 SetGroupToFollow(&myInfo->PriorCmdInvalidMsgs,
725 SetGroupToFollow(&myInfo->ii.CurrentCmdInvalidMsgs,
726 &myInfo->PriorCmdInvalidMsgs);
727 }
728 else
729 {
730 /*
731 * Here, we need only clear any array pointers left over from a prior
732 * transaction.
733 */
738 }
739
741 return (InvalidationInfo *) myInfo;
742}
743
744/*
745 * PrepareInplaceInvalidationState
746 * Initialize inval data for an inplace update.
747 *
748 * See previous function for more background.
749 */
750static InvalidationInfo *
752{
754
756 /* limit of one inplace update under assembly */
758
759 /* gone after WAL insertion CritSection ends, so use current context */
761
762 /* Stash our messages past end of the transactional messages, if any. */
763 if (transInvalInfo != NULL)
764 SetGroupToFollow(&myInfo->CurrentCmdInvalidMsgs,
766 else
767 {
772 }
773
775 return myInfo;
776}
777
778/* ----------------------------------------------------------------
779 * public functions
780 * ----------------------------------------------------------------
781 */
782
783void
785{
786 int i;
787
790 RelationCacheInvalidate(debug_discard); /* gets smgr and relmap too */
791
792 for (i = 0; i < syscache_callback_count; i++)
793 {
795
796 ccitem->function(ccitem->arg, ccitem->id, 0);
797 }
798
799 for (i = 0; i < relcache_callback_count; i++)
800 {
802
804 }
805
806 for (i = 0; i < relsync_callback_count; i++)
807 {
809
811 }
812}
813
814/*
815 * LocalExecuteInvalidationMessage
816 *
817 * Process a single invalidation message (which could be of any type).
818 * Only the local caches are flushed; this does not transmit the message
819 * to other backends.
820 */
821void
823{
824 if (msg->id >= 0)
825 {
826 if (msg->cc.dbId == MyDatabaseId || msg->cc.dbId == InvalidOid)
827 {
829
830 SysCacheInvalidate(msg->cc.id, msg->cc.hashValue);
831
833 }
834 }
835 else if (msg->id == SHAREDINVALCATALOG_ID)
836 {
837 if (msg->cat.dbId == MyDatabaseId || msg->cat.dbId == InvalidOid)
838 {
840
842
843 /* CatalogCacheFlushCatalog calls CallSyscacheCallbacks as needed */
844 }
845 }
846 else if (msg->id == SHAREDINVALRELCACHE_ID)
847 {
848 if (msg->rc.dbId == MyDatabaseId || msg->rc.dbId == InvalidOid)
849 {
850 int i;
851
852 if (msg->rc.relId == InvalidOid)
854 else
856
857 for (i = 0; i < relcache_callback_count; i++)
858 {
860
861 ccitem->function(ccitem->arg, msg->rc.relId);
862 }
863 }
864 }
865 else if (msg->id == SHAREDINVALSMGR_ID)
866 {
867 /*
868 * We could have smgr entries for relations of other databases, so no
869 * short-circuit test is possible here.
870 */
871 RelFileLocatorBackend rlocator;
872
873 rlocator.locator = msg->sm.rlocator;
874 rlocator.backend = (msg->sm.backend_hi << 16) | (int) msg->sm.backend_lo;
875 smgrreleaserellocator(rlocator);
876 }
877 else if (msg->id == SHAREDINVALRELMAP_ID)
878 {
879 /* We only care about our own database and shared catalogs */
880 if (msg->rm.dbId == InvalidOid)
882 else if (msg->rm.dbId == MyDatabaseId)
884 }
885 else if (msg->id == SHAREDINVALSNAPSHOT_ID)
886 {
887 /* We only care about our own database and shared catalogs */
888 if (msg->sn.dbId == InvalidOid)
890 else if (msg->sn.dbId == MyDatabaseId)
892 }
893 else if (msg->id == SHAREDINVALRELSYNC_ID)
894 {
895 /* We only care about our own database */
896 if (msg->rs.dbId == MyDatabaseId)
898 }
899 else
900 elog(FATAL, "unrecognized SI message ID: %d", msg->id);
901}
902
903/*
904 * InvalidateSystemCaches
905 *
906 * This blows away all tuples in the system catalog caches and
907 * all the cached relation descriptors and smgr cache entries.
908 * Relation descriptors that have positive refcounts are then rebuilt.
909 *
910 * We call this when we see a shared-inval-queue overflow signal,
911 * since that tells us we've lost some shared-inval messages and hence
912 * don't know what needs to be invalidated.
913 */
914void
916{
918}
919
920/*
921 * AcceptInvalidationMessages
922 * Read and process invalidation messages from the shared invalidation
923 * message queue.
924 *
925 * Note:
926 * This should be called as the first step in processing a transaction.
927 */
928void
930{
931#ifdef USE_ASSERT_CHECKING
932 /* message handlers shall access catalogs only during transactions */
933 if (IsTransactionState())
935#endif
936
939
940 /*----------
941 * Test code to force cache flushes anytime a flush could happen.
942 *
943 * This helps detect intermittent faults caused by code that reads a cache
944 * entry and then performs an action that could invalidate the entry, but
945 * rarely actually does so. This can spot issues that would otherwise
946 * only arise with badly timed concurrent DDL, for example.
947 *
948 * The default debug_discard_caches = 0 does no forced cache flushes.
949 *
950 * If used with CLOBBER_FREED_MEMORY,
951 * debug_discard_caches = 1 (formerly known as CLOBBER_CACHE_ALWAYS)
952 * provides a fairly thorough test that the system contains no cache-flush
953 * hazards. However, it also makes the system unbelievably slow --- the
954 * regression tests take about 100 times longer than normal.
955 *
956 * If you're a glutton for punishment, try
957 * debug_discard_caches = 3 (formerly known as CLOBBER_CACHE_RECURSIVELY).
958 * This slows things by at least a factor of 10000, so I wouldn't suggest
959 * trying to run the entire regression tests that way. It's useful to try
960 * a few simple tests, to make sure that cache reload isn't subject to
961 * internal cache-flush hazards, but after you've done a few thousand
962 * recursive reloads it's unlikely you'll learn more.
963 *----------
964 */
965#ifdef DISCARD_CACHES_ENABLED
966 {
967 static int recursion_depth = 0;
968
970 {
974 }
975 }
976#endif
977}
978
979/*
980 * PostPrepare_Inval
981 * Clean up after successful PREPARE.
982 *
983 * Here, we want to act as though the transaction aborted, so that we will
984 * undo any syscache changes it made, thereby bringing us into sync with the
985 * outside world, which doesn't believe the transaction committed yet.
986 *
987 * If the prepared transaction is later aborted, there is nothing more to
988 * do; if it commits, we will receive the consequent inval messages just
989 * like everyone else.
990 */
991void
993{
994 AtEOXact_Inval(false);
995}
996
997/*
998 * xactGetCommittedInvalidationMessages() is called by
999 * RecordTransactionCommit() to collect invalidation messages to add to the
1000 * commit record. This applies only to commit message types, never to
1001 * abort records. Must always run before AtEOXact_Inval(), since that
1002 * removes the data we need to see.
1003 *
1004 * Remember that this runs before we have officially committed, so we
1005 * must not do anything here to change what might occur *if* we should
1006 * fail between here and the actual commit.
1007 *
1008 * see also xact_redo_commit() and xact_desc_commit()
1009 */
1010int
1012 bool *RelcacheInitFileInval)
1013{
1015 int nummsgs;
1016 int nmsgs;
1017
1018 /* Quick exit if we haven't done anything with invalidation messages. */
1019 if (transInvalInfo == NULL)
1020 {
1021 *RelcacheInitFileInval = false;
1022 *msgs = NULL;
1023 return 0;
1024 }
1025
1026 /* Must be at top of stack */
1028
1029 /*
1030 * Relcache init file invalidation requires processing both before and
1031 * after we send the SI messages. However, we need not do anything unless
1032 * we committed.
1033 */
1034 *RelcacheInitFileInval = transInvalInfo->ii.RelcacheInitFileInval;
1035
1036 /*
1037 * Collect all the pending messages into a single contiguous array of
1038 * invalidation messages, to simplify what needs to happen while building
1039 * the commit WAL message. Maintain the order that they would be
1040 * processed in by AtEOXact_Inval(), to ensure emulated behaviour in redo
1041 * is as similar as possible to original. We want the same bugs, if any,
1042 * not new ones.
1043 */
1046
1050
1051 nmsgs = 0;
1054 (memcpy(msgarray + nmsgs,
1055 msgs,
1056 n * sizeof(SharedInvalidationMessage)),
1057 nmsgs += n));
1060 (memcpy(msgarray + nmsgs,
1061 msgs,
1062 n * sizeof(SharedInvalidationMessage)),
1063 nmsgs += n));
1066 (memcpy(msgarray + nmsgs,
1067 msgs,
1068 n * sizeof(SharedInvalidationMessage)),
1069 nmsgs += n));
1072 (memcpy(msgarray + nmsgs,
1073 msgs,
1074 n * sizeof(SharedInvalidationMessage)),
1075 nmsgs += n));
1076 Assert(nmsgs == nummsgs);
1077
1078 return nmsgs;
1079}
1080
1081/*
1082 * inplaceGetInvalidationMessages() is called by the inplace update to collect
1083 * invalidation messages to add to its WAL record. Like the previous
1084 * function, we might still fail.
1085 */
1086int
1088 bool *RelcacheInitFileInval)
1089{
1091 int nummsgs;
1092 int nmsgs;
1093
1094 /* Quick exit if we haven't done anything with invalidation messages. */
1095 if (inplaceInvalInfo == NULL)
1096 {
1097 *RelcacheInitFileInval = false;
1098 *msgs = NULL;
1099 return 0;
1100 }
1101
1102 *RelcacheInitFileInval = inplaceInvalInfo->RelcacheInitFileInval;
1106
1107 nmsgs = 0;
1110 (memcpy(msgarray + nmsgs,
1111 msgs,
1112 n * sizeof(SharedInvalidationMessage)),
1113 nmsgs += n));
1116 (memcpy(msgarray + nmsgs,
1117 msgs,
1118 n * sizeof(SharedInvalidationMessage)),
1119 nmsgs += n));
1120 Assert(nmsgs == nummsgs);
1121
1122 return nmsgs;
1123}
1124
1125/*
1126 * ProcessCommittedInvalidationMessages is executed by xact_redo_commit() or
1127 * standby_redo() to process invalidation messages. Currently that happens
1128 * only at end-of-xact.
1129 *
1130 * Relcache init file invalidation requires processing both
1131 * before and after we send the SI messages. See AtEOXact_Inval()
1132 */
1133void
1135 int nmsgs, bool RelcacheInitFileInval,
1136 Oid dbid, Oid tsid)
1137{
1138 if (nmsgs <= 0)
1139 return;
1140
1141 elog(DEBUG4, "replaying commit with %d messages%s", nmsgs,
1142 (RelcacheInitFileInval ? " and relcache file invalidation" : ""));
1143
1144 if (RelcacheInitFileInval)
1145 {
1146 elog(DEBUG4, "removing relcache init files for database %u", dbid);
1147
1148 /*
1149 * RelationCacheInitFilePreInvalidate, when the invalidation message
1150 * is for a specific database, requires DatabasePath to be set, but we
1151 * should not use SetDatabasePath during recovery, since it is
1152 * intended to be used only once by normal backends. Hence, a quick
1153 * hack: set DatabasePath directly then unset after use.
1154 */
1155 if (OidIsValid(dbid))
1156 DatabasePath = GetDatabasePath(dbid, tsid);
1157
1159
1160 if (OidIsValid(dbid))
1161 {
1164 }
1165 }
1166
1167 SendSharedInvalidMessages(msgs, nmsgs);
1168
1169 if (RelcacheInitFileInval)
1171}
1172
1173/*
1174 * AtEOXact_Inval
1175 * Process queued-up invalidation messages at end of main transaction.
1176 *
1177 * If isCommit, we must send out the messages in our PriorCmdInvalidMsgs list
1178 * to the shared invalidation message queue. Note that these will be read
1179 * not only by other backends, but also by our own backend at the next
1180 * transaction start (via AcceptInvalidationMessages). This means that
1181 * we can skip immediate local processing of anything that's still in
1182 * CurrentCmdInvalidMsgs, and just send that list out too.
1183 *
1184 * If not isCommit, we are aborting, and must locally process the messages
1185 * in PriorCmdInvalidMsgs. No messages need be sent to other backends,
1186 * since they'll not have seen our changed tuples anyway. We can forget
1187 * about CurrentCmdInvalidMsgs too, since those changes haven't touched
1188 * the caches yet.
1189 *
1190 * In any case, reset our state to empty. We need not physically
1191 * free memory here, since TopTransactionContext is about to be emptied
1192 * anyway.
1193 */
1194void
1196{
1198
1199 /* Quick exit if no transactional messages */
1200 if (transInvalInfo == NULL)
1201 return;
1202
1203 /* Must be at top of stack */
1205
1206 INJECTION_POINT("transaction-end-process-inval", NULL);
1207
1208 if (isCommit)
1209 {
1210 /*
1211 * Relcache init file invalidation requires processing both before and
1212 * after we send the SI messages. However, we need not do anything
1213 * unless we committed.
1214 */
1217
1220
1223
1226 }
1227 else
1228 {
1231 }
1232
1233 /* Need not free anything explicitly */
1235}
1236
1237/*
1238 * PreInplace_Inval
1239 * Process queued-up invalidation before inplace update critical section.
1240 *
1241 * Tasks belong here if they are safe even if the inplace update does not
1242 * complete. Currently, this just unlinks a cache file, which can fail. The
1243 * sum of this and AtInplace_Inval() mirrors AtEOXact_Inval(isCommit=true).
1244 */
1245void
1246PreInplace_Inval(void)
1247{
1249
1252}
1253
1254/*
1255 * AtInplace_Inval
1256 * Process queued-up invalidations after inplace update buffer mutation.
1257 */
1258void
1259AtInplace_Inval(void)
1260{
1262
1263 if (inplaceInvalInfo == NULL)
1264 return;
1265
1268
1271
1273}
1274
1275/*
1276 * ForgetInplace_Inval
1277 * Alternative to PreInplace_Inval()+AtInplace_Inval(): discard queued-up
1278 * invalidations. This lets inplace update enumerate invalidations
1279 * optimistically, before locking the buffer.
1280 */
1281void
1283{
1285}
1286
1287/*
1288 * AtEOSubXact_Inval
1289 * Process queued-up invalidation messages at end of subtransaction.
1290 *
1291 * If isCommit, process CurrentCmdInvalidMsgs if any (there probably aren't),
1292 * and then attach both CurrentCmdInvalidMsgs and PriorCmdInvalidMsgs to the
1293 * parent's PriorCmdInvalidMsgs list.
1294 *
1295 * If not isCommit, we are aborting, and must locally process the messages
1296 * in PriorCmdInvalidMsgs. No messages need be sent to other backends.
1297 * We can forget about CurrentCmdInvalidMsgs too, since those changes haven't
1298 * touched the caches yet.
1299 *
1300 * In any case, pop the transaction stack. We need not physically free memory
1301 * here, since CurTransactionContext is about to be emptied anyway
1302 * (if aborting). Beware of the possibility of aborting the same nesting
1303 * level twice, though.
1304 */
1305void
1307{
1308 int my_level;
1310
1311 /*
1312 * Successful inplace update must clear this, but we clear it on abort.
1313 * Inplace updates allocate this in CurrentMemoryContext, which has
1314 * lifespan <= subtransaction lifespan. Hence, don't free it explicitly.
1315 */
1316 if (isCommit)
1318 else
1320
1321 /* Quick exit if no transactional messages. */
1323 if (myInfo == NULL)
1324 return;
1325
1326 /* Also bail out quickly if messages are not for this level. */
1327 my_level = GetCurrentTransactionNestLevel();
1328 if (myInfo->my_level != my_level)
1329 {
1330 Assert(myInfo->my_level < my_level);
1331 return;
1332 }
1333
1334 if (isCommit)
1335 {
1336 /* If CurrentCmdInvalidMsgs still has anything, fix it */
1338
1339 /*
1340 * We create invalidation stack entries lazily, so the parent might
1341 * not have one. Instead of creating one, moving all the data over,
1342 * and then freeing our own, we can just adjust the level of our own
1343 * entry.
1344 */
1345 if (myInfo->parent == NULL || myInfo->parent->my_level < my_level - 1)
1346 {
1347 myInfo->my_level--;
1348 return;
1349 }
1350
1351 /*
1352 * Pass up my inval messages to parent. Notice that we stick them in
1353 * PriorCmdInvalidMsgs, not CurrentCmdInvalidMsgs, since they've
1354 * already been locally processed. (This would trigger the Assert in
1355 * AppendInvalidationMessageSubGroup if the parent's
1356 * CurrentCmdInvalidMsgs isn't empty; but we already checked that in
1357 * PrepareInvalidationState.)
1358 */
1359 AppendInvalidationMessages(&myInfo->parent->PriorCmdInvalidMsgs,
1360 &myInfo->PriorCmdInvalidMsgs);
1361
1362 /* Must readjust parent's CurrentCmdInvalidMsgs indexes now */
1363 SetGroupToFollow(&myInfo->parent->ii.CurrentCmdInvalidMsgs,
1364 &myInfo->parent->PriorCmdInvalidMsgs);
1365
1366 /* Pending relcache inval becomes parent's problem too */
1367 if (myInfo->ii.RelcacheInitFileInval)
1368 myInfo->parent->ii.RelcacheInitFileInval = true;
1369
1370 /* Pop the transaction state stack */
1372
1373 /* Need not free anything else explicitly */
1374 pfree(myInfo);
1375 }
1376 else
1377 {
1378 ProcessInvalidationMessages(&myInfo->PriorCmdInvalidMsgs,
1380
1381 /* Pop the transaction state stack */
1383
1384 /* Need not free anything else explicitly */
1385 pfree(myInfo);
1386 }
1387}
1388
1389/*
1390 * CommandEndInvalidationMessages
1391 * Process queued-up invalidation messages at end of one command
1392 * in a transaction.
1393 *
1394 * Here, we send no messages to the shared queue, since we don't know yet if
1395 * we will commit. We do need to locally process the CurrentCmdInvalidMsgs
1396 * list, so as to flush our caches of any entries we have outdated in the
1397 * current command. We then move the current-cmd list over to become part
1398 * of the prior-cmds list.
1399 *
1400 * Note:
1401 * This should be called during CommandCounterIncrement(),
1402 * after we have advanced the command ID.
1403 */
1404void
1406{
1407 /*
1408 * You might think this shouldn't be called outside any transaction, but
1409 * bootstrap does it, and also ABORT issued when not in a transaction. So
1410 * just quietly return if no state to work on.
1411 */
1412 if (transInvalInfo == NULL)
1413 return;
1414
1417
1418 /* WAL Log per-command invalidation messages for logical decoding */
1421
1424}
1425
1426
1427/*
1428 * CacheInvalidateHeapTupleCommon
1429 * Common logic for end-of-command and inplace variants.
1430 */
1431static void
1433 HeapTuple tuple,
1434 HeapTuple newtuple,
1436{
1437 InvalidationInfo *info;
1439 Oid databaseId;
1441
1442 /* PrepareToInvalidateCacheTuple() needs relcache */
1444
1445 /* Do nothing during bootstrap */
1447 return;
1448
1449 /*
1450 * We only need to worry about invalidation for tuples that are in system
1451 * catalogs; user-relation tuples are never in catcaches and can't affect
1452 * the relcache either.
1453 */
1454 if (!IsCatalogRelation(relation))
1455 return;
1456
1457 /*
1458 * IsCatalogRelation() will return true for TOAST tables of system
1459 * catalogs, but we don't care about those, either.
1460 */
1461 if (IsToastRelation(relation))
1462 return;
1463
1464 /* Allocate any required resources. */
1465 info = prepare_callback();
1466
1467 /*
1468 * First let the catcache do its thing
1469 */
1470 tupleRelId = RelationGetRelid(relation);
1472 {
1474 RegisterSnapshotInvalidation(info, databaseId, tupleRelId);
1475 }
1476 else
1477 PrepareToInvalidateCacheTuple(relation, tuple, newtuple,
1479 info);
1480
1481 /*
1482 * Now, is this tuple one of the primary definers of a relcache entry? See
1483 * comments in file header for deeper explanation.
1484 *
1485 * Note we ignore newtuple here; we assume an update cannot move a tuple
1486 * from being part of one relcache entry to being part of another.
1487 */
1489 {
1491
1492 relationId = classtup->oid;
1493 if (classtup->relisshared)
1494 databaseId = InvalidOid;
1495 else
1496 databaseId = MyDatabaseId;
1497 }
1498 else if (tupleRelId == AttributeRelationId)
1499 {
1501
1502 relationId = atttup->attrelid;
1503
1504 /*
1505 * KLUGE ALERT: we always send the relcache event with MyDatabaseId,
1506 * even if the rel in question is shared (which we can't easily tell).
1507 * This essentially means that only backends in this same database
1508 * will react to the relcache flush request. This is in fact
1509 * appropriate, since only those backends could see our pg_attribute
1510 * change anyway. It looks a bit ugly though. (In practice, shared
1511 * relations can't have schema changes after bootstrap, so we should
1512 * never come here for a shared rel anyway.)
1513 */
1514 databaseId = MyDatabaseId;
1515 }
1516 else if (tupleRelId == IndexRelationId)
1517 {
1519
1520 /*
1521 * When a pg_index row is updated, we should send out a relcache inval
1522 * for the index relation. As above, we don't know the shared status
1523 * of the index, but in practice it doesn't matter since indexes of
1524 * shared catalogs can't have such updates.
1525 */
1526 relationId = indextup->indexrelid;
1527 databaseId = MyDatabaseId;
1528 }
1529 else if (tupleRelId == ConstraintRelationId)
1530 {
1532
1533 /*
1534 * Foreign keys are part of relcache entries, too, so send out an
1535 * inval for the table that the FK applies to.
1536 */
1537 if (constrtup->contype == CONSTRAINT_FOREIGN &&
1538 OidIsValid(constrtup->conrelid))
1539 {
1540 relationId = constrtup->conrelid;
1541 databaseId = MyDatabaseId;
1542 }
1543 else
1544 return;
1545 }
1546 else
1547 return;
1548
1549 /*
1550 * Yes. We need to register a relcache invalidation event.
1551 */
1552 RegisterRelcacheInvalidation(info, databaseId, relationId);
1553}
1554
1555/*
1556 * CacheInvalidateHeapTuple
1557 * Register the given tuple for invalidation at end of command
1558 * (ie, current command is creating or outdating this tuple) and end of
1559 * transaction. Also, detect whether a relcache invalidation is implied.
1560 *
1561 * For an insert or delete, tuple is the target tuple and newtuple is NULL.
1562 * For an update, we are called just once, with tuple being the old tuple
1563 * version and newtuple the new version. This allows avoidance of duplicate
1564 * effort during an update.
1565 */
1566void
1568 HeapTuple tuple,
1569 HeapTuple newtuple)
1570{
1571 CacheInvalidateHeapTupleCommon(relation, tuple, newtuple,
1573}
1574
1575/*
1576 * CacheInvalidateHeapTupleInplace
1577 * Register the given tuple for nontransactional invalidation pertaining
1578 * to an inplace update. Also, detect whether a relcache invalidation is
1579 * implied.
1580 *
1581 * Like CacheInvalidateHeapTuple(), but for inplace updates.
1582 *
1583 * Just before and just after the inplace update, the tuple's cache keys must
1584 * match those in key_equivalent_tuple. Cache keys consist of catcache lookup
1585 * key columns and columns referencing pg_class.oid values,
1586 * e.g. pg_constraint.conrelid, which would trigger relcache inval.
1587 */
1588void
1591{
1594}
1595
1596/*
1597 * CacheInvalidateCatalog
1598 * Register invalidation of the whole content of a system catalog.
1599 *
1600 * This is normally used in VACUUM FULL/CLUSTER, where we haven't so much
1601 * changed any tuples as moved them around. Some uses of catcache entries
1602 * expect their TIDs to be correct, so we have to blow away the entries.
1603 *
1604 * Note: we expect caller to verify that the rel actually is a system
1605 * catalog. If it isn't, no great harm is done, just a wasted sinval message.
1606 */
1607void
1608CacheInvalidateCatalog(Oid catalogId)
1609{
1610 Oid databaseId;
1611
1612 if (IsSharedRelation(catalogId))
1613 databaseId = InvalidOid;
1614 else
1615 databaseId = MyDatabaseId;
1616
1618 databaseId, catalogId);
1619}
1620
1621/*
1622 * CacheInvalidateRelcache
1623 * Register invalidation of the specified relation's relcache entry
1624 * at end of command.
1625 *
1626 * This is used in places that need to force relcache rebuild but aren't
1627 * changing any of the tuples recognized as contributors to the relcache
1628 * entry by CacheInvalidateHeapTuple. (An example is dropping an index.)
1629 */
1630void
1632{
1633 Oid databaseId;
1635
1636 relationId = RelationGetRelid(relation);
1637 if (relation->rd_rel->relisshared)
1638 databaseId = InvalidOid;
1639 else
1640 databaseId = MyDatabaseId;
1641
1643 databaseId, relationId);
1644}
1645
1646/*
1647 * CacheInvalidateRelcacheAll
1648 * Register invalidation of the whole relcache at the end of command.
1649 *
1650 * This is used by alter publication as changes in publications may affect
1651 * large number of tables.
1652 */
1653void
1655{
1658}
1659
1660/*
1661 * CacheInvalidateRelcacheByTuple
1662 * As above, but relation is identified by passing its pg_class tuple.
1663 */
1664void
1666{
1668 Oid databaseId;
1670
1671 relationId = classtup->oid;
1672 if (classtup->relisshared)
1673 databaseId = InvalidOid;
1674 else
1675 databaseId = MyDatabaseId;
1677 databaseId, relationId);
1678}
1679
1680/*
1681 * CacheInvalidateRelcacheByRelid
1682 * As above, but relation is identified by passing its OID.
1683 * This is the least efficient of the three options; use one of
1684 * the above routines if you have a Relation or pg_class tuple.
1685 */
1686void
1688{
1689 HeapTuple tup;
1690
1692 if (!HeapTupleIsValid(tup))
1693 elog(ERROR, "cache lookup failed for relation %u", relid);
1696}
1697
1698/*
1699 * CacheInvalidateRelSync
1700 * Register invalidation of the cache in logical decoding output plugin
1701 * for a database.
1702 *
1703 * This type of invalidation message is used for the specific purpose of output
1704 * plugins. Processes which do not decode WALs would do nothing even when it
1705 * receives the message.
1706 */
1707void
1709{
1711 MyDatabaseId, relid);
1712}
1713
1714/*
1715 * CacheInvalidateRelSyncAll
1716 * Register invalidation of the whole cache in logical decoding output
1717 * plugin.
1718 */
1719void
1721{
1723}
1724
1725/*
1726 * CacheInvalidateSmgr
1727 * Register invalidation of smgr references to a physical relation.
1728 *
1729 * Sending this type of invalidation msg forces other backends to close open
1730 * smgr entries for the rel. This should be done to flush dangling open-file
1731 * references when the physical rel is being dropped or truncated. Because
1732 * these are nontransactional (i.e., not-rollback-able) operations, we just
1733 * send the inval message immediately without any queuing.
1734 *
1735 * Note: in most cases there will have been a relcache flush issued against
1736 * the rel at the logical level. We need a separate smgr-level flush because
1737 * it is possible for backends to have open smgr entries for rels they don't
1738 * have a relcache entry for, e.g. because the only thing they ever did with
1739 * the rel is write out dirty shared buffers.
1740 *
1741 * Note: because these messages are nontransactional, they won't be captured
1742 * in commit/abort WAL entries. Instead, calls to CacheInvalidateSmgr()
1743 * should happen in low-level smgr.c routines, which are executed while
1744 * replaying WAL as well as when creating it.
1745 *
1746 * Note: In order to avoid bloating SharedInvalidationMessage, we store only
1747 * three bytes of the ProcNumber using what would otherwise be padding space.
1748 * Thus, the maximum possible ProcNumber is 2^23-1.
1749 */
1750void
1752{
1754
1755 /* verify optimization stated above stays valid */
1757 "MAX_BACKENDS_BITS is too big for inval.c");
1758
1759 msg.sm.id = SHAREDINVALSMGR_ID;
1760 msg.sm.backend_hi = rlocator.backend >> 16;
1761 msg.sm.backend_lo = rlocator.backend & 0xffff;
1762 msg.sm.rlocator = rlocator.locator;
1763 /* check AddCatcacheInvalidationMessage() for an explanation */
1764 VALGRIND_MAKE_MEM_DEFINED(&msg, sizeof(msg));
1765
1767}
1768
1769/*
1770 * CacheInvalidateRelmap
1771 * Register invalidation of the relation mapping for a database,
1772 * or for the shared catalogs if databaseId is zero.
1773 *
1774 * Sending this type of invalidation msg forces other backends to re-read
1775 * the indicated relation mapping file. It is also necessary to send a
1776 * relcache inval for the specific relations whose mapping has been altered,
1777 * else the relcache won't get updated with the new filenode data.
1778 *
1779 * Note: because these messages are nontransactional, they won't be captured
1780 * in commit/abort WAL entries. Instead, calls to CacheInvalidateRelmap()
1781 * should happen in low-level relmapper.c routines, which are executed while
1782 * replaying WAL as well as when creating it.
1783 */
1784void
1785CacheInvalidateRelmap(Oid databaseId)
1786{
1788
1790 msg.rm.dbId = databaseId;
1791 /* check AddCatcacheInvalidationMessage() for an explanation */
1792 VALGRIND_MAKE_MEM_DEFINED(&msg, sizeof(msg));
1793
1795}
1796
1797
1798/*
1799 * CacheRegisterSyscacheCallback
1800 * Register the specified function to be called for all future
1801 * invalidation events in the specified cache. The cache ID and the
1802 * hash value of the tuple being invalidated will be passed to the
1803 * function.
1804 *
1805 * NOTE: Hash value zero will be passed if a cache reset request is received.
1806 * In this case the called routines should flush all cached state.
1807 * Yes, there's a possibility of a false match to zero, but it doesn't seem
1808 * worth troubling over, especially since most of the current callees just
1809 * flush all cached state anyway.
1810 */
1811void
1814 Datum arg)
1815{
1817 elog(FATAL, "invalid cache ID: %d", cacheid);
1819 elog(FATAL, "out of syscache_callback_list slots");
1820
1822 {
1823 /* first callback for this cache */
1825 }
1826 else
1827 {
1828 /* add to end of chain, so that older callbacks are called first */
1830
1831 while (syscache_callback_list[i].link > 0)
1834 }
1835
1840
1842}
1843
1844/*
1845 * CacheRegisterRelcacheCallback
1846 * Register the specified function to be called for all future
1847 * relcache invalidation events. The OID of the relation being
1848 * invalidated will be passed to the function.
1849 *
1850 * NOTE: InvalidOid will be passed if a cache reset request is received.
1851 * In this case the called routines should flush all cached state.
1852 */
1853void
1855 Datum arg)
1856{
1858 elog(FATAL, "out of relcache_callback_list slots");
1859
1862
1864}
1865
1866/*
1867 * CacheRegisterRelSyncCallback
1868 * Register the specified function to be called for all future
1869 * relsynccache invalidation events.
1870 *
1871 * This function is intended to be call from the logical decoding output
1872 * plugins.
1873 */
1874void
1876 Datum arg)
1877{
1879 elog(FATAL, "out of relsync_callback_list slots");
1880
1883
1885}
1886
1887/*
1888 * CallSyscacheCallbacks
1889 *
1890 * This is exported so that CatalogCacheFlushCatalog can call it, saving
1891 * this module from knowing which catcache IDs correspond to which catalogs.
1892 */
1893void
1895{
1896 int i;
1897
1899 elog(ERROR, "invalid cache ID: %d", cacheid);
1900
1902 while (i >= 0)
1903 {
1905
1906 Assert(ccitem->id == cacheid);
1907 ccitem->function(ccitem->arg, cacheid, hashvalue);
1908 i = ccitem->link - 1;
1909 }
1910}
1911
1912/*
1913 * CallSyscacheCallbacks
1914 */
1915void
1917{
1918 for (int i = 0; i < relsync_callback_count; i++)
1919 {
1921
1922 ccitem->function(ccitem->arg, relid);
1923 }
1924}
1925
1926/*
1927 * LogLogicalInvalidations
1928 *
1929 * Emit WAL for invalidations caused by the current command.
1930 *
1931 * This is currently only used for logging invalidations at the command end
1932 * or at commit time if any invalidations are pending.
1933 */
1934void
1936{
1938 InvalidationMsgsGroup *group;
1939 int nmsgs;
1940
1941 /* Quick exit if we haven't done anything with invalidation messages. */
1942 if (transInvalInfo == NULL)
1943 return;
1944
1946 nmsgs = NumMessagesInGroup(group);
1947
1948 if (nmsgs > 0)
1949 {
1950 /* prepare record */
1952 xlrec.nmsgs = nmsgs;
1953
1954 /* perform insertion */
1958 XLogRegisterData(msgs,
1959 n * sizeof(SharedInvalidationMessage)));
1961 XLogRegisterData(msgs,
1962 n * sizeof(SharedInvalidationMessage)));
1964 }
1965}
#define Assert(condition)
Definition c.h:943
int16_t int16
Definition c.h:619
int8_t int8
Definition c.h:618
uint32_t uint32
Definition c.h:624
#define StaticAssertDecl(condition, errmessage)
Definition c.h:1008
#define OidIsValid(objectId)
Definition c.h:858
bool IsToastRelation(Relation relation)
Definition catalog.c:206
bool IsCatalogRelation(Relation relation)
Definition catalog.c:104
bool IsSharedRelation(Oid relationId)
Definition catalog.c:304
void PrepareToInvalidateCacheTuple(Relation relation, HeapTuple tuple, HeapTuple newtuple, void(*function)(int, uint32, Oid, void *), void *context)
Definition catcache.c:2403
void CatalogCacheFlushCatalog(Oid catId)
Definition catcache.c:852
void ResetCatalogCachesExt(bool debug_discard)
Definition catcache.c:822
memcpy(sums, checksumBaseOffsets, sizeof(checksumBaseOffsets))
Datum arg
Definition elog.c:1323
static int recursion_depth
Definition elog.c:160
#define FATAL
Definition elog.h:42
#define ERROR
Definition elog.h:40
#define elog(elevel,...)
Definition elog.h:228
#define DEBUG4
Definition elog.h:28
#define palloc0_object(type)
Definition fe_memutils.h:90
volatile uint32 CritSectionCount
Definition globals.c:45
char * DatabasePath
Definition globals.c:106
Oid MyDatabaseId
Definition globals.c:96
#define HeapTupleIsValid(tuple)
Definition htup.h:78
static void * GETSTRUCT(const HeapTupleData *tuple)
#define INJECTION_POINT(name, arg)
void PostPrepare_Inval(void)
Definition inval.c:993
void InvalidateSystemCachesExtended(bool debug_discard)
Definition inval.c:785
void CallRelSyncCallbacks(Oid relid)
Definition inval.c:1917
static void AddCatcacheInvalidationMessage(InvalidationMsgsGroup *group, int id, uint32 hashValue, Oid dbId)
Definition inval.c:425
void CacheInvalidateRelSyncAll(void)
Definition inval.c:1721
void CallSyscacheCallbacks(SysCacheIdentifier cacheid, uint32 hashvalue)
Definition inval.c:1895
static void AddCatalogInvalidationMessage(InvalidationMsgsGroup *group, Oid dbId, Oid catId)
Definition inval.c:453
static void RegisterRelcacheInvalidation(InvalidationInfo *info, Oid dbId, Oid relId)
Definition inval.c:632
static int relcache_callback_count
Definition inval.c:294
#define NumMessagesInGroup(group)
Definition inval.c:207
static void AddRelcacheInvalidationMessage(InvalidationMsgsGroup *group, Oid dbId, Oid relId)
Definition inval.c:471
static int relsync_callback_count
Definition inval.c:302
static void AddRelsyncInvalidationMessage(InvalidationMsgsGroup *group, Oid dbId, Oid relId)
Definition inval.c:505
void LogLogicalInvalidations(void)
Definition inval.c:1936
void AcceptInvalidationMessages(void)
Definition inval.c:930
static void ProcessInvalidationMessages(InvalidationMsgsGroup *group, void(*func)(SharedInvalidationMessage *msg))
Definition inval.c:574
void CacheInvalidateRelmap(Oid databaseId)
Definition inval.c:1786
void LocalExecuteInvalidationMessage(SharedInvalidationMessage *msg)
Definition inval.c:823
static void RegisterCatcacheInvalidation(int cacheId, uint32 hashValue, Oid dbId, void *context)
Definition inval.c:604
void CacheInvalidateCatalog(Oid catalogId)
Definition inval.c:1609
#define ProcessMessageSubGroupMulti(group, subgroup, codeFragment)
Definition inval.c:402
void CacheRegisterSyscacheCallback(SysCacheIdentifier cacheid, SyscacheCallbackFunction func, Datum arg)
Definition inval.c:1813
static struct RELSYNCCALLBACK relsync_callback_list[MAX_RELSYNC_CALLBACKS]
static InvalidationInfo * inplaceInvalInfo
Definition inval.c:257
static void AppendInvalidationMessageSubGroup(InvalidationMsgsGroup *dest, InvalidationMsgsGroup *src, int subgroup)
Definition inval.c:360
static void RegisterSnapshotInvalidation(InvalidationInfo *info, Oid dbId, Oid relId)
Definition inval.c:672
static struct SYSCACHECALLBACK syscache_callback_list[MAX_SYSCACHE_CALLBACKS]
static struct RELCACHECALLBACK relcache_callback_list[MAX_RELCACHE_CALLBACKS]
static TransInvalidationInfo * transInvalInfo
Definition inval.c:255
int xactGetCommittedInvalidationMessages(SharedInvalidationMessage **msgs, bool *RelcacheInitFileInval)
Definition inval.c:1012
#define ProcessMessageSubGroup(group, subgroup, codeFragment)
Definition inval.c:384
void CacheInvalidateRelcache(Relation relation)
Definition inval.c:1632
static InvalidationInfo * PrepareInvalidationState(void)
Definition inval.c:682
static void AppendInvalidationMessages(InvalidationMsgsGroup *dest, InvalidationMsgsGroup *src)
Definition inval.c:560
#define MAX_RELSYNC_CALLBACKS
Definition inval.c:274
static void ProcessInvalidationMessagesMulti(InvalidationMsgsGroup *group, void(*func)(const SharedInvalidationMessage *msgs, int n))
Definition inval.c:586
int inplaceGetInvalidationMessages(SharedInvalidationMessage **msgs, bool *RelcacheInitFileInval)
Definition inval.c:1088
void CacheInvalidateRelcacheByRelid(Oid relid)
Definition inval.c:1688
void InvalidateSystemCaches(void)
Definition inval.c:916
void AtEOXact_Inval(bool isCommit)
Definition inval.c:1196
#define MAX_SYSCACHE_CALLBACKS
Definition inval.c:272
void CacheInvalidateSmgr(RelFileLocatorBackend rlocator)
Definition inval.c:1752
#define SetGroupToFollow(targetgroup, priorgroup)
Definition inval.c:198
void AtEOSubXact_Inval(bool isCommit)
Definition inval.c:1307
static void AddSnapshotInvalidationMessage(InvalidationMsgsGroup *group, Oid dbId, Oid relId)
Definition inval.c:533
static int16 syscache_callback_links[SysCacheSize]
Definition inval.c:284
static void AddInvalidationMessage(InvalidationMsgsGroup *group, int subgroup, const SharedInvalidationMessage *msg)
Definition inval.c:320
void PreInplace_Inval(void)
Definition inval.c:1247
void CommandEndInvalidationMessages(void)
Definition inval.c:1406
void CacheInvalidateHeapTupleInplace(Relation relation, HeapTuple key_equivalent_tuple)
Definition inval.c:1590
void AtInplace_Inval(void)
Definition inval.c:1260
static void RegisterCatalogInvalidation(InvalidationInfo *info, Oid dbId, Oid catId)
Definition inval.c:621
#define MAX_RELCACHE_CALLBACKS
Definition inval.c:273
void CacheRegisterRelcacheCallback(RelcacheCallbackFunction func, Datum arg)
Definition inval.c:1855
void CacheRegisterRelSyncCallback(RelSyncCallbackFunction func, Datum arg)
Definition inval.c:1876
void ForgetInplace_Inval(void)
Definition inval.c:1283
#define SetSubGroupToFollow(targetgroup, priorgroup, subgroup)
Definition inval.c:191
void CacheInvalidateRelSync(Oid relid)
Definition inval.c:1709
int debug_discard_caches
Definition inval.c:260
static InvalidationInfo * PrepareInplaceInvalidationState(void)
Definition inval.c:752
void CacheInvalidateHeapTuple(Relation relation, HeapTuple tuple, HeapTuple newtuple)
Definition inval.c:1568
static void CacheInvalidateHeapTupleCommon(Relation relation, HeapTuple tuple, HeapTuple newtuple, InvalidationInfo *(*prepare_callback)(void))
Definition inval.c:1433
void CacheInvalidateRelcacheByTuple(HeapTuple classTuple)
Definition inval.c:1666
static InvalMessageArray InvalMessageArrays[2]
Definition inval.c:181
static int syscache_callback_count
Definition inval.c:286
static void RegisterRelsyncInvalidation(InvalidationInfo *info, Oid dbId, Oid relId)
Definition inval.c:660
void ProcessCommittedInvalidationMessages(SharedInvalidationMessage *msgs, int nmsgs, bool RelcacheInitFileInval, Oid dbid, Oid tsid)
Definition inval.c:1135
void CacheInvalidateRelcacheAll(void)
Definition inval.c:1655
void(* RelcacheCallbackFunction)(Datum arg, Oid relid)
Definition inval.h:44
void(* RelSyncCallbackFunction)(Datum arg, Oid relid)
Definition inval.h:45
void(* SyscacheCallbackFunction)(Datum arg, SysCacheIdentifier cacheid, uint32 hashvalue)
Definition inval.h:42
int i
Definition isn.c:77
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition mcxt.c:1235
void * MemoryContextAllocZero(MemoryContext context, Size size)
Definition mcxt.c:1269
MemoryContext TopTransactionContext
Definition mcxt.c:172
void * repalloc(void *pointer, Size size)
Definition mcxt.c:1635
void pfree(void *pointer)
Definition mcxt.c:1619
void * palloc(Size size)
Definition mcxt.c:1390
MemoryContext CurTransactionContext
Definition mcxt.c:173
#define VALGRIND_MAKE_MEM_DEFINED(addr, size)
Definition memdebug.h:26
#define IsBootstrapProcessingMode()
Definition miscadmin.h:495
FormData_pg_attribute * Form_pg_attribute
FormData_pg_class * Form_pg_class
Definition pg_class.h:160
END_CATALOG_STRUCT typedef FormData_pg_constraint * Form_pg_constraint
END_CATALOG_STRUCT typedef FormData_pg_index * Form_pg_index
Definition pg_index.h:74
static Datum ObjectIdGetDatum(Oid X)
Definition postgres.h:252
uint64_t Datum
Definition postgres.h:70
#define InvalidOid
unsigned int Oid
#define MAX_BACKENDS_BITS
Definition procnumber.h:38
#define RelationGetRelid(relation)
Definition rel.h:516
void RelationCacheInvalidate(bool debug_discard)
Definition relcache.c:2994
void RelationCacheInitFilePostInvalidate(void)
Definition relcache.c:6911
void RelationCacheInitFilePreInvalidate(void)
Definition relcache.c:6886
bool RelationIdIsInInitFile(Oid relationId)
Definition relcache.c:6846
void RelationCacheInvalidateEntry(Oid relationId)
Definition relcache.c:2938
static void AssertCouldGetRelation(void)
Definition relcache.h:44
void RelationMapInvalidate(bool shared)
Definition relmapper.c:469
char * GetDatabasePath(Oid dbOid, Oid spcOid)
Definition relpath.c:110
void SendSharedInvalidMessages(const SharedInvalidationMessage *msgs, int n)
Definition sinval.c:47
void ReceiveSharedInvalidMessages(void(*invalFunction)(SharedInvalidationMessage *msg), void(*resetFunction)(void))
Definition sinval.c:69
#define SHAREDINVALCATALOG_ID
Definition sinval.h:68
#define SHAREDINVALRELSYNC_ID
Definition sinval.h:114
#define SHAREDINVALSMGR_ID
Definition sinval.h:86
#define SHAREDINVALSNAPSHOT_ID
Definition sinval.h:105
#define SHAREDINVALRELCACHE_ID
Definition sinval.h:77
#define SHAREDINVALRELMAP_ID
Definition sinval.h:97
void smgrreleaserellocator(RelFileLocatorBackend rlocator)
Definition smgr.c:443
void InvalidateCatalogSnapshot(void)
Definition snapmgr.c:455
SharedInvalidationMessage * msgs
Definition inval.c:177
bool RelcacheInitFileInval
Definition inval.c:236
InvalidationMsgsGroup CurrentCmdInvalidMsgs
Definition inval.c:233
RelcacheCallbackFunction function
Definition inval.c:290
RelSyncCallbackFunction function
Definition inval.c:298
RelFileLocator locator
Form_pg_class rd_rel
Definition rel.h:111
SyscacheCallbackFunction function
Definition inval.c:280
uint16 backend_lo
Definition sinval.h:93
RelFileLocator rlocator
Definition sinval.h:94
struct TransInvalidationInfo * parent
Definition inval.c:249
struct InvalidationInfo ii
Definition inval.c:243
InvalidationMsgsGroup PriorCmdInvalidMsgs
Definition inval.c:246
void ReleaseSysCache(HeapTuple tuple)
Definition syscache.c:265
void SysCacheInvalidate(SysCacheIdentifier cacheId, uint32 hashValue)
Definition syscache.c:691
bool RelationInvalidatesSnapshotsOnly(Oid relid)
Definition syscache.c:715
HeapTuple SearchSysCache1(SysCacheIdentifier cacheId, Datum key1)
Definition syscache.c:221
SharedInvalCatcacheMsg cc
Definition sinval.h:127
SharedInvalRelcacheMsg rc
Definition sinval.h:129
SharedInvalCatalogMsg cat
Definition sinval.h:128
SharedInvalRelSyncMsg rs
Definition sinval.h:133
SharedInvalSmgrMsg sm
Definition sinval.h:130
SharedInvalSnapshotMsg sn
Definition sinval.h:132
SharedInvalRelmapMsg rm
Definition sinval.h:131
int GetCurrentTransactionNestLevel(void)
Definition xact.c:931
bool IsTransactionState(void)
Definition xact.c:389
CommandId GetCurrentCommandId(bool used)
Definition xact.c:831
#define MinSizeOfXactInvals
Definition xact.h:308
#define XLOG_XACT_INVALIDATIONS
Definition xact.h:176
#define XLogLogicalInfoActive()
Definition xlog.h:137
XLogRecPtr XLogInsert(RmgrId rmid, uint8 info)
Definition xloginsert.c:482
void XLogRegisterData(const void *data, uint32 len)
Definition xloginsert.c:372
void XLogBeginInsert(void)
Definition xloginsert.c:153

◆ NumMessagesInSubGroup

#define NumMessagesInSubGroup (   group,
  subgroup 
)     ((group)->nextmsg[subgroup] - (group)->firstmsg[subgroup])

Definition at line 204 of file inval.c.

◆ ProcessMessageSubGroup

#define ProcessMessageSubGroup (   group,
  subgroup,
  codeFragment 
)
Value:
do { \
int _msgindex = (group)->firstmsg[subgroup]; \
int _endmsg = (group)->nextmsg[subgroup]; \
{ \
} \
} while (0)

Definition at line 384 of file inval.c.

385 { \
386 int _msgindex = (group)->firstmsg[subgroup]; \
387 int _endmsg = (group)->nextmsg[subgroup]; \
389 { \
392 codeFragment; \
393 } \
394 } while (0)

◆ ProcessMessageSubGroupMulti

#define ProcessMessageSubGroupMulti (   group,
  subgroup,
  codeFragment 
)
Value:
do { \
int n = NumMessagesInSubGroup(group, subgroup); \
if (n > 0) { \
&InvalMessageArrays[subgroup].msgs[(group)->firstmsg[subgroup]]; \
} \
} while (0)

Definition at line 402 of file inval.c.

403 { \
404 int n = NumMessagesInSubGroup(group, subgroup); \
405 if (n > 0) { \
407 &InvalMessageArrays[subgroup].msgs[(group)->firstmsg[subgroup]]; \
408 codeFragment; \
409 } \
410 } while (0)

◆ RelCacheMsgs

#define RelCacheMsgs   1

Definition at line 172 of file inval.c.

◆ SetGroupToFollow

◆ SetSubGroupToFollow

#define SetSubGroupToFollow (   targetgroup,
  priorgroup,
  subgroup 
)
Value:
do { \
(targetgroup)->firstmsg[subgroup] = \
(targetgroup)->nextmsg[subgroup] = \
(priorgroup)->nextmsg[subgroup]; \
} while (0)

Definition at line 191 of file inval.c.

192 { \
193 (targetgroup)->firstmsg[subgroup] = \
194 (targetgroup)->nextmsg[subgroup] = \
195 (priorgroup)->nextmsg[subgroup]; \
196 } while (0)

Typedef Documentation

◆ InvalidationInfo

◆ InvalidationMsgsGroup

◆ InvalMessageArray

◆ TransInvalidationInfo

Function Documentation

◆ AcceptInvalidationMessages()

void AcceptInvalidationMessages ( void  )

Definition at line 930 of file inval.c.

931{
932#ifdef USE_ASSERT_CHECKING
933 /* message handlers shall access catalogs only during transactions */
934 if (IsTransactionState())
936#endif
937
940
941 /*----------
942 * Test code to force cache flushes anytime a flush could happen.
943 *
944 * This helps detect intermittent faults caused by code that reads a cache
945 * entry and then performs an action that could invalidate the entry, but
946 * rarely actually does so. This can spot issues that would otherwise
947 * only arise with badly timed concurrent DDL, for example.
948 *
949 * The default debug_discard_caches = 0 does no forced cache flushes.
950 *
951 * If used with CLOBBER_FREED_MEMORY,
952 * debug_discard_caches = 1 (formerly known as CLOBBER_CACHE_ALWAYS)
953 * provides a fairly thorough test that the system contains no cache-flush
954 * hazards. However, it also makes the system unbelievably slow --- the
955 * regression tests take about 100 times longer than normal.
956 *
957 * If you're a glutton for punishment, try
958 * debug_discard_caches = 3 (formerly known as CLOBBER_CACHE_RECURSIVELY).
959 * This slows things by at least a factor of 10000, so I wouldn't suggest
960 * trying to run the entire regression tests that way. It's useful to try
961 * a few simple tests, to make sure that cache reload isn't subject to
962 * internal cache-flush hazards, but after you've done a few thousand
963 * recursive reloads it's unlikely you'll learn more.
964 *----------
965 */
966#ifdef DISCARD_CACHES_ENABLED
967 {
968 static int recursion_depth = 0;
969
971 {
975 }
976 }
977#endif
978}

References AssertCouldGetRelation(), debug_discard_caches, InvalidateSystemCaches(), InvalidateSystemCachesExtended(), IsTransactionState(), LocalExecuteInvalidationMessage(), ReceiveSharedInvalidMessages(), and recursion_depth.

Referenced by apply_handle_commit_internal(), AtStart_Cache(), ConditionalLockDatabaseObject(), ConditionalLockRelation(), ConditionalLockRelationOid(), ConditionalLockSharedObject(), delay_execution_planner(), heap_inplace_update_and_unlock(), InitializeSessionUserId(), LockDatabaseObject(), LockRelation(), LockRelationId(), LockRelationOid(), LockSharedObject(), LogicalRepApplyLoop(), pgstat_init_function_usage(), ProcessCatchupInterrupt(), RangeVarGetRelidExtended(), relation_openrv(), relation_openrv_extended(), RelationBuildPartitionDesc(), RemoveRelations(), SearchSysCacheLocked1(), and write_relcache_init_file().

◆ AddCatalogInvalidationMessage()

static void AddCatalogInvalidationMessage ( InvalidationMsgsGroup group,
Oid  dbId,
Oid  catId 
)
static

Definition at line 453 of file inval.c.

455{
457
459 msg.cat.dbId = dbId;
460 msg.cat.catId = catId;
461 /* check AddCatcacheInvalidationMessage() for an explanation */
462 VALGRIND_MAKE_MEM_DEFINED(&msg, sizeof(msg));
463
465}

References AddInvalidationMessage(), SharedInvalidationMessage::cat, CatCacheMsgs, SharedInvalCatalogMsg::catId, SharedInvalCatalogMsg::dbId, SharedInvalCatalogMsg::id, SHAREDINVALCATALOG_ID, and VALGRIND_MAKE_MEM_DEFINED.

Referenced by RegisterCatalogInvalidation().

◆ AddCatcacheInvalidationMessage()

static void AddCatcacheInvalidationMessage ( InvalidationMsgsGroup group,
int  id,
uint32  hashValue,
Oid  dbId 
)
static

Definition at line 425 of file inval.c.

427{
429
430 Assert(id < CHAR_MAX);
431 msg.cc.id = (int8) id;
432 msg.cc.dbId = dbId;
433 msg.cc.hashValue = hashValue;
434
435 /*
436 * Define padding bytes in SharedInvalidationMessage structs to be
437 * defined. Otherwise the sinvaladt.c ringbuffer, which is accessed by
438 * multiple processes, will cause spurious valgrind warnings about
439 * undefined memory being used. That's because valgrind remembers the
440 * undefined bytes from the last local process's store, not realizing that
441 * another process has written since, filling the previously uninitialized
442 * bytes
443 */
444 VALGRIND_MAKE_MEM_DEFINED(&msg, sizeof(msg));
445
447}

References AddInvalidationMessage(), Assert, CatCacheMsgs, SharedInvalidationMessage::cc, SharedInvalCatcacheMsg::dbId, fb(), SharedInvalCatcacheMsg::hashValue, SharedInvalCatcacheMsg::id, and VALGRIND_MAKE_MEM_DEFINED.

Referenced by RegisterCatcacheInvalidation().

◆ AddInvalidationMessage()

static void AddInvalidationMessage ( InvalidationMsgsGroup group,
int  subgroup,
const SharedInvalidationMessage msg 
)
static

Definition at line 320 of file inval.c.

322{
324 int nextindex = group->nextmsg[subgroup];
325
326 if (nextindex >= ima->maxmsgs)
327 {
328 if (ima->msgs == NULL)
329 {
330 /* Create new storage array in TopTransactionContext */
331 int reqsize = 32; /* arbitrary */
332
336 ima->maxmsgs = reqsize;
337 Assert(nextindex == 0);
338 }
339 else
340 {
341 /* Enlarge storage array */
342 int reqsize = 2 * ima->maxmsgs;
343
345 repalloc(ima->msgs,
347 ima->maxmsgs = reqsize;
348 }
349 }
350 /* Okay, add message to current group */
351 ima->msgs[nextindex] = *msg;
352 group->nextmsg[subgroup]++;
353}

References Assert, fb(), InvalMessageArrays, MemoryContextAlloc(), InvalidationMsgsGroup::nextmsg, repalloc(), and TopTransactionContext.

Referenced by AddCatalogInvalidationMessage(), AddCatcacheInvalidationMessage(), AddRelcacheInvalidationMessage(), AddRelsyncInvalidationMessage(), and AddSnapshotInvalidationMessage().

◆ AddRelcacheInvalidationMessage()

static void AddRelcacheInvalidationMessage ( InvalidationMsgsGroup group,
Oid  dbId,
Oid  relId 
)
static

Definition at line 471 of file inval.c.

473{
475
476 /*
477 * Don't add a duplicate item. We assume dbId need not be checked because
478 * it will never change. InvalidOid for relId means all relations so we
479 * don't need to add individual ones when it is present.
480 */
482 if (msg->rc.id == SHAREDINVALRELCACHE_ID &&
483 (msg->rc.relId == relId ||
484 msg->rc.relId == InvalidOid))
485 return);
486
487 /* OK, add the item */
489 msg.rc.dbId = dbId;
490 msg.rc.relId = relId;
491 /* check AddCatcacheInvalidationMessage() for an explanation */
492 VALGRIND_MAKE_MEM_DEFINED(&msg, sizeof(msg));
493
495}

References AddInvalidationMessage(), SharedInvalRelcacheMsg::dbId, SharedInvalRelcacheMsg::id, InvalidOid, ProcessMessageSubGroup, SharedInvalidationMessage::rc, RelCacheMsgs, SharedInvalRelcacheMsg::relId, SHAREDINVALRELCACHE_ID, and VALGRIND_MAKE_MEM_DEFINED.

Referenced by RegisterRelcacheInvalidation().

◆ AddRelsyncInvalidationMessage()

static void AddRelsyncInvalidationMessage ( InvalidationMsgsGroup group,
Oid  dbId,
Oid  relId 
)
static

Definition at line 505 of file inval.c.

507{
509
510 /* Don't add a duplicate item. */
512 if (msg->rc.id == SHAREDINVALRELSYNC_ID &&
513 (msg->rc.relId == relId ||
514 msg->rc.relId == InvalidOid))
515 return);
516
517 /* OK, add the item */
519 msg.rc.dbId = dbId;
520 msg.rc.relId = relId;
521 /* check AddCatcacheInvalidationMessage() for an explanation */
522 VALGRIND_MAKE_MEM_DEFINED(&msg, sizeof(msg));
523
525}

References AddInvalidationMessage(), SharedInvalRelcacheMsg::dbId, SharedInvalRelcacheMsg::id, InvalidOid, ProcessMessageSubGroup, SharedInvalidationMessage::rc, RelCacheMsgs, SharedInvalRelcacheMsg::relId, SHAREDINVALRELSYNC_ID, and VALGRIND_MAKE_MEM_DEFINED.

Referenced by RegisterRelsyncInvalidation().

◆ AddSnapshotInvalidationMessage()

static void AddSnapshotInvalidationMessage ( InvalidationMsgsGroup group,
Oid  dbId,
Oid  relId 
)
static

Definition at line 533 of file inval.c.

535{
537
538 /* Don't add a duplicate item */
539 /* We assume dbId need not be checked because it will never change */
541 if (msg->sn.id == SHAREDINVALSNAPSHOT_ID &&
542 msg->sn.relId == relId)
543 return);
544
545 /* OK, add the item */
547 msg.sn.dbId = dbId;
548 msg.sn.relId = relId;
549 /* check AddCatcacheInvalidationMessage() for an explanation */
550 VALGRIND_MAKE_MEM_DEFINED(&msg, sizeof(msg));
551
553}

References AddInvalidationMessage(), SharedInvalSnapshotMsg::dbId, SharedInvalSnapshotMsg::id, ProcessMessageSubGroup, RelCacheMsgs, SharedInvalSnapshotMsg::relId, SHAREDINVALSNAPSHOT_ID, SharedInvalidationMessage::sn, and VALGRIND_MAKE_MEM_DEFINED.

Referenced by RegisterSnapshotInvalidation().

◆ AppendInvalidationMessages()

static void AppendInvalidationMessages ( InvalidationMsgsGroup dest,
InvalidationMsgsGroup src 
)
static

◆ AppendInvalidationMessageSubGroup()

static void AppendInvalidationMessageSubGroup ( InvalidationMsgsGroup dest,
InvalidationMsgsGroup src,
int  subgroup 
)
static

Definition at line 360 of file inval.c.

363{
364 /* Messages must be adjacent in main array */
365 Assert(dest->nextmsg[subgroup] == src->firstmsg[subgroup]);
366
367 /* ... which makes this easy: */
368 dest->nextmsg[subgroup] = src->nextmsg[subgroup];
369
370 /*
371 * This is handy for some callers and irrelevant for others. But we do it
372 * always, reasoning that it's bad to leave different groups pointing at
373 * the same fragment of the message array.
374 */
375 SetSubGroupToFollow(src, dest, subgroup);
376}

References Assert, fb(), InvalidationMsgsGroup::firstmsg, InvalidationMsgsGroup::nextmsg, and SetSubGroupToFollow.

Referenced by AppendInvalidationMessages().

◆ AtEOSubXact_Inval()

void AtEOSubXact_Inval ( bool  isCommit)

Definition at line 1307 of file inval.c.

1308{
1309 int my_level;
1311
1312 /*
1313 * Successful inplace update must clear this, but we clear it on abort.
1314 * Inplace updates allocate this in CurrentMemoryContext, which has
1315 * lifespan <= subtransaction lifespan. Hence, don't free it explicitly.
1316 */
1317 if (isCommit)
1319 else
1321
1322 /* Quick exit if no transactional messages. */
1324 if (myInfo == NULL)
1325 return;
1326
1327 /* Also bail out quickly if messages are not for this level. */
1328 my_level = GetCurrentTransactionNestLevel();
1329 if (myInfo->my_level != my_level)
1330 {
1331 Assert(myInfo->my_level < my_level);
1332 return;
1333 }
1334
1335 if (isCommit)
1336 {
1337 /* If CurrentCmdInvalidMsgs still has anything, fix it */
1339
1340 /*
1341 * We create invalidation stack entries lazily, so the parent might
1342 * not have one. Instead of creating one, moving all the data over,
1343 * and then freeing our own, we can just adjust the level of our own
1344 * entry.
1345 */
1346 if (myInfo->parent == NULL || myInfo->parent->my_level < my_level - 1)
1347 {
1348 myInfo->my_level--;
1349 return;
1350 }
1351
1352 /*
1353 * Pass up my inval messages to parent. Notice that we stick them in
1354 * PriorCmdInvalidMsgs, not CurrentCmdInvalidMsgs, since they've
1355 * already been locally processed. (This would trigger the Assert in
1356 * AppendInvalidationMessageSubGroup if the parent's
1357 * CurrentCmdInvalidMsgs isn't empty; but we already checked that in
1358 * PrepareInvalidationState.)
1359 */
1360 AppendInvalidationMessages(&myInfo->parent->PriorCmdInvalidMsgs,
1361 &myInfo->PriorCmdInvalidMsgs);
1362
1363 /* Must readjust parent's CurrentCmdInvalidMsgs indexes now */
1364 SetGroupToFollow(&myInfo->parent->ii.CurrentCmdInvalidMsgs,
1365 &myInfo->parent->PriorCmdInvalidMsgs);
1366
1367 /* Pending relcache inval becomes parent's problem too */
1368 if (myInfo->ii.RelcacheInitFileInval)
1369 myInfo->parent->ii.RelcacheInitFileInval = true;
1370
1371 /* Pop the transaction state stack */
1373
1374 /* Need not free anything else explicitly */
1375 pfree(myInfo);
1376 }
1377 else
1378 {
1379 ProcessInvalidationMessages(&myInfo->PriorCmdInvalidMsgs,
1381
1382 /* Pop the transaction state stack */
1384
1385 /* Need not free anything else explicitly */
1386 pfree(myInfo);
1387 }
1388}

References AppendInvalidationMessages(), Assert, CommandEndInvalidationMessages(), fb(), GetCurrentTransactionNestLevel(), inplaceInvalInfo, LocalExecuteInvalidationMessage(), TransInvalidationInfo::parent, pfree(), ProcessInvalidationMessages(), SetGroupToFollow, and transInvalInfo.

Referenced by AbortSubTransaction(), and CommitSubTransaction().

◆ AtEOXact_Inval()

void AtEOXact_Inval ( bool  isCommit)

Definition at line 1196 of file inval.c.

1197{
1199
1200 /* Quick exit if no transactional messages */
1201 if (transInvalInfo == NULL)
1202 return;
1203
1204 /* Must be at top of stack */
1206
1207 INJECTION_POINT("transaction-end-process-inval", NULL);
1208
1209 if (isCommit)
1210 {
1211 /*
1212 * Relcache init file invalidation requires processing both before and
1213 * after we send the SI messages. However, we need not do anything
1214 * unless we committed.
1215 */
1218
1221
1224
1227 }
1228 else
1229 {
1232 }
1233
1234 /* Need not free anything explicitly */
1236}

References AppendInvalidationMessages(), Assert, InvalidationInfo::CurrentCmdInvalidMsgs, fb(), TransInvalidationInfo::ii, INJECTION_POINT, inplaceInvalInfo, LocalExecuteInvalidationMessage(), TransInvalidationInfo::my_level, TransInvalidationInfo::parent, TransInvalidationInfo::PriorCmdInvalidMsgs, ProcessInvalidationMessages(), ProcessInvalidationMessagesMulti(), RelationCacheInitFilePostInvalidate(), RelationCacheInitFilePreInvalidate(), InvalidationInfo::RelcacheInitFileInval, SendSharedInvalidMessages(), and transInvalInfo.

Referenced by AbortTransaction(), CommitTransaction(), and PostPrepare_Inval().

◆ AtInplace_Inval()

◆ CacheInvalidateCatalog()

void CacheInvalidateCatalog ( Oid  catalogId)

Definition at line 1609 of file inval.c.

1610{
1611 Oid databaseId;
1612
1613 if (IsSharedRelation(catalogId))
1614 databaseId = InvalidOid;
1615 else
1616 databaseId = MyDatabaseId;
1617
1619 databaseId, catalogId);
1620}

References InvalidOid, IsSharedRelation(), MyDatabaseId, PrepareInvalidationState(), and RegisterCatalogInvalidation().

Referenced by finish_heap_swap().

◆ CacheInvalidateHeapTuple()

void CacheInvalidateHeapTuple ( Relation  relation,
HeapTuple  tuple,
HeapTuple  newtuple 
)

◆ CacheInvalidateHeapTupleCommon()

static void CacheInvalidateHeapTupleCommon ( Relation  relation,
HeapTuple  tuple,
HeapTuple  newtuple,
InvalidationInfo *(*)(void prepare_callback 
)
static

Definition at line 1433 of file inval.c.

1437{
1438 InvalidationInfo *info;
1440 Oid databaseId;
1442
1443 /* PrepareToInvalidateCacheTuple() needs relcache */
1445
1446 /* Do nothing during bootstrap */
1448 return;
1449
1450 /*
1451 * We only need to worry about invalidation for tuples that are in system
1452 * catalogs; user-relation tuples are never in catcaches and can't affect
1453 * the relcache either.
1454 */
1455 if (!IsCatalogRelation(relation))
1456 return;
1457
1458 /*
1459 * IsCatalogRelation() will return true for TOAST tables of system
1460 * catalogs, but we don't care about those, either.
1461 */
1462 if (IsToastRelation(relation))
1463 return;
1464
1465 /* Allocate any required resources. */
1466 info = prepare_callback();
1467
1468 /*
1469 * First let the catcache do its thing
1470 */
1471 tupleRelId = RelationGetRelid(relation);
1473 {
1475 RegisterSnapshotInvalidation(info, databaseId, tupleRelId);
1476 }
1477 else
1478 PrepareToInvalidateCacheTuple(relation, tuple, newtuple,
1480 info);
1481
1482 /*
1483 * Now, is this tuple one of the primary definers of a relcache entry? See
1484 * comments in file header for deeper explanation.
1485 *
1486 * Note we ignore newtuple here; we assume an update cannot move a tuple
1487 * from being part of one relcache entry to being part of another.
1488 */
1490 {
1492
1493 relationId = classtup->oid;
1494 if (classtup->relisshared)
1495 databaseId = InvalidOid;
1496 else
1497 databaseId = MyDatabaseId;
1498 }
1499 else if (tupleRelId == AttributeRelationId)
1500 {
1502
1503 relationId = atttup->attrelid;
1504
1505 /*
1506 * KLUGE ALERT: we always send the relcache event with MyDatabaseId,
1507 * even if the rel in question is shared (which we can't easily tell).
1508 * This essentially means that only backends in this same database
1509 * will react to the relcache flush request. This is in fact
1510 * appropriate, since only those backends could see our pg_attribute
1511 * change anyway. It looks a bit ugly though. (In practice, shared
1512 * relations can't have schema changes after bootstrap, so we should
1513 * never come here for a shared rel anyway.)
1514 */
1515 databaseId = MyDatabaseId;
1516 }
1517 else if (tupleRelId == IndexRelationId)
1518 {
1520
1521 /*
1522 * When a pg_index row is updated, we should send out a relcache inval
1523 * for the index relation. As above, we don't know the shared status
1524 * of the index, but in practice it doesn't matter since indexes of
1525 * shared catalogs can't have such updates.
1526 */
1527 relationId = indextup->indexrelid;
1528 databaseId = MyDatabaseId;
1529 }
1530 else if (tupleRelId == ConstraintRelationId)
1531 {
1533
1534 /*
1535 * Foreign keys are part of relcache entries, too, so send out an
1536 * inval for the table that the FK applies to.
1537 */
1538 if (constrtup->contype == CONSTRAINT_FOREIGN &&
1539 OidIsValid(constrtup->conrelid))
1540 {
1541 relationId = constrtup->conrelid;
1542 databaseId = MyDatabaseId;
1543 }
1544 else
1545 return;
1546 }
1547 else
1548 return;
1549
1550 /*
1551 * Yes. We need to register a relcache invalidation event.
1552 */
1553 RegisterRelcacheInvalidation(info, databaseId, relationId);
1554}

References AssertCouldGetRelation(), fb(), Form_pg_constraint, Form_pg_index, GETSTRUCT(), InvalidOid, IsBootstrapProcessingMode, IsCatalogRelation(), IsSharedRelation(), IsToastRelation(), MyDatabaseId, OidIsValid, PrepareToInvalidateCacheTuple(), RegisterCatcacheInvalidation(), RegisterRelcacheInvalidation(), RegisterSnapshotInvalidation(), RelationGetRelid, and RelationInvalidatesSnapshotsOnly().

Referenced by CacheInvalidateHeapTuple(), and CacheInvalidateHeapTupleInplace().

◆ CacheInvalidateHeapTupleInplace()

void CacheInvalidateHeapTupleInplace ( Relation  relation,
HeapTuple  key_equivalent_tuple 
)

◆ CacheInvalidateRelcache()

◆ CacheInvalidateRelcacheAll()

◆ CacheInvalidateRelcacheByRelid()

◆ CacheInvalidateRelcacheByTuple()

◆ CacheInvalidateRelmap()

void CacheInvalidateRelmap ( Oid  databaseId)

Definition at line 1786 of file inval.c.

1787{
1789
1791 msg.rm.dbId = databaseId;
1792 /* check AddCatcacheInvalidationMessage() for an explanation */
1793 VALGRIND_MAKE_MEM_DEFINED(&msg, sizeof(msg));
1794
1796}

References SharedInvalRelmapMsg::dbId, SharedInvalRelmapMsg::id, SharedInvalidationMessage::rm, SendSharedInvalidMessages(), SHAREDINVALRELMAP_ID, and VALGRIND_MAKE_MEM_DEFINED.

Referenced by write_relmap_file().

◆ CacheInvalidateRelSync()

void CacheInvalidateRelSync ( Oid  relid)

◆ CacheInvalidateRelSyncAll()

void CacheInvalidateRelSyncAll ( void  )

Definition at line 1721 of file inval.c.

1722{
1724}

References CacheInvalidateRelSync(), and InvalidOid.

Referenced by InvalidatePubRelSyncCache().

◆ CacheInvalidateSmgr()

void CacheInvalidateSmgr ( RelFileLocatorBackend  rlocator)

Definition at line 1752 of file inval.c.

1753{
1755
1756 /* verify optimization stated above stays valid */
1758 "MAX_BACKENDS_BITS is too big for inval.c");
1759
1760 msg.sm.id = SHAREDINVALSMGR_ID;
1761 msg.sm.backend_hi = rlocator.backend >> 16;
1762 msg.sm.backend_lo = rlocator.backend & 0xffff;
1763 msg.sm.rlocator = rlocator.locator;
1764 /* check AddCatcacheInvalidationMessage() for an explanation */
1765 VALGRIND_MAKE_MEM_DEFINED(&msg, sizeof(msg));
1766
1768}

References RelFileLocatorBackend::backend, SharedInvalSmgrMsg::backend_hi, SharedInvalSmgrMsg::backend_lo, SharedInvalSmgrMsg::id, RelFileLocatorBackend::locator, MAX_BACKENDS_BITS, SharedInvalSmgrMsg::rlocator, SendSharedInvalidMessages(), SHAREDINVALSMGR_ID, SharedInvalidationMessage::sm, StaticAssertDecl, and VALGRIND_MAKE_MEM_DEFINED.

Referenced by smgrdounlinkall(), smgrtruncate(), and vm_extend().

◆ CacheRegisterRelcacheCallback()

◆ CacheRegisterRelSyncCallback()

void CacheRegisterRelSyncCallback ( RelSyncCallbackFunction  func,
Datum  arg 
)

◆ CacheRegisterSyscacheCallback()

void CacheRegisterSyscacheCallback ( SysCacheIdentifier  cacheid,
SyscacheCallbackFunction  func,
Datum  arg 
)

Definition at line 1813 of file inval.c.

1816{
1818 elog(FATAL, "invalid cache ID: %d", cacheid);
1820 elog(FATAL, "out of syscache_callback_list slots");
1821
1823 {
1824 /* first callback for this cache */
1826 }
1827 else
1828 {
1829 /* add to end of chain, so that older callbacks are called first */
1831
1832 while (syscache_callback_list[i].link > 0)
1835 }
1836
1841
1843}

References SYSCACHECALLBACK::arg, arg, elog, FATAL, fb(), SYSCACHECALLBACK::function, i, SYSCACHECALLBACK::id, SYSCACHECALLBACK::link, MAX_SYSCACHE_CALLBACKS, syscache_callback_count, syscache_callback_links, and syscache_callback_list.

Referenced by BuildEventTriggerCache(), find_oper_cache_entry(), get_function_sibling_type(), GetConnection(), init_rel_sync_cache(), init_ts_config_cache(), initialize_acl(), InitializeAttoptCache(), InitializeLogRepWorker(), InitializeSearchPath(), InitializeShippableCache(), InitializeTableSpaceCache(), InitPlanCache(), lookup_proof_cache(), lookup_ts_dictionary_cache(), lookup_ts_parser_cache(), lookup_type_cache(), ParallelApplyWorkerMain(), pgoutput_startup(), ri_InitHashTables(), SetupApplyOrSyncWorker(), and superuser_arg().

◆ CallRelSyncCallbacks()

void CallRelSyncCallbacks ( Oid  relid)

Definition at line 1917 of file inval.c.

1918{
1919 for (int i = 0; i < relsync_callback_count; i++)
1920 {
1922
1923 ccitem->function(ccitem->arg, relid);
1924 }
1925}

References fb(), RELSYNCCALLBACK::function, i, relsync_callback_count, and relsync_callback_list.

Referenced by LocalExecuteInvalidationMessage().

◆ CallSyscacheCallbacks()

void CallSyscacheCallbacks ( SysCacheIdentifier  cacheid,
uint32  hashvalue 
)

Definition at line 1895 of file inval.c.

1896{
1897 int i;
1898
1900 elog(ERROR, "invalid cache ID: %d", cacheid);
1901
1903 while (i >= 0)
1904 {
1906
1907 Assert(ccitem->id == cacheid);
1908 ccitem->function(ccitem->arg, cacheid, hashvalue);
1909 i = ccitem->link - 1;
1910 }
1911}

References Assert, elog, ERROR, fb(), i, syscache_callback_links, and syscache_callback_list.

Referenced by CatalogCacheFlushCatalog(), and LocalExecuteInvalidationMessage().

◆ CommandEndInvalidationMessages()

void CommandEndInvalidationMessages ( void  )

Definition at line 1406 of file inval.c.

1407{
1408 /*
1409 * You might think this shouldn't be called outside any transaction, but
1410 * bootstrap does it, and also ABORT issued when not in a transaction. So
1411 * just quietly return if no state to work on.
1412 */
1413 if (transInvalInfo == NULL)
1414 return;
1415
1418
1419 /* WAL Log per-command invalidation messages for logical decoding */
1422
1425}

References AppendInvalidationMessages(), InvalidationInfo::CurrentCmdInvalidMsgs, fb(), TransInvalidationInfo::ii, LocalExecuteInvalidationMessage(), LogLogicalInvalidations(), TransInvalidationInfo::PriorCmdInvalidMsgs, ProcessInvalidationMessages(), transInvalInfo, and XLogLogicalInfoActive.

Referenced by AtCCI_LocalCache(), and AtEOSubXact_Inval().

◆ ForgetInplace_Inval()

void ForgetInplace_Inval ( void  )

Definition at line 1283 of file inval.c.

1284{
1286}

References fb(), and inplaceInvalInfo.

Referenced by heap_inplace_lock(), and heap_inplace_unlock().

◆ inplaceGetInvalidationMessages()

int inplaceGetInvalidationMessages ( SharedInvalidationMessage **  msgs,
bool RelcacheInitFileInval 
)

Definition at line 1088 of file inval.c.

1090{
1092 int nummsgs;
1093 int nmsgs;
1094
1095 /* Quick exit if we haven't done anything with invalidation messages. */
1096 if (inplaceInvalInfo == NULL)
1097 {
1098 *RelcacheInitFileInval = false;
1099 *msgs = NULL;
1100 return 0;
1101 }
1102
1103 *RelcacheInitFileInval = inplaceInvalInfo->RelcacheInitFileInval;
1107
1108 nmsgs = 0;
1111 (memcpy(msgarray + nmsgs,
1112 msgs,
1113 n * sizeof(SharedInvalidationMessage)),
1114 nmsgs += n));
1117 (memcpy(msgarray + nmsgs,
1118 msgs,
1119 n * sizeof(SharedInvalidationMessage)),
1120 nmsgs += n));
1121 Assert(nmsgs == nummsgs);
1122
1123 return nmsgs;
1124}

References Assert, CatCacheMsgs, InvalidationInfo::CurrentCmdInvalidMsgs, fb(), inplaceInvalInfo, memcpy(), NumMessagesInGroup, palloc(), ProcessMessageSubGroupMulti, InvalidationInfo::RelcacheInitFileInval, and RelCacheMsgs.

Referenced by heap_inplace_update_and_unlock().

◆ InvalidateSystemCaches()

◆ InvalidateSystemCachesExtended()

◆ LocalExecuteInvalidationMessage()

void LocalExecuteInvalidationMessage ( SharedInvalidationMessage msg)

Definition at line 823 of file inval.c.

824{
825 if (msg->id >= 0)
826 {
827 if (msg->cc.dbId == MyDatabaseId || msg->cc.dbId == InvalidOid)
828 {
830
831 SysCacheInvalidate(msg->cc.id, msg->cc.hashValue);
832
834 }
835 }
836 else if (msg->id == SHAREDINVALCATALOG_ID)
837 {
838 if (msg->cat.dbId == MyDatabaseId || msg->cat.dbId == InvalidOid)
839 {
841
843
844 /* CatalogCacheFlushCatalog calls CallSyscacheCallbacks as needed */
845 }
846 }
847 else if (msg->id == SHAREDINVALRELCACHE_ID)
848 {
849 if (msg->rc.dbId == MyDatabaseId || msg->rc.dbId == InvalidOid)
850 {
851 int i;
852
853 if (msg->rc.relId == InvalidOid)
855 else
857
858 for (i = 0; i < relcache_callback_count; i++)
859 {
861
862 ccitem->function(ccitem->arg, msg->rc.relId);
863 }
864 }
865 }
866 else if (msg->id == SHAREDINVALSMGR_ID)
867 {
868 /*
869 * We could have smgr entries for relations of other databases, so no
870 * short-circuit test is possible here.
871 */
872 RelFileLocatorBackend rlocator;
873
874 rlocator.locator = msg->sm.rlocator;
875 rlocator.backend = (msg->sm.backend_hi << 16) | (int) msg->sm.backend_lo;
876 smgrreleaserellocator(rlocator);
877 }
878 else if (msg->id == SHAREDINVALRELMAP_ID)
879 {
880 /* We only care about our own database and shared catalogs */
881 if (msg->rm.dbId == InvalidOid)
883 else if (msg->rm.dbId == MyDatabaseId)
885 }
886 else if (msg->id == SHAREDINVALSNAPSHOT_ID)
887 {
888 /* We only care about our own database and shared catalogs */
889 if (msg->sn.dbId == InvalidOid)
891 else if (msg->sn.dbId == MyDatabaseId)
893 }
894 else if (msg->id == SHAREDINVALRELSYNC_ID)
895 {
896 /* We only care about our own database */
897 if (msg->rs.dbId == MyDatabaseId)
899 }
900 else
901 elog(FATAL, "unrecognized SI message ID: %d", msg->id);
902}

References RelFileLocatorBackend::backend, SharedInvalSmgrMsg::backend_hi, SharedInvalSmgrMsg::backend_lo, CallRelSyncCallbacks(), CallSyscacheCallbacks(), SharedInvalidationMessage::cat, CatalogCacheFlushCatalog(), SharedInvalCatalogMsg::catId, SharedInvalidationMessage::cc, SharedInvalCatcacheMsg::dbId, SharedInvalCatalogMsg::dbId, SharedInvalRelcacheMsg::dbId, SharedInvalRelmapMsg::dbId, SharedInvalSnapshotMsg::dbId, SharedInvalRelSyncMsg::dbId, elog, FATAL, fb(), RELCACHECALLBACK::function, SharedInvalCatcacheMsg::hashValue, i, SharedInvalCatcacheMsg::id, SharedInvalidationMessage::id, InvalidateCatalogSnapshot(), InvalidOid, RelFileLocatorBackend::locator, MyDatabaseId, SharedInvalidationMessage::rc, RelationCacheInvalidate(), RelationCacheInvalidateEntry(), RelationMapInvalidate(), relcache_callback_count, relcache_callback_list, SharedInvalRelcacheMsg::relId, SharedInvalRelSyncMsg::relid, SharedInvalSmgrMsg::rlocator, SharedInvalidationMessage::rm, SharedInvalidationMessage::rs, SHAREDINVALCATALOG_ID, SHAREDINVALRELCACHE_ID, SHAREDINVALRELMAP_ID, SHAREDINVALRELSYNC_ID, SHAREDINVALSMGR_ID, SHAREDINVALSNAPSHOT_ID, SharedInvalidationMessage::sm, smgrreleaserellocator(), SharedInvalidationMessage::sn, and SysCacheInvalidate().

Referenced by AcceptInvalidationMessages(), AtEOSubXact_Inval(), AtEOXact_Inval(), CommandEndInvalidationMessages(), ReorderBufferExecuteInvalidations(), and ReorderBufferImmediateInvalidation().

◆ LogLogicalInvalidations()

void LogLogicalInvalidations ( void  )

Definition at line 1936 of file inval.c.

1937{
1939 InvalidationMsgsGroup *group;
1940 int nmsgs;
1941
1942 /* Quick exit if we haven't done anything with invalidation messages. */
1943 if (transInvalInfo == NULL)
1944 return;
1945
1947 nmsgs = NumMessagesInGroup(group);
1948
1949 if (nmsgs > 0)
1950 {
1951 /* prepare record */
1953 xlrec.nmsgs = nmsgs;
1954
1955 /* perform insertion */
1959 XLogRegisterData(msgs,
1960 n * sizeof(SharedInvalidationMessage)));
1962 XLogRegisterData(msgs,
1963 n * sizeof(SharedInvalidationMessage)));
1965 }
1966}

References CatCacheMsgs, InvalidationInfo::CurrentCmdInvalidMsgs, fb(), TransInvalidationInfo::ii, MinSizeOfXactInvals, NumMessagesInGroup, ProcessMessageSubGroupMulti, RelCacheMsgs, transInvalInfo, XLOG_XACT_INVALIDATIONS, XLogBeginInsert(), XLogInsert(), and XLogRegisterData().

Referenced by CommandEndInvalidationMessages(), and RecordTransactionCommit().

◆ PostPrepare_Inval()

void PostPrepare_Inval ( void  )

Definition at line 993 of file inval.c.

994{
995 AtEOXact_Inval(false);
996}

References AtEOXact_Inval().

Referenced by PrepareTransaction().

◆ PreInplace_Inval()

◆ PrepareInplaceInvalidationState()

static InvalidationInfo * PrepareInplaceInvalidationState ( void  )
static

Definition at line 752 of file inval.c.

753{
755
757 /* limit of one inplace update under assembly */
759
760 /* gone after WAL insertion CritSection ends, so use current context */
762
763 /* Stash our messages past end of the transactional messages, if any. */
764 if (transInvalInfo != NULL)
765 SetGroupToFollow(&myInfo->CurrentCmdInvalidMsgs,
767 else
768 {
773 }
774
776 return myInfo;
777}

References Assert, AssertCouldGetRelation(), CatCacheMsgs, InvalidationInfo::CurrentCmdInvalidMsgs, fb(), TransInvalidationInfo::ii, inplaceInvalInfo, InvalMessageArrays, InvalMessageArray::maxmsgs, InvalMessageArray::msgs, palloc0_object, RelCacheMsgs, SetGroupToFollow, and transInvalInfo.

Referenced by CacheInvalidateHeapTupleInplace().

◆ PrepareInvalidationState()

static InvalidationInfo * PrepareInvalidationState ( void  )
static

Definition at line 682 of file inval.c.

683{
685
686 /* PrepareToInvalidateCacheTuple() needs relcache */
688 /* Can't queue transactional message while collecting inplace messages. */
690
691 if (transInvalInfo != NULL &&
694
697 sizeof(TransInvalidationInfo));
700
701 /* Now, do we have a previous stack entry? */
702 if (transInvalInfo != NULL)
703 {
704 /* Yes; this one should be for a deeper nesting level. */
705 Assert(myInfo->my_level > transInvalInfo->my_level);
706
707 /*
708 * The parent (sub)transaction must not have any current (i.e.,
709 * not-yet-locally-processed) messages. If it did, we'd have a
710 * semantic problem: the new subtransaction presumably ought not be
711 * able to see those events yet, but since the CommandCounter is
712 * linear, that can't work once the subtransaction advances the
713 * counter. This is a convenient place to check for that, as well as
714 * being important to keep management of the message arrays simple.
715 */
717 elog(ERROR, "cannot start a subtransaction when there are unprocessed inval messages");
718
719 /*
720 * MemoryContextAllocZero set firstmsg = nextmsg = 0 in each group,
721 * which is fine for the first (sub)transaction, but otherwise we need
722 * to update them to follow whatever is already in the arrays.
723 */
724 SetGroupToFollow(&myInfo->PriorCmdInvalidMsgs,
726 SetGroupToFollow(&myInfo->ii.CurrentCmdInvalidMsgs,
727 &myInfo->PriorCmdInvalidMsgs);
728 }
729 else
730 {
731 /*
732 * Here, we need only clear any array pointers left over from a prior
733 * transaction.
734 */
739 }
740
742 return (InvalidationInfo *) myInfo;
743}

References Assert, AssertCouldGetRelation(), CatCacheMsgs, InvalidationInfo::CurrentCmdInvalidMsgs, elog, ERROR, fb(), GetCurrentTransactionNestLevel(), TransInvalidationInfo::ii, inplaceInvalInfo, InvalMessageArrays, InvalMessageArray::maxmsgs, MemoryContextAllocZero(), InvalMessageArray::msgs, TransInvalidationInfo::my_level, NumMessagesInGroup, TransInvalidationInfo::parent, RelCacheMsgs, SetGroupToFollow, TopTransactionContext, and transInvalInfo.

Referenced by CacheInvalidateCatalog(), CacheInvalidateHeapTuple(), CacheInvalidateRelcache(), CacheInvalidateRelcacheAll(), CacheInvalidateRelcacheByTuple(), and CacheInvalidateRelSync().

◆ ProcessCommittedInvalidationMessages()

void ProcessCommittedInvalidationMessages ( SharedInvalidationMessage msgs,
int  nmsgs,
bool  RelcacheInitFileInval,
Oid  dbid,
Oid  tsid 
)

Definition at line 1135 of file inval.c.

1138{
1139 if (nmsgs <= 0)
1140 return;
1141
1142 elog(DEBUG4, "replaying commit with %d messages%s", nmsgs,
1143 (RelcacheInitFileInval ? " and relcache file invalidation" : ""));
1144
1145 if (RelcacheInitFileInval)
1146 {
1147 elog(DEBUG4, "removing relcache init files for database %u", dbid);
1148
1149 /*
1150 * RelationCacheInitFilePreInvalidate, when the invalidation message
1151 * is for a specific database, requires DatabasePath to be set, but we
1152 * should not use SetDatabasePath during recovery, since it is
1153 * intended to be used only once by normal backends. Hence, a quick
1154 * hack: set DatabasePath directly then unset after use.
1155 */
1156 if (OidIsValid(dbid))
1157 DatabasePath = GetDatabasePath(dbid, tsid);
1158
1160
1161 if (OidIsValid(dbid))
1162 {
1165 }
1166 }
1167
1168 SendSharedInvalidMessages(msgs, nmsgs);
1169
1170 if (RelcacheInitFileInval)
1172}

References DatabasePath, DEBUG4, elog, fb(), GetDatabasePath(), OidIsValid, pfree(), RelationCacheInitFilePostInvalidate(), RelationCacheInitFilePreInvalidate(), and SendSharedInvalidMessages().

Referenced by heap_xlog_inplace(), standby_redo(), and xact_redo_commit().

◆ ProcessInvalidationMessages()

static void ProcessInvalidationMessages ( InvalidationMsgsGroup group,
void(*)(SharedInvalidationMessage *msg)  func 
)
static

Definition at line 574 of file inval.c.

576{
577 ProcessMessageSubGroup(group, CatCacheMsgs, func(msg));
578 ProcessMessageSubGroup(group, RelCacheMsgs, func(msg));
579}

References CatCacheMsgs, ProcessMessageSubGroup, and RelCacheMsgs.

Referenced by AtEOSubXact_Inval(), AtEOXact_Inval(), and CommandEndInvalidationMessages().

◆ ProcessInvalidationMessagesMulti()

static void ProcessInvalidationMessagesMulti ( InvalidationMsgsGroup group,
void(*)(const SharedInvalidationMessage *msgs, int n)  func 
)
static

Definition at line 586 of file inval.c.

588{
589 ProcessMessageSubGroupMulti(group, CatCacheMsgs, func(msgs, n));
590 ProcessMessageSubGroupMulti(group, RelCacheMsgs, func(msgs, n));
591}

References CatCacheMsgs, ProcessMessageSubGroupMulti, and RelCacheMsgs.

Referenced by AtEOXact_Inval(), and AtInplace_Inval().

◆ RegisterCatalogInvalidation()

static void RegisterCatalogInvalidation ( InvalidationInfo info,
Oid  dbId,
Oid  catId 
)
static

Definition at line 621 of file inval.c.

622{
624}

References AddCatalogInvalidationMessage(), and InvalidationInfo::CurrentCmdInvalidMsgs.

Referenced by CacheInvalidateCatalog().

◆ RegisterCatcacheInvalidation()

static void RegisterCatcacheInvalidation ( int  cacheId,
uint32  hashValue,
Oid  dbId,
void context 
)
static

Definition at line 604 of file inval.c.

608{
609 InvalidationInfo *info = (InvalidationInfo *) context;
610
612 cacheId, hashValue, dbId);
613}

References AddCatcacheInvalidationMessage(), and InvalidationInfo::CurrentCmdInvalidMsgs.

Referenced by CacheInvalidateHeapTupleCommon().

◆ RegisterRelcacheInvalidation()

static void RegisterRelcacheInvalidation ( InvalidationInfo info,
Oid  dbId,
Oid  relId 
)
static

Definition at line 632 of file inval.c.

633{
635
636 /*
637 * Most of the time, relcache invalidation is associated with system
638 * catalog updates, but there are a few cases where it isn't. Quick hack
639 * to ensure that the next CommandCounterIncrement() will think that we
640 * need to do CommandEndInvalidationMessages().
641 */
643
644 /*
645 * If the relation being invalidated is one of those cached in a relcache
646 * init file, mark that we need to zap that file at commit. For simplicity
647 * invalidations for a specific database always invalidate the shared file
648 * as well. Also zap when we are invalidating whole relcache.
649 */
650 if (relId == InvalidOid || RelationIdIsInInitFile(relId))
651 info->RelcacheInitFileInval = true;
652}

References AddRelcacheInvalidationMessage(), InvalidationInfo::CurrentCmdInvalidMsgs, fb(), GetCurrentCommandId(), InvalidOid, RelationIdIsInInitFile(), and InvalidationInfo::RelcacheInitFileInval.

Referenced by CacheInvalidateHeapTupleCommon(), CacheInvalidateRelcache(), CacheInvalidateRelcacheAll(), and CacheInvalidateRelcacheByTuple().

◆ RegisterRelsyncInvalidation()

static void RegisterRelsyncInvalidation ( InvalidationInfo info,
Oid  dbId,
Oid  relId 
)
static

Definition at line 660 of file inval.c.

661{
663}

References AddRelsyncInvalidationMessage(), and InvalidationInfo::CurrentCmdInvalidMsgs.

Referenced by CacheInvalidateRelSync().

◆ RegisterSnapshotInvalidation()

static void RegisterSnapshotInvalidation ( InvalidationInfo info,
Oid  dbId,
Oid  relId 
)
static

◆ xactGetCommittedInvalidationMessages()

int xactGetCommittedInvalidationMessages ( SharedInvalidationMessage **  msgs,
bool RelcacheInitFileInval 
)

Definition at line 1012 of file inval.c.

1014{
1016 int nummsgs;
1017 int nmsgs;
1018
1019 /* Quick exit if we haven't done anything with invalidation messages. */
1020 if (transInvalInfo == NULL)
1021 {
1022 *RelcacheInitFileInval = false;
1023 *msgs = NULL;
1024 return 0;
1025 }
1026
1027 /* Must be at top of stack */
1029
1030 /*
1031 * Relcache init file invalidation requires processing both before and
1032 * after we send the SI messages. However, we need not do anything unless
1033 * we committed.
1034 */
1035 *RelcacheInitFileInval = transInvalInfo->ii.RelcacheInitFileInval;
1036
1037 /*
1038 * Collect all the pending messages into a single contiguous array of
1039 * invalidation messages, to simplify what needs to happen while building
1040 * the commit WAL message. Maintain the order that they would be
1041 * processed in by AtEOXact_Inval(), to ensure emulated behaviour in redo
1042 * is as similar as possible to original. We want the same bugs, if any,
1043 * not new ones.
1044 */
1047
1051
1052 nmsgs = 0;
1055 (memcpy(msgarray + nmsgs,
1056 msgs,
1057 n * sizeof(SharedInvalidationMessage)),
1058 nmsgs += n));
1061 (memcpy(msgarray + nmsgs,
1062 msgs,
1063 n * sizeof(SharedInvalidationMessage)),
1064 nmsgs += n));
1067 (memcpy(msgarray + nmsgs,
1068 msgs,
1069 n * sizeof(SharedInvalidationMessage)),
1070 nmsgs += n));
1073 (memcpy(msgarray + nmsgs,
1074 msgs,
1075 n * sizeof(SharedInvalidationMessage)),
1076 nmsgs += n));
1077 Assert(nmsgs == nummsgs);
1078
1079 return nmsgs;
1080}

References Assert, CatCacheMsgs, InvalidationInfo::CurrentCmdInvalidMsgs, CurTransactionContext, fb(), TransInvalidationInfo::ii, memcpy(), MemoryContextAlloc(), TransInvalidationInfo::my_level, NumMessagesInGroup, TransInvalidationInfo::parent, TransInvalidationInfo::PriorCmdInvalidMsgs, ProcessMessageSubGroupMulti, InvalidationInfo::RelcacheInitFileInval, RelCacheMsgs, and transInvalInfo.

Referenced by RecordTransactionCommit(), and StartPrepare().

Variable Documentation

◆ debug_discard_caches

int debug_discard_caches = 0

Definition at line 260 of file inval.c.

Referenced by AcceptInvalidationMessages(), LookupOpclassInfo(), and RelationBuildDesc().

◆ inplaceInvalInfo

◆ InvalMessageArrays

InvalMessageArray InvalMessageArrays[2]
static

◆ relcache_callback_count

int relcache_callback_count = 0
static

◆ relcache_callback_list

◆ relsync_callback_count

int relsync_callback_count = 0
static

◆ relsync_callback_list

◆ syscache_callback_count

int syscache_callback_count = 0
static

Definition at line 286 of file inval.c.

Referenced by CacheRegisterSyscacheCallback(), and InvalidateSystemCachesExtended().

◆ syscache_callback_links

int16 syscache_callback_links[SysCacheSize]
static

Definition at line 284 of file inval.c.

Referenced by CacheRegisterSyscacheCallback(), and CallSyscacheCallbacks().

◆ syscache_callback_list

◆ transInvalInfo