mirror of
https://git.postgresql.org/git/postgresql.git
synced 2024-12-27 08:39:28 +08:00
Keep the list of to-be-NOTIFYed names in a plain List palloc'd in
TopTransactionContext, rather than using Dllist. This simplifies and speeds up the code, and eliminates a former risk of coredump when out of memory (since the old code didn't bother to check for malloc failure). It also moves us one step closer to retiring Dllist...
This commit is contained in:
parent
1f1ca182be
commit
6054b33290
@ -7,7 +7,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/async.c,v 1.78 2001/06/12 05:55:49 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/async.c,v 1.79 2001/06/17 22:27:15 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -82,7 +82,6 @@
|
||||
#include "catalog/catname.h"
|
||||
#include "catalog/pg_listener.h"
|
||||
#include "commands/async.h"
|
||||
#include "lib/dllist.h"
|
||||
#include "libpq/libpq.h"
|
||||
#include "libpq/pqformat.h"
|
||||
#include "miscadmin.h"
|
||||
@ -100,10 +99,11 @@ extern CommandDest whereToSendOutput;
|
||||
/*
|
||||
* State for outbound notifies consists of a list of all relnames NOTIFYed
|
||||
* in the current transaction. We do not actually perform a NOTIFY until
|
||||
* and unless the transaction commits. pendingNotifies is NULL if no
|
||||
* NOTIFYs have been done in the current transaction.
|
||||
* and unless the transaction commits. pendingNotifies is NIL if no
|
||||
* NOTIFYs have been done in the current transaction. The List nodes and
|
||||
* referenced strings are all palloc'd in TopTransactionContext.
|
||||
*/
|
||||
static Dllist *pendingNotifies = NULL;
|
||||
static List *pendingNotifies = NIL;
|
||||
|
||||
/*
|
||||
* State for inbound notifies consists of two flags: one saying whether
|
||||
@ -121,16 +121,16 @@ static volatile int notifyInterruptOccurred = 0;
|
||||
/* True if we've registered an on_shmem_exit cleanup */
|
||||
static bool unlistenExitRegistered = false;
|
||||
|
||||
bool Trace_notify = false;
|
||||
|
||||
|
||||
static void Async_UnlistenAll(void);
|
||||
static void Async_UnlistenOnExit(void);
|
||||
static void ProcessIncomingNotify(void);
|
||||
static void NotifyMyFrontEnd(char *relname, int32 listenerPID);
|
||||
static int AsyncExistsPendingNotify(char *relname);
|
||||
static bool AsyncExistsPendingNotify(const char *relname);
|
||||
static void ClearPendingNotifies(void);
|
||||
|
||||
bool Trace_notify = false;
|
||||
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------
|
||||
@ -150,26 +150,23 @@ bool Trace_notify = false;
|
||||
void
|
||||
Async_Notify(char *relname)
|
||||
{
|
||||
char *notifyName;
|
||||
|
||||
if (Trace_notify)
|
||||
elog(DEBUG, "Async_Notify: %s", relname);
|
||||
|
||||
if (!pendingNotifies)
|
||||
pendingNotifies = DLNewList();
|
||||
/* no point in making duplicate entries in the list ... */
|
||||
if (!AsyncExistsPendingNotify(relname))
|
||||
if (! AsyncExistsPendingNotify(relname))
|
||||
{
|
||||
|
||||
/*
|
||||
* We allocate list memory from the global malloc pool to ensure
|
||||
* that it will live until we want to use it. This is probably
|
||||
* not necessary any longer, since we will use it before the end
|
||||
* of the transaction. DLList only knows how to use malloc()
|
||||
* anyway, but we could probably palloc() the strings...
|
||||
* The name list needs to live until end of transaction, so
|
||||
* store it in the top transaction context.
|
||||
*/
|
||||
notifyName = strdup(relname);
|
||||
DLAddHead(pendingNotifies, DLNewElem(notifyName));
|
||||
MemoryContext oldcontext;
|
||||
|
||||
oldcontext = MemoryContextSwitchTo(TopTransactionContext);
|
||||
|
||||
pendingNotifies = lcons(pstrdup(relname), pendingNotifies);
|
||||
|
||||
MemoryContextSwitchTo(oldcontext);
|
||||
}
|
||||
}
|
||||
|
||||
@ -352,7 +349,7 @@ Async_Unlisten(char *relname, int pid)
|
||||
*--------------------------------------------------------------
|
||||
*/
|
||||
static void
|
||||
Async_UnlistenAll()
|
||||
Async_UnlistenAll(void)
|
||||
{
|
||||
Relation lRel;
|
||||
TupleDesc tdesc;
|
||||
@ -401,7 +398,6 @@ Async_UnlistenAll()
|
||||
static void
|
||||
Async_UnlistenOnExit(void)
|
||||
{
|
||||
|
||||
/*
|
||||
* We need to start/commit a transaction for the unlisten, but if
|
||||
* there is already an active transaction we had better abort that one
|
||||
@ -438,7 +434,7 @@ Async_UnlistenOnExit(void)
|
||||
*--------------------------------------------------------------
|
||||
*/
|
||||
void
|
||||
AtCommit_Notify()
|
||||
AtCommit_Notify(void)
|
||||
{
|
||||
Relation lRel;
|
||||
TupleDesc tdesc;
|
||||
@ -449,7 +445,7 @@ AtCommit_Notify()
|
||||
char repl[Natts_pg_listener],
|
||||
nulls[Natts_pg_listener];
|
||||
|
||||
if (!pendingNotifies)
|
||||
if (pendingNotifies == NIL)
|
||||
return; /* no NOTIFY statements in this
|
||||
* transaction */
|
||||
|
||||
@ -579,7 +575,7 @@ AtCommit_Notify()
|
||||
*--------------------------------------------------------------
|
||||
*/
|
||||
void
|
||||
AtAbort_Notify()
|
||||
AtAbort_Notify(void)
|
||||
{
|
||||
ClearPendingNotifies();
|
||||
}
|
||||
@ -601,7 +597,6 @@ AtAbort_Notify()
|
||||
* per above
|
||||
*--------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void
|
||||
Async_NotifyHandler(SIGNAL_ARGS)
|
||||
{
|
||||
@ -671,7 +666,6 @@ Async_NotifyHandler(SIGNAL_ARGS)
|
||||
* PostgresMain calls this the first time.
|
||||
* --------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void
|
||||
EnableNotifyInterrupt(void)
|
||||
{
|
||||
@ -729,7 +723,6 @@ EnableNotifyInterrupt(void)
|
||||
* is disabled until the next EnableNotifyInterrupt call.
|
||||
* --------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void
|
||||
DisableNotifyInterrupt(void)
|
||||
{
|
||||
@ -848,8 +841,9 @@ ProcessIncomingNotify(void)
|
||||
elog(DEBUG, "ProcessIncomingNotify: done");
|
||||
}
|
||||
|
||||
/* Send NOTIFY message to my front end. */
|
||||
|
||||
/*
|
||||
* Send NOTIFY message to my front end.
|
||||
*/
|
||||
static void
|
||||
NotifyMyFrontEnd(char *relname, int32 listenerPID)
|
||||
{
|
||||
@ -874,50 +868,32 @@ NotifyMyFrontEnd(char *relname, int32 listenerPID)
|
||||
elog(NOTICE, "NOTIFY for %s", relname);
|
||||
}
|
||||
|
||||
/* Does pendingNotifies include the given relname?
|
||||
*
|
||||
* NB: not called unless pendingNotifies != NULL.
|
||||
*/
|
||||
|
||||
static int
|
||||
AsyncExistsPendingNotify(char *relname)
|
||||
/* Does pendingNotifies include the given relname? */
|
||||
static bool
|
||||
AsyncExistsPendingNotify(const char *relname)
|
||||
{
|
||||
Dlelem *p;
|
||||
List *p;
|
||||
|
||||
for (p = DLGetHead(pendingNotifies);
|
||||
p != NULL;
|
||||
p = DLGetSucc(p))
|
||||
foreach(p, pendingNotifies)
|
||||
{
|
||||
/* Use NAMEDATALEN for relname comparison. DZ - 26-08-1996 */
|
||||
if (strncmp((const char *) DLE_VAL(p), relname, NAMEDATALEN) == 0)
|
||||
return 1;
|
||||
if (strncmp((const char *) lfirst(p), relname, NAMEDATALEN) == 0)
|
||||
return true;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Clear the pendingNotifies list. */
|
||||
|
||||
static void
|
||||
ClearPendingNotifies()
|
||||
ClearPendingNotifies(void)
|
||||
{
|
||||
Dlelem *p;
|
||||
|
||||
if (pendingNotifies)
|
||||
{
|
||||
|
||||
/*
|
||||
* Since the referenced strings are malloc'd, we have to scan the
|
||||
* list and delete them individually. If we used palloc for the
|
||||
* strings then we could just do DLFreeList to get rid of both the
|
||||
* list nodes and the list base...
|
||||
*/
|
||||
while ((p = DLRemHead(pendingNotifies)) != NULL)
|
||||
{
|
||||
free(DLE_VAL(p));
|
||||
DLFreeElem(p);
|
||||
}
|
||||
DLFreeList(pendingNotifies);
|
||||
pendingNotifies = NULL;
|
||||
}
|
||||
/*
|
||||
* We used to have to explicitly deallocate the list members and nodes,
|
||||
* because they were malloc'd. Now, since we know they are palloc'd
|
||||
* in TopTransactionContext, we need not do that --- they'll go away
|
||||
* automatically at transaction exit. We need only reset the list head
|
||||
* pointer.
|
||||
*/
|
||||
pendingNotifies = NIL;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user