From 6054b33290cccd414cfd70bb134e7d05c980db7f Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Sun, 17 Jun 2001 22:27:15 +0000 Subject: [PATCH] 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... --- src/backend/commands/async.c | 108 ++++++++++++++--------------------- 1 file changed, 42 insertions(+), 66 deletions(-) diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c index 5fda53d02c..dde2412a6e 100644 --- a/src/backend/commands/async.c +++ b/src/backend/commands/async.c @@ -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; }