1996-07-09 08:22:35 +02:00
|
|
|
/*-------------------------------------------------------------------------
|
|
|
|
*
|
1999-02-14 00:22:53 +01:00
|
|
|
* inval.c
|
1997-09-07 07:04:48 +02:00
|
|
|
* POSTGRES cache invalidation dispatcher code.
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
2001-01-05 23:54:37 +01:00
|
|
|
* This is subtle stuff, so pay attention:
|
|
|
|
*
|
2002-03-03 18:47:56 +01:00
|
|
|
* When a tuple is updated or deleted, our standard time qualification rules
|
|
|
|
* consider that it is *still valid* so long as we are in the same command,
|
|
|
|
* ie, until the next CommandCounterIncrement() or transaction commit.
|
|
|
|
* (See utils/time/tqual.c, and note that system catalogs are generally
|
|
|
|
* scanned under SnapshotNow rules by the system, or plain user snapshots
|
2002-09-04 22:31:48 +02:00
|
|
|
* for user queries.) At the command boundary, the old tuple stops
|
2001-01-05 23:54:37 +01:00
|
|
|
* being valid and the new version, if any, becomes valid. Therefore,
|
|
|
|
* we cannot simply flush a tuple from the system caches during heap_update()
|
|
|
|
* or heap_delete(). The tuple is still good at that point; what's more,
|
|
|
|
* even if we did flush it, it might be reloaded into the caches by a later
|
|
|
|
* request in the same command. So the correct behavior is to keep a list
|
|
|
|
* of outdated (updated/deleted) tuples and then do the required cache
|
2002-03-03 18:47:56 +01:00
|
|
|
* flushes at the next command boundary. We must also keep track of
|
|
|
|
* inserted tuples so that we can flush "negative" cache entries that match
|
|
|
|
* the new tuples; again, that mustn't happen until end of command.
|
|
|
|
*
|
|
|
|
* Once we have finished the command, we still need to remember inserted
|
|
|
|
* tuples (including new versions of updated tuples), so that we can flush
|
|
|
|
* them from the caches if we abort the transaction. Similarly, we'd better
|
|
|
|
* be able to flush "negative" cache entries that may have been loaded in
|
|
|
|
* place of deleted tuples, so we still need the deleted ones too.
|
|
|
|
*
|
|
|
|
* If we successfully complete the transaction, we have to broadcast all
|
|
|
|
* these invalidation events to other backends (via the SI message queue)
|
2002-09-04 22:31:48 +02:00
|
|
|
* so that they can flush obsolete entries from their caches. Note we have
|
2002-03-03 18:47:56 +01:00
|
|
|
* to record the transaction commit before sending SI messages, otherwise
|
|
|
|
* the other backends won't see our updated tuples as good.
|
|
|
|
*
|
2004-07-01 02:52:04 +02:00
|
|
|
* When a subtransaction aborts, we can process and discard any events
|
2004-08-29 07:07:03 +02:00
|
|
|
* it has queued. When a subtransaction commits, we just add its events
|
2004-07-01 02:52:04 +02:00
|
|
|
* to the pending lists of the parent transaction.
|
|
|
|
*
|
2002-03-03 18:47:56 +01:00
|
|
|
* In short, we need to remember until xact end every insert or delete
|
2002-09-04 22:31:48 +02:00
|
|
|
* of a tuple that might be in the system caches. Updates are treated as
|
2002-03-03 18:47:56 +01:00
|
|
|
* two events, delete + insert, for simplicity. (There are cases where
|
|
|
|
* it'd be possible to record just one event, but we don't currently try.)
|
2001-01-05 23:54:37 +01:00
|
|
|
*
|
|
|
|
* We do not need to register EVERY tuple operation in this way, just those
|
2001-10-25 07:50:21 +02:00
|
|
|
* on tuples in relations that have associated catcaches. We do, however,
|
2001-06-19 21:42:16 +02:00
|
|
|
* have to register every operation on every tuple that *could* be in a
|
2001-10-25 07:50:21 +02:00
|
|
|
* catcache, whether or not it currently is in our cache. Also, if the
|
2001-06-19 21:42:16 +02:00
|
|
|
* tuple is in a relation that has multiple catcaches, we need to register
|
|
|
|
* an invalidation message for each such catcache. catcache.c's
|
|
|
|
* PrepareToInvalidateCacheTuple() routine provides the knowledge of which
|
|
|
|
* catcaches may need invalidation for a given tuple.
|
|
|
|
*
|
|
|
|
* Also, whenever we see an operation on a pg_class or pg_attribute tuple,
|
|
|
|
* we register a relcache flush operation for the relation described by that
|
2010-02-03 02:14:17 +01:00
|
|
|
* tuple.
|
2005-01-10 22:57:19 +01:00
|
|
|
*
|
2010-02-03 02:14:17 +01:00
|
|
|
* We keep the relcache flush requests in lists separate from the catcache
|
|
|
|
* tuple flush requests. This allows us to issue all the pending catcache
|
|
|
|
* flushes before we issue relcache flushes, which saves us from loading
|
|
|
|
* a catcache tuple during relcache load only to flush it again right away.
|
|
|
|
* Also, we avoid queuing multiple relcache flush requests for the same
|
|
|
|
* relation, since a relcache flush is relatively expensive to do.
|
2001-06-19 21:42:16 +02:00
|
|
|
* (XXX is it worth testing likewise for duplicate catcache flush entries?
|
|
|
|
* Probably not.)
|
|
|
|
*
|
2002-02-19 21:11:20 +01:00
|
|
|
* If a relcache flush is issued for a system relation that we preload
|
|
|
|
* from the relcache init file, we must also delete the init file so that
|
|
|
|
* it will be rebuilt during the next backend restart. The actual work of
|
|
|
|
* manipulating the init file is in relcache.c, but we keep track of the
|
|
|
|
* need for it here.
|
|
|
|
*
|
2004-07-01 02:52:04 +02:00
|
|
|
* The request lists proper are kept in CurTransactionContext of their
|
|
|
|
* creating (sub)transaction, since they can be forgotten on abort of that
|
|
|
|
* transaction but must be kept till top-level commit otherwise. For
|
|
|
|
* simplicity we keep the controlling list-of-lists in TopTransactionContext.
|
2001-01-05 23:54:37 +01:00
|
|
|
*
|
|
|
|
*
|
2010-01-02 17:58:17 +01:00
|
|
|
* Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
|
2000-01-26 06:58:53 +01:00
|
|
|
* Portions Copyright (c) 1994, Regents of the University of California
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
* IDENTIFICATION
|
2010-02-13 17:15:48 +01:00
|
|
|
* $PostgreSQL: pgsql/src/backend/utils/cache/inval.c,v 1.96 2010/02/13 16:15:47 sriggs Exp $
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
#include "postgres.h"
|
1996-11-06 11:32:10 +01:00
|
|
|
|
2005-06-18 00:32:51 +02:00
|
|
|
#include "access/twophase_rmgr.h"
|
2004-09-07 01:33:48 +02:00
|
|
|
#include "access/xact.h"
|
1996-07-09 08:22:35 +02:00
|
|
|
#include "catalog/catalog.h"
|
2010-01-09 17:49:27 +01:00
|
|
|
#include "catalog/pg_tablespace.h"
|
1999-07-16 07:00:38 +02:00
|
|
|
#include "miscadmin.h"
|
1996-07-09 08:22:35 +02:00
|
|
|
#include "storage/sinval.h"
|
2004-02-10 02:55:27 +01:00
|
|
|
#include "storage/smgr.h"
|
1996-07-09 08:22:35 +02:00
|
|
|
#include "utils/inval.h"
|
2001-06-19 21:42:16 +02:00
|
|
|
#include "utils/memutils.h"
|
2008-06-19 02:46:06 +02:00
|
|
|
#include "utils/rel.h"
|
2010-02-07 21:48:13 +01:00
|
|
|
#include "utils/relmapper.h"
|
2004-05-06 18:10:57 +02:00
|
|
|
#include "utils/syscache.h"
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1997-08-19 23:40:56 +02:00
|
|
|
|
2001-02-22 19:39:20 +01:00
|
|
|
/*
|
2001-06-19 21:42:16 +02:00
|
|
|
* To minimize palloc traffic, we keep pending requests in successively-
|
|
|
|
* larger chunks (a slightly more sophisticated version of an expansible
|
2001-10-25 07:50:21 +02:00
|
|
|
* array). All request types can be stored as SharedInvalidationMessage
|
2004-07-01 02:52:04 +02:00
|
|
|
* records. The ordering of requests within a list is never significant.
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
2001-06-19 21:42:16 +02:00
|
|
|
typedef struct InvalidationChunk
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
2001-10-25 07:50:21 +02:00
|
|
|
struct InvalidationChunk *next; /* list link */
|
2001-06-19 21:42:16 +02:00
|
|
|
int nitems; /* # items currently stored in chunk */
|
|
|
|
int maxitems; /* size of allocated array in this chunk */
|
2001-10-25 07:50:21 +02:00
|
|
|
SharedInvalidationMessage msgs[1]; /* VARIABLE LENGTH ARRAY */
|
2001-06-19 21:42:16 +02:00
|
|
|
} InvalidationChunk; /* VARIABLE LENGTH STRUCTURE */
|
1996-07-09 08:22:35 +02:00
|
|
|
|
2001-06-19 21:42:16 +02:00
|
|
|
typedef struct InvalidationListHeader
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
2001-06-19 21:42:16 +02:00
|
|
|
InvalidationChunk *cclist; /* list of chunks holding catcache msgs */
|
2010-02-03 02:14:17 +01:00
|
|
|
InvalidationChunk *rclist; /* list of chunks holding relcache msgs */
|
2001-06-19 21:42:16 +02:00
|
|
|
} InvalidationListHeader;
|
2000-01-10 07:30:56 +01:00
|
|
|
|
2002-04-30 00:14:34 +02:00
|
|
|
/*----------------
|
2004-07-01 02:52:04 +02:00
|
|
|
* Invalidation info is divided into two lists:
|
2002-03-03 18:47:56 +01:00
|
|
|
* 1) events so far in current command, not yet reflected to caches.
|
|
|
|
* 2) events in previous commands of current transaction; these have
|
|
|
|
* been reflected to local caches, and must be either broadcast to
|
|
|
|
* other backends or rolled back from local cache when we commit
|
|
|
|
* or abort the transaction.
|
2004-07-01 02:52:04 +02:00
|
|
|
* Actually, we need two such lists for each level of nested transaction,
|
|
|
|
* so that we can discard events from an aborted subtransaction. When
|
|
|
|
* a subtransaction commits, we append its lists to the parent's lists.
|
2002-03-03 18:47:56 +01:00
|
|
|
*
|
|
|
|
* The relcache-file-invalidated flag can just be a simple boolean,
|
|
|
|
* since we only act on it at transaction commit; we don't care which
|
|
|
|
* command of the transaction set it.
|
2002-04-30 00:14:34 +02:00
|
|
|
*----------------
|
2000-01-10 07:30:56 +01:00
|
|
|
*/
|
|
|
|
|
2004-07-01 02:52:04 +02:00
|
|
|
typedef struct TransInvalidationInfo
|
|
|
|
{
|
|
|
|
/* Back link to parent transaction's info */
|
|
|
|
struct TransInvalidationInfo *parent;
|
|
|
|
|
2004-09-07 01:33:48 +02:00
|
|
|
/* Subtransaction nesting depth */
|
2005-10-15 04:49:52 +02:00
|
|
|
int my_level;
|
2004-09-07 01:33:48 +02:00
|
|
|
|
2004-07-01 02:52:04 +02:00
|
|
|
/* head of current-command event list */
|
|
|
|
InvalidationListHeader CurrentCmdInvalidMsgs;
|
2000-04-12 19:17:23 +02:00
|
|
|
|
2004-07-01 02:52:04 +02:00
|
|
|
/* head of previous-commands event list */
|
|
|
|
InvalidationListHeader PriorCmdInvalidMsgs;
|
2002-02-19 21:11:20 +01:00
|
|
|
|
2004-07-01 02:52:04 +02:00
|
|
|
/* init file must be invalidated? */
|
2004-08-29 07:07:03 +02:00
|
|
|
bool RelcacheInitFileInval;
|
2004-07-01 02:52:04 +02:00
|
|
|
} TransInvalidationInfo;
|
|
|
|
|
|
|
|
static TransInvalidationInfo *transInvalInfo = NULL;
|
1999-11-21 02:58:22 +01:00
|
|
|
|
Allow read only connections during recovery, known as Hot Standby.
Enabled by recovery_connections = on (default) and forcing archive recovery using a recovery.conf. Recovery processing now emulates the original transactions as they are replayed, providing full locking and MVCC behaviour for read only queries. Recovery must enter consistent state before connections are allowed, so there is a delay, typically short, before connections succeed. Replay of recovering transactions can conflict and in some cases deadlock with queries during recovery; these result in query cancellation after max_standby_delay seconds have expired. Infrastructure changes have minor effects on normal running, though introduce four new types of WAL record.
New test mode "make standbycheck" allows regression tests of static command behaviour on a standby server while in recovery. Typical and extreme dynamic behaviours have been checked via code inspection and manual testing. Few port specific behaviours have been utilised, though primary testing has been on Linux only so far.
This commit is the basic patch. Additional changes will follow in this release to enhance some aspects of behaviour, notably improved handling of conflicts, deadlock detection and query cancellation. Changes to VACUUM FULL are also required.
Simon Riggs, with significant and lengthy review by Heikki Linnakangas, including streamlined redesign of snapshot creation and two-phase commit.
Important contributions from Florian Pflug, Mark Kirkwood, Merlin Moncure, Greg Stark, Gianni Ciolli, Gabriele Bartolini, Hannu Krosing, Robert Haas, Tatsuo Ishii, Hiroyuki Yamada plus support and feedback from many other community members.
2009-12-19 02:32:45 +01:00
|
|
|
static SharedInvalidationMessage *SharedInvalidMessagesArray;
|
|
|
|
static int numSharedInvalidMessagesArray;
|
|
|
|
static int maxSharedInvalidMessagesArray;
|
|
|
|
|
|
|
|
|
2002-04-30 00:14:34 +02:00
|
|
|
/*
|
|
|
|
* Dynamically-registered callback functions. Current implementation
|
|
|
|
* assumes there won't be very many of these at once; could improve if needed.
|
|
|
|
*/
|
|
|
|
|
2008-09-09 20:58:09 +02:00
|
|
|
#define MAX_SYSCACHE_CALLBACKS 20
|
|
|
|
#define MAX_RELCACHE_CALLBACKS 5
|
2002-04-30 00:14:34 +02:00
|
|
|
|
2008-09-09 20:58:09 +02:00
|
|
|
static struct SYSCACHECALLBACK
|
2002-04-30 00:14:34 +02:00
|
|
|
{
|
2008-09-09 20:58:09 +02:00
|
|
|
int16 id; /* cache number */
|
|
|
|
SyscacheCallbackFunction function;
|
2002-04-30 00:14:34 +02:00
|
|
|
Datum arg;
|
2008-09-09 20:58:09 +02:00
|
|
|
} syscache_callback_list[MAX_SYSCACHE_CALLBACKS];
|
2002-04-30 00:14:34 +02:00
|
|
|
|
2008-09-09 20:58:09 +02:00
|
|
|
static int syscache_callback_count = 0;
|
|
|
|
|
|
|
|
static struct RELCACHECALLBACK
|
|
|
|
{
|
|
|
|
RelcacheCallbackFunction function;
|
|
|
|
Datum arg;
|
|
|
|
} relcache_callback_list[MAX_RELCACHE_CALLBACKS];
|
|
|
|
|
|
|
|
static int relcache_callback_count = 0;
|
2002-04-30 00:14:34 +02:00
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
/* ----------------------------------------------------------------
|
2001-06-19 21:42:16 +02:00
|
|
|
* Invalidation list support functions
|
|
|
|
*
|
|
|
|
* These three routines encapsulate processing of the "chunked"
|
|
|
|
* representation of what is logically just a list of messages.
|
1996-07-09 08:22:35 +02:00
|
|
|
* ----------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
|
2001-02-22 19:39:20 +01:00
|
|
|
/*
|
2001-06-19 21:42:16 +02:00
|
|
|
* AddInvalidationMessage
|
|
|
|
* Add an invalidation message to a list (of chunks).
|
|
|
|
*
|
|
|
|
* Note that we do not pay any great attention to maintaining the original
|
|
|
|
* ordering of the messages.
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
2001-06-19 21:42:16 +02:00
|
|
|
static void
|
|
|
|
AddInvalidationMessage(InvalidationChunk **listHdr,
|
|
|
|
SharedInvalidationMessage *msg)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
2001-06-19 21:42:16 +02:00
|
|
|
InvalidationChunk *chunk = *listHdr;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2001-06-19 21:42:16 +02:00
|
|
|
if (chunk == NULL)
|
|
|
|
{
|
|
|
|
/* First time through; create initial chunk */
|
2008-06-19 23:32:56 +02:00
|
|
|
#define FIRSTCHUNKSIZE 32
|
2001-06-19 21:42:16 +02:00
|
|
|
chunk = (InvalidationChunk *)
|
2004-07-01 02:52:04 +02:00
|
|
|
MemoryContextAlloc(CurTransactionContext,
|
2001-06-19 21:42:16 +02:00
|
|
|
sizeof(InvalidationChunk) +
|
2005-10-15 04:49:52 +02:00
|
|
|
(FIRSTCHUNKSIZE - 1) *sizeof(SharedInvalidationMessage));
|
2001-06-19 21:42:16 +02:00
|
|
|
chunk->nitems = 0;
|
|
|
|
chunk->maxitems = FIRSTCHUNKSIZE;
|
|
|
|
chunk->next = *listHdr;
|
|
|
|
*listHdr = chunk;
|
|
|
|
}
|
|
|
|
else if (chunk->nitems >= chunk->maxitems)
|
|
|
|
{
|
|
|
|
/* Need another chunk; double size of last chunk */
|
2001-10-25 07:50:21 +02:00
|
|
|
int chunksize = 2 * chunk->maxitems;
|
2001-06-19 21:42:16 +02:00
|
|
|
|
|
|
|
chunk = (InvalidationChunk *)
|
2004-07-01 02:52:04 +02:00
|
|
|
MemoryContextAlloc(CurTransactionContext,
|
2001-06-19 21:42:16 +02:00
|
|
|
sizeof(InvalidationChunk) +
|
2005-10-15 04:49:52 +02:00
|
|
|
(chunksize - 1) *sizeof(SharedInvalidationMessage));
|
2001-06-19 21:42:16 +02:00
|
|
|
chunk->nitems = 0;
|
|
|
|
chunk->maxitems = chunksize;
|
|
|
|
chunk->next = *listHdr;
|
|
|
|
*listHdr = chunk;
|
|
|
|
}
|
|
|
|
/* Okay, add message to current chunk */
|
|
|
|
chunk->msgs[chunk->nitems] = *msg;
|
|
|
|
chunk->nitems++;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
2002-03-03 18:47:56 +01:00
|
|
|
/*
|
|
|
|
* Append one list of invalidation message chunks to another, resetting
|
|
|
|
* the source chunk-list pointer to NULL.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
AppendInvalidationMessageList(InvalidationChunk **destHdr,
|
|
|
|
InvalidationChunk **srcHdr)
|
|
|
|
{
|
|
|
|
InvalidationChunk *chunk = *srcHdr;
|
|
|
|
|
|
|
|
if (chunk == NULL)
|
|
|
|
return; /* nothing to do */
|
|
|
|
|
|
|
|
while (chunk->next != NULL)
|
|
|
|
chunk = chunk->next;
|
|
|
|
|
|
|
|
chunk->next = *destHdr;
|
|
|
|
|
|
|
|
*destHdr = *srcHdr;
|
|
|
|
|
|
|
|
*srcHdr = NULL;
|
|
|
|
}
|
|
|
|
|
2001-06-19 21:42:16 +02:00
|
|
|
/*
|
|
|
|
* Process a list of invalidation messages.
|
|
|
|
*
|
|
|
|
* This is a macro that executes the given code fragment for each message in
|
|
|
|
* a message chunk list. The fragment should refer to the message as *msg.
|
|
|
|
*/
|
|
|
|
#define ProcessMessageList(listHdr, codeFragment) \
|
|
|
|
do { \
|
|
|
|
InvalidationChunk *_chunk; \
|
|
|
|
for (_chunk = (listHdr); _chunk != NULL; _chunk = _chunk->next) \
|
|
|
|
{ \
|
|
|
|
int _cindex; \
|
|
|
|
for (_cindex = 0; _cindex < _chunk->nitems; _cindex++) \
|
|
|
|
{ \
|
|
|
|
SharedInvalidationMessage *msg = &_chunk->msgs[_cindex]; \
|
|
|
|
codeFragment; \
|
|
|
|
} \
|
|
|
|
} \
|
|
|
|
} while (0)
|
|
|
|
|
2008-06-19 23:32:56 +02:00
|
|
|
/*
|
|
|
|
* Process a list of invalidation messages group-wise.
|
|
|
|
*
|
|
|
|
* As above, but the code fragment can handle an array of messages.
|
|
|
|
* The fragment should refer to the messages as msgs[], with n entries.
|
|
|
|
*/
|
|
|
|
#define ProcessMessageListMulti(listHdr, codeFragment) \
|
|
|
|
do { \
|
|
|
|
InvalidationChunk *_chunk; \
|
|
|
|
for (_chunk = (listHdr); _chunk != NULL; _chunk = _chunk->next) \
|
|
|
|
{ \
|
|
|
|
SharedInvalidationMessage *msgs = _chunk->msgs; \
|
|
|
|
int n = _chunk->nitems; \
|
|
|
|
codeFragment; \
|
|
|
|
} \
|
|
|
|
} while (0)
|
|
|
|
|
2000-01-10 07:30:56 +01:00
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
/* ----------------------------------------------------------------
|
2001-06-19 21:42:16 +02:00
|
|
|
* Invalidation set support functions
|
|
|
|
*
|
|
|
|
* These routines understand about the division of a logical invalidation
|
2010-02-03 02:14:17 +01:00
|
|
|
* list into separate physical lists for catcache and relcache entries.
|
1996-07-09 08:22:35 +02:00
|
|
|
* ----------------------------------------------------------------
|
|
|
|
*/
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2001-02-22 19:39:20 +01:00
|
|
|
/*
|
2001-06-19 21:42:16 +02:00
|
|
|
* Add a catcache inval entry
|
2000-01-10 07:30:56 +01:00
|
|
|
*/
|
2001-06-19 21:42:16 +02:00
|
|
|
static void
|
|
|
|
AddCatcacheInvalidationMessage(InvalidationListHeader *hdr,
|
2002-03-03 18:47:56 +01:00
|
|
|
int id, uint32 hashValue,
|
2001-06-19 21:42:16 +02:00
|
|
|
ItemPointer tuplePtr, Oid dbId)
|
2000-01-10 07:30:56 +01:00
|
|
|
{
|
2001-06-19 21:42:16 +02:00
|
|
|
SharedInvalidationMessage msg;
|
2000-01-10 07:30:56 +01:00
|
|
|
|
2001-06-19 21:42:16 +02:00
|
|
|
msg.cc.id = (int16) id;
|
|
|
|
msg.cc.tuplePtr = *tuplePtr;
|
2002-03-03 18:47:56 +01:00
|
|
|
msg.cc.dbId = dbId;
|
|
|
|
msg.cc.hashValue = hashValue;
|
2001-06-19 21:42:16 +02:00
|
|
|
AddInvalidationMessage(&hdr->cclist, &msg);
|
2000-01-10 07:30:56 +01:00
|
|
|
}
|
|
|
|
|
2010-02-07 21:48:13 +01:00
|
|
|
/*
|
|
|
|
* Add a whole-catalog inval entry
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
AddCatalogInvalidationMessage(InvalidationListHeader *hdr,
|
|
|
|
Oid dbId, Oid catId)
|
|
|
|
{
|
|
|
|
SharedInvalidationMessage msg;
|
|
|
|
|
|
|
|
msg.cat.id = SHAREDINVALCATALOG_ID;
|
|
|
|
msg.cat.dbId = dbId;
|
|
|
|
msg.cat.catId = catId;
|
|
|
|
AddInvalidationMessage(&hdr->cclist, &msg);
|
|
|
|
}
|
|
|
|
|
2001-02-22 19:39:20 +01:00
|
|
|
/*
|
2001-06-19 21:42:16 +02:00
|
|
|
* Add a relcache inval entry
|
2000-01-10 07:30:56 +01:00
|
|
|
*/
|
1996-07-09 08:22:35 +02:00
|
|
|
static void
|
2001-06-19 21:42:16 +02:00
|
|
|
AddRelcacheInvalidationMessage(InvalidationListHeader *hdr,
|
2005-01-10 22:57:19 +01:00
|
|
|
Oid dbId, Oid relId)
|
2000-01-10 07:30:56 +01:00
|
|
|
{
|
2001-06-19 21:42:16 +02:00
|
|
|
SharedInvalidationMessage msg;
|
|
|
|
|
|
|
|
/* Don't add a duplicate item */
|
2004-02-10 02:55:27 +01:00
|
|
|
/* We assume dbId need not be checked because it will never change */
|
2001-06-19 21:42:16 +02:00
|
|
|
ProcessMessageList(hdr->rclist,
|
2005-01-10 22:57:19 +01:00
|
|
|
if (msg->rc.id == SHAREDINVALRELCACHE_ID &&
|
|
|
|
msg->rc.relId == relId)
|
2005-10-15 04:49:52 +02:00
|
|
|
return);
|
2001-06-19 21:42:16 +02:00
|
|
|
|
|
|
|
/* OK, add the item */
|
|
|
|
msg.rc.id = SHAREDINVALRELCACHE_ID;
|
|
|
|
msg.rc.dbId = dbId;
|
|
|
|
msg.rc.relId = relId;
|
2005-01-10 22:57:19 +01:00
|
|
|
AddInvalidationMessage(&hdr->rclist, &msg);
|
|
|
|
}
|
|
|
|
|
2002-03-03 18:47:56 +01:00
|
|
|
/*
|
|
|
|
* Append one list of invalidation messages to another, resetting
|
|
|
|
* the source list to empty.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
AppendInvalidationMessages(InvalidationListHeader *dest,
|
|
|
|
InvalidationListHeader *src)
|
|
|
|
{
|
|
|
|
AppendInvalidationMessageList(&dest->cclist, &src->cclist);
|
|
|
|
AppendInvalidationMessageList(&dest->rclist, &src->rclist);
|
|
|
|
}
|
|
|
|
|
2001-02-22 19:39:20 +01:00
|
|
|
/*
|
2001-06-19 21:42:16 +02:00
|
|
|
* Execute the given function for all the messages in an invalidation list.
|
|
|
|
* The list is not altered.
|
|
|
|
*
|
|
|
|
* catcache entries are processed first, for reasons mentioned above.
|
2000-01-10 07:30:56 +01:00
|
|
|
*/
|
2001-06-19 21:42:16 +02:00
|
|
|
static void
|
|
|
|
ProcessInvalidationMessages(InvalidationListHeader *hdr,
|
|
|
|
void (*func) (SharedInvalidationMessage *msg))
|
2000-01-10 07:30:56 +01:00
|
|
|
{
|
2001-06-19 21:42:16 +02:00
|
|
|
ProcessMessageList(hdr->cclist, func(msg));
|
|
|
|
ProcessMessageList(hdr->rclist, func(msg));
|
|
|
|
}
|
2000-01-10 07:30:56 +01:00
|
|
|
|
2008-06-19 23:32:56 +02:00
|
|
|
/*
|
|
|
|
* As above, but the function is able to process an array of messages
|
|
|
|
* rather than just one at a time.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
ProcessInvalidationMessagesMulti(InvalidationListHeader *hdr,
|
2009-06-11 16:49:15 +02:00
|
|
|
void (*func) (const SharedInvalidationMessage *msgs, int n))
|
2008-06-19 23:32:56 +02:00
|
|
|
{
|
|
|
|
ProcessMessageListMulti(hdr->cclist, func(msgs, n));
|
|
|
|
ProcessMessageListMulti(hdr->rclist, func(msgs, n));
|
|
|
|
}
|
|
|
|
|
2001-06-19 21:42:16 +02:00
|
|
|
/* ----------------------------------------------------------------
|
|
|
|
* private support functions
|
|
|
|
* ----------------------------------------------------------------
|
|
|
|
*/
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2001-06-19 21:42:16 +02:00
|
|
|
/*
|
|
|
|
* RegisterCatcacheInvalidation
|
|
|
|
*
|
2002-03-03 18:47:56 +01:00
|
|
|
* Register an invalidation event for a catcache tuple entry.
|
2001-06-19 21:42:16 +02:00
|
|
|
*/
|
|
|
|
static void
|
|
|
|
RegisterCatcacheInvalidation(int cacheId,
|
2002-03-03 18:47:56 +01:00
|
|
|
uint32 hashValue,
|
2001-06-19 21:42:16 +02:00
|
|
|
ItemPointer tuplePtr,
|
|
|
|
Oid dbId)
|
|
|
|
{
|
2004-07-01 02:52:04 +02:00
|
|
|
AddCatcacheInvalidationMessage(&transInvalInfo->CurrentCmdInvalidMsgs,
|
2002-03-03 18:47:56 +01:00
|
|
|
cacheId, hashValue, tuplePtr, dbId);
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
2010-02-07 21:48:13 +01:00
|
|
|
/*
|
|
|
|
* RegisterCatalogInvalidation
|
|
|
|
*
|
|
|
|
* Register an invalidation event for all catcache entries from a catalog.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
RegisterCatalogInvalidation(Oid dbId, Oid catId)
|
|
|
|
{
|
|
|
|
AddCatalogInvalidationMessage(&transInvalInfo->CurrentCmdInvalidMsgs,
|
|
|
|
dbId, catId);
|
|
|
|
}
|
|
|
|
|
2001-02-22 19:39:20 +01:00
|
|
|
/*
|
2001-06-19 21:42:16 +02:00
|
|
|
* RegisterRelcacheInvalidation
|
|
|
|
*
|
|
|
|
* As above, but register a relcache invalidation event.
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
|
|
|
static void
|
2005-01-10 22:57:19 +01:00
|
|
|
RegisterRelcacheInvalidation(Oid dbId, Oid relId)
|
2000-01-10 07:30:56 +01:00
|
|
|
{
|
2004-07-01 02:52:04 +02:00
|
|
|
AddRelcacheInvalidationMessage(&transInvalInfo->CurrentCmdInvalidMsgs,
|
2005-01-10 22:57:19 +01:00
|
|
|
dbId, relId);
|
2002-09-04 22:31:48 +02:00
|
|
|
|
2007-11-30 22:22:54 +01:00
|
|
|
/*
|
|
|
|
* Most of the time, relcache invalidation is associated with system
|
2009-06-11 16:49:15 +02:00
|
|
|
* catalog updates, but there are a few cases where it isn't. Quick hack
|
|
|
|
* to ensure that the next CommandCounterIncrement() will think that we
|
|
|
|
* need to do CommandEndInvalidationMessages().
|
2007-11-30 22:22:54 +01:00
|
|
|
*/
|
|
|
|
(void) GetCurrentCommandId(true);
|
|
|
|
|
2002-02-19 21:11:20 +01:00
|
|
|
/*
|
|
|
|
* If the relation being invalidated is one of those cached in the
|
|
|
|
* relcache init file, mark that we need to zap that file at commit.
|
|
|
|
*/
|
|
|
|
if (RelationIdIsInInitFile(relId))
|
2004-07-01 02:52:04 +02:00
|
|
|
transInvalInfo->RelcacheInitFileInval = true;
|
2000-01-10 07:30:56 +01:00
|
|
|
}
|
|
|
|
|
2001-06-19 21:42:16 +02:00
|
|
|
/*
|
|
|
|
* LocalExecuteInvalidationMessage
|
|
|
|
*
|
2005-01-10 22:57:19 +01:00
|
|
|
* Process a single invalidation message (which could be of any type).
|
2001-06-19 21:42:16 +02:00
|
|
|
* Only the local caches are flushed; this does not transmit the message
|
|
|
|
* to other backends.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
LocalExecuteInvalidationMessage(SharedInvalidationMessage *msg)
|
|
|
|
{
|
|
|
|
if (msg->id >= 0)
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
2010-02-07 21:48:13 +01:00
|
|
|
if (msg->cc.dbId == MyDatabaseId || msg->cc.dbId == InvalidOid)
|
2002-04-30 00:14:34 +02:00
|
|
|
{
|
2001-06-19 21:42:16 +02:00
|
|
|
CatalogCacheIdInvalidate(msg->cc.id,
|
2002-03-03 18:47:56 +01:00
|
|
|
msg->cc.hashValue,
|
2001-06-19 21:42:16 +02:00
|
|
|
&msg->cc.tuplePtr);
|
2002-04-30 00:14:34 +02:00
|
|
|
|
2010-02-07 21:48:13 +01:00
|
|
|
CallSyscacheCallbacks(msg->cc.id, &msg->cc.tuplePtr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (msg->id == SHAREDINVALCATALOG_ID)
|
|
|
|
{
|
|
|
|
if (msg->cat.dbId == MyDatabaseId || msg->cat.dbId == InvalidOid)
|
|
|
|
{
|
|
|
|
CatalogCacheFlushCatalog(msg->cat.catId);
|
2002-04-30 00:14:34 +02:00
|
|
|
|
2010-02-07 21:48:13 +01:00
|
|
|
/* CatalogCacheFlushCatalog calls CallSyscacheCallbacks as needed */
|
2002-04-30 00:14:34 +02:00
|
|
|
}
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
2001-06-19 21:42:16 +02:00
|
|
|
else if (msg->id == SHAREDINVALRELCACHE_ID)
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
2004-02-10 02:55:27 +01:00
|
|
|
if (msg->rc.dbId == MyDatabaseId || msg->rc.dbId == InvalidOid)
|
2002-04-30 00:14:34 +02:00
|
|
|
{
|
2010-02-07 21:48:13 +01:00
|
|
|
int i;
|
|
|
|
|
2005-01-10 21:02:24 +01:00
|
|
|
RelationCacheInvalidateEntry(msg->rc.relId);
|
2002-04-30 00:14:34 +02:00
|
|
|
|
2008-09-09 20:58:09 +02:00
|
|
|
for (i = 0; i < relcache_callback_count; i++)
|
2002-04-30 00:14:34 +02:00
|
|
|
{
|
2008-09-09 20:58:09 +02:00
|
|
|
struct RELCACHECALLBACK *ccitem = relcache_callback_list + i;
|
2002-04-30 00:14:34 +02:00
|
|
|
|
2008-09-09 20:58:09 +02:00
|
|
|
(*ccitem->function) (ccitem->arg, msg->rc.relId);
|
2002-04-30 00:14:34 +02:00
|
|
|
}
|
|
|
|
}
|
2005-01-10 22:57:19 +01:00
|
|
|
}
|
|
|
|
else if (msg->id == SHAREDINVALSMGR_ID)
|
|
|
|
{
|
2005-01-10 21:02:24 +01:00
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* We could have smgr entries for relations of other databases, so no
|
|
|
|
* short-circuit test is possible here.
|
2005-01-10 21:02:24 +01:00
|
|
|
*/
|
2005-01-10 22:57:19 +01:00
|
|
|
smgrclosenode(msg->sm.rnode);
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
2010-02-07 21:48:13 +01:00
|
|
|
else if (msg->id == SHAREDINVALRELMAP_ID)
|
|
|
|
{
|
|
|
|
/* We only care about our own database and shared catalogs */
|
|
|
|
if (msg->rm.dbId == InvalidOid)
|
|
|
|
RelationMapInvalidate(true);
|
|
|
|
else if (msg->rm.dbId == MyDatabaseId)
|
|
|
|
RelationMapInvalidate(false);
|
|
|
|
}
|
2001-06-19 21:42:16 +02:00
|
|
|
else
|
2003-07-25 22:18:01 +02:00
|
|
|
elog(FATAL, "unrecognized SI message id: %d", msg->id);
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
2001-02-22 19:39:20 +01:00
|
|
|
/*
|
2001-06-18 05:35:07 +02:00
|
|
|
* InvalidateSystemCaches
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
2000-01-29 20:51:59 +01:00
|
|
|
* This blows away all tuples in the system catalog caches and
|
2004-02-10 02:55:27 +01:00
|
|
|
* all the cached relation descriptors and smgr cache entries.
|
2000-01-29 20:51:59 +01:00
|
|
|
* Relation descriptors that have positive refcounts are then rebuilt.
|
2001-06-18 05:35:07 +02:00
|
|
|
*
|
|
|
|
* We call this when we see a shared-inval-queue overflow signal,
|
|
|
|
* since that tells us we've lost some shared-inval messages and hence
|
|
|
|
* don't know what needs to be invalidated.
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
|
|
|
static void
|
2001-06-18 05:35:07 +02:00
|
|
|
InvalidateSystemCaches(void)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
2002-04-30 00:14:34 +02:00
|
|
|
int i;
|
|
|
|
|
2001-06-18 05:35:07 +02:00
|
|
|
ResetCatalogCaches();
|
2010-02-07 21:48:13 +01:00
|
|
|
RelationCacheInvalidate(); /* gets smgr and relmap too */
|
2002-04-30 00:14:34 +02:00
|
|
|
|
2008-09-09 20:58:09 +02:00
|
|
|
for (i = 0; i < syscache_callback_count; i++)
|
2002-04-30 00:14:34 +02:00
|
|
|
{
|
2008-09-09 20:58:09 +02:00
|
|
|
struct SYSCACHECALLBACK *ccitem = syscache_callback_list + i;
|
|
|
|
|
|
|
|
(*ccitem->function) (ccitem->arg, ccitem->id, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < relcache_callback_count; i++)
|
|
|
|
{
|
|
|
|
struct RELCACHECALLBACK *ccitem = relcache_callback_list + i;
|
2002-04-30 00:14:34 +02:00
|
|
|
|
|
|
|
(*ccitem->function) (ccitem->arg, InvalidOid);
|
|
|
|
}
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
2001-02-22 19:39:20 +01:00
|
|
|
/*
|
2001-06-19 21:42:16 +02:00
|
|
|
* PrepareForTupleInvalidation
|
2002-02-19 21:11:20 +01:00
|
|
|
* Detect whether invalidation of this tuple implies invalidation
|
|
|
|
* of catalog/relation cache entries; if so, register inval events.
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
|
|
|
static void
|
2005-01-10 22:57:19 +01:00
|
|
|
PrepareForTupleInvalidation(Relation relation, HeapTuple tuple)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
2001-06-19 21:42:16 +02:00
|
|
|
Oid tupleRelId;
|
2004-02-10 02:55:27 +01:00
|
|
|
Oid databaseId;
|
2001-06-19 21:42:16 +02:00
|
|
|
Oid relationId;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2004-02-10 02:55:27 +01:00
|
|
|
/* Do nothing during bootstrap */
|
2001-06-19 21:42:16 +02:00
|
|
|
if (IsBootstrapProcessingMode())
|
|
|
|
return;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
2001-06-19 21:42:16 +02:00
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* We only need to worry about invalidation for tuples that are in system
|
|
|
|
* relations; user-relation tuples are never in catcaches and can't affect
|
|
|
|
* the relcache either.
|
2001-06-19 21:42:16 +02:00
|
|
|
*/
|
2002-04-12 22:38:31 +02:00
|
|
|
if (!IsSystemRelation(relation))
|
2001-06-19 21:42:16 +02:00
|
|
|
return;
|
2002-09-04 22:31:48 +02:00
|
|
|
|
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* TOAST tuples can likewise be ignored here. Note that TOAST tables are
|
|
|
|
* considered system relations so they are not filtered by the above test.
|
2002-04-12 22:38:31 +02:00
|
|
|
*/
|
|
|
|
if (IsToastRelation(relation))
|
2001-11-17 00:30:35 +01:00
|
|
|
return;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2001-02-22 19:39:20 +01:00
|
|
|
/*
|
2001-06-19 21:42:16 +02:00
|
|
|
* First let the catcache do its thing
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
2001-06-19 21:42:16 +02:00
|
|
|
PrepareToInvalidateCacheTuple(relation, tuple,
|
2005-01-10 22:57:19 +01:00
|
|
|
RegisterCatcacheInvalidation);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2001-02-22 19:39:20 +01:00
|
|
|
/*
|
2001-06-19 21:42:16 +02:00
|
|
|
* Now, is this tuple one of the primary definers of a relcache entry?
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
2001-06-19 21:42:16 +02:00
|
|
|
tupleRelId = RelationGetRelid(relation);
|
|
|
|
|
2005-04-14 03:38:22 +02:00
|
|
|
if (tupleRelId == RelationRelationId)
|
2004-02-10 02:55:27 +01:00
|
|
|
{
|
|
|
|
Form_pg_class classtup = (Form_pg_class) GETSTRUCT(tuple);
|
|
|
|
|
2002-07-20 07:16:59 +02:00
|
|
|
relationId = HeapTupleGetOid(tuple);
|
2004-02-10 02:55:27 +01:00
|
|
|
if (classtup->relisshared)
|
|
|
|
databaseId = InvalidOid;
|
|
|
|
else
|
|
|
|
databaseId = MyDatabaseId;
|
|
|
|
}
|
2005-04-14 03:38:22 +02:00
|
|
|
else if (tupleRelId == AttributeRelationId)
|
2004-02-10 02:55:27 +01:00
|
|
|
{
|
|
|
|
Form_pg_attribute atttup = (Form_pg_attribute) GETSTRUCT(tuple);
|
|
|
|
|
|
|
|
relationId = atttup->attrelid;
|
2004-08-29 07:07:03 +02:00
|
|
|
|
2004-02-10 02:55:27 +01:00
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* KLUGE ALERT: we always send the relcache event with MyDatabaseId,
|
|
|
|
* even if the rel in question is shared (which we can't easily tell).
|
|
|
|
* This essentially means that only backends in this same database
|
2007-05-02 23:08:46 +02:00
|
|
|
* will react to the relcache flush request. This is in fact
|
2005-10-15 04:49:52 +02:00
|
|
|
* appropriate, since only those backends could see our pg_attribute
|
2007-11-15 22:14:46 +01:00
|
|
|
* change anyway. It looks a bit ugly though. (In practice, shared
|
2007-05-02 23:08:46 +02:00
|
|
|
* relations can't have schema changes after bootstrap, so we should
|
|
|
|
* never come here for a shared rel anyway.)
|
2004-02-10 02:55:27 +01:00
|
|
|
*/
|
|
|
|
databaseId = MyDatabaseId;
|
|
|
|
}
|
2007-05-02 23:08:46 +02:00
|
|
|
else if (tupleRelId == IndexRelationId)
|
|
|
|
{
|
|
|
|
Form_pg_index indextup = (Form_pg_index) GETSTRUCT(tuple);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* When a pg_index row is updated, we should send out a relcache inval
|
2007-11-15 22:14:46 +01:00
|
|
|
* for the index relation. As above, we don't know the shared status
|
2007-05-02 23:08:46 +02:00
|
|
|
* of the index, but in practice it doesn't matter since indexes of
|
|
|
|
* shared catalogs can't have such updates.
|
|
|
|
*/
|
|
|
|
relationId = indextup->indexrelid;
|
|
|
|
databaseId = MyDatabaseId;
|
|
|
|
}
|
1997-09-07 07:04:48 +02:00
|
|
|
else
|
|
|
|
return;
|
|
|
|
|
2001-02-22 19:39:20 +01:00
|
|
|
/*
|
2004-02-10 02:55:27 +01:00
|
|
|
* Yes. We need to register a relcache invalidation event.
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
2005-01-10 22:57:19 +01:00
|
|
|
RegisterRelcacheInvalidation(databaseId, relationId);
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
1998-02-23 18:44:24 +01:00
|
|
|
|
2001-06-19 21:42:16 +02:00
|
|
|
/* ----------------------------------------------------------------
|
|
|
|
* public functions
|
|
|
|
* ----------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
/*
|
2001-06-19 21:42:16 +02:00
|
|
|
* AcceptInvalidationMessages
|
|
|
|
* Read and process invalidation messages from the shared invalidation
|
|
|
|
* message queue.
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
* Note:
|
1997-09-07 07:04:48 +02:00
|
|
|
* This should be called as the first step in processing a transaction.
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
|
|
|
void
|
2001-06-19 21:42:16 +02:00
|
|
|
AcceptInvalidationMessages(void)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
2001-06-19 21:42:16 +02:00
|
|
|
ReceiveSharedInvalidMessages(LocalExecuteInvalidationMessage,
|
|
|
|
InvalidateSystemCaches);
|
2006-01-19 22:49:21 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Test code to force cache flushes anytime a flush could happen.
|
|
|
|
*
|
|
|
|
* If used with CLOBBER_FREED_MEMORY, CLOBBER_CACHE_ALWAYS provides a
|
|
|
|
* fairly thorough test that the system contains no cache-flush hazards.
|
|
|
|
* However, it also makes the system unbelievably slow --- the regression
|
|
|
|
* tests take about 100 times longer than normal.
|
|
|
|
*
|
2006-10-04 02:30:14 +02:00
|
|
|
* If you're a glutton for punishment, try CLOBBER_CACHE_RECURSIVELY. This
|
|
|
|
* slows things by at least a factor of 10000, so I wouldn't suggest
|
|
|
|
* trying to run the entire regression tests that way. It's useful to try
|
|
|
|
* a few simple tests, to make sure that cache reload isn't subject to
|
|
|
|
* internal cache-flush hazards, but after you've done a few thousand
|
2006-01-19 22:49:21 +01:00
|
|
|
* recursive reloads it's unlikely you'll learn more.
|
|
|
|
*/
|
|
|
|
#if defined(CLOBBER_CACHE_ALWAYS)
|
|
|
|
{
|
|
|
|
static bool in_recursion = false;
|
|
|
|
|
|
|
|
if (!in_recursion)
|
|
|
|
{
|
|
|
|
in_recursion = true;
|
|
|
|
InvalidateSystemCaches();
|
|
|
|
in_recursion = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#elif defined(CLOBBER_CACHE_RECURSIVELY)
|
|
|
|
InvalidateSystemCaches();
|
|
|
|
#endif
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2004-07-01 02:52:04 +02:00
|
|
|
* AtStart_Inval
|
|
|
|
* Initialize inval lists at start of a main transaction.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
AtStart_Inval(void)
|
|
|
|
{
|
|
|
|
Assert(transInvalInfo == NULL);
|
|
|
|
transInvalInfo = (TransInvalidationInfo *)
|
|
|
|
MemoryContextAllocZero(TopTransactionContext,
|
|
|
|
sizeof(TransInvalidationInfo));
|
2004-09-07 01:33:48 +02:00
|
|
|
transInvalInfo->my_level = GetCurrentTransactionNestLevel();
|
Allow read only connections during recovery, known as Hot Standby.
Enabled by recovery_connections = on (default) and forcing archive recovery using a recovery.conf. Recovery processing now emulates the original transactions as they are replayed, providing full locking and MVCC behaviour for read only queries. Recovery must enter consistent state before connections are allowed, so there is a delay, typically short, before connections succeed. Replay of recovering transactions can conflict and in some cases deadlock with queries during recovery; these result in query cancellation after max_standby_delay seconds have expired. Infrastructure changes have minor effects on normal running, though introduce four new types of WAL record.
New test mode "make standbycheck" allows regression tests of static command behaviour on a standby server while in recovery. Typical and extreme dynamic behaviours have been checked via code inspection and manual testing. Few port specific behaviours have been utilised, though primary testing has been on Linux only so far.
This commit is the basic patch. Additional changes will follow in this release to enhance some aspects of behaviour, notably improved handling of conflicts, deadlock detection and query cancellation. Changes to VACUUM FULL are also required.
Simon Riggs, with significant and lengthy review by Heikki Linnakangas, including streamlined redesign of snapshot creation and two-phase commit.
Important contributions from Florian Pflug, Mark Kirkwood, Merlin Moncure, Greg Stark, Gianni Ciolli, Gabriele Bartolini, Hannu Krosing, Robert Haas, Tatsuo Ishii, Hiroyuki Yamada plus support and feedback from many other community members.
2009-12-19 02:32:45 +01:00
|
|
|
SharedInvalidMessagesArray = NULL;
|
|
|
|
numSharedInvalidMessagesArray = 0;
|
2005-06-18 00:32:51 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* PostPrepare_Inval
|
2005-10-15 04:49:52 +02:00
|
|
|
* Clean up after successful PREPARE.
|
2005-06-18 00:32:51 +02:00
|
|
|
*
|
|
|
|
* Here, we want to act as though the transaction aborted, so that we will
|
|
|
|
* undo any syscache changes it made, thereby bringing us into sync with the
|
|
|
|
* outside world, which doesn't believe the transaction committed yet.
|
|
|
|
*
|
|
|
|
* If the prepared transaction is later aborted, there is nothing more to
|
|
|
|
* do; if it commits, we will receive the consequent inval messages just
|
|
|
|
* like everyone else.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
PostPrepare_Inval(void)
|
|
|
|
{
|
|
|
|
AtEOXact_Inval(false);
|
|
|
|
}
|
|
|
|
|
2004-07-01 02:52:04 +02:00
|
|
|
/*
|
|
|
|
* AtSubStart_Inval
|
|
|
|
* Initialize inval lists at start of a subtransaction.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
AtSubStart_Inval(void)
|
|
|
|
{
|
|
|
|
TransInvalidationInfo *myInfo;
|
|
|
|
|
|
|
|
Assert(transInvalInfo != NULL);
|
|
|
|
myInfo = (TransInvalidationInfo *)
|
|
|
|
MemoryContextAllocZero(TopTransactionContext,
|
|
|
|
sizeof(TransInvalidationInfo));
|
|
|
|
myInfo->parent = transInvalInfo;
|
2004-09-07 01:33:48 +02:00
|
|
|
myInfo->my_level = GetCurrentTransactionNestLevel();
|
2004-07-01 02:52:04 +02:00
|
|
|
transInvalInfo = myInfo;
|
|
|
|
}
|
|
|
|
|
2005-06-18 00:32:51 +02:00
|
|
|
/*
|
Allow read only connections during recovery, known as Hot Standby.
Enabled by recovery_connections = on (default) and forcing archive recovery using a recovery.conf. Recovery processing now emulates the original transactions as they are replayed, providing full locking and MVCC behaviour for read only queries. Recovery must enter consistent state before connections are allowed, so there is a delay, typically short, before connections succeed. Replay of recovering transactions can conflict and in some cases deadlock with queries during recovery; these result in query cancellation after max_standby_delay seconds have expired. Infrastructure changes have minor effects on normal running, though introduce four new types of WAL record.
New test mode "make standbycheck" allows regression tests of static command behaviour on a standby server while in recovery. Typical and extreme dynamic behaviours have been checked via code inspection and manual testing. Few port specific behaviours have been utilised, though primary testing has been on Linux only so far.
This commit is the basic patch. Additional changes will follow in this release to enhance some aspects of behaviour, notably improved handling of conflicts, deadlock detection and query cancellation. Changes to VACUUM FULL are also required.
Simon Riggs, with significant and lengthy review by Heikki Linnakangas, including streamlined redesign of snapshot creation and two-phase commit.
Important contributions from Florian Pflug, Mark Kirkwood, Merlin Moncure, Greg Stark, Gianni Ciolli, Gabriele Bartolini, Hannu Krosing, Robert Haas, Tatsuo Ishii, Hiroyuki Yamada plus support and feedback from many other community members.
2009-12-19 02:32:45 +01:00
|
|
|
* Collect invalidation messages into SharedInvalidMessagesArray array.
|
2005-06-18 00:32:51 +02:00
|
|
|
*/
|
|
|
|
static void
|
Allow read only connections during recovery, known as Hot Standby.
Enabled by recovery_connections = on (default) and forcing archive recovery using a recovery.conf. Recovery processing now emulates the original transactions as they are replayed, providing full locking and MVCC behaviour for read only queries. Recovery must enter consistent state before connections are allowed, so there is a delay, typically short, before connections succeed. Replay of recovering transactions can conflict and in some cases deadlock with queries during recovery; these result in query cancellation after max_standby_delay seconds have expired. Infrastructure changes have minor effects on normal running, though introduce four new types of WAL record.
New test mode "make standbycheck" allows regression tests of static command behaviour on a standby server while in recovery. Typical and extreme dynamic behaviours have been checked via code inspection and manual testing. Few port specific behaviours have been utilised, though primary testing has been on Linux only so far.
This commit is the basic patch. Additional changes will follow in this release to enhance some aspects of behaviour, notably improved handling of conflicts, deadlock detection and query cancellation. Changes to VACUUM FULL are also required.
Simon Riggs, with significant and lengthy review by Heikki Linnakangas, including streamlined redesign of snapshot creation and two-phase commit.
Important contributions from Florian Pflug, Mark Kirkwood, Merlin Moncure, Greg Stark, Gianni Ciolli, Gabriele Bartolini, Hannu Krosing, Robert Haas, Tatsuo Ishii, Hiroyuki Yamada plus support and feedback from many other community members.
2009-12-19 02:32:45 +01:00
|
|
|
MakeSharedInvalidMessagesArray(const SharedInvalidationMessage *msgs, int n)
|
2005-06-18 00:32:51 +02:00
|
|
|
{
|
Allow read only connections during recovery, known as Hot Standby.
Enabled by recovery_connections = on (default) and forcing archive recovery using a recovery.conf. Recovery processing now emulates the original transactions as they are replayed, providing full locking and MVCC behaviour for read only queries. Recovery must enter consistent state before connections are allowed, so there is a delay, typically short, before connections succeed. Replay of recovering transactions can conflict and in some cases deadlock with queries during recovery; these result in query cancellation after max_standby_delay seconds have expired. Infrastructure changes have minor effects on normal running, though introduce four new types of WAL record.
New test mode "make standbycheck" allows regression tests of static command behaviour on a standby server while in recovery. Typical and extreme dynamic behaviours have been checked via code inspection and manual testing. Few port specific behaviours have been utilised, though primary testing has been on Linux only so far.
This commit is the basic patch. Additional changes will follow in this release to enhance some aspects of behaviour, notably improved handling of conflicts, deadlock detection and query cancellation. Changes to VACUUM FULL are also required.
Simon Riggs, with significant and lengthy review by Heikki Linnakangas, including streamlined redesign of snapshot creation and two-phase commit.
Important contributions from Florian Pflug, Mark Kirkwood, Merlin Moncure, Greg Stark, Gianni Ciolli, Gabriele Bartolini, Hannu Krosing, Robert Haas, Tatsuo Ishii, Hiroyuki Yamada plus support and feedback from many other community members.
2009-12-19 02:32:45 +01:00
|
|
|
/*
|
|
|
|
* Initialise array first time through in each commit
|
|
|
|
*/
|
|
|
|
if (SharedInvalidMessagesArray == NULL)
|
|
|
|
{
|
|
|
|
maxSharedInvalidMessagesArray = FIRSTCHUNKSIZE;
|
|
|
|
numSharedInvalidMessagesArray = 0;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Although this is being palloc'd we don't actually free it directly.
|
|
|
|
* We're so close to EOXact that we now we're going to lose it anyhow.
|
|
|
|
*/
|
|
|
|
SharedInvalidMessagesArray = palloc(maxSharedInvalidMessagesArray
|
|
|
|
* sizeof(SharedInvalidationMessage));
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((numSharedInvalidMessagesArray + n) > maxSharedInvalidMessagesArray)
|
|
|
|
{
|
|
|
|
while ((numSharedInvalidMessagesArray + n) > maxSharedInvalidMessagesArray)
|
|
|
|
maxSharedInvalidMessagesArray *= 2;
|
|
|
|
|
|
|
|
SharedInvalidMessagesArray = repalloc(SharedInvalidMessagesArray,
|
|
|
|
maxSharedInvalidMessagesArray
|
|
|
|
* sizeof(SharedInvalidationMessage));
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Append the next chunk onto the array
|
|
|
|
*/
|
|
|
|
memcpy(SharedInvalidMessagesArray + numSharedInvalidMessagesArray,
|
|
|
|
msgs, n * sizeof(SharedInvalidationMessage));
|
|
|
|
numSharedInvalidMessagesArray += n;
|
2005-06-18 00:32:51 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
Allow read only connections during recovery, known as Hot Standby.
Enabled by recovery_connections = on (default) and forcing archive recovery using a recovery.conf. Recovery processing now emulates the original transactions as they are replayed, providing full locking and MVCC behaviour for read only queries. Recovery must enter consistent state before connections are allowed, so there is a delay, typically short, before connections succeed. Replay of recovering transactions can conflict and in some cases deadlock with queries during recovery; these result in query cancellation after max_standby_delay seconds have expired. Infrastructure changes have minor effects on normal running, though introduce four new types of WAL record.
New test mode "make standbycheck" allows regression tests of static command behaviour on a standby server while in recovery. Typical and extreme dynamic behaviours have been checked via code inspection and manual testing. Few port specific behaviours have been utilised, though primary testing has been on Linux only so far.
This commit is the basic patch. Additional changes will follow in this release to enhance some aspects of behaviour, notably improved handling of conflicts, deadlock detection and query cancellation. Changes to VACUUM FULL are also required.
Simon Riggs, with significant and lengthy review by Heikki Linnakangas, including streamlined redesign of snapshot creation and two-phase commit.
Important contributions from Florian Pflug, Mark Kirkwood, Merlin Moncure, Greg Stark, Gianni Ciolli, Gabriele Bartolini, Hannu Krosing, Robert Haas, Tatsuo Ishii, Hiroyuki Yamada plus support and feedback from many other community members.
2009-12-19 02:32:45 +01:00
|
|
|
* xactGetCommittedInvalidationMessages() is executed by
|
|
|
|
* RecordTransactionCommit() to add invalidation messages onto the
|
|
|
|
* commit record. This applies only to commit message types, never to
|
|
|
|
* abort records. Must always run before AtEOXact_Inval(), since that
|
|
|
|
* removes the data we need to see.
|
|
|
|
*
|
|
|
|
* Remember that this runs before we have officially committed, so we
|
|
|
|
* must not do anything here to change what might occur *if* we should
|
|
|
|
* fail between here and the actual commit.
|
|
|
|
*
|
|
|
|
* see also xact_redo_commit() and xact_desc_commit()
|
2005-06-18 00:32:51 +02:00
|
|
|
*/
|
Allow read only connections during recovery, known as Hot Standby.
Enabled by recovery_connections = on (default) and forcing archive recovery using a recovery.conf. Recovery processing now emulates the original transactions as they are replayed, providing full locking and MVCC behaviour for read only queries. Recovery must enter consistent state before connections are allowed, so there is a delay, typically short, before connections succeed. Replay of recovering transactions can conflict and in some cases deadlock with queries during recovery; these result in query cancellation after max_standby_delay seconds have expired. Infrastructure changes have minor effects on normal running, though introduce four new types of WAL record.
New test mode "make standbycheck" allows regression tests of static command behaviour on a standby server while in recovery. Typical and extreme dynamic behaviours have been checked via code inspection and manual testing. Few port specific behaviours have been utilised, though primary testing has been on Linux only so far.
This commit is the basic patch. Additional changes will follow in this release to enhance some aspects of behaviour, notably improved handling of conflicts, deadlock detection and query cancellation. Changes to VACUUM FULL are also required.
Simon Riggs, with significant and lengthy review by Heikki Linnakangas, including streamlined redesign of snapshot creation and two-phase commit.
Important contributions from Florian Pflug, Mark Kirkwood, Merlin Moncure, Greg Stark, Gianni Ciolli, Gabriele Bartolini, Hannu Krosing, Robert Haas, Tatsuo Ishii, Hiroyuki Yamada plus support and feedback from many other community members.
2009-12-19 02:32:45 +01:00
|
|
|
int
|
|
|
|
xactGetCommittedInvalidationMessages(SharedInvalidationMessage **msgs,
|
|
|
|
bool *RelcacheInitFileInval)
|
2005-06-18 00:32:51 +02:00
|
|
|
{
|
Allow read only connections during recovery, known as Hot Standby.
Enabled by recovery_connections = on (default) and forcing archive recovery using a recovery.conf. Recovery processing now emulates the original transactions as they are replayed, providing full locking and MVCC behaviour for read only queries. Recovery must enter consistent state before connections are allowed, so there is a delay, typically short, before connections succeed. Replay of recovering transactions can conflict and in some cases deadlock with queries during recovery; these result in query cancellation after max_standby_delay seconds have expired. Infrastructure changes have minor effects on normal running, though introduce four new types of WAL record.
New test mode "make standbycheck" allows regression tests of static command behaviour on a standby server while in recovery. Typical and extreme dynamic behaviours have been checked via code inspection and manual testing. Few port specific behaviours have been utilised, though primary testing has been on Linux only so far.
This commit is the basic patch. Additional changes will follow in this release to enhance some aspects of behaviour, notably improved handling of conflicts, deadlock detection and query cancellation. Changes to VACUUM FULL are also required.
Simon Riggs, with significant and lengthy review by Heikki Linnakangas, including streamlined redesign of snapshot creation and two-phase commit.
Important contributions from Florian Pflug, Mark Kirkwood, Merlin Moncure, Greg Stark, Gianni Ciolli, Gabriele Bartolini, Hannu Krosing, Robert Haas, Tatsuo Ishii, Hiroyuki Yamada plus support and feedback from many other community members.
2009-12-19 02:32:45 +01:00
|
|
|
MemoryContext oldcontext;
|
2005-06-18 00:32:51 +02:00
|
|
|
|
Allow read only connections during recovery, known as Hot Standby.
Enabled by recovery_connections = on (default) and forcing archive recovery using a recovery.conf. Recovery processing now emulates the original transactions as they are replayed, providing full locking and MVCC behaviour for read only queries. Recovery must enter consistent state before connections are allowed, so there is a delay, typically short, before connections succeed. Replay of recovering transactions can conflict and in some cases deadlock with queries during recovery; these result in query cancellation after max_standby_delay seconds have expired. Infrastructure changes have minor effects on normal running, though introduce four new types of WAL record.
New test mode "make standbycheck" allows regression tests of static command behaviour on a standby server while in recovery. Typical and extreme dynamic behaviours have been checked via code inspection and manual testing. Few port specific behaviours have been utilised, though primary testing has been on Linux only so far.
This commit is the basic patch. Additional changes will follow in this release to enhance some aspects of behaviour, notably improved handling of conflicts, deadlock detection and query cancellation. Changes to VACUUM FULL are also required.
Simon Riggs, with significant and lengthy review by Heikki Linnakangas, including streamlined redesign of snapshot creation and two-phase commit.
Important contributions from Florian Pflug, Mark Kirkwood, Merlin Moncure, Greg Stark, Gianni Ciolli, Gabriele Bartolini, Hannu Krosing, Robert Haas, Tatsuo Ishii, Hiroyuki Yamada plus support and feedback from many other community members.
2009-12-19 02:32:45 +01:00
|
|
|
/* Must be at top of stack */
|
|
|
|
Assert(transInvalInfo != NULL && transInvalInfo->parent == NULL);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Relcache init file invalidation requires processing both before and
|
|
|
|
* after we send the SI messages. However, we need not do anything
|
|
|
|
* unless we committed.
|
|
|
|
*/
|
|
|
|
*RelcacheInitFileInval = transInvalInfo->RelcacheInitFileInval;
|
2005-06-18 00:32:51 +02:00
|
|
|
|
Allow read only connections during recovery, known as Hot Standby.
Enabled by recovery_connections = on (default) and forcing archive recovery using a recovery.conf. Recovery processing now emulates the original transactions as they are replayed, providing full locking and MVCC behaviour for read only queries. Recovery must enter consistent state before connections are allowed, so there is a delay, typically short, before connections succeed. Replay of recovering transactions can conflict and in some cases deadlock with queries during recovery; these result in query cancellation after max_standby_delay seconds have expired. Infrastructure changes have minor effects on normal running, though introduce four new types of WAL record.
New test mode "make standbycheck" allows regression tests of static command behaviour on a standby server while in recovery. Typical and extreme dynamic behaviours have been checked via code inspection and manual testing. Few port specific behaviours have been utilised, though primary testing has been on Linux only so far.
This commit is the basic patch. Additional changes will follow in this release to enhance some aspects of behaviour, notably improved handling of conflicts, deadlock detection and query cancellation. Changes to VACUUM FULL are also required.
Simon Riggs, with significant and lengthy review by Heikki Linnakangas, including streamlined redesign of snapshot creation and two-phase commit.
Important contributions from Florian Pflug, Mark Kirkwood, Merlin Moncure, Greg Stark, Gianni Ciolli, Gabriele Bartolini, Hannu Krosing, Robert Haas, Tatsuo Ishii, Hiroyuki Yamada plus support and feedback from many other community members.
2009-12-19 02:32:45 +01:00
|
|
|
/*
|
|
|
|
* Walk through TransInvalidationInfo to collect all the messages
|
|
|
|
* into a single contiguous array of invalidation messages. It must
|
|
|
|
* be contiguous so we can copy directly into WAL message. Maintain the
|
|
|
|
* order that they would be processed in by AtEOXact_Inval(), to ensure
|
|
|
|
* emulated behaviour in redo is as similar as possible to original.
|
|
|
|
* We want the same bugs, if any, not new ones.
|
|
|
|
*/
|
|
|
|
oldcontext = MemoryContextSwitchTo(CurTransactionContext);
|
|
|
|
|
|
|
|
ProcessInvalidationMessagesMulti(&transInvalInfo->CurrentCmdInvalidMsgs,
|
|
|
|
MakeSharedInvalidMessagesArray);
|
|
|
|
ProcessInvalidationMessagesMulti(&transInvalInfo->PriorCmdInvalidMsgs,
|
|
|
|
MakeSharedInvalidMessagesArray);
|
|
|
|
MemoryContextSwitchTo(oldcontext);
|
|
|
|
|
|
|
|
Assert(!(numSharedInvalidMessagesArray > 0 &&
|
|
|
|
SharedInvalidMessagesArray == NULL));
|
|
|
|
|
|
|
|
*msgs = SharedInvalidMessagesArray;
|
|
|
|
|
|
|
|
return numSharedInvalidMessagesArray;
|
|
|
|
}
|
2005-06-18 00:32:51 +02:00
|
|
|
|
2010-01-09 17:49:27 +01:00
|
|
|
#define RecoveryRelationCacheInitFileInvalidate(dbo, tbo, tf) \
|
|
|
|
{ \
|
|
|
|
DatabasePath = GetDatabasePath(dbo, tbo); \
|
|
|
|
elog(trace_recovery(DEBUG4), "removing relcache init file in %s", DatabasePath); \
|
|
|
|
RelationCacheInitFileInvalidate(tf); \
|
|
|
|
pfree(DatabasePath); \
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* ProcessCommittedInvalidationMessages is executed by xact_redo_commit()
|
|
|
|
* to process invalidation messages added to commit records.
|
|
|
|
*
|
|
|
|
* Relcache init file invalidation requires processing both
|
|
|
|
* before and after we send the SI messages. See AtEOXact_Inval()
|
|
|
|
*
|
|
|
|
* We deliberately avoid SetDatabasePath() since it is intended to be used
|
|
|
|
* only once by normal backends, so we set DatabasePath directly then
|
|
|
|
* pfree after use. See RecoveryRelationCacheInitFileInvalidate() macro.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
ProcessCommittedInvalidationMessages(SharedInvalidationMessage *msgs,
|
2010-02-13 17:15:48 +01:00
|
|
|
int nmsgs, bool RelcacheInitFileInval,
|
|
|
|
Oid dbid, Oid tsid)
|
2010-01-09 17:49:27 +01:00
|
|
|
{
|
2010-02-13 17:15:48 +01:00
|
|
|
if (nmsgs <= 0)
|
|
|
|
return;
|
2010-01-09 17:49:27 +01:00
|
|
|
|
2010-02-13 17:15:48 +01:00
|
|
|
elog(trace_recovery(DEBUG4), "replaying commit with %d messages%s", nmsgs,
|
2010-01-09 17:49:27 +01:00
|
|
|
(RelcacheInitFileInval ? " and relcache file invalidation" : ""));
|
|
|
|
|
|
|
|
if (RelcacheInitFileInval)
|
2010-02-13 17:15:48 +01:00
|
|
|
RecoveryRelationCacheInitFileInvalidate(dbid, tsid, true);
|
2010-01-09 17:49:27 +01:00
|
|
|
|
|
|
|
SendSharedInvalidMessages(msgs, nmsgs);
|
|
|
|
|
|
|
|
if (RelcacheInitFileInval)
|
2010-02-13 17:15:48 +01:00
|
|
|
RecoveryRelationCacheInitFileInvalidate(dbid, tsid, false);
|
2010-01-09 17:49:27 +01:00
|
|
|
}
|
|
|
|
|
2004-07-01 02:52:04 +02:00
|
|
|
/*
|
|
|
|
* AtEOXact_Inval
|
|
|
|
* Process queued-up invalidation messages at end of main transaction.
|
2001-06-19 21:42:16 +02:00
|
|
|
*
|
2002-03-03 18:47:56 +01:00
|
|
|
* If isCommit, we must send out the messages in our PriorCmdInvalidMsgs list
|
2001-06-19 21:42:16 +02:00
|
|
|
* to the shared invalidation message queue. Note that these will be read
|
|
|
|
* not only by other backends, but also by our own backend at the next
|
2002-09-04 22:31:48 +02:00
|
|
|
* transaction start (via AcceptInvalidationMessages). This means that
|
2002-03-03 18:47:56 +01:00
|
|
|
* we can skip immediate local processing of anything that's still in
|
|
|
|
* CurrentCmdInvalidMsgs, and just send that list out too.
|
2001-06-19 21:42:16 +02:00
|
|
|
*
|
|
|
|
* If not isCommit, we are aborting, and must locally process the messages
|
2002-09-04 22:31:48 +02:00
|
|
|
* in PriorCmdInvalidMsgs. No messages need be sent to other backends,
|
2002-03-03 18:47:56 +01:00
|
|
|
* since they'll not have seen our changed tuples anyway. We can forget
|
|
|
|
* about CurrentCmdInvalidMsgs too, since those changes haven't touched
|
|
|
|
* the caches yet.
|
2001-06-19 21:42:16 +02:00
|
|
|
*
|
|
|
|
* In any case, reset the various lists to empty. We need not physically
|
|
|
|
* free memory here, since TopTransactionContext is about to be emptied
|
|
|
|
* anyway.
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
* Note:
|
1997-09-07 07:04:48 +02:00
|
|
|
* This should be called as the last step in processing a transaction.
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
|
|
|
void
|
2004-07-01 02:52:04 +02:00
|
|
|
AtEOXact_Inval(bool isCommit)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
2001-06-19 21:42:16 +02:00
|
|
|
if (isCommit)
|
2000-01-10 07:30:56 +01:00
|
|
|
{
|
2004-09-07 01:33:48 +02:00
|
|
|
/* Must be at top of stack */
|
|
|
|
Assert(transInvalInfo != NULL && transInvalInfo->parent == NULL);
|
|
|
|
|
2002-02-19 21:11:20 +01:00
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* Relcache init file invalidation requires processing both before and
|
|
|
|
* after we send the SI messages. However, we need not do anything
|
|
|
|
* unless we committed.
|
2002-02-19 21:11:20 +01:00
|
|
|
*/
|
2004-07-01 02:52:04 +02:00
|
|
|
if (transInvalInfo->RelcacheInitFileInval)
|
2002-02-19 21:11:20 +01:00
|
|
|
RelationCacheInitFileInvalidate(true);
|
|
|
|
|
2004-07-01 02:52:04 +02:00
|
|
|
AppendInvalidationMessages(&transInvalInfo->PriorCmdInvalidMsgs,
|
2005-10-15 04:49:52 +02:00
|
|
|
&transInvalInfo->CurrentCmdInvalidMsgs);
|
2002-03-03 18:47:56 +01:00
|
|
|
|
2008-06-19 23:32:56 +02:00
|
|
|
ProcessInvalidationMessagesMulti(&transInvalInfo->PriorCmdInvalidMsgs,
|
|
|
|
SendSharedInvalidMessages);
|
2002-02-19 21:11:20 +01:00
|
|
|
|
2004-07-01 02:52:04 +02:00
|
|
|
if (transInvalInfo->RelcacheInitFileInval)
|
2002-02-19 21:11:20 +01:00
|
|
|
RelationCacheInitFileInvalidate(false);
|
2000-01-10 07:30:56 +01:00
|
|
|
}
|
2004-09-07 01:33:48 +02:00
|
|
|
else if (transInvalInfo != NULL)
|
2000-01-10 07:30:56 +01:00
|
|
|
{
|
2004-09-07 01:33:48 +02:00
|
|
|
/* Must be at top of stack */
|
|
|
|
Assert(transInvalInfo->parent == NULL);
|
|
|
|
|
2004-07-01 02:52:04 +02:00
|
|
|
ProcessInvalidationMessages(&transInvalInfo->PriorCmdInvalidMsgs,
|
2001-06-19 21:42:16 +02:00
|
|
|
LocalExecuteInvalidationMessage);
|
2000-01-10 07:30:56 +01:00
|
|
|
}
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2004-07-01 02:52:04 +02:00
|
|
|
/* Need not free anything explicitly */
|
|
|
|
transInvalInfo = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2004-07-28 16:23:31 +02:00
|
|
|
* AtEOSubXact_Inval
|
2004-07-01 02:52:04 +02:00
|
|
|
* Process queued-up invalidation messages at end of subtransaction.
|
|
|
|
*
|
|
|
|
* If isCommit, process CurrentCmdInvalidMsgs if any (there probably aren't),
|
|
|
|
* and then attach both CurrentCmdInvalidMsgs and PriorCmdInvalidMsgs to the
|
|
|
|
* parent's PriorCmdInvalidMsgs list.
|
|
|
|
*
|
|
|
|
* If not isCommit, we are aborting, and must locally process the messages
|
|
|
|
* in PriorCmdInvalidMsgs. No messages need be sent to other backends.
|
|
|
|
* We can forget about CurrentCmdInvalidMsgs too, since those changes haven't
|
|
|
|
* touched the caches yet.
|
|
|
|
*
|
2004-08-29 07:07:03 +02:00
|
|
|
* In any case, pop the transaction stack. We need not physically free memory
|
2004-07-01 02:52:04 +02:00
|
|
|
* here, since CurTransactionContext is about to be emptied anyway
|
2004-09-07 01:33:48 +02:00
|
|
|
* (if aborting). Beware of the possibility of aborting the same nesting
|
|
|
|
* level twice, though.
|
2004-07-01 02:52:04 +02:00
|
|
|
*/
|
|
|
|
void
|
2004-07-28 16:23:31 +02:00
|
|
|
AtEOSubXact_Inval(bool isCommit)
|
2004-07-01 02:52:04 +02:00
|
|
|
{
|
2004-09-07 01:33:48 +02:00
|
|
|
int my_level = GetCurrentTransactionNestLevel();
|
2004-07-01 02:52:04 +02:00
|
|
|
TransInvalidationInfo *myInfo = transInvalInfo;
|
|
|
|
|
|
|
|
if (isCommit)
|
|
|
|
{
|
2004-09-07 01:33:48 +02:00
|
|
|
/* Must be at non-top of stack */
|
|
|
|
Assert(myInfo != NULL && myInfo->parent != NULL);
|
|
|
|
Assert(myInfo->my_level == my_level);
|
|
|
|
|
2004-07-01 02:52:04 +02:00
|
|
|
/* If CurrentCmdInvalidMsgs still has anything, fix it */
|
|
|
|
CommandEndInvalidationMessages();
|
|
|
|
|
|
|
|
/* Pass up my inval messages to parent */
|
|
|
|
AppendInvalidationMessages(&myInfo->parent->PriorCmdInvalidMsgs,
|
|
|
|
&myInfo->PriorCmdInvalidMsgs);
|
2002-02-19 21:11:20 +01:00
|
|
|
|
2004-07-01 02:52:04 +02:00
|
|
|
/* Pending relcache inval becomes parent's problem too */
|
|
|
|
if (myInfo->RelcacheInitFileInval)
|
|
|
|
myInfo->parent->RelcacheInitFileInval = true;
|
2004-09-07 01:33:48 +02:00
|
|
|
|
|
|
|
/* Pop the transaction state stack */
|
|
|
|
transInvalInfo = myInfo->parent;
|
|
|
|
|
|
|
|
/* Need not free anything else explicitly */
|
|
|
|
pfree(myInfo);
|
2004-07-01 02:52:04 +02:00
|
|
|
}
|
2004-09-07 01:33:48 +02:00
|
|
|
else if (myInfo != NULL && myInfo->my_level == my_level)
|
2004-07-01 02:52:04 +02:00
|
|
|
{
|
2004-09-07 01:33:48 +02:00
|
|
|
/* Must be at non-top of stack */
|
|
|
|
Assert(myInfo->parent != NULL);
|
|
|
|
|
2004-07-01 02:52:04 +02:00
|
|
|
ProcessInvalidationMessages(&myInfo->PriorCmdInvalidMsgs,
|
|
|
|
LocalExecuteInvalidationMessage);
|
|
|
|
|
2004-09-07 01:33:48 +02:00
|
|
|
/* Pop the transaction state stack */
|
|
|
|
transInvalInfo = myInfo->parent;
|
2004-07-01 02:52:04 +02:00
|
|
|
|
2004-09-07 01:33:48 +02:00
|
|
|
/* Need not free anything else explicitly */
|
|
|
|
pfree(myInfo);
|
|
|
|
}
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2001-06-19 21:42:16 +02:00
|
|
|
* CommandEndInvalidationMessages
|
|
|
|
* Process queued-up invalidation messages at end of one command
|
|
|
|
* in a transaction.
|
|
|
|
*
|
|
|
|
* Here, we send no messages to the shared queue, since we don't know yet if
|
2002-03-03 18:47:56 +01:00
|
|
|
* we will commit. We do need to locally process the CurrentCmdInvalidMsgs
|
|
|
|
* list, so as to flush our caches of any entries we have outdated in the
|
|
|
|
* current command. We then move the current-cmd list over to become part
|
|
|
|
* of the prior-cmds list.
|
2001-06-19 21:42:16 +02:00
|
|
|
*
|
1996-07-09 08:22:35 +02:00
|
|
|
* Note:
|
2001-01-05 23:54:37 +01:00
|
|
|
* This should be called during CommandCounterIncrement(),
|
|
|
|
* after we have advanced the command ID.
|
2000-01-10 07:30:56 +01:00
|
|
|
*/
|
|
|
|
void
|
2004-07-01 02:52:04 +02:00
|
|
|
CommandEndInvalidationMessages(void)
|
2000-01-10 07:30:56 +01:00
|
|
|
{
|
2004-07-01 02:52:04 +02:00
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* You might think this shouldn't be called outside any transaction, but
|
|
|
|
* bootstrap does it, and also ABORT issued when not in a transaction. So
|
|
|
|
* just quietly return if no state to work on.
|
2004-07-01 02:52:04 +02:00
|
|
|
*/
|
|
|
|
if (transInvalInfo == NULL)
|
|
|
|
return;
|
|
|
|
|
|
|
|
ProcessInvalidationMessages(&transInvalInfo->CurrentCmdInvalidMsgs,
|
|
|
|
LocalExecuteInvalidationMessage);
|
|
|
|
AppendInvalidationMessages(&transInvalInfo->PriorCmdInvalidMsgs,
|
|
|
|
&transInvalInfo->CurrentCmdInvalidMsgs);
|
2000-01-10 07:30:56 +01:00
|
|
|
}
|
2000-04-12 19:17:23 +02:00
|
|
|
|
2008-03-13 19:00:32 +01:00
|
|
|
|
2000-01-10 07:30:56 +01:00
|
|
|
/*
|
2002-03-03 18:47:56 +01:00
|
|
|
* CacheInvalidateHeapTuple
|
2001-01-05 23:54:37 +01:00
|
|
|
* Register the given tuple for invalidation at end of command
|
2004-02-10 02:55:27 +01:00
|
|
|
* (ie, current command is creating or outdating this tuple).
|
2000-01-10 07:30:56 +01:00
|
|
|
*/
|
|
|
|
void
|
2002-03-03 18:47:56 +01:00
|
|
|
CacheInvalidateHeapTuple(Relation relation, HeapTuple tuple)
|
2000-01-10 07:30:56 +01:00
|
|
|
{
|
2005-01-10 22:57:19 +01:00
|
|
|
PrepareForTupleInvalidation(relation, tuple);
|
2000-01-10 07:30:56 +01:00
|
|
|
}
|
|
|
|
|
2010-02-07 21:48:13 +01:00
|
|
|
/*
|
|
|
|
* CacheInvalidateCatalog
|
|
|
|
* Register invalidation of the whole content of a system catalog.
|
|
|
|
*
|
|
|
|
* This is normally used in VACUUM FULL/CLUSTER, where we haven't so much
|
|
|
|
* changed any tuples as moved them around. Some uses of catcache entries
|
|
|
|
* expect their TIDs to be correct, so we have to blow away the entries.
|
|
|
|
*
|
|
|
|
* Note: we expect caller to verify that the rel actually is a system
|
|
|
|
* catalog. If it isn't, no great harm is done, just a wasted sinval message.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
CacheInvalidateCatalog(Oid catalogId)
|
|
|
|
{
|
|
|
|
Oid databaseId;
|
|
|
|
|
|
|
|
if (IsSharedRelation(catalogId))
|
|
|
|
databaseId = InvalidOid;
|
|
|
|
else
|
|
|
|
databaseId = MyDatabaseId;
|
|
|
|
|
|
|
|
RegisterCatalogInvalidation(databaseId, catalogId);
|
|
|
|
}
|
|
|
|
|
2000-01-10 07:30:56 +01:00
|
|
|
/*
|
2002-03-03 18:47:56 +01:00
|
|
|
* CacheInvalidateRelcache
|
|
|
|
* Register invalidation of the specified relation's relcache entry
|
|
|
|
* at end of command.
|
|
|
|
*
|
|
|
|
* This is used in places that need to force relcache rebuild but aren't
|
|
|
|
* changing any of the tuples recognized as contributors to the relcache
|
|
|
|
* entry by PrepareForTupleInvalidation. (An example is dropping an index.)
|
2000-01-10 07:30:56 +01:00
|
|
|
*/
|
|
|
|
void
|
2004-02-10 02:55:27 +01:00
|
|
|
CacheInvalidateRelcache(Relation relation)
|
2000-01-10 07:30:56 +01:00
|
|
|
{
|
2004-02-10 02:55:27 +01:00
|
|
|
Oid databaseId;
|
|
|
|
Oid relationId;
|
|
|
|
|
|
|
|
relationId = RelationGetRelid(relation);
|
|
|
|
if (relation->rd_rel->relisshared)
|
|
|
|
databaseId = InvalidOid;
|
|
|
|
else
|
|
|
|
databaseId = MyDatabaseId;
|
|
|
|
|
2005-01-10 22:57:19 +01:00
|
|
|
RegisterRelcacheInvalidation(databaseId, relationId);
|
2004-02-10 02:55:27 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* CacheInvalidateRelcacheByTuple
|
|
|
|
* As above, but relation is identified by passing its pg_class tuple.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
CacheInvalidateRelcacheByTuple(HeapTuple classTuple)
|
|
|
|
{
|
|
|
|
Form_pg_class classtup = (Form_pg_class) GETSTRUCT(classTuple);
|
|
|
|
Oid databaseId;
|
|
|
|
Oid relationId;
|
|
|
|
|
|
|
|
relationId = HeapTupleGetOid(classTuple);
|
|
|
|
if (classtup->relisshared)
|
|
|
|
databaseId = InvalidOid;
|
|
|
|
else
|
|
|
|
databaseId = MyDatabaseId;
|
2005-01-10 22:57:19 +01:00
|
|
|
RegisterRelcacheInvalidation(databaseId, relationId);
|
2000-01-10 07:30:56 +01:00
|
|
|
}
|
2002-04-30 00:14:34 +02:00
|
|
|
|
2004-05-06 18:10:57 +02:00
|
|
|
/*
|
|
|
|
* CacheInvalidateRelcacheByRelid
|
|
|
|
* As above, but relation is identified by passing its OID.
|
|
|
|
* This is the least efficient of the three options; use one of
|
|
|
|
* the above routines if you have a Relation or pg_class tuple.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
CacheInvalidateRelcacheByRelid(Oid relid)
|
|
|
|
{
|
|
|
|
HeapTuple tup;
|
|
|
|
|
|
|
|
tup = SearchSysCache(RELOID,
|
|
|
|
ObjectIdGetDatum(relid),
|
|
|
|
0, 0, 0);
|
|
|
|
if (!HeapTupleIsValid(tup))
|
|
|
|
elog(ERROR, "cache lookup failed for relation %u", relid);
|
|
|
|
CacheInvalidateRelcacheByTuple(tup);
|
|
|
|
ReleaseSysCache(tup);
|
|
|
|
}
|
|
|
|
|
2010-02-03 02:14:17 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* CacheInvalidateSmgr
|
|
|
|
* Register invalidation of smgr references to a physical relation.
|
|
|
|
*
|
|
|
|
* Sending this type of invalidation msg forces other backends to close open
|
|
|
|
* smgr entries for the rel. This should be done to flush dangling open-file
|
|
|
|
* references when the physical rel is being dropped or truncated. Because
|
|
|
|
* these are nontransactional (i.e., not-rollback-able) operations, we just
|
|
|
|
* send the inval message immediately without any queuing.
|
|
|
|
*
|
|
|
|
* Note: in most cases there will have been a relcache flush issued against
|
|
|
|
* the rel at the logical level. We need a separate smgr-level flush because
|
|
|
|
* it is possible for backends to have open smgr entries for rels they don't
|
|
|
|
* have a relcache entry for, e.g. because the only thing they ever did with
|
|
|
|
* the rel is write out dirty shared buffers.
|
|
|
|
*
|
|
|
|
* Note: because these messages are nontransactional, they won't be captured
|
|
|
|
* in commit/abort WAL entries. Instead, calls to CacheInvalidateSmgr()
|
|
|
|
* should happen in low-level smgr.c routines, which are executed while
|
|
|
|
* replaying WAL as well as when creating it.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
CacheInvalidateSmgr(RelFileNode rnode)
|
|
|
|
{
|
|
|
|
SharedInvalidationMessage msg;
|
|
|
|
|
|
|
|
msg.sm.id = SHAREDINVALSMGR_ID;
|
|
|
|
msg.sm.rnode = rnode;
|
|
|
|
SendSharedInvalidMessages(&msg, 1);
|
|
|
|
}
|
|
|
|
|
2010-02-07 21:48:13 +01:00
|
|
|
/*
|
|
|
|
* CacheInvalidateRelmap
|
|
|
|
* Register invalidation of the relation mapping for a database,
|
|
|
|
* or for the shared catalogs if databaseId is zero.
|
|
|
|
*
|
|
|
|
* Sending this type of invalidation msg forces other backends to re-read
|
|
|
|
* the indicated relation mapping file. It is also necessary to send a
|
|
|
|
* relcache inval for the specific relations whose mapping has been altered,
|
|
|
|
* else the relcache won't get updated with the new filenode data.
|
|
|
|
*
|
|
|
|
* Note: because these messages are nontransactional, they won't be captured
|
|
|
|
* in commit/abort WAL entries. Instead, calls to CacheInvalidateRelmap()
|
|
|
|
* should happen in low-level relmapper.c routines, which are executed while
|
|
|
|
* replaying WAL as well as when creating it.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
CacheInvalidateRelmap(Oid databaseId)
|
|
|
|
{
|
|
|
|
SharedInvalidationMessage msg;
|
|
|
|
|
|
|
|
msg.rm.id = SHAREDINVALRELMAP_ID;
|
|
|
|
msg.rm.dbId = databaseId;
|
|
|
|
SendSharedInvalidMessages(&msg, 1);
|
|
|
|
}
|
|
|
|
|
2010-02-03 02:14:17 +01:00
|
|
|
|
2002-04-30 00:14:34 +02:00
|
|
|
/*
|
|
|
|
* CacheRegisterSyscacheCallback
|
|
|
|
* Register the specified function to be called for all future
|
2008-09-09 20:58:09 +02:00
|
|
|
* invalidation events in the specified cache. The cache ID and the
|
|
|
|
* TID of the tuple being invalidated will be passed to the function.
|
2002-04-30 00:14:34 +02:00
|
|
|
*
|
2008-09-09 20:58:09 +02:00
|
|
|
* NOTE: NULL will be passed for the TID if a cache reset request is received.
|
|
|
|
* In this case the called routines should flush all cached state.
|
2002-04-30 00:14:34 +02:00
|
|
|
*/
|
|
|
|
void
|
|
|
|
CacheRegisterSyscacheCallback(int cacheid,
|
2008-09-09 20:58:09 +02:00
|
|
|
SyscacheCallbackFunction func,
|
2002-04-30 00:14:34 +02:00
|
|
|
Datum arg)
|
|
|
|
{
|
2008-09-09 20:58:09 +02:00
|
|
|
if (syscache_callback_count >= MAX_SYSCACHE_CALLBACKS)
|
|
|
|
elog(FATAL, "out of syscache_callback_list slots");
|
2002-04-30 00:14:34 +02:00
|
|
|
|
2008-09-09 20:58:09 +02:00
|
|
|
syscache_callback_list[syscache_callback_count].id = cacheid;
|
|
|
|
syscache_callback_list[syscache_callback_count].function = func;
|
|
|
|
syscache_callback_list[syscache_callback_count].arg = arg;
|
2002-04-30 00:14:34 +02:00
|
|
|
|
2008-09-09 20:58:09 +02:00
|
|
|
++syscache_callback_count;
|
2002-04-30 00:14:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* CacheRegisterRelcacheCallback
|
|
|
|
* Register the specified function to be called for all future
|
|
|
|
* relcache invalidation events. The OID of the relation being
|
|
|
|
* invalidated will be passed to the function.
|
|
|
|
*
|
|
|
|
* NOTE: InvalidOid will be passed if a cache reset request is received.
|
|
|
|
* In this case the called routines should flush all cached state.
|
|
|
|
*/
|
|
|
|
void
|
2008-09-09 20:58:09 +02:00
|
|
|
CacheRegisterRelcacheCallback(RelcacheCallbackFunction func,
|
2002-04-30 00:14:34 +02:00
|
|
|
Datum arg)
|
|
|
|
{
|
2008-09-09 20:58:09 +02:00
|
|
|
if (relcache_callback_count >= MAX_RELCACHE_CALLBACKS)
|
|
|
|
elog(FATAL, "out of relcache_callback_list slots");
|
2002-04-30 00:14:34 +02:00
|
|
|
|
2008-09-09 20:58:09 +02:00
|
|
|
relcache_callback_list[relcache_callback_count].function = func;
|
|
|
|
relcache_callback_list[relcache_callback_count].arg = arg;
|
2002-04-30 00:14:34 +02:00
|
|
|
|
2008-09-09 20:58:09 +02:00
|
|
|
++relcache_callback_count;
|
2002-04-30 00:14:34 +02:00
|
|
|
}
|
2010-02-07 21:48:13 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* CallSyscacheCallbacks
|
|
|
|
*
|
|
|
|
* This is exported so that CatalogCacheFlushCatalog can call it, saving
|
|
|
|
* this module from knowing which catcache IDs correspond to which catalogs.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
CallSyscacheCallbacks(int cacheid, ItemPointer tuplePtr)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < syscache_callback_count; i++)
|
|
|
|
{
|
|
|
|
struct SYSCACHECALLBACK *ccitem = syscache_callback_list + i;
|
|
|
|
|
|
|
|
if (ccitem->id == cacheid)
|
|
|
|
(*ccitem->function) (ccitem->arg, cacheid, tuplePtr);
|
|
|
|
}
|
|
|
|
}
|