Commit 6054b332 authored by Tom Lane's avatar Tom Lane

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...
parent 1f1ca182
...@@ -7,7 +7,7 @@ ...@@ -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 @@ ...@@ -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; ...@@ -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; ...@@ -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; ...@@ -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()
* anyway, but we could probably palloc() the strings...
*/ */
notifyName = strdup(relname); MemoryContext oldcontext;
DLAddHead(pendingNotifies, DLNewElem(notifyName));
oldcontext = MemoryContextSwitchTo(TopTransactionContext);
pendingNotifies = lcons(pstrdup(relname), pendingNotifies);
MemoryContextSwitchTo(oldcontext);
} }
} }
...@@ -352,7 +349,7 @@ Async_Unlisten(char *relname, int pid) ...@@ -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() ...@@ -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) ...@@ -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() ...@@ -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() ...@@ -579,7 +575,7 @@ AtCommit_Notify()
*-------------------------------------------------------------- *--------------------------------------------------------------
*/ */
void void
AtAbort_Notify() AtAbort_Notify(void)
{ {
ClearPendingNotifies(); ClearPendingNotifies();
} }
...@@ -601,7 +597,6 @@ AtAbort_Notify() ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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; /*
* We used to have to explicitly deallocate the list members and nodes,
if (pendingNotifies) * 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.
* Since the referenced strings are malloc'd, we have to scan the */
* list and delete them individually. If we used palloc for the pendingNotifies = NIL;
* 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;
}
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment