📄 vacuum.c
字号:
func_operator = oper("=", stats->attr->atttypid, stats->attr->atttypid, true); if (func_operator != NULL) { pgopform = (Form_pg_operator) GETSTRUCT(func_operator); fmgr_info(pgopform->oprcode, &(stats->f_cmpeq)); } else stats->f_cmpeq.fn_addr = NULL; func_operator = oper("<", stats->attr->atttypid, stats->attr->atttypid, true); if (func_operator != NULL) { pgopform = (Form_pg_operator) GETSTRUCT(func_operator); fmgr_info(pgopform->oprcode, &(stats->f_cmplt)); } else stats->f_cmplt.fn_addr = NULL; func_operator = oper(">", stats->attr->atttypid, stats->attr->atttypid, true); if (func_operator != NULL) { pgopform = (Form_pg_operator) GETSTRUCT(func_operator); fmgr_info(pgopform->oprcode, &(stats->f_cmpgt)); } else stats->f_cmpgt.fn_addr = NULL; typetuple = SearchSysCacheTuple(TYPOID, ObjectIdGetDatum(stats->attr->atttypid), 0, 0, 0); if (HeapTupleIsValid(typetuple)) stats->outfunc = ((Form_pg_type) GETSTRUCT(typetuple))->typoutput; else stats->outfunc = InvalidOid; } vacrelstats->va_natts = attr_cnt; vc_delhilowstats(relid, ((attnums) ? attr_cnt : 0), attnums); if (attnums) pfree(attnums); } else { vacrelstats->va_natts = 0; vacrelstats->vacattrstats = (VacAttrStats *) NULL; } /* we require the relation to be locked until the indices are cleaned */ LockRelation(onerel, AccessExclusiveLock); GetXmaxRecent(&XmaxRecent); /* scan it */ vacuum_pages.vpl_num_pages = fraged_pages.vpl_num_pages = 0; vc_scanheap(vacrelstats, onerel, &vacuum_pages, &fraged_pages); /* Now open indices */ Irel = (Relation *) NULL; vc_getindices(vacrelstats->relid, &nindices, &Irel); if (nindices > 0) vacrelstats->hasindex = true; else vacrelstats->hasindex = false; /* Clean/scan index relation(s) */ if (Irel != (Relation *) NULL) { if (vacuum_pages.vpl_num_pages > 0) { for (i = 0; i < nindices; i++) vc_vaconeind(&vacuum_pages, Irel[i], vacrelstats->num_tuples, 0); } else/* just scan indices to update statistic */ { for (i = 0; i < nindices; i++) vc_scanoneind(Irel[i], vacrelstats->num_tuples); } } if (fraged_pages.vpl_num_pages > 0) /* Try to shrink heap */ vc_rpfheap(vacrelstats, onerel, &vacuum_pages, &fraged_pages, nindices, Irel); else { if (Irel != (Relation *) NULL) vc_clsindices(nindices, Irel); if (vacuum_pages.vpl_num_pages > 0) /* Clean pages from * vacuum_pages list */ vc_vacheap(vacrelstats, onerel, &vacuum_pages); } /* ok - free vacuum_pages list of reapped pages */ if (vacuum_pages.vpl_num_pages > 0) { vpp = vacuum_pages.vpl_pagedesc; for (i = 0; i < vacuum_pages.vpl_num_pages; i++, vpp++) pfree(*vpp); pfree(vacuum_pages.vpl_pagedesc); if (fraged_pages.vpl_num_pages > 0) pfree(fraged_pages.vpl_pagedesc); } /* all done with this class */ heap_close(onerel); /* update statistics in pg_class */ vc_updstats(vacrelstats->relid, vacrelstats->num_pages, vacrelstats->num_tuples, vacrelstats->hasindex, vacrelstats); /* next command frees attribute stats */ CommitTransactionCommand();}/* * vc_scanheap() -- scan an open heap relation * * This routine sets commit times, constructs vacuum_pages list of * empty/uninitialized pages and pages with dead tuples and * ~LP_USED line pointers, constructs fraged_pages list of pages * appropriate for purposes of shrinking and maintains statistics * on the number of live tuples in a heap. */static voidvc_scanheap(VRelStats *vacrelstats, Relation onerel, VPageList vacuum_pages, VPageList fraged_pages){ int nblocks, blkno; ItemId itemid; Buffer buf; HeapTupleData tuple; Page page, tempPage = NULL; OffsetNumber offnum, maxoff; bool pgchanged, tupgone, dobufrel, notup; char *relname; VPageDescr vpc, vp; uint32 tups_vacuumed, num_tuples, nkeep, nunused, ncrash, empty_pages, new_pages, changed_pages, empty_end_pages; Size free_size, usable_free_size; Size min_tlen = MaxTupleSize; Size max_tlen = 0; int32 i; struct rusage ru0, ru1; bool do_shrinking = true; VTupleLink vtlinks = (VTupleLink) palloc(100 * sizeof(VTupleLinkData)); int num_vtlinks = 0; int free_vtlinks = 100; getrusage(RUSAGE_SELF, &ru0); relname = (RelationGetRelationName(onerel))->data; elog(MESSAGE_LEVEL, "--Relation %s--", relname); tups_vacuumed = num_tuples = nkeep = nunused = ncrash = empty_pages = new_pages = changed_pages = empty_end_pages = 0; free_size = usable_free_size = 0; nblocks = RelationGetNumberOfBlocks(onerel); vpc = (VPageDescr) palloc(sizeof(VPageDescrData) + MaxOffsetNumber * sizeof(OffsetNumber)); vpc->vpd_offsets_used = 0; for (blkno = 0; blkno < nblocks; blkno++) { buf = ReadBuffer(onerel, blkno); page = BufferGetPage(buf); vpc->vpd_blkno = blkno; vpc->vpd_offsets_free = 0; if (PageIsNew(page)) { elog(NOTICE, "Rel %s: Uninitialized page %u - fixing", relname, blkno); PageInit(page, BufferGetPageSize(buf), 0); vpc->vpd_free = ((PageHeader) page)->pd_upper - ((PageHeader) page)->pd_lower; free_size += (vpc->vpd_free - sizeof(ItemIdData)); new_pages++; empty_end_pages++; vc_reappage(vacuum_pages, vpc); WriteBuffer(buf); continue; } if (PageIsEmpty(page)) { vpc->vpd_free = ((PageHeader) page)->pd_upper - ((PageHeader) page)->pd_lower; free_size += (vpc->vpd_free - sizeof(ItemIdData)); empty_pages++; empty_end_pages++; vc_reappage(vacuum_pages, vpc); ReleaseBuffer(buf); continue; } pgchanged = false; notup = true; maxoff = PageGetMaxOffsetNumber(page); for (offnum = FirstOffsetNumber; offnum <= maxoff; offnum = OffsetNumberNext(offnum)) { itemid = PageGetItemId(page, offnum); /* * Collect un-used items too - it's possible to have indices * pointing here after crash. */ if (!ItemIdIsUsed(itemid)) { vpc->vpd_offsets[vpc->vpd_offsets_free++] = offnum; nunused++; continue; } tuple.t_data = (HeapTupleHeader) PageGetItem(page, itemid); tuple.t_len = ItemIdGetLength(itemid); ItemPointerSet(&(tuple.t_self), blkno, offnum); tupgone = false; if (!(tuple.t_data->t_infomask & HEAP_XMIN_COMMITTED)) { if (tuple.t_data->t_infomask & HEAP_XMIN_INVALID) tupgone = true; else if (tuple.t_data->t_infomask & HEAP_MOVED_OFF) { if (TransactionIdDidCommit((TransactionId) tuple.t_data->t_cmin)) { tuple.t_data->t_infomask |= HEAP_XMIN_INVALID; tupgone = true; } else { tuple.t_data->t_infomask |= HEAP_XMIN_COMMITTED; pgchanged = true; } } else if (tuple.t_data->t_infomask & HEAP_MOVED_IN) { if (!TransactionIdDidCommit((TransactionId) tuple.t_data->t_cmin)) { tuple.t_data->t_infomask |= HEAP_XMIN_INVALID; tupgone = true; } else { tuple.t_data->t_infomask |= HEAP_XMIN_COMMITTED; pgchanged = true; } } else { if (TransactionIdDidAbort(tuple.t_data->t_xmin)) tupgone = true; else if (TransactionIdDidCommit(tuple.t_data->t_xmin)) { tuple.t_data->t_infomask |= HEAP_XMIN_COMMITTED; pgchanged = true; } else if (!TransactionIdIsInProgress(tuple.t_data->t_xmin)) { /* * Not Aborted, Not Committed, Not in Progress - * so it's from crashed process. - vadim 11/26/96 */ ncrash++; tupgone = true; } else { elog(NOTICE, "Rel %s: TID %u/%u: InsertTransactionInProgress %u - can't shrink relation", relname, blkno, offnum, tuple.t_data->t_xmin); do_shrinking = false; } } } /* * here we are concerned about tuples with xmin committed and * xmax unknown or committed */ if (tuple.t_data->t_infomask & HEAP_XMIN_COMMITTED && !(tuple.t_data->t_infomask & HEAP_XMAX_INVALID)) { if (tuple.t_data->t_infomask & HEAP_XMAX_COMMITTED) { if (tuple.t_data->t_infomask & HEAP_MARKED_FOR_UPDATE) { pgchanged = true; tuple.t_data->t_infomask |= HEAP_XMAX_INVALID; } else tupgone = true; } else if (TransactionIdDidAbort(tuple.t_data->t_xmax)) { tuple.t_data->t_infomask |= HEAP_XMAX_INVALID; pgchanged = true; } else if (TransactionIdDidCommit(tuple.t_data->t_xmax)) { if (tuple.t_data->t_infomask & HEAP_MARKED_FOR_UPDATE) { tuple.t_data->t_infomask |= HEAP_XMAX_INVALID; pgchanged = true; } else tupgone = true; } else if (!TransactionIdIsInProgress(tuple.t_data->t_xmax)) { /* * Not Aborted, Not Committed, Not in Progress - so it * from crashed process. - vadim 06/02/97 */ tuple.t_data->t_infomask |= HEAP_XMAX_INVALID; pgchanged = true; } else { elog(NOTICE, "Rel %s: TID %u/%u: DeleteTransactionInProgress %u - can't shrink relation", relname, blkno, offnum, tuple.t_data->t_xmax); do_shrinking = false; } /* * If tuple is recently deleted then we must not remove it * from relation. */ if (tupgone && tuple.t_data->t_xmax >= XmaxRecent) { tupgone = false; nkeep++; if (!(tuple.t_data->t_infomask & HEAP_XMAX_COMMITTED)) { tuple.t_data->t_infomask |= HEAP_XMAX_COMMITTED; pgchanged = true; } /* * If we do shrinking and this tuple is updated one * then remember it to construct updated tuple * dependencies. */ if (do_shrinking && !(ItemPointerEquals(&(tuple.t_self), &(tuple.t_data->t_ctid)))) { if (free_vtlinks == 0) { free_vtlinks = 1000; vtlinks = (VTupleLink) repalloc(vtlinks, (free_vtlinks + num_vtlinks) * sizeof(VTupleLinkData)); } vtlinks[num_vtlinks].new_tid = tuple.t_data->t_ctid; vtlinks[num_vtlinks].this_tid = tuple.t_self; free_vtlinks--; num_vtlinks++; } } } /* * Other checks... */ if (!OidIsValid(tuple.t_data->t_oid)) { elog(NOTICE, "Rel %s: TID %u/%u: OID IS INVALID. TUPGONE %d.", relname, blkno, offnum, tupgone); } if (tupgone) { ItemId lpp; if (tempPage == (Page) NULL) { Size pageSize; pageSize = PageGetPageSize(page); tempPage = (Page) palloc(pageSize); memmove(tempPage, page, pageSize); } lpp = &(((PageHeader) tempPage)->pd_linp[offnum - 1]); /* mark it unused */ lpp->lp_flags &= ~LP_USED; vpc->vpd_offsets[vpc->vpd_offsets_free++] = offnum; tups_vacuumed++; } else { num_tuples++; notup = false; if (tuple.t_len < min_tlen) min_tlen = tuple.t_len; if (tuple.t_len > max_tlen) max_tlen = tuple.t_len; vc_attrstats(onerel, vacrelstats, &tuple); } } if (pgchanged) { WriteBuffer(buf); dobufrel = false; changed_pages++; } else dobufrel = true; if (tempPage != (Page) NULL) { /* Some tuples are gone */ PageRepairFragmentation(tempPage); vpc->vpd_free = ((PageHeader) tempPage)->pd_upper - ((PageHeader) tempPage)->pd_lower; free_size += vpc->vpd_free; vc_reappage(vacuum_pages, vpc); pfree(tempPage); tempPage = (Page) NULL; } else if (vpc->vpd_offsets_free > 0) { /* there are only ~LP_USED line pointers */ vpc->vpd_free = ((PageHeader) page)->pd_upper - ((PageHeader) page)->pd_lower; free_size += vpc->vpd_free; vc_reappage(vacuum_pages, vpc); } if (dobufrel) ReleaseBuffer(buf); if (notup) empty_end_pages++; else empty_end_pages = 0; } pfree(vpc); /* save stats in the rel list for use later */ vacrelstats->num_tuples = num_tuples; vacrelstats->num_pages = nblocks;/* vacrelstats->natts = attr_cnt;*/ if (num_tuples == 0)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -