diff options
Diffstat (limited to 'src/backend/commands/async.c')
-rw-r--r-- | src/backend/commands/async.c | 213 |
1 files changed, 100 insertions, 113 deletions
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c index da133788960..69d97d09237 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 - * $PostgreSQL: pgsql/src/backend/commands/async.c,v 1.125 2005/10/06 21:30:32 neilc Exp $ + * $PostgreSQL: pgsql/src/backend/commands/async.c,v 1.126 2005/10/15 02:49:15 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -106,8 +106,7 @@ */ static List *pendingNotifies = NIL; -static List *upperPendingNotifies = NIL; /* list of upper-xact - * lists */ +static List *upperPendingNotifies = NIL; /* list of upper-xact lists */ /* * State for inbound notifies consists of two flags: one saying whether @@ -158,8 +157,8 @@ Async_Notify(const char *relname) if (!AsyncExistsPendingNotify(relname)) { /* - * The name list needs to live until end of transaction, so store - * it in the transaction context. + * The name list needs to live until end of transaction, so store it + * in the transaction context. */ MemoryContext oldcontext; @@ -208,7 +207,7 @@ Async_Listen(const char *relname) Form_pg_listener listener = (Form_pg_listener) GETSTRUCT(tuple); if (listener->listenerpid == MyProcPid && - strncmp(NameStr(listener->relname), relname, NAMEDATALEN) == 0) + strncmp(NameStr(listener->relname), relname, NAMEDATALEN) == 0) { alreadyListener = true; /* No need to scan the rest of the table */ @@ -298,14 +297,14 @@ Async_Unlisten(const char *relname) Form_pg_listener listener = (Form_pg_listener) GETSTRUCT(tuple); if (listener->listenerpid == MyProcPid && - strncmp(NameStr(listener->relname), relname, NAMEDATALEN) == 0) + strncmp(NameStr(listener->relname), relname, NAMEDATALEN) == 0) { /* Found the matching tuple, delete it */ simple_heap_delete(lRel, &tuple->t_self); /* - * We assume there can be only one match, so no need to scan - * the rest of the table + * We assume there can be only one match, so no need to scan the + * rest of the table */ break; } @@ -387,10 +386,10 @@ static void Async_UnlistenOnExit(int code, Datum arg) { /* - * We need to start/commit a transaction for the unlisten, but if - * there is already an active transaction we had better abort that one - * first. Otherwise we'd end up committing changes that probably - * ought to be discarded. + * We need to start/commit a transaction for the unlisten, but if there is + * already an active transaction we had better abort that one first. + * Otherwise we'd end up committing changes that probably ought to be + * discarded. */ AbortOutOfAnyTransaction(); /* Now we can do the unlisten */ @@ -404,14 +403,14 @@ Async_UnlistenOnExit(int code, Datum arg) *-------------------------------------------------------------- * AtPrepare_Notify * - * This is called at the prepare phase of a two-phase + * This is called at the prepare phase of a two-phase * transaction. Save the state for possible commit later. *-------------------------------------------------------------- */ void AtPrepare_Notify(void) { - ListCell *p; + ListCell *p; foreach(p, pendingNotifies) { @@ -423,8 +422,8 @@ AtPrepare_Notify(void) /* * We can clear the state immediately, rather than needing a separate - * PostPrepare call, because if the transaction fails we'd just - * discard the state anyway. + * PostPrepare call, because if the transaction fails we'd just discard + * the state anyway. */ ClearPendingNotifies(); } @@ -464,12 +463,11 @@ AtCommit_Notify(void) nulls[Natts_pg_listener]; if (pendingNotifies == NIL) - return; /* no NOTIFY statements in this - * transaction */ + return; /* no NOTIFY statements in this transaction */ /* - * NOTIFY is disabled if not normal processing mode. This test used to - * be in xact.c, but it seems cleaner to do it here. + * NOTIFY is disabled if not normal processing mode. This test used to be + * in xact.c, but it seems cleaner to do it here. */ if (!IsNormalProcessingMode()) { @@ -503,10 +501,10 @@ AtCommit_Notify(void) if (listenerPID == MyProcPid) { /* - * Self-notify: no need to bother with table update. Indeed, - * we *must not* clear the notification field in this path, or - * we could lose an outside notify, which'd be bad for - * applications that ignore self-notify messages. + * Self-notify: no need to bother with table update. Indeed, we + * *must not* clear the notification field in this path, or we + * could lose an outside notify, which'd be bad for applications + * that ignore self-notify messages. */ if (Trace_notify) @@ -521,27 +519,27 @@ AtCommit_Notify(void) listenerPID); /* - * If someone has already notified this listener, we don't - * bother modifying the table, but we do still send a SIGUSR2 - * signal, just in case that backend missed the earlier signal - * for some reason. It's OK to send the signal first, because - * the other guy can't read pg_listener until we unlock it. + * If someone has already notified this listener, we don't bother + * modifying the table, but we do still send a SIGUSR2 signal, + * just in case that backend missed the earlier signal for some + * reason. It's OK to send the signal first, because the other + * guy can't read pg_listener until we unlock it. */ if (kill(listenerPID, SIGUSR2) < 0) { /* - * Get rid of pg_listener entry if it refers to a PID that - * no longer exists. Presumably, that backend crashed - * without deleting its pg_listener entries. This code - * used to only delete the entry if errno==ESRCH, but as - * far as I can see we should just do it for any failure - * (certainly at least for EPERM too...) + * Get rid of pg_listener entry if it refers to a PID that no + * longer exists. Presumably, that backend crashed without + * deleting its pg_listener entries. This code used to only + * delete the entry if errno==ESRCH, but as far as I can see + * we should just do it for any failure (certainly at least + * for EPERM too...) */ simple_heap_delete(lRel, &lTuple->t_self); } else if (listener->notification == 0) { - HTSU_Result result; + HTSU_Result result; ItemPointerData update_ctid; TransactionId update_xmax; @@ -551,17 +549,16 @@ AtCommit_Notify(void) /* * We cannot use simple_heap_update here because the tuple * could have been modified by an uncommitted transaction; - * specifically, since UNLISTEN releases exclusive lock on - * the table before commit, the other guy could already - * have tried to unlisten. There are no other cases where - * we should be able to see an uncommitted update or - * delete. Therefore, our response to a - * HeapTupleBeingUpdated result is just to ignore it. We - * do *not* wait for the other guy to commit --- that - * would risk deadlock, and we don't want to block while - * holding the table lock anyway for performance reasons. - * We also ignore HeapTupleUpdated, which could occur if - * the other guy commits between our heap_getnext and + * specifically, since UNLISTEN releases exclusive lock on the + * table before commit, the other guy could already have tried + * to unlisten. There are no other cases where we should be + * able to see an uncommitted update or delete. Therefore, our + * response to a HeapTupleBeingUpdated result is just to + * ignore it. We do *not* wait for the other guy to commit + * --- that would risk deadlock, and we don't want to block + * while holding the table lock anyway for performance + * reasons. We also ignore HeapTupleUpdated, which could occur + * if the other guy commits between our heap_getnext and * heap_update calls. */ result = heap_update(lRel, &lTuple->t_self, rTuple, @@ -603,10 +600,10 @@ AtCommit_Notify(void) /* * We do NOT release the lock on pg_listener here; we need to hold it - * until end of transaction (which is about to happen, anyway) to - * ensure that notified backends see our tuple updates when they look. - * Else they might disregard the signal, which would make the - * application programmer very unhappy. + * until end of transaction (which is about to happen, anyway) to ensure + * that notified backends see our tuple updates when they look. Else they + * might disregard the signal, which would make the application programmer + * very unhappy. */ heap_close(lRel, NoLock); @@ -676,8 +673,7 @@ AtSubCommit_Notify(void) GetCurrentTransactionNestLevel() - 2); /* - * We could try to eliminate duplicates here, but it seems not - * worthwhile. + * We could try to eliminate duplicates here, but it seems not worthwhile. */ pendingNotifies = list_concat(parentPendingNotifies, pendingNotifies); } @@ -695,10 +691,10 @@ AtSubAbort_Notify(void) * subxact are no longer interesting, and the space will be freed when * CurTransactionContext is recycled. * - * This routine could be called more than once at a given nesting level - * if there is trouble during subxact abort. Avoid dumping core by - * using GetCurrentTransactionNestLevel as the indicator of how far - * we need to prune the list. + * This routine could be called more than once at a given nesting level if + * there is trouble during subxact abort. Avoid dumping core by using + * GetCurrentTransactionNestLevel as the indicator of how far we need to + * prune the list. */ while (list_length(upperPendingNotifies) > my_level - 2) { @@ -731,9 +727,9 @@ NotifyInterruptHandler(SIGNAL_ARGS) /* * Note: this is a SIGNAL HANDLER. You must be very wary what you do - * here. Some helpful soul had this routine sprinkled with TPRINTFs, - * which would likely lead to corruption of stdio buffers if they were - * ever turned on. + * here. Some helpful soul had this routine sprinkled with TPRINTFs, which + * would likely lead to corruption of stdio buffers if they were ever + * turned on. */ /* Don't joggle the elbow of proc_exit */ @@ -745,19 +741,18 @@ NotifyInterruptHandler(SIGNAL_ARGS) bool save_ImmediateInterruptOK = ImmediateInterruptOK; /* - * We may be called while ImmediateInterruptOK is true; turn it - * off while messing with the NOTIFY state. (We would have to - * save and restore it anyway, because PGSemaphore operations - * inside ProcessIncomingNotify() might reset it.) + * We may be called while ImmediateInterruptOK is true; turn it off + * while messing with the NOTIFY state. (We would have to save and + * restore it anyway, because PGSemaphore operations inside + * ProcessIncomingNotify() might reset it.) */ ImmediateInterruptOK = false; /* * I'm not sure whether some flavors of Unix might allow another - * SIGUSR2 occurrence to recursively interrupt this routine. To - * cope with the possibility, we do the same sort of dance that - * EnableNotifyInterrupt must do --- see that routine for - * comments. + * SIGUSR2 occurrence to recursively interrupt this routine. To cope + * with the possibility, we do the same sort of dance that + * EnableNotifyInterrupt must do --- see that routine for comments. */ notifyInterruptEnabled = 0; /* disable any recursive signal */ notifyInterruptOccurred = 1; /* do at least one iteration */ @@ -781,8 +776,7 @@ NotifyInterruptHandler(SIGNAL_ARGS) } /* - * Restore ImmediateInterruptOK, and check for interrupts if - * needed. + * Restore ImmediateInterruptOK, and check for interrupts if needed. */ ImmediateInterruptOK = save_ImmediateInterruptOK; if (save_ImmediateInterruptOK) @@ -791,8 +785,7 @@ NotifyInterruptHandler(SIGNAL_ARGS) else { /* - * In this path it is NOT SAFE to do much of anything, except - * this: + * In this path it is NOT SAFE to do much of anything, except this: */ notifyInterruptOccurred = 1; } @@ -820,27 +813,25 @@ EnableNotifyInterrupt(void) return; /* not really idle */ /* - * This code is tricky because we are communicating with a signal - * handler that could interrupt us at any point. If we just checked - * notifyInterruptOccurred and then set notifyInterruptEnabled, we - * could fail to respond promptly to a signal that happens in between - * those two steps. (A very small time window, perhaps, but Murphy's - * Law says you can hit it...) Instead, we first set the enable flag, - * then test the occurred flag. If we see an unserviced interrupt has - * occurred, we re-clear the enable flag before going off to do the - * service work. (That prevents re-entrant invocation of - * ProcessIncomingNotify() if another interrupt occurs.) If an - * interrupt comes in between the setting and clearing of - * notifyInterruptEnabled, then it will have done the service work and - * left notifyInterruptOccurred zero, so we have to check again after - * clearing enable. The whole thing has to be in a loop in case - * another interrupt occurs while we're servicing the first. Once we - * get out of the loop, enable is set and we know there is no - * unserviced interrupt. + * This code is tricky because we are communicating with a signal handler + * that could interrupt us at any point. If we just checked + * notifyInterruptOccurred and then set notifyInterruptEnabled, we could + * fail to respond promptly to a signal that happens in between those two + * steps. (A very small time window, perhaps, but Murphy's Law says you + * can hit it...) Instead, we first set the enable flag, then test the + * occurred flag. If we see an unserviced interrupt has occurred, we + * re-clear the enable flag before going off to do the service work. + * (That prevents re-entrant invocation of ProcessIncomingNotify() if + * another interrupt occurs.) If an interrupt comes in between the setting + * and clearing of notifyInterruptEnabled, then it will have done the + * service work and left notifyInterruptOccurred zero, so we have to check + * again after clearing enable. The whole thing has to be in a loop in + * case another interrupt occurs while we're servicing the first. Once we + * get out of the loop, enable is set and we know there is no unserviced + * interrupt. * - * NB: an overenthusiastic optimizing compiler could easily break this - * code. Hopefully, they all understand what "volatile" means these - * days. + * NB: an overenthusiastic optimizing compiler could easily break this code. + * Hopefully, they all understand what "volatile" means these days. */ for (;;) { @@ -960,8 +951,7 @@ ProcessIncomingNotify(void) * Rewrite the tuple with 0 in notification column. * * simple_heap_update is safe here because no one else would have - * tried to UNLISTEN us, so there can be no uncommitted - * changes. + * tried to UNLISTEN us, so there can be no uncommitted changes. */ rTuple = heap_modifytuple(lTuple, tdesc, value, nulls, repl); simple_heap_update(lRel, &lTuple->t_self, rTuple); @@ -975,18 +965,17 @@ ProcessIncomingNotify(void) /* * We do NOT release the lock on pg_listener here; we need to hold it - * until end of transaction (which is about to happen, anyway) to - * ensure that other backends see our tuple updates when they look. - * Otherwise, a transaction started after this one might mistakenly - * think it doesn't need to send this backend a new NOTIFY. + * until end of transaction (which is about to happen, anyway) to ensure + * that other backends see our tuple updates when they look. Otherwise, a + * transaction started after this one might mistakenly think it doesn't + * need to send this backend a new NOTIFY. */ heap_close(lRel, NoLock); CommitTransactionCommand(); /* - * Must flush the notify messages to ensure frontend gets them - * promptly. + * Must flush the notify messages to ensure frontend gets them promptly. */ pq_flush(); @@ -1022,8 +1011,7 @@ NotifyMyFrontEnd(char *relname, int32 listenerPID) /* * NOTE: we do not do pq_flush() here. For a self-notify, it will * happen at the end of the transaction, and for incoming notifies - * ProcessIncomingNotify will do it after finding all the - * notifies. + * ProcessIncomingNotify will do it after finding all the notifies. */ } else @@ -1052,11 +1040,11 @@ static void ClearPendingNotifies(void) { /* - * 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 CurTransactionContext, we need not do that --- they'll - * go away automatically at transaction exit. We need only reset the - * list head pointer. + * 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 + * CurTransactionContext, we need not do that --- they'll go away + * automatically at transaction exit. We need only reset the list head + * pointer. */ pendingNotifies = NIL; } @@ -1071,11 +1059,10 @@ notify_twophase_postcommit(TransactionId xid, uint16 info, void *recdata, uint32 len) { /* - * Set up to issue the NOTIFY at the end of my own - * current transaction. (XXX this has some issues if my own - * transaction later rolls back, or if there is any significant - * delay before I commit. OK for now because we disallow - * COMMIT PREPARED inside a transaction block.) + * Set up to issue the NOTIFY at the end of my own current transaction. + * (XXX this has some issues if my own transaction later rolls back, or if + * there is any significant delay before I commit. OK for now because we + * disallow COMMIT PREPARED inside a transaction block.) */ Async_Notify((char *) recdata); } |