OSDN Git Service

Change error messages to oids come out as %u and not %d. Change has no
[pg-rex/syncrep.git] / src / backend / utils / cache / inval.c
1 /*-------------------------------------------------------------------------
2  *
3  * inval.c
4  *        POSTGRES cache invalidation dispatcher code.
5  *
6  * Copyright (c) 1994, Regents of the University of California
7  *
8  *
9  * IDENTIFICATION
10  *        $Header: /cvsroot/pgsql/src/backend/utils/cache/inval.c,v 1.22 1999/05/10 00:46:07 momjian Exp $
11  *
12  * Note - this code is real crufty...
13  *
14  *-------------------------------------------------------------------------
15  */
16 #include "postgres.h"
17
18 #include <miscadmin.h>
19
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 */
34
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);
40
41
42 /* ----------------
43  *              private invalidation structures
44  * ----------------
45  */
46 typedef struct CatalogInvalidationData
47 {
48         Index           cacheId;
49         Index           hashIndex;
50         ItemPointerData pointerData;
51 } CatalogInvalidationData;
52
53 typedef struct RelationInvalidationData
54 {
55         Oid                     relationId;
56         Oid                     objectId;
57 } RelationInvalidationData;
58
59 typedef union AnyInvalidation
60 {
61         CatalogInvalidationData catalog;
62         RelationInvalidationData relation;
63 } AnyInvalidation;
64
65 typedef struct InvalidationMessageData
66 {
67         char            kind;
68         AnyInvalidation any;
69 } InvalidationMessageData;
70
71 typedef InvalidationMessageData *InvalidationMessage;
72
73 /* ----------------
74  *              variables and macros
75  * ----------------
76  */
77 static LocalInvalid Invalid = EmptyLocalInvalid;                /* XXX global */
78
79 Oid                     MyRelationRelationId = InvalidOid;
80 Oid                     MyAttributeRelationId = InvalidOid;
81 Oid                     MyAMRelationId = InvalidOid;
82 Oid                     MyAMOPRelationId = InvalidOid;
83
84 #define ValidateHacks() \
85         if (!OidIsValid(MyRelationRelationId)) getmyrelids()
86
87 /* ----------------------------------------------------------------
88  *                              "local" invalidation support functions
89  * ----------------------------------------------------------------
90  */
91
92 /* --------------------------------
93  *              InvalidationEntryAllocate
94  *                              Allocates an invalidation entry.
95  * --------------------------------
96  */
97 static InvalidationEntry
98 InvalidationEntryAllocate(uint16 size)
99 {
100         InvalidationEntryData *entryDataP;
101
102         entryDataP = (InvalidationEntryData *)
103                 malloc(sizeof(char *) + size);  /* XXX alignment */
104         entryDataP->nextP = NULL;
105         return (Pointer) &entryDataP->userData;
106 }
107
108 /* --------------------------------
109  *              LocalInvalidRegister 
110  *                 Returns a new local cache invalidation state containing a new entry.
111  * --------------------------------
112  */
113 static LocalInvalid
114 LocalInvalidRegister(LocalInvalid invalid,
115                                          InvalidationEntry entry)
116 {
117         Assert(PointerIsValid(entry));
118
119         ((InvalidationUserData *) entry)->dataP[-1] =
120                         (InvalidationUserData *) invalid;
121
122         return entry;
123 }
124
125 /* --------------------------------
126  *              LocalInvalidInvalidate
127  *                              Processes, then frees all entries in a local cache
128  *                              invalidation state.
129  * --------------------------------
130  */
131 static void
132 LocalInvalidInvalidate(LocalInvalid invalid, void (*function) ())
133 {
134         InvalidationEntryData *entryDataP;
135
136         while (PointerIsValid(invalid))
137         {
138                 entryDataP = (InvalidationEntryData *)
139                         &((InvalidationUserData *) invalid)->dataP[-1];
140
141                 if (PointerIsValid(function))
142                         (*function) ((Pointer) &entryDataP->userData);
143
144                 invalid = (Pointer) entryDataP->nextP;
145
146                 /* help catch errors */
147                 entryDataP->nextP = (InvalidationUserData *) NULL;
148
149                 free((Pointer) entryDataP);
150         }
151 }
152
153 /* ----------------------------------------------------------------
154  *                                        private support functions
155  * ----------------------------------------------------------------
156  */
157 /* --------------------------------
158  *              CacheIdRegisterLocalInvalid
159  * --------------------------------
160  */
161 #ifdef  INVALIDDEBUG
162 #define CacheIdRegisterLocalInvalid_DEBUG1 \
163 elog(DEBUG, "CacheIdRegisterLocalInvalid(%d, %d, [%d, %d])", \
164          cacheId, hashIndex, ItemPointerGetBlockNumber(pointer), \
165          ItemPointerGetOffsetNumber(pointer))
166 #else
167 #define CacheIdRegisterLocalInvalid_DEBUG1
168 #endif   /* INVALIDDEBUG */
169
170 static void
171 CacheIdRegisterLocalInvalid(Index cacheId,
172                                                         Index hashIndex,
173                                                         ItemPointer pointer)
174 {
175         InvalidationMessage message;
176
177         /* ----------------
178          *      debugging stuff
179          * ----------------
180          */
181         CacheIdRegisterLocalInvalid_DEBUG1;
182
183         /* ----------------
184          *      create a message describing the system catalog tuple
185          *      we wish to invalidate.
186          * ----------------
187          */
188         message = (InvalidationMessage)
189                 InvalidationEntryAllocate(sizeof(InvalidationMessageData));
190
191         message->kind = 'c';
192         message->any.catalog.cacheId = cacheId;
193         message->any.catalog.hashIndex = hashIndex;
194
195         ItemPointerCopy(pointer, &message->any.catalog.pointerData);
196
197         /* ----------------
198          *      Note: Invalid is a global variable
199          * ----------------
200          */
201         Invalid = LocalInvalidRegister(Invalid, (InvalidationEntry) message);
202 }
203
204 /* --------------------------------
205  *              RelationIdRegisterLocalInvalid
206  * --------------------------------
207  */
208 static void
209 RelationIdRegisterLocalInvalid(Oid relationId, Oid objectId)
210 {
211         InvalidationMessage message;
212
213         /* ----------------
214          *      debugging stuff
215          * ----------------
216          */
217 #ifdef  INVALIDDEBUG
218         elog(DEBUG, "RelationRegisterLocalInvalid(%u, %u)", relationId,
219                  objectId);
220 #endif   /* defined(INVALIDDEBUG) */
221
222         /* ----------------
223          *      create a message describing the relation descriptor
224          *      we wish to invalidate.
225          * ----------------
226          */
227         message = (InvalidationMessage)
228                 InvalidationEntryAllocate(sizeof(InvalidationMessageData));
229
230         message->kind = 'r';
231         message->any.relation.relationId = relationId;
232         message->any.relation.objectId = objectId;
233
234         /* ----------------
235          *      Note: Invalid is a global variable
236          * ----------------
237          */
238         Invalid = LocalInvalidRegister(Invalid, (InvalidationEntry) message);
239 }
240
241 /* --------------------------------
242  *              getmyrelids
243  * --------------------------------
244  */
245 static void
246 getmyrelids()
247 {
248         MyRelationRelationId = RelnameFindRelid(RelationRelationName);
249         Assert(RelationRelationName != InvalidOid);
250
251         MyAttributeRelationId = RelnameFindRelid(AttributeRelationName);
252         Assert(AttributeRelationName != InvalidOid);
253
254         MyAMRelationId = RelnameFindRelid(AccessMethodRelationName);
255         Assert(MyAMRelationId != InvalidOid);
256
257         MyAMOPRelationId = RelnameFindRelid(AccessMethodOperatorRelationName);
258         Assert(MyAMOPRelationId != InvalidOid);
259 }
260
261 /* --------------------------------
262  *              CacheIdInvalidate
263  *
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  * --------------------------------
268  */
269 #ifdef  INVALIDDEBUG
270 #define CacheIdInvalidate_DEBUG1 \
271 elog(DEBUG, "CacheIdInvalidate(%d, %d, 0x%x[%d])", cacheId, hashIndex,\
272          pointer, ItemPointerIsValid(pointer))
273 #else
274 #define CacheIdInvalidate_DEBUG1
275 #endif   /* defined(INVALIDDEBUG) */
276
277 static void
278 CacheIdInvalidate(Index cacheId,
279                                   Index hashIndex,
280                                   ItemPointer pointer)
281 {
282         /* ----------------
283          *      assume that if the item pointer is valid, then we are
284          *      invalidating an item in the specified system catalog cache.
285          * ----------------
286          */
287         if (ItemPointerIsValid(pointer))
288         {
289                 CatalogCacheIdInvalidate(cacheId, hashIndex, pointer);
290                 return;
291         }
292
293         CacheIdInvalidate_DEBUG1;
294
295         ValidateHacks();                        /* XXX */
296
297         /* ----------------
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
301          * ----------------
302          */
303         if (cacheId == MyRelationRelationId)
304         {
305                 RelationIdInvalidateRelationCacheByRelationId(hashIndex);
306                 return;
307         }
308
309         if (cacheId == MyAttributeRelationId)
310         {
311                 RelationIdInvalidateRelationCacheByRelationId(hashIndex);
312                 return;
313         }
314
315         if (cacheId == MyAMRelationId)
316         {
317                 RelationIdInvalidateRelationCacheByAccessMethodId(hashIndex);
318                 return;
319         }
320
321         if (cacheId == MyAMOPRelationId)
322         {
323                 RelationIdInvalidateRelationCacheByAccessMethodId(InvalidOid);
324                 return;
325         }
326
327         /* ----------------
328          *      Yow! the caller asked us to invalidate something else.
329          * ----------------
330          */
331         elog(FATAL, "CacheIdInvalidate: cacheId=%d relation id?", cacheId);
332 }
333
334 /* --------------------------------
335  *              ResetSystemCaches
336  *
337  *              this blows away all tuples in the system catalog caches and
338  *              all the cached relation descriptors (and closes the files too).
339  * --------------------------------
340  */
341 static void
342 ResetSystemCaches()
343 {
344         ResetSystemCache();
345         RelationCacheInvalidate(false);
346 }
347
348 /* --------------------------------
349  *              InvalidationMessageRegisterSharedInvalid
350  * --------------------------------
351  */
352 #ifdef  INVALIDDEBUG
353 #define InvalidationMessageRegisterSharedInvalid_DEBUG1 \
354 elog(DEBUG,\
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 \
361          elog(DEBUG, \
362                   "InvalidationMessageRegisterSharedInvalid(r, %u, %u)", \
363                   message->any.relation.relationId, \
364                   message->any.relation.objectId)
365 #else
366 #define InvalidationMessageRegisterSharedInvalid_DEBUG1
367 #define InvalidationMessageRegisterSharedInvalid_DEBUG2
368 #endif   /* INVALIDDEBUG */
369
370 static void
371 InvalidationMessageRegisterSharedInvalid(InvalidationMessage message)
372 {
373         Assert(PointerIsValid(message));
374
375         switch (message->kind)
376         {
377                 case 'c':                               /* cached system catalog tuple */
378                         InvalidationMessageRegisterSharedInvalid_DEBUG1;
379
380                         RegisterSharedInvalid(message->any.catalog.cacheId,
381                                                                   message->any.catalog.hashIndex,
382                                                                   &message->any.catalog.pointerData);
383                         break;
384
385                 case 'r':                               /* cached relation descriptor */
386                         InvalidationMessageRegisterSharedInvalid_DEBUG2;
387
388                         RegisterSharedInvalid(message->any.relation.relationId,
389                                                                   message->any.relation.objectId,
390                                                                   (ItemPointer) NULL);
391                         break;
392
393                 default:
394                         elog(FATAL,
395                                  "InvalidationMessageRegisterSharedInvalid: `%c' kind",
396                                  message->kind);
397         }
398 }
399
400 /* --------------------------------
401  *              InvalidationMessageCacheInvalidate
402  * --------------------------------
403  */
404 #ifdef  INVALIDDEBUG
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)
415 #else
416 #define InvalidationMessageCacheInvalidate_DEBUG1
417 #define InvalidationMessageCacheInvalidate_DEBUG2
418 #endif   /* defined(INVALIDDEBUG) */
419
420 static void
421 InvalidationMessageCacheInvalidate(InvalidationMessage message)
422 {
423         Assert(PointerIsValid(message));
424
425         switch (message->kind)
426         {
427                 case 'c':                               /* cached system catalog tuple */
428                         InvalidationMessageCacheInvalidate_DEBUG1;
429
430                         CatalogCacheIdInvalidate(message->any.catalog.cacheId,
431                                                                          message->any.catalog.hashIndex,
432                                                                          &message->any.catalog.pointerData);
433                         break;
434
435                 case 'r':                               /* cached relation descriptor */
436                         InvalidationMessageCacheInvalidate_DEBUG2;
437
438                         /* XXX ignore this--is this correct ??? */
439                         break;
440
441                 default:
442                         elog(FATAL, "InvalidationMessageCacheInvalidate: `%c' kind",
443                                  message->kind);
444         }
445 }
446
447 /* --------------------------------
448  *              RelationInvalidateRelationCache
449  * --------------------------------
450  */
451 static void
452 RelationInvalidateRelationCache(Relation relation,
453                                                                 HeapTuple tuple,
454                                                                 void (*function) ())
455 {
456         Oid                     relationId;
457         Oid                     objectId = (Oid) 0;
458
459         /* ----------------
460          *      get the relation object id
461          * ----------------
462          */
463         ValidateHacks();                        /* XXX */
464         relationId = RelationGetRelid(relation);
465
466         /* ----------------
467          *
468          * ----------------
469          */
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)
477         {
478                 ;                                               /* objectId is unused */
479         }
480         else
481                 return;
482
483         /* ----------------
484          *        can't handle immediate relation descriptor invalidation
485          * ----------------
486          */
487         Assert(PointerIsValid(function));
488
489         (*function) (relationId, objectId);
490 }
491
492
493 /*
494  *      InitLocalInvalidateData
495  *
496  *      Setup this before anything could ever get invalid!
497  *      Called by InitPostgres();
498  */
499 void
500 InitLocalInvalidateData()
501 {
502         ValidateHacks();
503 }
504
505
506 /*
507  * DiscardInvalid 
508  *              Causes the invalidated cache state to be discarded.
509  *
510  * Note:
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.
514  */
515 void
516 DiscardInvalid()
517 {
518         /* ----------------
519          *      debugging stuff
520          * ----------------
521          */
522 #ifdef  INVALIDDEBUG
523         elog(DEBUG, "DiscardInvalid called");
524 #endif   /* defined(INVALIDDEBUG) */
525
526         InvalidateSharedInvalid(CacheIdInvalidate, ResetSystemCaches);
527 }
528
529 /*
530  * RegisterInvalid 
531  *              Causes registration of invalidated state with other backends iff true.
532  *
533  * Note:
534  *              This should be called as the last step in processing a transaction.
535  */
536 void
537 RegisterInvalid(bool send)
538 {
539         /* ----------------
540          *      debugging stuff
541          * ----------------
542          */
543 #ifdef  INVALIDDEBUG
544         elog(DEBUG, "RegisterInvalid(%d) called", send);
545 #endif   /* defined(INVALIDDEBUG) */
546
547         /* ----------------
548          *      Note: Invalid is a global variable
549          * ----------------
550          */
551         if (send)
552                 LocalInvalidInvalidate(Invalid,
553                                                            InvalidationMessageRegisterSharedInvalid);
554         else
555                 LocalInvalidInvalidate(Invalid,
556                                                            InvalidationMessageCacheInvalidate);
557
558         Invalid = EmptyLocalInvalid;
559 }
560
561 /*
562  * RelationIdInvalidateHeapTuple 
563  *              Causes the given tuple in a relation to be invalidated.
564  *
565  * Note:
566  *              Assumes object id is valid.
567  *              Assumes tuple is valid.
568  */
569 #ifdef  INVALIDDEBUG
570 #define RelationInvalidateHeapTuple_DEBUG1 \
571 elog(DEBUG, "RelationInvalidateHeapTuple(%s, [%d,%d])", \
572          RelationGetRelationName(relation), \
573          ItemPointerGetBlockNumber(&tuple->t_ctid), \
574          ItemPointerGetOffsetNumber(&tuple->t_ctid))
575 #else
576 #define RelationInvalidateHeapTuple_DEBUG1
577 #endif   /* defined(INVALIDDEBUG) */
578
579 void
580 RelationInvalidateHeapTuple(Relation relation, HeapTuple tuple)
581 {
582         /* ----------------
583          *      sanity checks
584          * ----------------
585          */
586         Assert(RelationIsValid(relation));
587         Assert(HeapTupleIsValid(tuple));
588
589         if (IsBootstrapProcessingMode())
590                 return;
591         /* ----------------
592          *      this only works for system relations now
593          * ----------------
594          */
595         if (!IsSystemRelationName(RelationGetForm(relation)->relname.data))
596                 return;
597
598         /* ----------------
599          *      debugging stuff
600          * ----------------
601          */
602         RelationInvalidateHeapTuple_DEBUG1;
603
604         RelationInvalidateCatalogCacheTuple(relation,
605                                                                                 tuple,
606                                                                                 CacheIdRegisterLocalInvalid);
607
608         RelationInvalidateRelationCache(relation,
609                                                                         tuple,
610                                                                         RelationIdRegisterLocalInvalid);
611 }