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

📄 vacuum.c

📁 关系型数据库 Postgresql 6.5.2
💻 C
📖 第 1 页 / 共 5 页
字号:
		min_tlen = max_tlen = 0;	vacrelstats->min_tlen = min_tlen;	vacrelstats->max_tlen = max_tlen;	vacuum_pages->vpl_empty_end_pages = empty_end_pages;	fraged_pages->vpl_empty_end_pages = empty_end_pages;	/*	 * Try to make fraged_pages keeping in mind that we can't use free	 * space of "empty" end-pages and last page if it reapped.	 */	if (do_shrinking && vacuum_pages->vpl_num_pages - empty_end_pages > 0)	{		int			nusf;		/* blocks usefull for re-using */		nusf = vacuum_pages->vpl_num_pages - empty_end_pages;		if ((vacuum_pages->vpl_pagedesc[nusf - 1])->vpd_blkno == nblocks - empty_end_pages - 1)			nusf--;		for (i = 0; i < nusf; i++)		{			vp = vacuum_pages->vpl_pagedesc[i];			if (vc_enough_space(vp, min_tlen))			{				vc_vpinsert(fraged_pages, vp);				usable_free_size += vp->vpd_free;			}		}	}	if (usable_free_size > 0 && num_vtlinks > 0)	{		qsort((char *) vtlinks, num_vtlinks, sizeof(VTupleLinkData),			  vc_cmp_vtlinks);		vacrelstats->vtlinks = vtlinks;		vacrelstats->num_vtlinks = num_vtlinks;	}	else	{		vacrelstats->vtlinks = NULL;		vacrelstats->num_vtlinks = 0;		pfree(vtlinks);	}	getrusage(RUSAGE_SELF, &ru1);	elog(MESSAGE_LEVEL, "Pages %u: Changed %u, Reapped %u, Empty %u, New %u; \Tup %u: Vac %u, Keep/VTL %u/%u, Crash %u, UnUsed %u, MinLen %u, MaxLen %u; \Re-using: Free/Avail. Space %u/%u; EndEmpty/Avail. Pages %u/%u. \Elapsed %u/%u sec.",		 nblocks, changed_pages, vacuum_pages->vpl_num_pages, empty_pages,		 new_pages, num_tuples, tups_vacuumed,		 nkeep, vacrelstats->num_vtlinks, ncrash,		 nunused, min_tlen, max_tlen, free_size, usable_free_size,		 empty_end_pages, fraged_pages->vpl_num_pages,		 ru1.ru_stime.tv_sec - ru0.ru_stime.tv_sec,		 ru1.ru_utime.tv_sec - ru0.ru_utime.tv_sec);}	/* vc_scanheap *//* *	vc_rpfheap() -- try to repaire relation' fragmentation * *		This routine marks dead tuples as unused and tries re-use dead space *		by moving tuples (and inserting indices if needed). It constructs *		Nvpl list of free-ed pages (moved tuples) and clean indices *		for them after committing (in hack-manner - without losing locks *		and freeing memory!) current transaction. It truncates relation *		if some end-blocks are gone away. */static voidvc_rpfheap(VRelStats *vacrelstats, Relation onerel,		   VPageList vacuum_pages, VPageList fraged_pages, int nindices, Relation *Irel){	TransactionId myXID;	CommandId	myCID;	Buffer		buf,				cur_buffer;	int			nblocks,				blkno;	Page		page,				ToPage = NULL;	OffsetNumber offnum = 0,				maxoff = 0,				newoff,				max_offset;	ItemId		itemid,				newitemid;	HeapTupleData tuple,				newtup;	TupleDesc	tupdesc = NULL;	Datum	   *idatum = NULL;	char	   *inulls = NULL;	InsertIndexResult iresult;	VPageListData Nvpl;	VPageDescr	cur_page = NULL,				last_fraged_page,				last_vacuum_page,				vpc,			   *vpp;	int			cur_item = 0;	IndDesc    *Idesc,			   *idcur;	int			last_fraged_block,				last_vacuum_block,				i = 0;	Size		tuple_len;	int			num_moved,				num_fraged_pages,				vacuumed_pages;	int			checked_moved,				num_tuples,				keep_tuples = 0;	bool		isempty,				dowrite,				chain_tuple_moved;	struct rusage ru0,				ru1;	getrusage(RUSAGE_SELF, &ru0);	myXID = GetCurrentTransactionId();	myCID = GetCurrentCommandId();	if (Irel != (Relation *) NULL)		/* preparation for index' inserts */	{		vc_mkindesc(onerel, nindices, Irel, &Idesc);		tupdesc = RelationGetDescr(onerel);		idatum = (Datum *) palloc(INDEX_MAX_KEYS * sizeof(*idatum));		inulls = (char *) palloc(INDEX_MAX_KEYS * sizeof(*inulls));	}	Nvpl.vpl_num_pages = 0;	num_fraged_pages = fraged_pages->vpl_num_pages;	last_fraged_page = fraged_pages->vpl_pagedesc[num_fraged_pages - 1];	last_fraged_block = last_fraged_page->vpd_blkno;	Assert(vacuum_pages->vpl_num_pages > vacuum_pages->vpl_empty_end_pages);	vacuumed_pages = vacuum_pages->vpl_num_pages - vacuum_pages->vpl_empty_end_pages;	last_vacuum_page = vacuum_pages->vpl_pagedesc[vacuumed_pages - 1];	last_vacuum_block = last_vacuum_page->vpd_blkno;	Assert(last_vacuum_block >= last_fraged_block);	cur_buffer = InvalidBuffer;	num_moved = 0;	vpc = (VPageDescr) palloc(sizeof(VPageDescrData) + MaxOffsetNumber * sizeof(OffsetNumber));	vpc->vpd_offsets_used = vpc->vpd_offsets_free = 0;	nblocks = vacrelstats->num_pages;	for (blkno = nblocks - vacuum_pages->vpl_empty_end_pages - 1;; blkno--)	{		/* if it's reapped page and it was used by me - quit */		if (blkno == last_fraged_block && last_fraged_page->vpd_offsets_used > 0)			break;		buf = ReadBuffer(onerel, blkno);		page = BufferGetPage(buf);		vpc->vpd_offsets_free = 0;		isempty = PageIsEmpty(page);		dowrite = false;		if (blkno == last_vacuum_block) /* it's reapped page */		{			if (last_vacuum_page->vpd_offsets_free > 0) /* there are dead tuples */			{					/* on this page - clean */				Assert(!isempty);				vc_vacpage(page, last_vacuum_page);				dowrite = true;			}			else				Assert(isempty);			--vacuumed_pages;			Assert(vacuumed_pages > 0);			/* get prev reapped page from vacuum_pages */			last_vacuum_page = vacuum_pages->vpl_pagedesc[vacuumed_pages - 1];			last_vacuum_block = last_vacuum_page->vpd_blkno;			if (blkno == last_fraged_block)		/* this page in												 * fraged_pages too */			{				--num_fraged_pages;				Assert(num_fraged_pages > 0);				Assert(last_fraged_page->vpd_offsets_used == 0);				/* get prev reapped page from fraged_pages */				last_fraged_page = fraged_pages->vpl_pagedesc[num_fraged_pages - 1];				last_fraged_block = last_fraged_page->vpd_blkno;			}			Assert(last_fraged_block <= last_vacuum_block);			if (isempty)			{				ReleaseBuffer(buf);				continue;			}		}		else			Assert(!isempty);		chain_tuple_moved = false;		/* no one chain-tuple was moved										 * off this page, yet */		vpc->vpd_blkno = blkno;		maxoff = PageGetMaxOffsetNumber(page);		for (offnum = FirstOffsetNumber;			 offnum <= maxoff;			 offnum = OffsetNumberNext(offnum))		{			itemid = PageGetItemId(page, offnum);			if (!ItemIdIsUsed(itemid))				continue;			tuple.t_data = (HeapTupleHeader) PageGetItem(page, itemid);			tuple_len = tuple.t_len = ItemIdGetLength(itemid);			ItemPointerSet(&(tuple.t_self), blkno, offnum);			if (!(tuple.t_data->t_infomask & HEAP_XMIN_COMMITTED))			{				if ((TransactionId) tuple.t_data->t_cmin != myXID)					elog(ERROR, "Invalid XID in t_cmin");				if (tuple.t_data->t_infomask & HEAP_MOVED_IN)					elog(ERROR, "HEAP_MOVED_IN was not expected");				/*				 * If this (chain) tuple is moved by me already then I				 * have to check is it in vpc or not - i.e. is it moved				 * while cleaning this page or some previous one.				 */				if (tuple.t_data->t_infomask & HEAP_MOVED_OFF)				{					if (keep_tuples == 0)						continue;					if (chain_tuple_moved)		/* some chains was moved												 * while */					{			/* cleaning this page */						Assert(vpc->vpd_offsets_free > 0);						for (i = 0; i < vpc->vpd_offsets_free; i++)						{							if (vpc->vpd_offsets[i] == offnum)								break;						}						if (i >= vpc->vpd_offsets_free) /* not found */						{							vpc->vpd_offsets[vpc->vpd_offsets_free++] = offnum;							keep_tuples--;						}					}					else					{						vpc->vpd_offsets[vpc->vpd_offsets_free++] = offnum;						keep_tuples--;					}					continue;				}				elog(ERROR, "HEAP_MOVED_OFF was expected");			}			/*			 * If this tuple is in the chain of tuples created in updates			 * by "recent" transactions then we have to move all chain of			 * tuples to another places.			 */			if ((tuple.t_data->t_infomask & HEAP_UPDATED &&				 tuple.t_data->t_xmin >= XmaxRecent) ||				(!(tuple.t_data->t_infomask & HEAP_XMAX_INVALID) &&				 !(ItemPointerEquals(&(tuple.t_self), &(tuple.t_data->t_ctid)))))			{				Buffer		Cbuf = buf;				Page		Cpage;				ItemId		Citemid;				ItemPointerData Ctid;				HeapTupleData tp = tuple;				Size		tlen = tuple_len;				VTupleMove	vtmove = (VTupleMove)				palloc(100 * sizeof(VTupleMoveData));				int			num_vtmove = 0;				int			free_vtmove = 100;				VPageDescr	to_vpd = fraged_pages->vpl_pagedesc[0];				int			to_item = 0;				bool		freeCbuf = false;				int			ti;				if (vacrelstats->vtlinks == NULL)					elog(ERROR, "No one parent tuple was found");				if (cur_buffer != InvalidBuffer)				{					WriteBuffer(cur_buffer);					cur_buffer = InvalidBuffer;				}				/*				 * If this tuple is in the begin/middle of the chain then				 * we have to move to the end of chain.				 */				while (!(tp.t_data->t_infomask & HEAP_XMAX_INVALID) &&				!(ItemPointerEquals(&(tp.t_self), &(tp.t_data->t_ctid))))				{					Ctid = tp.t_data->t_ctid;					if (freeCbuf)						ReleaseBuffer(Cbuf);					freeCbuf = true;					Cbuf = ReadBuffer(onerel,									  ItemPointerGetBlockNumber(&Ctid));					Cpage = BufferGetPage(Cbuf);					Citemid = PageGetItemId(Cpage,									  ItemPointerGetOffsetNumber(&Ctid));					if (!ItemIdIsUsed(Citemid))					{						/*						 * This means that in the middle of chain there was						 * tuple updated by older (than XmaxRecent) xaction						 * and this tuple is already deleted by me. Actually,						 * upper part of chain should be removed and seems 						 * that this should be handled in vc_scanheap(), but						 * it's not implemented at the moment and so we						 * just stop shrinking here.						 */						ReleaseBuffer(Cbuf);						pfree(vtmove);						vtmove = NULL;						elog(NOTICE, "Child itemid in update-chain marked as unused - can't continue vc_rpfheap");						break;					}					tp.t_data = (HeapTupleHeader) PageGetItem(Cpage, Citemid);					tp.t_self = Ctid;					tlen = tp.t_len = ItemIdGetLength(Citemid);				}				if (vtmove == NULL)					break;				/* first, can chain be moved ? */				for (;;)				{					if (!vc_enough_space(to_vpd, tlen))					{						if (to_vpd != last_fraged_page &&						 !vc_enough_space(to_vpd, vacrelstats->min_tlen))						{							Assert(num_fraged_pages > to_item + 1);							memmove(fraged_pages->vpl_pagedesc + to_item,								fraged_pages->vpl_pagedesc + to_item + 1,									sizeof(VPageDescr *) * (num_fraged_pages - to_item - 1));							num_fraged_pages--;							Assert(last_fraged_page == fraged_pages->vpl_pagedesc[num_fraged_pages - 1]);						}						for (i = 0; i < num_fraged_pages; i++)						{							if (vc_enough_space(fraged_pages->vpl_pagedesc[i], tlen))								break;						}						if (i == num_fraged_pages)		/* can't move item														 * anywhere */						{							for (i = 0; i < num_vtmove; i++)							{								Assert(vtmove[i].vpd->vpd_offsets_used > 0);								(vtmove[i].vpd->vpd_offsets_used)--;							}							num_vtmove = 0;							break;						}						to_item = i;						to_vpd = fraged_pages->vpl_pagedesc[to_item];					}					to_vpd->vpd_free -= MAXALIGN(tlen);					if (to_vpd->vpd_offsets_used >= to_vpd->vpd_offsets_free)						to_vpd->vpd_free -= MAXALIGN(sizeof(ItemIdData));					(to_vpd->vpd_offsets_used)++;					if (free_vtmove == 0)					{						free_vtmove = 1000;						vtmove = (VTupleMove) repalloc(vtmove,											 (free_vtmove + num_vtmove) *												 sizeof(VTupleMoveData));					}					vtmove[num_vtmove].tid = tp.t_self;					vtmove[num_vtmove].vpd = to_vpd;					if (to_vpd->vpd_offsets_used == 1)						vtmove[num_vtmove].cleanVpd = true;					else						vtmove[num_vtmove].cleanVpd = false;					free_vtmove--;					num_vtmove++;					/*					 * All done ?					 */					if (!(tp.t_data->t_infomask & HEAP_UPDATED) ||						tp.t_data->t_xmin < XmaxRecent)						break;					/*					 * Well, try to find tuple with old row version					 */					for (;;)					{						Buffer		Pbuf;						Page		Ppage;						ItemId		Pitemid;						HeapTupleData Ptp;						VTupleLinkData vtld,								   *vtlp;						vtld.new_tid = tp.t_self;						vtlp = (VTupleLink)							vc_find_eq((void *) (vacrelstats->vtlinks),									   vacrelstats->num_vtlinks,									   sizeof(VTupleLinkData),									   (void *) &vtld,									   vc_cmp_vtlinks);						if (vtlp == NULL)							elog(ERROR, "Parent tuple was not found");						tp.t_self = vtlp->this_tid;						Pbuf = ReadBuffer(onerel,								ItemPointerGetBlockNumber(&(tp.t_self)));						Ppage = BufferGetPage(Pbuf);						Pitemid = PageGetItemId(Ppage,							   ItemPointerGetOffsetNumber(&(tp.t_self)));						if (!ItemIdIsUsed(Pitemid))							elog(ERROR, "Parent itemid marked as unused");						Ptp.t_data = (HeapTupleHeader) PageGetItem(Ppage, Pitemid);						Assert(ItemPointerEquals(&(vtld.new_tid),												&(Ptp.t_data->t_ctid)));						/*						 * Read above about cases when !ItemIdIsUsed(Citemid)						 * (child item is removed)... Due to the fact that						 * at the moment we don't remove unuseful part of 						 * update-chain, it's possible to get too old						 * parent row here. Like as in the case which 						 * caused this problem, we stop shrinking here.						 * I could try to find real parent row but want						 * not to do it because of real solution will						 * be implemented anyway, latter, and we are too						 * close to 6.5 release.		- vadim 06/11/99						 */						if (Ptp.t_data->t_xmax != tp.t_data->t_xmin)						{							if (freeCbuf)								ReleaseBuffer(Cbuf);							freeCbuf = false;							ReleaseBuffer(Pbuf);							for (i = 0; i < num_vtmove; i++)							{								Assert(vtmove[i].vpd->vpd_offsets_used > 0);								(vtmove[i].vpd->vpd_offsets_used)--;							}							num_vtmove = 0;							elog(NOTICE, "Too old parent tuple found - can't continue vc_rpfheap");							break;						}#ifdef NOT_USED			/* I'm not sure that this will wotk properly... */						/*						 * If this tuple is updated version of row and it						 * was created by the same transaction then no one						 * is interested in this tuple - mark it as						 * removed.						 */						if (Ptp.t_data->t_infomask & HEAP_UPDATED &&							Ptp.t_data->t_xmin == Ptp.t_data->t_xmax)						{							TransactionIdStore(myXID,								(TransactionId *) &(Ptp.t_data->t_cmin));							Ptp.t_data->t_infomask &=

⌨️ 快捷键说明

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