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...
REL7_2_STABLE
Tom Lane 25 years ago
parent 1f1ca182be
commit 6054b33290
  1. 106
      src/backend/commands/async.c

@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * 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/catname.h"
#include "catalog/pg_listener.h" #include "catalog/pg_listener.h"
#include "commands/async.h" #include "commands/async.h"
#include "lib/dllist.h"
#include "libpq/libpq.h" #include "libpq/libpq.h"
#include "libpq/pqformat.h" #include "libpq/pqformat.h"
#include "miscadmin.h" #include "miscadmin.h"
@ -100,10 +99,11 @@ extern CommandDest whereToSendOutput;
/* /*
* State for outbound notifies consists of a list of all relnames NOTIFYed * State for outbound notifies consists of a list of all relnames NOTIFYed
* in the current transaction. We do not actually perform a NOTIFY until * in the current transaction. We do not actually perform a NOTIFY until
* and unless the transaction commits. pendingNotifies is NULL if no * and unless the transaction commits. pendingNotifies is NIL if no
* NOTIFYs have been done in the current transaction. * 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 * 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 */ /* True if we've registered an on_shmem_exit cleanup */
static bool unlistenExitRegistered = false; static bool unlistenExitRegistered = false;
bool Trace_notify = false;
static void Async_UnlistenAll(void); static void Async_UnlistenAll(void);
static void Async_UnlistenOnExit(void); static void Async_UnlistenOnExit(void);
static void ProcessIncomingNotify(void); static void ProcessIncomingNotify(void);
static void NotifyMyFrontEnd(char *relname, int32 listenerPID); static void NotifyMyFrontEnd(char *relname, int32 listenerPID);
static int AsyncExistsPendingNotify(char *relname); static bool AsyncExistsPendingNotify(const char *relname);
static void ClearPendingNotifies(void); static void ClearPendingNotifies(void);
bool Trace_notify = false;
/* /*
*-------------------------------------------------------------- *--------------------------------------------------------------
@ -150,26 +150,23 @@ bool Trace_notify = false;
void void
Async_Notify(char *relname) Async_Notify(char *relname)
{ {
char *notifyName;
if (Trace_notify) if (Trace_notify)
elog(DEBUG, "Async_Notify: %s", relname); elog(DEBUG, "Async_Notify: %s", relname);
if (!pendingNotifies)
pendingNotifies = DLNewList();
/* no point in making duplicate entries in the list ... */ /* 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 * The name list needs to live until end of transaction, so
* that it will live until we want to use it. This is probably * store it in the top transaction context.
* not necessary any longer, since we will use it before the end */
* of the transaction. DLList only knows how to use malloc() MemoryContext oldcontext;
* anyway, but we could probably palloc() the strings...
*/ oldcontext = MemoryContextSwitchTo(TopTransactionContext);
notifyName = strdup(relname);
DLAddHead(pendingNotifies, DLNewElem(notifyName)); pendingNotifies = lcons(pstrdup(relname), pendingNotifies);
MemoryContextSwitchTo(oldcontext);
} }
} }
@ -352,7 +349,7 @@ Async_Unlisten(char *relname, int pid)
*-------------------------------------------------------------- *--------------------------------------------------------------
*/ */
static void static void
Async_UnlistenAll() Async_UnlistenAll(void)
{ {
Relation lRel; Relation lRel;
TupleDesc tdesc; TupleDesc tdesc;
@ -401,7 +398,6 @@ Async_UnlistenAll()
static void static void
Async_UnlistenOnExit(void) Async_UnlistenOnExit(void)
{ {
/* /*
* We need to start/commit a transaction for the unlisten, but if * We need to start/commit a transaction for the unlisten, but if
* there is already an active transaction we had better abort that one * there is already an active transaction we had better abort that one
@ -438,7 +434,7 @@ Async_UnlistenOnExit(void)
*-------------------------------------------------------------- *--------------------------------------------------------------
*/ */
void void
AtCommit_Notify() AtCommit_Notify(void)
{ {
Relation lRel; Relation lRel;
TupleDesc tdesc; TupleDesc tdesc;
@ -449,7 +445,7 @@ AtCommit_Notify()
char repl[Natts_pg_listener], char repl[Natts_pg_listener],
nulls[Natts_pg_listener]; nulls[Natts_pg_listener];
if (!pendingNotifies) if (pendingNotifies == NIL)
return; /* no NOTIFY statements in this return; /* no NOTIFY statements in this
* transaction */ * transaction */
@ -579,7 +575,7 @@ AtCommit_Notify()
*-------------------------------------------------------------- *--------------------------------------------------------------
*/ */
void void
AtAbort_Notify() AtAbort_Notify(void)
{ {
ClearPendingNotifies(); ClearPendingNotifies();
} }
@ -601,7 +597,6 @@ AtAbort_Notify()
* per above * per above
*-------------------------------------------------------------- *--------------------------------------------------------------
*/ */
void void
Async_NotifyHandler(SIGNAL_ARGS) Async_NotifyHandler(SIGNAL_ARGS)
{ {
@ -671,7 +666,6 @@ Async_NotifyHandler(SIGNAL_ARGS)
* PostgresMain calls this the first time. * PostgresMain calls this the first time.
* -------------------------------------------------------------- * --------------------------------------------------------------
*/ */
void void
EnableNotifyInterrupt(void) EnableNotifyInterrupt(void)
{ {
@ -729,7 +723,6 @@ EnableNotifyInterrupt(void)
* is disabled until the next EnableNotifyInterrupt call. * is disabled until the next EnableNotifyInterrupt call.
* -------------------------------------------------------------- * --------------------------------------------------------------
*/ */
void void
DisableNotifyInterrupt(void) DisableNotifyInterrupt(void)
{ {
@ -848,8 +841,9 @@ ProcessIncomingNotify(void)
elog(DEBUG, "ProcessIncomingNotify: done"); elog(DEBUG, "ProcessIncomingNotify: done");
} }
/* Send NOTIFY message to my front end. */ /*
* Send NOTIFY message to my front end.
*/
static void static void
NotifyMyFrontEnd(char *relname, int32 listenerPID) NotifyMyFrontEnd(char *relname, int32 listenerPID)
{ {
@ -874,50 +868,32 @@ NotifyMyFrontEnd(char *relname, int32 listenerPID)
elog(NOTICE, "NOTIFY for %s", relname); elog(NOTICE, "NOTIFY for %s", relname);
} }
/* Does pendingNotifies include the given relname? /* Does pendingNotifies include the given relname? */
* static bool
* NB: not called unless pendingNotifies != NULL. AsyncExistsPendingNotify(const char *relname)
*/
static int
AsyncExistsPendingNotify(char *relname)
{ {
Dlelem *p; List *p;
for (p = DLGetHead(pendingNotifies); foreach(p, pendingNotifies)
p != NULL;
p = DLGetSucc(p))
{ {
/* Use NAMEDATALEN for relname comparison. DZ - 26-08-1996 */ /* Use NAMEDATALEN for relname comparison. DZ - 26-08-1996 */
if (strncmp((const char *) DLE_VAL(p), relname, NAMEDATALEN) == 0) if (strncmp((const char *) lfirst(p), relname, NAMEDATALEN) == 0)
return 1; return true;
} }
return 0; return false;
} }
/* Clear the pendingNotifies list. */ /* Clear the pendingNotifies list. */
static void static void
ClearPendingNotifies() ClearPendingNotifies(void)
{ {
Dlelem *p;
if (pendingNotifies)
{
/* /*
* Since the referenced strings are malloc'd, we have to scan the * We used to have to explicitly deallocate the list members and nodes,
* list and delete them individually. If we used palloc for the * because they were malloc'd. Now, since we know they are palloc'd
* strings then we could just do DLFreeList to get rid of both the * in TopTransactionContext, we need not do that --- they'll go away
* list nodes and the list base... * automatically at transaction exit. We need only reset the list head
* pointer.
*/ */
while ((p = DLRemHead(pendingNotifies)) != NULL) pendingNotifies = NIL;
{
free(DLE_VAL(p));
DLFreeElem(p);
}
DLFreeList(pendingNotifies);
pendingNotifies = NULL;
}
} }

Loading…
Cancel
Save