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 (int cacheid, SyscacheCallbackFunction func, Datum arg)
 
void CacheRegisterRelcacheCallback (RelcacheCallbackFunction func, Datum arg)
 
void CacheRegisterRelSyncCallback (RelSyncCallbackFunction func, Datum arg)
 
void CallSyscacheCallbacks (int 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 *
1194 * Note:
1195 * This should be called as the last step in processing a transaction.
1196 */
1197void
1199{
1201
1202 /* Quick exit if no transactional messages */
1203 if (transInvalInfo == NULL)
1204 return;
1205
1206 /* Must be at top of stack */
1208
1209 INJECTION_POINT("transaction-end-process-inval", NULL);
1210
1211 if (isCommit)
1212 {
1213 /*
1214 * Relcache init file invalidation requires processing both before and
1215 * after we send the SI messages. However, we need not do anything
1216 * unless we committed.
1217 */
1220
1223
1226
1229 }
1230 else
1231 {
1234 }
1235
1236 /* Need not free anything explicitly */
1238}
1239
1240/*
1241 * PreInplace_Inval
1242 * Process queued-up invalidation before inplace update critical section.
1243 *
1244 * Tasks belong here if they are safe even if the inplace update does not
1245 * complete. Currently, this just unlinks a cache file, which can fail. The
1246 * sum of this and AtInplace_Inval() mirrors AtEOXact_Inval(isCommit=true).
1247 */
1248void
1249PreInplace_Inval(void)
1250{
1252
1255}
1256
1257/*
1258 * AtInplace_Inval
1259 * Process queued-up invalidations after inplace update buffer mutation.
1260 */
1261void
1262AtInplace_Inval(void)
1263{
1265
1266 if (inplaceInvalInfo == NULL)
1267 return;
1268
1271
1274
1276}
1277
1278/*
1279 * ForgetInplace_Inval
1280 * Alternative to PreInplace_Inval()+AtInplace_Inval(): discard queued-up
1281 * invalidations. This lets inplace update enumerate invalidations
1282 * optimistically, before locking the buffer.
1283 */
1284void
1286{
1288}
1289
1290/*
1291 * AtEOSubXact_Inval
1292 * Process queued-up invalidation messages at end of subtransaction.
1293 *
1294 * If isCommit, process CurrentCmdInvalidMsgs if any (there probably aren't),
1295 * and then attach both CurrentCmdInvalidMsgs and PriorCmdInvalidMsgs to the
1296 * parent's PriorCmdInvalidMsgs list.
1297 *
1298 * If not isCommit, we are aborting, and must locally process the messages
1299 * in PriorCmdInvalidMsgs. No messages need be sent to other backends.
1300 * We can forget about CurrentCmdInvalidMsgs too, since those changes haven't
1301 * touched the caches yet.
1302 *
1303 * In any case, pop the transaction stack. We need not physically free memory
1304 * here, since CurTransactionContext is about to be emptied anyway
1305 * (if aborting). Beware of the possibility of aborting the same nesting
1306 * level twice, though.
1307 */
1308void
1310{
1311 int my_level;
1313
1314 /*
1315 * Successful inplace update must clear this, but we clear it on abort.
1316 * Inplace updates allocate this in CurrentMemoryContext, which has
1317 * lifespan <= subtransaction lifespan. Hence, don't free it explicitly.
1318 */
1319 if (isCommit)
1321 else
1323
1324 /* Quick exit if no transactional messages. */
1326 if (myInfo == NULL)
1327 return;
1328
1329 /* Also bail out quickly if messages are not for this level. */
1330 my_level = GetCurrentTransactionNestLevel();
1331 if (myInfo->my_level != my_level)
1332 {
1333 Assert(myInfo->my_level < my_level);
1334 return;
1335 }
1336
1337 if (isCommit)
1338 {
1339 /* If CurrentCmdInvalidMsgs still has anything, fix it */
1341
1342 /*
1343 * We create invalidation stack entries lazily, so the parent might
1344 * not have one. Instead of creating one, moving all the data over,
1345 * and then freeing our own, we can just adjust the level of our own
1346 * entry.
1347 */
1348 if (myInfo->parent == NULL || myInfo->parent->my_level < my_level - 1)
1349 {
1350 myInfo->my_level--;
1351 return;
1352 }
1353
1354 /*
1355 * Pass up my inval messages to parent. Notice that we stick them in
1356 * PriorCmdInvalidMsgs, not CurrentCmdInvalidMsgs, since they've
1357 * already been locally processed. (This would trigger the Assert in
1358 * AppendInvalidationMessageSubGroup if the parent's
1359 * CurrentCmdInvalidMsgs isn't empty; but we already checked that in
1360 * PrepareInvalidationState.)
1361 */
1362 AppendInvalidationMessages(&myInfo->parent->PriorCmdInvalidMsgs,
1363 &myInfo->PriorCmdInvalidMsgs);
1364
1365 /* Must readjust parent's CurrentCmdInvalidMsgs indexes now */
1366 SetGroupToFollow(&myInfo->parent->ii.CurrentCmdInvalidMsgs,
1367 &myInfo->parent->PriorCmdInvalidMsgs);
1368
1369 /* Pending relcache inval becomes parent's problem too */
1370 if (myInfo->ii.RelcacheInitFileInval)
1371 myInfo->parent->ii.RelcacheInitFileInval = true;
1372
1373 /* Pop the transaction state stack */
1375
1376 /* Need not free anything else explicitly */
1377 pfree(myInfo);
1378 }
1379 else
1380 {
1381 ProcessInvalidationMessages(&myInfo->PriorCmdInvalidMsgs,
1383
1384 /* Pop the transaction state stack */
1386
1387 /* Need not free anything else explicitly */
1388 pfree(myInfo);
1389 }
1390}
1391
1392/*
1393 * CommandEndInvalidationMessages
1394 * Process queued-up invalidation messages at end of one command
1395 * in a transaction.
1396 *
1397 * Here, we send no messages to the shared queue, since we don't know yet if
1398 * we will commit. We do need to locally process the CurrentCmdInvalidMsgs
1399 * list, so as to flush our caches of any entries we have outdated in the
1400 * current command. We then move the current-cmd list over to become part
1401 * of the prior-cmds list.
1402 *
1403 * Note:
1404 * This should be called during CommandCounterIncrement(),
1405 * after we have advanced the command ID.
1406 */
1407void
1409{
1410 /*
1411 * You might think this shouldn't be called outside any transaction, but
1412 * bootstrap does it, and also ABORT issued when not in a transaction. So
1413 * just quietly return if no state to work on.
1414 */
1415 if (transInvalInfo == NULL)
1416 return;
1417
1420
1421 /* WAL Log per-command invalidation messages for logical decoding */
1424
1427}
1428
1429
1430/*
1431 * CacheInvalidateHeapTupleCommon
1432 * Common logic for end-of-command and inplace variants.
1433 */
1434static void
1436 HeapTuple tuple,
1437 HeapTuple newtuple,
1439{
1440 InvalidationInfo *info;
1442 Oid databaseId;
1444
1445 /* PrepareToInvalidateCacheTuple() needs relcache */
1447
1448 /* Do nothing during bootstrap */
1450 return;
1451
1452 /*
1453 * We only need to worry about invalidation for tuples that are in system
1454 * catalogs; user-relation tuples are never in catcaches and can't affect
1455 * the relcache either.
1456 */
1457 if (!IsCatalogRelation(relation))
1458 return;
1459
1460 /*
1461 * IsCatalogRelation() will return true for TOAST tables of system
1462 * catalogs, but we don't care about those, either.
1463 */
1464 if (IsToastRelation(relation))
1465 return;
1466
1467 /* Allocate any required resources. */
1468 info = prepare_callback();
1469
1470 /*
1471 * First let the catcache do its thing
1472 */
1473 tupleRelId = RelationGetRelid(relation);
1475 {
1477 RegisterSnapshotInvalidation(info, databaseId, tupleRelId);
1478 }
1479 else
1480 PrepareToInvalidateCacheTuple(relation, tuple, newtuple,
1482 info);
1483
1484 /*
1485 * Now, is this tuple one of the primary definers of a relcache entry? See
1486 * comments in file header for deeper explanation.
1487 *
1488 * Note we ignore newtuple here; we assume an update cannot move a tuple
1489 * from being part of one relcache entry to being part of another.
1490 */
1492 {
1494
1495 relationId = classtup->oid;
1496 if (classtup->relisshared)
1497 databaseId = InvalidOid;
1498 else
1499 databaseId = MyDatabaseId;
1500 }
1501 else if (tupleRelId == AttributeRelationId)
1502 {
1504
1505 relationId = atttup->attrelid;
1506
1507 /*
1508 * KLUGE ALERT: we always send the relcache event with MyDatabaseId,
1509 * even if the rel in question is shared (which we can't easily tell).
1510 * This essentially means that only backends in this same database
1511 * will react to the relcache flush request. This is in fact
1512 * appropriate, since only those backends could see our pg_attribute
1513 * change anyway. It looks a bit ugly though. (In practice, shared
1514 * relations can't have schema changes after bootstrap, so we should
1515 * never come here for a shared rel anyway.)
1516 */
1517 databaseId = MyDatabaseId;
1518 }
1519 else if (tupleRelId == IndexRelationId)
1520 {
1522
1523 /*
1524 * When a pg_index row is updated, we should send out a relcache inval
1525 * for the index relation. As above, we don't know the shared status
1526 * of the index, but in practice it doesn't matter since indexes of
1527 * shared catalogs can't have such updates.
1528 */
1529 relationId = indextup->indexrelid;
1530 databaseId = MyDatabaseId;
1531 }
1532 else if (tupleRelId == ConstraintRelationId)
1533 {
1535
1536 /*
1537 * Foreign keys are part of relcache entries, too, so send out an
1538 * inval for the table that the FK applies to.
1539 */
1540 if (constrtup->contype == CONSTRAINT_FOREIGN &&
1541 OidIsValid(constrtup->conrelid))
1542 {
1543 relationId = constrtup->conrelid;
1544 databaseId = MyDatabaseId;
1545 }
1546 else
1547 return;
1548 }
1549 else
1550 return;
1551
1552 /*
1553 * Yes. We need to register a relcache invalidation event.
1554 */
1555 RegisterRelcacheInvalidation(info, databaseId, relationId);
1556}
1557
1558/*
1559 * CacheInvalidateHeapTuple
1560 * Register the given tuple for invalidation at end of command
1561 * (ie, current command is creating or outdating this tuple) and end of
1562 * transaction. Also, detect whether a relcache invalidation is implied.
1563 *
1564 * For an insert or delete, tuple is the target tuple and newtuple is NULL.
1565 * For an update, we are called just once, with tuple being the old tuple
1566 * version and newtuple the new version. This allows avoidance of duplicate
1567 * effort during an update.
1568 */
1569void
1571 HeapTuple tuple,
1572 HeapTuple newtuple)
1573{
1574 CacheInvalidateHeapTupleCommon(relation, tuple, newtuple,
1576}
1577
1578/*
1579 * CacheInvalidateHeapTupleInplace
1580 * Register the given tuple for nontransactional invalidation pertaining
1581 * to an inplace update. Also, detect whether a relcache invalidation is
1582 * implied.
1583 *
1584 * Like CacheInvalidateHeapTuple(), but for inplace updates.
1585 *
1586 * Just before and just after the inplace update, the tuple's cache keys must
1587 * match those in key_equivalent_tuple. Cache keys consist of catcache lookup
1588 * key columns and columns referencing pg_class.oid values,
1589 * e.g. pg_constraint.conrelid, which would trigger relcache inval.
1590 */
1591void
1594{
1597}
1598
1599/*
1600 * CacheInvalidateCatalog
1601 * Register invalidation of the whole content of a system catalog.
1602 *
1603 * This is normally used in VACUUM FULL/CLUSTER, where we haven't so much
1604 * changed any tuples as moved them around. Some uses of catcache entries
1605 * expect their TIDs to be correct, so we have to blow away the entries.
1606 *
1607 * Note: we expect caller to verify that the rel actually is a system
1608 * catalog. If it isn't, no great harm is done, just a wasted sinval message.
1609 */
1610void
1611CacheInvalidateCatalog(Oid catalogId)
1612{
1613 Oid databaseId;
1614
1615 if (IsSharedRelation(catalogId))
1616 databaseId = InvalidOid;
1617 else
1618 databaseId = MyDatabaseId;
1619
1621 databaseId, catalogId);
1622}
1623
1624/*
1625 * CacheInvalidateRelcache
1626 * Register invalidation of the specified relation's relcache entry
1627 * at end of command.
1628 *
1629 * This is used in places that need to force relcache rebuild but aren't
1630 * changing any of the tuples recognized as contributors to the relcache
1631 * entry by CacheInvalidateHeapTuple. (An example is dropping an index.)
1632 */
1633void
1635{
1636 Oid databaseId;
1638
1639 relationId = RelationGetRelid(relation);
1640 if (relation->rd_rel->relisshared)
1641 databaseId = InvalidOid;
1642 else
1643 databaseId = MyDatabaseId;
1644
1646 databaseId, relationId);
1647}
1648
1649/*
1650 * CacheInvalidateRelcacheAll
1651 * Register invalidation of the whole relcache at the end of command.
1652 *
1653 * This is used by alter publication as changes in publications may affect
1654 * large number of tables.
1655 */
1656void
1658{
1661}
1662
1663/*
1664 * CacheInvalidateRelcacheByTuple
1665 * As above, but relation is identified by passing its pg_class tuple.
1666 */
1667void
1669{
1671 Oid databaseId;
1673
1674 relationId = classtup->oid;
1675 if (classtup->relisshared)
1676 databaseId = InvalidOid;
1677 else
1678 databaseId = MyDatabaseId;
1680 databaseId, relationId);
1681}
1682
1683/*
1684 * CacheInvalidateRelcacheByRelid
1685 * As above, but relation is identified by passing its OID.
1686 * This is the least efficient of the three options; use one of
1687 * the above routines if you have a Relation or pg_class tuple.
1688 */
1689void
1691{
1692 HeapTuple tup;
1693
1695 if (!HeapTupleIsValid(tup))
1696 elog(ERROR, "cache lookup failed for relation %u", relid);
1699}
1700
1701/*
1702 * CacheInvalidateRelSync
1703 * Register invalidation of the cache in logical decoding output plugin
1704 * for a database.
1705 *
1706 * This type of invalidation message is used for the specific purpose of output
1707 * plugins. Processes which do not decode WALs would do nothing even when it
1708 * receives the message.
1709 */
1710void
1712{
1714 MyDatabaseId, relid);
1715}
1716
1717/*
1718 * CacheInvalidateRelSyncAll
1719 * Register invalidation of the whole cache in logical decoding output
1720 * plugin.
1721 */
1722void
1724{
1726}
1727
1728/*
1729 * CacheInvalidateSmgr
1730 * Register invalidation of smgr references to a physical relation.
1731 *
1732 * Sending this type of invalidation msg forces other backends to close open
1733 * smgr entries for the rel. This should be done to flush dangling open-file
1734 * references when the physical rel is being dropped or truncated. Because
1735 * these are nontransactional (i.e., not-rollback-able) operations, we just
1736 * send the inval message immediately without any queuing.
1737 *
1738 * Note: in most cases there will have been a relcache flush issued against
1739 * the rel at the logical level. We need a separate smgr-level flush because
1740 * it is possible for backends to have open smgr entries for rels they don't
1741 * have a relcache entry for, e.g. because the only thing they ever did with
1742 * the rel is write out dirty shared buffers.
1743 *
1744 * Note: because these messages are nontransactional, they won't be captured
1745 * in commit/abort WAL entries. Instead, calls to CacheInvalidateSmgr()
1746 * should happen in low-level smgr.c routines, which are executed while
1747 * replaying WAL as well as when creating it.
1748 *
1749 * Note: In order to avoid bloating SharedInvalidationMessage, we store only
1750 * three bytes of the ProcNumber using what would otherwise be padding space.
1751 * Thus, the maximum possible ProcNumber is 2^23-1.
1752 */
1753void
1755{
1757
1758 /* verify optimization stated above stays valid */
1760 "MAX_BACKENDS_BITS is too big for inval.c");
1761
1762 msg.sm.id = SHAREDINVALSMGR_ID;
1763 msg.sm.backend_hi = rlocator.backend >> 16;
1764 msg.sm.backend_lo = rlocator.backend & 0xffff;
1765 msg.sm.rlocator = rlocator.locator;
1766 /* check AddCatcacheInvalidationMessage() for an explanation */
1767 VALGRIND_MAKE_MEM_DEFINED(&msg, sizeof(msg));
1768
1770}
1771
1772/*
1773 * CacheInvalidateRelmap
1774 * Register invalidation of the relation mapping for a database,
1775 * or for the shared catalogs if databaseId is zero.
1776 *
1777 * Sending this type of invalidation msg forces other backends to re-read
1778 * the indicated relation mapping file. It is also necessary to send a
1779 * relcache inval for the specific relations whose mapping has been altered,
1780 * else the relcache won't get updated with the new filenode data.
1781 *
1782 * Note: because these messages are nontransactional, they won't be captured
1783 * in commit/abort WAL entries. Instead, calls to CacheInvalidateRelmap()
1784 * should happen in low-level relmapper.c routines, which are executed while
1785 * replaying WAL as well as when creating it.
1786 */
1787void
1788CacheInvalidateRelmap(Oid databaseId)
1789{
1791
1793 msg.rm.dbId = databaseId;
1794 /* check AddCatcacheInvalidationMessage() for an explanation */
1795 VALGRIND_MAKE_MEM_DEFINED(&msg, sizeof(msg));
1796
1798}
1799
1800
1801/*
1802 * CacheRegisterSyscacheCallback
1803 * Register the specified function to be called for all future
1804 * invalidation events in the specified cache. The cache ID and the
1805 * hash value of the tuple being invalidated will be passed to the
1806 * function.
1807 *
1808 * NOTE: Hash value zero will be passed if a cache reset request is received.
1809 * In this case the called routines should flush all cached state.
1810 * Yes, there's a possibility of a false match to zero, but it doesn't seem
1811 * worth troubling over, especially since most of the current callees just
1812 * flush all cached state anyway.
1813 */
1814void
1817 Datum arg)
1818{
1820 elog(FATAL, "invalid cache ID: %d", cacheid);
1822 elog(FATAL, "out of syscache_callback_list slots");
1823
1825 {
1826 /* first callback for this cache */
1828 }
1829 else
1830 {
1831 /* add to end of chain, so that older callbacks are called first */
1833
1834 while (syscache_callback_list[i].link > 0)
1837 }
1838
1843
1845}
1846
1847/*
1848 * CacheRegisterRelcacheCallback
1849 * Register the specified function to be called for all future
1850 * relcache invalidation events. The OID of the relation being
1851 * invalidated will be passed to the function.
1852 *
1853 * NOTE: InvalidOid will be passed if a cache reset request is received.
1854 * In this case the called routines should flush all cached state.
1855 */
1856void
1858 Datum arg)
1859{
1861 elog(FATAL, "out of relcache_callback_list slots");
1862
1865
1867}
1868
1869/*
1870 * CacheRegisterRelSyncCallback
1871 * Register the specified function to be called for all future
1872 * relsynccache invalidation events.
1873 *
1874 * This function is intended to be call from the logical decoding output
1875 * plugins.
1876 */
1877void
1879 Datum arg)
1880{
1882 elog(FATAL, "out of relsync_callback_list slots");
1883
1886
1888}
1889
1890/*
1891 * CallSyscacheCallbacks
1892 *
1893 * This is exported so that CatalogCacheFlushCatalog can call it, saving
1894 * this module from knowing which catcache IDs correspond to which catalogs.
1895 */
1896void
1897CallSyscacheCallbacks(int cacheid, uint32 hashvalue)
1898{
1899 int i;
1900
1902 elog(ERROR, "invalid cache ID: %d", cacheid);
1903
1905 while (i >= 0)
1906 {
1908
1909 Assert(ccitem->id == cacheid);
1910 ccitem->function(ccitem->arg, cacheid, hashvalue);
1911 i = ccitem->link - 1;
1912 }
1913}
1914
1915/*
1916 * CallSyscacheCallbacks
1917 */
1918void
1920{
1921 for (int i = 0; i < relsync_callback_count; i++)
1922 {
1924
1925 ccitem->function(ccitem->arg, relid);
1926 }
1927}
1928
1929/*
1930 * LogLogicalInvalidations
1931 *
1932 * Emit WAL for invalidations caused by the current command.
1933 *
1934 * This is currently only used for logging invalidations at the command end
1935 * or at commit time if any invalidations are pending.
1936 */
1937void
1939{
1941 InvalidationMsgsGroup *group;
1942 int nmsgs;
1943
1944 /* Quick exit if we haven't done anything with invalidation messages. */
1945 if (transInvalInfo == NULL)
1946 return;
1947
1949 nmsgs = NumMessagesInGroup(group);
1950
1951 if (nmsgs > 0)
1952 {
1953 /* prepare record */
1955 xlrec.nmsgs = nmsgs;
1956
1957 /* perform insertion */
1961 XLogRegisterData(msgs,
1962 n * sizeof(SharedInvalidationMessage)));
1964 XLogRegisterData(msgs,
1965 n * sizeof(SharedInvalidationMessage)));
1967 }
1968}
#define Assert(condition)
Definition c.h:873
int16_t int16
Definition c.h:541
int8_t int8
Definition c.h:540
uint32_t uint32
Definition c.h:546
#define StaticAssertDecl(condition, errmessage)
Definition c.h:942
#define OidIsValid(objectId)
Definition c.h:788
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:2394
void CatalogCacheFlushCatalog(Oid catId)
Definition catcache.c:841
void ResetCatalogCachesExt(bool debug_discard)
Definition catcache.c:811
static int recursion_depth
Definition elog.c:150
#define FATAL
Definition elog.h:41
#define ERROR
Definition elog.h:39
#define elog(elevel,...)
Definition elog.h:226
#define DEBUG4
Definition elog.h:27
#define palloc0_object(type)
Definition fe_memutils.h:75
volatile uint32 CritSectionCount
Definition globals.c:45
char * DatabasePath
Definition globals.c:104
Oid MyDatabaseId
Definition globals.c:94
#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:1920
static void AddCatcacheInvalidationMessage(InvalidationMsgsGroup *group, int id, uint32 hashValue, Oid dbId)
Definition inval.c:425
void CacheInvalidateRelSyncAll(void)
Definition inval.c:1724
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:1939
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:1789
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:1612
#define ProcessMessageSubGroupMulti(group, subgroup, codeFragment)
Definition inval.c:402
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
void CallSyscacheCallbacks(int cacheid, uint32 hashvalue)
Definition inval.c:1898
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:1635
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:1691
void InvalidateSystemCaches(void)
Definition inval.c:916
void AtEOXact_Inval(bool isCommit)
Definition inval.c:1199
#define MAX_SYSCACHE_CALLBACKS
Definition inval.c:272
void CacheInvalidateSmgr(RelFileLocatorBackend rlocator)
Definition inval.c:1755
#define SetGroupToFollow(targetgroup, priorgroup)
Definition inval.c:198
void AtEOSubXact_Inval(bool isCommit)
Definition inval.c:1310
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:1250
void CommandEndInvalidationMessages(void)
Definition inval.c:1409
void CacheInvalidateHeapTupleInplace(Relation relation, HeapTuple key_equivalent_tuple)
Definition inval.c:1593
void AtInplace_Inval(void)
Definition inval.c:1263
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:1858
void CacheRegisterRelSyncCallback(RelSyncCallbackFunction func, Datum arg)
Definition inval.c:1879
void ForgetInplace_Inval(void)
Definition inval.c:1286
#define SetSubGroupToFollow(targetgroup, priorgroup, subgroup)
Definition inval.c:191
void CacheInvalidateRelSync(Oid relid)
Definition inval.c:1712
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:1571
static void CacheInvalidateHeapTupleCommon(Relation relation, HeapTuple tuple, HeapTuple newtuple, InvalidationInfo *(*prepare_callback)(void))
Definition inval.c:1436
void CacheInvalidateRelcacheByTuple(HeapTuple classTuple)
Definition inval.c:1669
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:1658
void CacheRegisterSyscacheCallback(int cacheid, SyscacheCallbackFunction func, Datum arg)
Definition inval.c:1816
void(* SyscacheCallbackFunction)(Datum arg, int cacheid, uint32 hashvalue)
Definition inval.h:41
void(* RelcacheCallbackFunction)(Datum arg, Oid relid)
Definition inval.h:42
void(* RelSyncCallbackFunction)(Datum arg, Oid relid)
Definition inval.h:43
int i
Definition isn.c:77
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition mcxt.c:1232
void * MemoryContextAllocZero(MemoryContext context, Size size)
Definition mcxt.c:1266
MemoryContext TopTransactionContext
Definition mcxt.c:171
void * repalloc(void *pointer, Size size)
Definition mcxt.c:1632
void pfree(void *pointer)
Definition mcxt.c:1616
void * palloc(Size size)
Definition mcxt.c:1387
MemoryContext CurTransactionContext
Definition mcxt.c:172
#define VALGRIND_MAKE_MEM_DEFINED(addr, size)
Definition memdebug.h:26
#define IsBootstrapProcessingMode()
Definition miscadmin.h:477
FormData_pg_attribute * Form_pg_attribute
void * arg
FormData_pg_class * Form_pg_class
Definition pg_class.h:156
FormData_pg_constraint * Form_pg_constraint
FormData_pg_index * Form_pg_index
Definition pg_index.h:70
static Datum ObjectIdGetDatum(Oid X)
Definition postgres.h:262
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:514
void RelationCacheInvalidate(bool debug_discard)
Definition relcache.c:2989
void RelationCacheInitFilePostInvalidate(void)
Definition relcache.c:6880
void RelationCacheInitFilePreInvalidate(void)
Definition relcache.c:6855
bool RelationIdIsInInitFile(Oid relationId)
Definition relcache.c:6815
void RelationCacheInvalidateEntry(Oid relationId)
Definition relcache.c:2933
static void AssertCouldGetRelation(void)
Definition relcache.h:44
void RelationMapInvalidate(bool shared)
Definition relmapper.c:468
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 SysCacheInvalidate(int cacheId, uint32 hashValue)
Definition syscache.c:690
void ReleaseSysCache(HeapTuple tuple)
Definition syscache.c:264
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition syscache.c:220
bool RelationInvalidatesSnapshotsOnly(Oid relid)
Definition syscache.c:714
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:930
bool IsTransactionState(void)
Definition xact.c:388
CommandId GetCurrentCommandId(bool used)
Definition xact.c:830
#define MinSizeOfXactInvals
Definition xact.h:308
#define XLOG_XACT_INVALIDATIONS
Definition xact.h:176
#define XLogLogicalInfoActive()
Definition xlog.h:136
XLogRecPtr XLogInsert(RmgrId rmid, uint8 info)
Definition xloginsert.c:478
void XLogRegisterData(const void *data, uint32 len)
Definition xloginsert.c:368
void XLogBeginInsert(void)
Definition xloginsert.c:152

◆ 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 1310 of file inval.c.

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

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 1199 of file inval.c.

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

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 1612 of file inval.c.

1613{
1614 Oid databaseId;
1615
1616 if (IsSharedRelation(catalogId))
1617 databaseId = InvalidOid;
1618 else
1619 databaseId = MyDatabaseId;
1620
1622 databaseId, catalogId);
1623}

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 1436 of file inval.c.

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

References AssertCouldGetRelation(), fb(), 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 1789 of file inval.c.

1790{
1792
1794 msg.rm.dbId = databaseId;
1795 /* check AddCatcacheInvalidationMessage() for an explanation */
1796 VALGRIND_MAKE_MEM_DEFINED(&msg, sizeof(msg));
1797
1799}

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 1724 of file inval.c.

1725{
1727}

References CacheInvalidateRelSync(), and InvalidOid.

Referenced by InvalidatePubRelSyncCache().

◆ CacheInvalidateSmgr()

void CacheInvalidateSmgr ( RelFileLocatorBackend  rlocator)

Definition at line 1755 of file inval.c.

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

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 ( int  cacheid,
SyscacheCallbackFunction  func,
Datum  arg 
)

Definition at line 1816 of file inval.c.

1819{
1821 elog(FATAL, "invalid cache ID: %d", cacheid);
1823 elog(FATAL, "out of syscache_callback_list slots");
1824
1826 {
1827 /* first callback for this cache */
1829 }
1830 else
1831 {
1832 /* add to end of chain, so that older callbacks are called first */
1834
1835 while (syscache_callback_list[i].link > 0)
1838 }
1839
1844
1846}

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(), 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 1920 of file inval.c.

1921{
1922 for (int i = 0; i < relsync_callback_count; i++)
1923 {
1925
1926 ccitem->function(ccitem->arg, relid);
1927 }
1928}

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

Referenced by LocalExecuteInvalidationMessage().

◆ CallSyscacheCallbacks()

void CallSyscacheCallbacks ( int  cacheid,
uint32  hashvalue 
)

Definition at line 1898 of file inval.c.

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

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 1409 of file inval.c.

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

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 1286 of file inval.c.

1287{
1289}

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, 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 1939 of file inval.c.

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

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, 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