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

📄 multixact.c

📁 postgresql8.3.4源码,开源数据库
💻 C
📖 第 1 页 / 共 4 页
字号:
		slotno = SimpleLruReadPage(MultiXactMemberCtl, pageno, true, offset);		xidptr = (TransactionId *) MultiXactMemberCtl->shared->page_buffer[slotno];		xidptr += entryno;		MemSet(xidptr, 0, BLCKSZ - (entryno * sizeof(TransactionId)));		MultiXactMemberCtl->shared->page_dirty[slotno] = true;	}	LWLockRelease(MultiXactMemberControlLock);	/*	 * Initialize lastTruncationPoint to invalid, ensuring that the first	 * checkpoint will try to do truncation.	 */	MultiXactState->lastTruncationPoint = InvalidMultiXactId;}/* * This must be called ONCE during postmaster or standalone-backend shutdown */voidShutdownMultiXact(void){	/* Flush dirty MultiXact pages to disk */	SimpleLruFlush(MultiXactOffsetCtl, false);	SimpleLruFlush(MultiXactMemberCtl, false);}/* * Get the next MultiXactId and offset to save in a checkpoint record */voidMultiXactGetCheckptMulti(bool is_shutdown,						 MultiXactId *nextMulti,						 MultiXactOffset *nextMultiOffset){	LWLockAcquire(MultiXactGenLock, LW_SHARED);	*nextMulti = MultiXactState->nextMXact;	*nextMultiOffset = MultiXactState->nextOffset;	LWLockRelease(MultiXactGenLock);	debug_elog4(DEBUG2, "MultiXact: checkpoint is nextMulti %u, nextOffset %u",				*nextMulti, *nextMultiOffset);}/* * Perform a checkpoint --- either during shutdown, or on-the-fly */voidCheckPointMultiXact(void){	/* Flush dirty MultiXact pages to disk */	SimpleLruFlush(MultiXactOffsetCtl, true);	SimpleLruFlush(MultiXactMemberCtl, true);	/*	 * Truncate the SLRU files.  This could be done at any time, but	 * checkpoint seems a reasonable place for it.	There is one exception: if	 * we are called during xlog recovery, then shared->latest_page_number	 * isn't valid (because StartupMultiXact hasn't been called yet) and so	 * SimpleLruTruncate would get confused.  It seems best not to risk	 * removing any data during recovery anyway, so don't truncate.	 */	if (!InRecovery)		TruncateMultiXact();}/* * Set the next-to-be-assigned MultiXactId and offset * * This is used when we can determine the correct next ID/offset exactly * from a checkpoint record.  We need no locking since it is only called * during bootstrap and XLog replay. */voidMultiXactSetNextMXact(MultiXactId nextMulti,					  MultiXactOffset nextMultiOffset){	debug_elog4(DEBUG2, "MultiXact: setting next multi to %u offset %u",				nextMulti, nextMultiOffset);	MultiXactState->nextMXact = nextMulti;	MultiXactState->nextOffset = nextMultiOffset;}/* * Ensure the next-to-be-assigned MultiXactId is at least minMulti, * and similarly nextOffset is at least minMultiOffset * * This is used when we can determine minimum safe values from an XLog * record (either an on-line checkpoint or an mxact creation log entry). * We need no locking since it is only called during XLog replay. */voidMultiXactAdvanceNextMXact(MultiXactId minMulti,						  MultiXactOffset minMultiOffset){	if (MultiXactIdPrecedes(MultiXactState->nextMXact, minMulti))	{		debug_elog3(DEBUG2, "MultiXact: setting next multi to %u", minMulti);		MultiXactState->nextMXact = minMulti;	}	if (MultiXactOffsetPrecedes(MultiXactState->nextOffset, minMultiOffset))	{		debug_elog3(DEBUG2, "MultiXact: setting next offset to %u",					minMultiOffset);		MultiXactState->nextOffset = minMultiOffset;	}}/* * Make sure that MultiXactOffset has room for a newly-allocated MultiXactId. * * NB: this is called while holding MultiXactGenLock.  We want it to be very * fast most of the time; even when it's not so fast, no actual I/O need * happen unless we're forced to write out a dirty log or xlog page to make * room in shared memory. */static voidExtendMultiXactOffset(MultiXactId multi){	int			pageno;	/*	 * No work except at first MultiXactId of a page.  But beware: just after	 * wraparound, the first MultiXactId of page zero is FirstMultiXactId.	 */	if (MultiXactIdToOffsetEntry(multi) != 0 &&		multi != FirstMultiXactId)		return;	pageno = MultiXactIdToOffsetPage(multi);	LWLockAcquire(MultiXactOffsetControlLock, LW_EXCLUSIVE);	/* Zero the page and make an XLOG entry about it */	ZeroMultiXactOffsetPage(pageno, true);	LWLockRelease(MultiXactOffsetControlLock);}/* * Make sure that MultiXactMember has room for the members of a newly- * allocated MultiXactId. * * Like the above routine, this is called while holding MultiXactGenLock; * same comments apply. */static voidExtendMultiXactMember(MultiXactOffset offset, int nmembers){	/*	 * It's possible that the members span more than one page of the members	 * file, so we loop to ensure we consider each page.  The coding is not	 * optimal if the members span several pages, but that seems unusual	 * enough to not worry much about.	 */	while (nmembers > 0)	{		int			entryno;		/*		 * Only zero when at first entry of a page.		 */		entryno = MXOffsetToMemberEntry(offset);		if (entryno == 0)		{			int			pageno;			pageno = MXOffsetToMemberPage(offset);			LWLockAcquire(MultiXactMemberControlLock, LW_EXCLUSIVE);			/* Zero the page and make an XLOG entry about it */			ZeroMultiXactMemberPage(pageno, true);			LWLockRelease(MultiXactMemberControlLock);		}		/* Advance to next page (OK if nmembers goes negative) */		offset += (MULTIXACT_MEMBERS_PER_PAGE - entryno);		nmembers -= (MULTIXACT_MEMBERS_PER_PAGE - entryno);	}}/* * Remove all MultiXactOffset and MultiXactMember segments before the oldest * ones still of interest. * * This is called only during checkpoints.	We assume no more than one * backend does this at a time. * * XXX do we have any issues with needing to checkpoint here? */static voidTruncateMultiXact(void){	MultiXactId nextMXact;	MultiXactOffset nextOffset;	MultiXactId oldestMXact;	MultiXactOffset oldestOffset;	int			cutoffPage;	int			i;	/*	 * First, compute where we can safely truncate.  Per notes above, this is	 * the oldest valid value among all the OldestMemberMXactId[] and	 * OldestVisibleMXactId[] entries, or nextMXact if none are valid.	 */	LWLockAcquire(MultiXactGenLock, LW_SHARED);	/*	 * We have to beware of the possibility that nextMXact is in the	 * wrapped-around state.  We don't fix the counter itself here, but we	 * must be sure to use a valid value in our calculation.	 */	nextMXact = MultiXactState->nextMXact;	if (nextMXact < FirstMultiXactId)		nextMXact = FirstMultiXactId;	oldestMXact = nextMXact;	for (i = 1; i <= MaxBackends; i++)	{		MultiXactId thisoldest;		thisoldest = OldestMemberMXactId[i];		if (MultiXactIdIsValid(thisoldest) &&			MultiXactIdPrecedes(thisoldest, oldestMXact))			oldestMXact = thisoldest;		thisoldest = OldestVisibleMXactId[i];		if (MultiXactIdIsValid(thisoldest) &&			MultiXactIdPrecedes(thisoldest, oldestMXact))			oldestMXact = thisoldest;	}	/* Save the current nextOffset too */	nextOffset = MultiXactState->nextOffset;	LWLockRelease(MultiXactGenLock);	debug_elog3(DEBUG2, "MultiXact: truncation point = %u", oldestMXact);	/*	 * If we already truncated at this point, do nothing.  This saves time	 * when no MultiXacts are getting used, which is probably not uncommon.	 */	if (MultiXactState->lastTruncationPoint == oldestMXact)		return;	/*	 * We need to determine where to truncate MultiXactMember.	If we found a	 * valid oldest MultiXactId, read its starting offset; otherwise we use	 * the nextOffset value we saved above.	 */	if (oldestMXact == nextMXact)		oldestOffset = nextOffset;	else	{		int			pageno;		int			slotno;		int			entryno;		MultiXactOffset *offptr;		/* lock is acquired by SimpleLruReadPage_ReadOnly */		pageno = MultiXactIdToOffsetPage(oldestMXact);		entryno = MultiXactIdToOffsetEntry(oldestMXact);		slotno = SimpleLruReadPage_ReadOnly(MultiXactOffsetCtl, pageno, oldestMXact);		offptr = (MultiXactOffset *) MultiXactOffsetCtl->shared->page_buffer[slotno];		offptr += entryno;		oldestOffset = *offptr;		LWLockRelease(MultiXactOffsetControlLock);	}	/*	 * The cutoff point is the start of the segment containing oldestMXact. We	 * pass the *page* containing oldestMXact to SimpleLruTruncate.	 */	cutoffPage = MultiXactIdToOffsetPage(oldestMXact);	SimpleLruTruncate(MultiXactOffsetCtl, cutoffPage);	/*	 * Also truncate MultiXactMember at the previously determined offset.	 */	cutoffPage = MXOffsetToMemberPage(oldestOffset);	SimpleLruTruncate(MultiXactMemberCtl, cutoffPage);	/*	 * Set the last known truncation point.  We don't need a lock for this	 * since only one backend does checkpoints at a time.	 */	MultiXactState->lastTruncationPoint = oldestMXact;}/* * Decide which of two MultiXactOffset page numbers is "older" for truncation * purposes. * * We need to use comparison of MultiXactId here in order to do the right * thing with wraparound.  However, if we are asked about page number zero, we * don't want to hand InvalidMultiXactId to MultiXactIdPrecedes: it'll get * weird.  So, offset both multis by FirstMultiXactId to avoid that. * (Actually, the current implementation doesn't do anything weird with * InvalidMultiXactId, but there's no harm in leaving this code like this.) */static boolMultiXactOffsetPagePrecedes(int page1, int page2){	MultiXactId multi1;	MultiXactId multi2;	multi1 = ((MultiXactId) page1) * MULTIXACT_OFFSETS_PER_PAGE;	multi1 += FirstMultiXactId;	multi2 = ((MultiXactId) page2) * MULTIXACT_OFFSETS_PER_PAGE;	multi2 += FirstMultiXactId;	return MultiXactIdPrecedes(multi1, multi2);}/* * Decide which of two MultiXactMember page numbers is "older" for truncation * purposes.  There is no "invalid offset number" so use the numbers verbatim. */static boolMultiXactMemberPagePrecedes(int page1, int page2){	MultiXactOffset offset1;	MultiXactOffset offset2;	offset1 = ((MultiXactOffset) page1) * MULTIXACT_MEMBERS_PER_PAGE;	offset2 = ((MultiXactOffset) page2) * MULTIXACT_MEMBERS_PER_PAGE;	return MultiXactOffsetPrecedes(offset1, offset2);}/* * Decide which of two MultiXactIds is earlier. * * XXX do we need to do something special for InvalidMultiXactId? * (Doesn't look like it.) */static boolMultiXactIdPrecedes(MultiXactId multi1, MultiXactId multi2){	int32		diff = (int32) (multi1 - multi2);	return (diff < 0);}/* * Decide which of two offsets is earlier. */static boolMultiXactOffsetPrecedes(MultiXactOffset offset1, MultiXactOffset offset2){	int32		diff = (int32) (offset1 - offset2);	return (diff < 0);}/* * Write an xlog record reflecting the zeroing of either a MEMBERs or * OFFSETs page (info shows which) */static voidWriteMZeroPageXlogRec(int pageno, uint8 info){	XLogRecData rdata;	rdata.data = (char *) (&pageno);	rdata.len = sizeof(int);	rdata.buffer = InvalidBuffer;	rdata.next = NULL;	(void) XLogInsert(RM_MULTIXACT_ID, info, &rdata);}/* * MULTIXACT resource manager's routines */voidmultixact_redo(XLogRecPtr lsn, XLogRecord *record){	uint8		info = record->xl_info & ~XLR_INFO_MASK;	if (info == XLOG_MULTIXACT_ZERO_OFF_PAGE)	{		int			pageno;		int			slotno;		memcpy(&pageno, XLogRecGetData(record), sizeof(int));		LWLockAcquire(MultiXactOffsetControlLock, LW_EXCLUSIVE);		slotno = ZeroMultiXactOffsetPage(pageno, false);		SimpleLruWritePage(MultiXactOffsetCtl, slotno, NULL);		Assert(!MultiXactOffsetCtl->shared->page_dirty[slotno]);		LWLockRelease(MultiXactOffsetControlLock);	}	else if (info == XLOG_MULTIXACT_ZERO_MEM_PAGE)	{		int			pageno;		int			slotno;		memcpy(&pageno, XLogRecGetData(record), sizeof(int));		LWLockAcquire(MultiXactMemberControlLock, LW_EXCLUSIVE);		slotno = ZeroMultiXactMemberPage(pageno, false);		SimpleLruWritePage(MultiXactMemberCtl, slotno, NULL);		Assert(!MultiXactMemberCtl->shared->page_dirty[slotno]);		LWLockRelease(MultiXactMemberControlLock);	}	else if (info == XLOG_MULTIXACT_CREATE_ID)	{		xl_multixact_create *xlrec = (xl_multixact_create *) XLogRecGetData(record);		TransactionId *xids = xlrec->xids;		TransactionId max_xid;		int			i;		/* Store the data back into the SLRU files */		RecordNewMultiXact(xlrec->mid, xlrec->moff, xlrec->nxids, xids);		/* Make sure nextMXact/nextOffset are beyond what this record has */		MultiXactAdvanceNextMXact(xlrec->mid + 1, xlrec->moff + xlrec->nxids);		/*		 * Make sure nextXid is beyond any XID mentioned in the record. This		 * should be unnecessary, since any XID found here ought to have other		 * evidence in the XLOG, but let's be safe.		 */		max_xid = record->xl_xid;		for (i = 0; i < xlrec->nxids; i++)		{			if (TransactionIdPrecedes(max_xid, xids[i]))				max_xid = xids[i];		}		if (TransactionIdFollowsOrEquals(max_xid,										 ShmemVariableCache->nextXid))		{			ShmemVariableCache->nextXid = max_xid;			TransactionIdAdvance(ShmemVariableCache->nextXid);		}	}	else		elog(PANIC, "multixact_redo: unknown op code %u", info);}voidmultixact_desc(StringInfo buf, uint8 xl_info, char *rec){	uint8		info = xl_info & ~XLR_INFO_MASK;	if (info == XLOG_MULTIXACT_ZERO_OFF_PAGE)	{		int			pageno;		memcpy(&pageno, rec, sizeof(int));		appendStringInfo(buf, "zero offsets page: %d", pageno);	}	else if (info == XLOG_MULTIXACT_ZERO_MEM_PAGE)	{		int			pageno;		memcpy(&pageno, rec, sizeof(int));		appendStringInfo(buf, "zero members page: %d", pageno);	}	else if (info == XLOG_MULTIXACT_CREATE_ID)	{		xl_multixact_create *xlrec = (xl_multixact_create *) rec;		int			i;		appendStringInfo(buf, "create multixact %u offset %u:",						 xlrec->mid, xlrec->moff);		for (i = 0; i < xlrec->nxids; i++)			appendStringInfo(buf, " %u", xlrec->xids[i]);	}	else		appendStringInfo(buf, "UNKNOWN");}

⌨️ 快捷键说明

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