1 /*-------------------------------------------------------------------------
4 * POSTGRES cache invalidation dispatcher code.
6 * Copyright (c) 1994, Regents of the University of California
10 * $Header: /cvsroot/pgsql/src/backend/utils/cache/inval.c,v 1.22 1999/05/10 00:46:07 momjian Exp $
12 * Note - this code is real crufty...
14 *-------------------------------------------------------------------------
18 #include <miscadmin.h>
20 #include "access/heapam.h" /* XXX to support hacks below */
21 #include "access/htup.h"
22 #include "catalog/catalog.h"
23 #include "catalog/heap.h"
24 #include "storage/bufpage.h"
25 #include "storage/buf.h" /* XXX for InvalidBuffer */
26 #include "storage/ipc.h"
27 #include "storage/sinval.h"
28 #include "utils/catcache.h"
29 #include "utils/inval.h"
30 #include "utils/rel.h"
31 #include "utils/relcache.h"
32 #include "catalog/catname.h" /* XXX to support hacks below */
33 #include "utils/syscache.h" /* XXX to support the hacks below */
35 static InvalidationEntry InvalidationEntryAllocate(uint16 size);
36 static void LocalInvalidInvalidate(LocalInvalid invalid, void (*function) ());
37 static LocalInvalid LocalInvalidRegister(LocalInvalid invalid,
38 InvalidationEntry entry);
39 static void getmyrelids(void);
43 * private invalidation structures
46 typedef struct CatalogInvalidationData
50 ItemPointerData pointerData;
51 } CatalogInvalidationData;
53 typedef struct RelationInvalidationData
57 } RelationInvalidationData;
59 typedef union AnyInvalidation
61 CatalogInvalidationData catalog;
62 RelationInvalidationData relation;
65 typedef struct InvalidationMessageData
69 } InvalidationMessageData;
71 typedef InvalidationMessageData *InvalidationMessage;
74 * variables and macros
77 static LocalInvalid Invalid = EmptyLocalInvalid; /* XXX global */
79 Oid MyRelationRelationId = InvalidOid;
80 Oid MyAttributeRelationId = InvalidOid;
81 Oid MyAMRelationId = InvalidOid;
82 Oid MyAMOPRelationId = InvalidOid;
84 #define ValidateHacks() \
85 if (!OidIsValid(MyRelationRelationId)) getmyrelids()
87 /* ----------------------------------------------------------------
88 * "local" invalidation support functions
89 * ----------------------------------------------------------------
92 /* --------------------------------
93 * InvalidationEntryAllocate
94 * Allocates an invalidation entry.
95 * --------------------------------
97 static InvalidationEntry
98 InvalidationEntryAllocate(uint16 size)
100 InvalidationEntryData *entryDataP;
102 entryDataP = (InvalidationEntryData *)
103 malloc(sizeof(char *) + size); /* XXX alignment */
104 entryDataP->nextP = NULL;
105 return (Pointer) &entryDataP->userData;
108 /* --------------------------------
109 * LocalInvalidRegister
110 * Returns a new local cache invalidation state containing a new entry.
111 * --------------------------------
114 LocalInvalidRegister(LocalInvalid invalid,
115 InvalidationEntry entry)
117 Assert(PointerIsValid(entry));
119 ((InvalidationUserData *) entry)->dataP[-1] =
120 (InvalidationUserData *) invalid;
125 /* --------------------------------
126 * LocalInvalidInvalidate
127 * Processes, then frees all entries in a local cache
128 * invalidation state.
129 * --------------------------------
132 LocalInvalidInvalidate(LocalInvalid invalid, void (*function) ())
134 InvalidationEntryData *entryDataP;
136 while (PointerIsValid(invalid))
138 entryDataP = (InvalidationEntryData *)
139 &((InvalidationUserData *) invalid)->dataP[-1];
141 if (PointerIsValid(function))
142 (*function) ((Pointer) &entryDataP->userData);
144 invalid = (Pointer) entryDataP->nextP;
146 /* help catch errors */
147 entryDataP->nextP = (InvalidationUserData *) NULL;
149 free((Pointer) entryDataP);
153 /* ----------------------------------------------------------------
154 * private support functions
155 * ----------------------------------------------------------------
157 /* --------------------------------
158 * CacheIdRegisterLocalInvalid
159 * --------------------------------
162 #define CacheIdRegisterLocalInvalid_DEBUG1 \
163 elog(DEBUG, "CacheIdRegisterLocalInvalid(%d, %d, [%d, %d])", \
164 cacheId, hashIndex, ItemPointerGetBlockNumber(pointer), \
165 ItemPointerGetOffsetNumber(pointer))
167 #define CacheIdRegisterLocalInvalid_DEBUG1
168 #endif /* INVALIDDEBUG */
171 CacheIdRegisterLocalInvalid(Index cacheId,
175 InvalidationMessage message;
181 CacheIdRegisterLocalInvalid_DEBUG1;
184 * create a message describing the system catalog tuple
185 * we wish to invalidate.
188 message = (InvalidationMessage)
189 InvalidationEntryAllocate(sizeof(InvalidationMessageData));
192 message->any.catalog.cacheId = cacheId;
193 message->any.catalog.hashIndex = hashIndex;
195 ItemPointerCopy(pointer, &message->any.catalog.pointerData);
198 * Note: Invalid is a global variable
201 Invalid = LocalInvalidRegister(Invalid, (InvalidationEntry) message);
204 /* --------------------------------
205 * RelationIdRegisterLocalInvalid
206 * --------------------------------
209 RelationIdRegisterLocalInvalid(Oid relationId, Oid objectId)
211 InvalidationMessage message;
218 elog(DEBUG, "RelationRegisterLocalInvalid(%u, %u)", relationId,
220 #endif /* defined(INVALIDDEBUG) */
223 * create a message describing the relation descriptor
224 * we wish to invalidate.
227 message = (InvalidationMessage)
228 InvalidationEntryAllocate(sizeof(InvalidationMessageData));
231 message->any.relation.relationId = relationId;
232 message->any.relation.objectId = objectId;
235 * Note: Invalid is a global variable
238 Invalid = LocalInvalidRegister(Invalid, (InvalidationEntry) message);
241 /* --------------------------------
243 * --------------------------------
248 MyRelationRelationId = RelnameFindRelid(RelationRelationName);
249 Assert(RelationRelationName != InvalidOid);
251 MyAttributeRelationId = RelnameFindRelid(AttributeRelationName);
252 Assert(AttributeRelationName != InvalidOid);
254 MyAMRelationId = RelnameFindRelid(AccessMethodRelationName);
255 Assert(MyAMRelationId != InvalidOid);
257 MyAMOPRelationId = RelnameFindRelid(AccessMethodOperatorRelationName);
258 Assert(MyAMOPRelationId != InvalidOid);
261 /* --------------------------------
264 * This routine can invalidate a tuple in a system catalog cache
265 * or a cached relation descriptor. You pay your money and you
266 * take your chances...
267 * --------------------------------
270 #define CacheIdInvalidate_DEBUG1 \
271 elog(DEBUG, "CacheIdInvalidate(%d, %d, 0x%x[%d])", cacheId, hashIndex,\
272 pointer, ItemPointerIsValid(pointer))
274 #define CacheIdInvalidate_DEBUG1
275 #endif /* defined(INVALIDDEBUG) */
278 CacheIdInvalidate(Index cacheId,
283 * assume that if the item pointer is valid, then we are
284 * invalidating an item in the specified system catalog cache.
287 if (ItemPointerIsValid(pointer))
289 CatalogCacheIdInvalidate(cacheId, hashIndex, pointer);
293 CacheIdInvalidate_DEBUG1;
295 ValidateHacks(); /* XXX */
298 * if the cacheId is the oid of any of the tuples in the
299 * following system relations, then assume we are invalidating
300 * a relation descriptor
303 if (cacheId == MyRelationRelationId)
305 RelationIdInvalidateRelationCacheByRelationId(hashIndex);
309 if (cacheId == MyAttributeRelationId)
311 RelationIdInvalidateRelationCacheByRelationId(hashIndex);
315 if (cacheId == MyAMRelationId)
317 RelationIdInvalidateRelationCacheByAccessMethodId(hashIndex);
321 if (cacheId == MyAMOPRelationId)
323 RelationIdInvalidateRelationCacheByAccessMethodId(InvalidOid);
328 * Yow! the caller asked us to invalidate something else.
331 elog(FATAL, "CacheIdInvalidate: cacheId=%d relation id?", cacheId);
334 /* --------------------------------
337 * this blows away all tuples in the system catalog caches and
338 * all the cached relation descriptors (and closes the files too).
339 * --------------------------------
345 RelationCacheInvalidate(false);
348 /* --------------------------------
349 * InvalidationMessageRegisterSharedInvalid
350 * --------------------------------
353 #define InvalidationMessageRegisterSharedInvalid_DEBUG1 \
355 "InvalidationMessageRegisterSharedInvalid(c, %d, %d, [%d, %d])",\
356 message->any.catalog.cacheId,\
357 message->any.catalog.hashIndex,\
358 ItemPointerGetBlockNumber(&message->any.catalog.pointerData),\
359 ItemPointerGetOffsetNumber(&message->any.catalog.pointerData))
360 #define InvalidationMessageRegisterSharedInvalid_DEBUG2 \
362 "InvalidationMessageRegisterSharedInvalid(r, %u, %u)", \
363 message->any.relation.relationId, \
364 message->any.relation.objectId)
366 #define InvalidationMessageRegisterSharedInvalid_DEBUG1
367 #define InvalidationMessageRegisterSharedInvalid_DEBUG2
368 #endif /* INVALIDDEBUG */
371 InvalidationMessageRegisterSharedInvalid(InvalidationMessage message)
373 Assert(PointerIsValid(message));
375 switch (message->kind)
377 case 'c': /* cached system catalog tuple */
378 InvalidationMessageRegisterSharedInvalid_DEBUG1;
380 RegisterSharedInvalid(message->any.catalog.cacheId,
381 message->any.catalog.hashIndex,
382 &message->any.catalog.pointerData);
385 case 'r': /* cached relation descriptor */
386 InvalidationMessageRegisterSharedInvalid_DEBUG2;
388 RegisterSharedInvalid(message->any.relation.relationId,
389 message->any.relation.objectId,
395 "InvalidationMessageRegisterSharedInvalid: `%c' kind",
400 /* --------------------------------
401 * InvalidationMessageCacheInvalidate
402 * --------------------------------
405 #define InvalidationMessageCacheInvalidate_DEBUG1 \
406 elog(DEBUG, "InvalidationMessageCacheInvalidate(c, %d, %d, [%d, %d])",\
407 message->any.catalog.cacheId,\
408 message->any.catalog.hashIndex,\
409 ItemPointerGetBlockNumber(&message->any.catalog.pointerData),\
410 ItemPointerGetOffsetNumber(&message->any.catalog.pointerData))
411 #define InvalidationMessageCacheInvalidate_DEBUG2 \
412 elog(DEBUG, "InvalidationMessageCacheInvalidate(r, %u, %u)", \
413 message->any.relation.relationId, \
414 message->any.relation.objectId)
416 #define InvalidationMessageCacheInvalidate_DEBUG1
417 #define InvalidationMessageCacheInvalidate_DEBUG2
418 #endif /* defined(INVALIDDEBUG) */
421 InvalidationMessageCacheInvalidate(InvalidationMessage message)
423 Assert(PointerIsValid(message));
425 switch (message->kind)
427 case 'c': /* cached system catalog tuple */
428 InvalidationMessageCacheInvalidate_DEBUG1;
430 CatalogCacheIdInvalidate(message->any.catalog.cacheId,
431 message->any.catalog.hashIndex,
432 &message->any.catalog.pointerData);
435 case 'r': /* cached relation descriptor */
436 InvalidationMessageCacheInvalidate_DEBUG2;
438 /* XXX ignore this--is this correct ??? */
442 elog(FATAL, "InvalidationMessageCacheInvalidate: `%c' kind",
447 /* --------------------------------
448 * RelationInvalidateRelationCache
449 * --------------------------------
452 RelationInvalidateRelationCache(Relation relation,
457 Oid objectId = (Oid) 0;
460 * get the relation object id
463 ValidateHacks(); /* XXX */
464 relationId = RelationGetRelid(relation);
470 if (relationId == MyRelationRelationId)
471 objectId = tuple->t_data->t_oid;
472 else if (relationId == MyAttributeRelationId)
473 objectId = ((Form_pg_attribute) GETSTRUCT(tuple))->attrelid;
474 else if (relationId == MyAMRelationId)
475 objectId = tuple->t_data->t_oid;
476 else if (relationId == MyAMOPRelationId)
478 ; /* objectId is unused */
484 * can't handle immediate relation descriptor invalidation
487 Assert(PointerIsValid(function));
489 (*function) (relationId, objectId);
494 * InitLocalInvalidateData
496 * Setup this before anything could ever get invalid!
497 * Called by InitPostgres();
500 InitLocalInvalidateData()
508 * Causes the invalidated cache state to be discarded.
511 * This should be called as the first step in processing a transaction.
512 * This should be called while waiting for a query from the front end
513 * when other backends are active.
523 elog(DEBUG, "DiscardInvalid called");
524 #endif /* defined(INVALIDDEBUG) */
526 InvalidateSharedInvalid(CacheIdInvalidate, ResetSystemCaches);
531 * Causes registration of invalidated state with other backends iff true.
534 * This should be called as the last step in processing a transaction.
537 RegisterInvalid(bool send)
544 elog(DEBUG, "RegisterInvalid(%d) called", send);
545 #endif /* defined(INVALIDDEBUG) */
548 * Note: Invalid is a global variable
552 LocalInvalidInvalidate(Invalid,
553 InvalidationMessageRegisterSharedInvalid);
555 LocalInvalidInvalidate(Invalid,
556 InvalidationMessageCacheInvalidate);
558 Invalid = EmptyLocalInvalid;
562 * RelationIdInvalidateHeapTuple
563 * Causes the given tuple in a relation to be invalidated.
566 * Assumes object id is valid.
567 * Assumes tuple is valid.
570 #define RelationInvalidateHeapTuple_DEBUG1 \
571 elog(DEBUG, "RelationInvalidateHeapTuple(%s, [%d,%d])", \
572 RelationGetRelationName(relation), \
573 ItemPointerGetBlockNumber(&tuple->t_ctid), \
574 ItemPointerGetOffsetNumber(&tuple->t_ctid))
576 #define RelationInvalidateHeapTuple_DEBUG1
577 #endif /* defined(INVALIDDEBUG) */
580 RelationInvalidateHeapTuple(Relation relation, HeapTuple tuple)
586 Assert(RelationIsValid(relation));
587 Assert(HeapTupleIsValid(tuple));
589 if (IsBootstrapProcessingMode())
592 * this only works for system relations now
595 if (!IsSystemRelationName(RelationGetForm(relation)->relname.data))
602 RelationInvalidateHeapTuple_DEBUG1;
604 RelationInvalidateCatalogCacheTuple(relation,
606 CacheIdRegisterLocalInvalid);
608 RelationInvalidateRelationCache(relation,
610 RelationIdRegisterLocalInvalid);