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:
Tom Lane 2001-06-17 22:27:15 +00:00
parent 1f1ca182be
commit 6054b33290
1 changed files with 42 additions and 66 deletions

View File

@ -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;
}