⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 async.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
📖 第 1 页 / 共 3 页
字号:
	scan = heap_beginscan(lRel, SnapshotNow, 1, key);	while ((lTuple = heap_getnext(scan, ForwardScanDirection)) != NULL)		simple_heap_delete(lRel, &lTuple->t_self);	heap_endscan(scan);	heap_close(lRel, ExclusiveLock);}/* *-------------------------------------------------------------- * Async_UnlistenOnExit * *		Clean up the pg_listener table at backend exit. * *		This is executed if we have done any LISTENs in this backend. *		It might not be necessary anymore, if the user UNLISTENed everything, *		but we don't try to detect that case. * * Results: *		XXX * * Side effects: *		pg_listener is updated if necessary. * *-------------------------------------------------------------- */static voidAsync_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.	 */	AbortOutOfAnyTransaction();	/* Now we can do the unlisten */	StartTransactionCommand();	Async_UnlistenAll();	CommitTransactionCommand();}/* *-------------------------------------------------------------- * AtPrepare_Notify * *		This is called at the prepare phase of a two-phase *		transaction.  Save the state for possible commit later. *-------------------------------------------------------------- */voidAtPrepare_Notify(void){	ListCell   *p;	foreach(p, pendingNotifies)	{		const char *relname = (const char *) lfirst(p);		RegisterTwoPhaseRecord(TWOPHASE_RM_NOTIFY_ID, 0,							   relname, strlen(relname) + 1);	}	/*	 * 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.	 */	ClearPendingNotifies();}/* *-------------------------------------------------------------- * AtCommit_Notify * *		This is called at transaction commit. * *		If there are outbound notify requests in the pendingNotifies list, *		scan pg_listener for matching tuples, and either signal the other *		backend or send a message to our own frontend. * *		NOTE: we are still inside the current transaction, therefore can *		piggyback on its committing of changes. * * Results: *		XXX * * Side effects: *		Tuples in pg_listener that have matching relnames and other peoples' *		listenerPIDs are updated with a nonzero notification field. * *-------------------------------------------------------------- */voidAtCommit_Notify(void){	Relation	lRel;	TupleDesc	tdesc;	HeapScanDesc scan;	HeapTuple	lTuple,				rTuple;	Datum		value[Natts_pg_listener];	char		repl[Natts_pg_listener],				nulls[Natts_pg_listener];	if (pendingNotifies == NIL)		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.	 */	if (!IsNormalProcessingMode())	{		ClearPendingNotifies();		return;	}	if (Trace_notify)		elog(DEBUG1, "AtCommit_Notify");	/* preset data to update notify column to MyProcPid */	nulls[0] = nulls[1] = nulls[2] = ' ';	repl[0] = repl[1] = repl[2] = ' ';	repl[Anum_pg_listener_notify - 1] = 'r';	value[0] = value[1] = value[2] = (Datum) 0;	value[Anum_pg_listener_notify - 1] = Int32GetDatum(MyProcPid);	lRel = heap_open(ListenerRelationId, ExclusiveLock);	tdesc = RelationGetDescr(lRel);	scan = heap_beginscan(lRel, SnapshotNow, 0, NULL);	while ((lTuple = heap_getnext(scan, ForwardScanDirection)) != NULL)	{		Form_pg_listener listener = (Form_pg_listener) GETSTRUCT(lTuple);		char	   *relname = NameStr(listener->relname);		int32		listenerPID = listener->listenerpid;		if (!AsyncExistsPendingNotify(relname))			continue;		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.			 */			if (Trace_notify)				elog(DEBUG1, "AtCommit_Notify: notifying self");			NotifyMyFrontEnd(relname, listenerPID);		}		else		{			if (Trace_notify)				elog(DEBUG1, "AtCommit_Notify: notifying pid %d",					 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 (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...)				 */				simple_heap_delete(lRel, &lTuple->t_self);			}			else if (listener->notification == 0)			{				HTSU_Result result;				ItemPointerData update_ctid;				TransactionId update_xmax;				rTuple = heap_modifytuple(lTuple, tdesc,										  value, nulls, repl);				/*				 * 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				 * heap_update calls.				 */				result = heap_update(lRel, &lTuple->t_self, rTuple,									 &update_ctid, &update_xmax,									 GetCurrentCommandId(), InvalidSnapshot,									 false /* no wait for commit */ );				switch (result)				{					case HeapTupleSelfUpdated:						/* Tuple was already updated in current command? */						elog(ERROR, "tuple already updated by self");						break;					case HeapTupleMayBeUpdated:						/* done successfully */#ifdef NOT_USED					/* currently there are no indexes */						CatalogUpdateIndexes(lRel, rTuple);#endif						break;					case HeapTupleBeingUpdated:						/* ignore uncommitted tuples */						break;					case HeapTupleUpdated:						/* ignore just-committed tuples */						break;					default:						elog(ERROR, "unrecognized heap_update status: %u",							 result);						break;				}			}		}	}	heap_endscan(scan);	/*	 * 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.	 */	heap_close(lRel, NoLock);	ClearPendingNotifies();	if (Trace_notify)		elog(DEBUG1, "AtCommit_Notify: done");}/* *-------------------------------------------------------------- * AtAbort_Notify * *		This is called at transaction abort. * *		Gets rid of pending outbound notifies that we would have executed *		if the transaction got committed. * * Results: *		XXX * *-------------------------------------------------------------- */voidAtAbort_Notify(void){	ClearPendingNotifies();}/* * AtSubStart_Notify() --- Take care of subtransaction start. * * Push empty state for the new subtransaction. */voidAtSubStart_Notify(void){	MemoryContext old_cxt;	/* Keep the list-of-lists in TopTransactionContext for simplicity */	old_cxt = MemoryContextSwitchTo(TopTransactionContext);	upperPendingNotifies = lcons(pendingNotifies, upperPendingNotifies);	Assert(list_length(upperPendingNotifies) ==		   GetCurrentTransactionNestLevel() - 1);	pendingNotifies = NIL;	MemoryContextSwitchTo(old_cxt);}/* * AtSubCommit_Notify() --- Take care of subtransaction commit. * * Reassign all items in the pending notifies list to the parent transaction. */voidAtSubCommit_Notify(void){	List	   *parentPendingNotifies;	parentPendingNotifies = (List *) linitial(upperPendingNotifies);	upperPendingNotifies = list_delete_first(upperPendingNotifies);	Assert(list_length(upperPendingNotifies) ==		   GetCurrentTransactionNestLevel() - 2);	/*	 * We could try to eliminate duplicates here, but it seems not worthwhile.	 */	pendingNotifies = list_concat(parentPendingNotifies, pendingNotifies);}/* * AtSubAbort_Notify() --- Take care of subtransaction abort. */voidAtSubAbort_Notify(void){	int			my_level = GetCurrentTransactionNestLevel();	/*	 * All we have to do is pop the stack --- the notifies made in this	 * 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.	 */	while (list_length(upperPendingNotifies) > my_level - 2)	{		pendingNotifies = (List *) linitial(upperPendingNotifies);		upperPendingNotifies = list_delete_first(upperPendingNotifies);	}}/* *-------------------------------------------------------------- * NotifyInterruptHandler * *		This is the signal handler for SIGUSR2. * *		If we are idle (notifyInterruptEnabled is set), we can safely invoke *		ProcessIncomingNotify directly.  Otherwise, just set a flag *		to do it later.

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -