summaryrefslogtreecommitdiff
path: root/src/backend/commands/vacuum.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/commands/vacuum.c')
-rw-r--r--src/backend/commands/vacuum.c547
1 files changed, 487 insertions, 60 deletions
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index 6b9b0ce0a1..285a256f57 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.96 1999/02/21 03:48:33 scrappy Exp $
+ * $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.97 1999/03/28 20:32:01 vadim Exp $
*
*-------------------------------------------------------------------------
*/
@@ -65,6 +65,9 @@ static Portal vc_portal;
static int MESSAGE_LEVEL; /* message level */
+static TransactionId XmaxRecent;
+extern void GetXmaxRecent(TransactionId *xid);
+
#define swapLong(a,b) {long tmp; tmp=a; a=b; b=tmp;}
#define swapInt(a,b) {int tmp; tmp=a; a=b; b=tmp;}
#define swapDatum(a,b) {Datum tmp; tmp=a; a=b; b=tmp;}
@@ -98,9 +101,11 @@ static void vc_free(VRelList vrl);
static void vc_getindices(Oid relid, int *nindices, Relation **Irel);
static void vc_clsindices(int nindices, Relation *Irel);
static void vc_mkindesc(Relation onerel, int nindices, Relation *Irel, IndDesc **Idesc);
-static char *vc_find_eq(char *bot, int nelem, int size, char *elm, int (*compar) (char *, char *));
-static int vc_cmp_blk(char *left, char *right);
-static int vc_cmp_offno(char *left, char *right);
+static void *vc_find_eq(void *bot, int nelem, int size, void *elm,
+ int (*compar) (const void *, const void *));
+static int vc_cmp_blk(const void *left, const void *right);
+static int vc_cmp_offno(const void *left, const void *right);
+static int vc_cmp_vtlinks(const void *left, const void *right);
static bool vc_enough_space(VPageDescr vpd, Size len);
void
@@ -502,6 +507,8 @@ vc_vacone(Oid relid, bool analyze, List *va_cols)
/* 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);
@@ -595,6 +602,7 @@ vc_scanheap(VRelStats *vacrelstats, Relation onerel,
vp;
uint32 tups_vacuumed,
num_tuples,
+ nkeep,
nunused,
ncrash,
empty_pages,
@@ -609,22 +617,24 @@ vc_scanheap(VRelStats *vacrelstats, Relation onerel,
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);
- tups_vacuumed = num_tuples = nunused = ncrash = empty_pages =
+ 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;
- relname = (RelationGetRelationName(onerel))->data;
-
nblocks = RelationGetNumberOfBlocks(onerel);
vpc = (VPageDescr) palloc(sizeof(VPageDescrData) + MaxOffsetNumber * sizeof(OffsetNumber));
vpc->vpd_offsets_used = 0;
- elog(MESSAGE_LEVEL, "--Relation %s--", relname);
-
for (blkno = 0; blkno < nblocks; blkno++)
{
buf = ReadBuffer(onerel, blkno);
@@ -686,6 +696,34 @@ vc_scanheap(VRelStats *vacrelstats, Relation onerel,
{
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))
@@ -722,22 +760,37 @@ vc_scanheap(VRelStats *vacrelstats, Relation onerel,
!(tuple.t_data->t_infomask & HEAP_XMAX_INVALID))
{
if (tuple.t_data->t_infomask & HEAP_XMAX_COMMITTED)
- tupgone = true;
+ {
+ 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))
- tupgone = true;
+ {
+ 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;;
+ tuple.t_data->t_infomask |= HEAP_XMAX_INVALID;
pgchanged = true;
}
else
@@ -746,6 +799,41 @@ vc_scanheap(VRelStats *vacrelstats, Relation onerel,
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 &&
+ tuple.t_data->t_infomask & HEAP_XMIN_COMMITTED)
+ {
+ 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++;
+ }
+ }
}
/*
@@ -859,13 +947,31 @@ vc_scanheap(VRelStats *vacrelstats, Relation onerel,
}
}
+ 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, 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, ncrash, nunused, min_tlen, max_tlen,
- free_size, usable_free_size, empty_end_pages, fraged_pages->vpl_num_pages,
+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);
@@ -917,7 +1023,7 @@ vc_rpfheap(VRelStats *vacrelstats, Relation onerel,
*idcur;
int last_fraged_block,
last_vacuum_block,
- i;
+ i = 0;
Size tuple_len;
int num_moved,
num_fraged_pages,
@@ -1022,6 +1128,280 @@ vc_rpfheap(VRelStats *vacrelstats, Relation onerel,
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_OFF)
+ continue; /* already removed by me */
+ if (tuple.t_data->t_infomask & HEAP_MOVED_IN)
+ break;
+ elog(ERROR, "HEAP_MOVED_OFF/HEAP_MOVED_IN 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))
+ elog(ERROR, "Child itemid marked as unused");
+ tp.t_data = (HeapTupleHeader) PageGetItem(Cpage, Citemid);
+ tp.t_self = Ctid;
+ tlen = tp.t_len = ItemIdGetLength(Citemid);
+ }
+ /* 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 -= DOUBLEALIGN(tlen);
+ if (to_vpd->vpd_offsets_used >= to_vpd->vpd_offsets_free)
+ to_vpd->vpd_free -= DOUBLEALIGN(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(Ptp.t_data->t_xmax == tp.t_data->t_xmin);
+ /*
+ * 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 &=
+ ~(HEAP_XMIN_COMMITTED|HEAP_XMIN_INVALID|HEAP_MOVED_IN);
+ Ptp.t_data->t_infomask |= HEAP_MOVED_OFF;
+ WriteBuffer(Pbuf);
+ continue;
+ }
+ tp.t_data = Ptp.t_data;
+ tlen = tp.t_len = ItemIdGetLength(Pitemid);
+ if (freeCbuf)
+ ReleaseBuffer(Cbuf);
+ Cbuf = Pbuf;
+ freeCbuf = true;
+ break;
+ }
+ }
+ if (freeCbuf)
+ ReleaseBuffer(Cbuf);
+ if (num_vtmove == 0) /* chain can't be moved */
+ {
+ pfree(vtmove);
+ break;
+ }
+ ItemPointerSetInvalid(&Ctid);
+ for (ti = 0; ti < num_vtmove; ti++)
+ {
+ /* Get tuple from chain */
+ tuple.t_self = vtmove[ti].tid;
+ Cbuf = ReadBuffer(onerel,
+ ItemPointerGetBlockNumber(&(tuple.t_self)));
+ Cpage = BufferGetPage(Cbuf);
+ Citemid = PageGetItemId(Cpage,
+ ItemPointerGetOffsetNumber(&(tuple.t_self)));
+ tuple.t_data = (HeapTupleHeader) PageGetItem(Cpage, Citemid);
+ tuple_len = tuple.t_len = ItemIdGetLength(Citemid);
+ /* Get page to move in */
+ cur_buffer = ReadBuffer(onerel, vtmove[ti].vpd->vpd_blkno);
+ ToPage = BufferGetPage(cur_buffer);
+ /* if this page was not used before - clean it */
+ if (!PageIsEmpty(ToPage) && vtmove[i].cleanVpd)
+ vc_vacpage(ToPage, vtmove[ti].vpd);
+ heap_copytuple_with_tuple(&tuple, &newtup);
+ RelationInvalidateHeapTuple(onerel, &tuple);
+ TransactionIdStore(myXID, (TransactionId*) &(newtup.t_data->t_cmin));
+ newtup.t_data->t_infomask &=
+ ~(HEAP_XMIN_COMMITTED|HEAP_XMIN_INVALID|HEAP_MOVED_OFF);
+ newtup.t_data->t_infomask |= HEAP_MOVED_IN;
+ newoff = PageAddItem(ToPage, (Item) newtup.t_data, tuple_len,
+ InvalidOffsetNumber, LP_USED);
+ if (newoff == InvalidOffsetNumber)
+ {
+ elog(ERROR, "\
+moving chain: failed to add item with len = %u to page %u",
+ tuple_len, vtmove[ti].vpd->vpd_blkno);
+ }
+ newitemid = PageGetItemId(ToPage, newoff);
+ pfree(newtup.t_data);
+ newtup.t_data = (HeapTupleHeader) PageGetItem(ToPage, newitemid);
+ ItemPointerSet(&(newtup.t_self), vtmove[i].vpd->vpd_blkno, newoff);
+ /*
+ * Set t_ctid pointing to itself for last tuple in
+ * chain and to next tuple in chain otherwise.
+ */
+ if (!ItemPointerIsValid(&Ctid))
+ newtup.t_data->t_ctid = newtup.t_self;
+ else
+ newtup.t_data->t_ctid = Ctid;
+ Ctid = newtup.t_self;
+
+ TransactionIdStore(myXID, (TransactionId*) &(tuple.t_data->t_cmin));
+ tuple.t_data->t_infomask &=
+ ~(HEAP_XMIN_COMMITTED|HEAP_XMIN_INVALID|HEAP_MOVED_IN);
+ tuple.t_data->t_infomask |= HEAP_MOVED_OFF;
+
+ num_moved++;
+ if (Cbuf == buf)
+ vpc->vpd_offsets[vpc->vpd_offsets_free++] =
+ ItemPointerGetOffsetNumber(&(tuple.t_self));
+
+ if (Irel != (Relation *) NULL)
+ {
+ for (i = 0, idcur = Idesc; i < nindices; i++, idcur++)
+ {
+ FormIndexDatum(idcur->natts,
+ (AttrNumber *) &(idcur->tform->indkey[0]),
+ &newtup,
+ tupdesc,
+ idatum,
+ inulls,
+ idcur->finfoP);
+ iresult = index_insert(Irel[i],
+ idatum,
+ inulls,
+ &newtup.t_self,
+ onerel);
+ if (iresult)
+ pfree(iresult);
+ }
+ }
+ WriteBuffer(cur_buffer);
+ if (Cbuf == buf)
+ ReleaseBuffer(Cbuf);
+ else
+ WriteBuffer(Cbuf);
+ }
+ cur_buffer = InvalidBuffer;
+ pfree(vtmove);
+ continue;
+ }
+
/* try to find new page for this tuple */
if (cur_buffer == InvalidBuffer ||
!vc_enough_space(cur_page, tuple_len))
@@ -1070,13 +1450,14 @@ vc_rpfheap(VRelStats *vacrelstats, Relation onerel,
RelationInvalidateHeapTuple(onerel, &tuple);
- /* store transaction information */
- TransactionIdStore(myXID, &(newtup.t_data->t_xmin));
- newtup.t_data->t_cmin = myCID;
- StoreInvalidTransactionId(&(newtup.t_data->t_xmax));
- /* set xmin to unknown and xmax to invalid */
- newtup.t_data->t_infomask &= ~(HEAP_XACT_MASK);
- newtup.t_data->t_infomask |= HEAP_XMAX_INVALID;
+ /*
+ * Mark new tuple as moved_in by vacuum and
+ * store vacuum XID in t_cmin !!!
+ */
+ TransactionIdStore(myXID, (TransactionId*) &(newtup.t_data->t_cmin));
+ newtup.t_data->t_infomask &=
+ ~(HEAP_XMIN_COMMITTED|HEAP_XMIN_INVALID|HEAP_MOVED_OFF);
+ newtup.t_data->t_infomask |= HEAP_MOVED_IN;
/* add tuple to the page */
newoff = PageAddItem(ToPage, (Item) newtup.t_data, tuple_len,
@@ -1094,11 +1475,14 @@ failed to add item with len = %u to page %u (free space %u, nusd %u, noff %u)",
ItemPointerSet(&(newtup.t_data->t_ctid), cur_page->vpd_blkno, newoff);
newtup.t_self = newtup.t_data->t_ctid;
- /* now logically delete end-tuple */
- TransactionIdStore(myXID, &(tuple.t_data->t_xmax));
- tuple.t_data->t_cmax = myCID;
- /* set xmax to unknown */
- tuple.t_data->t_infomask &= ~(HEAP_XMAX_INVALID | HEAP_XMAX_COMMITTED);
+ /*
+ * Mark old tuple as moved_off by vacuum and
+ * store vacuum XID in t_cmin !!!
+ */
+ TransactionIdStore(myXID, (TransactionId*) &(tuple.t_data->t_cmin));
+ tuple.t_data->t_infomask &=
+ ~(HEAP_XMIN_COMMITTED|HEAP_XMIN_INVALID|HEAP_MOVED_IN);
+ tuple.t_data->t_infomask |= HEAP_MOVED_OFF;
cur_page->vpd_offsets_used++;
num_moved++;
@@ -1131,6 +1515,8 @@ failed to add item with len = %u to page %u (free space %u, nusd %u, noff %u)",
if (vpc->vpd_offsets_free > 0) /* some tuples were moved */
{
+ qsort((char *) (vpc->vpd_offsets), vpc->vpd_offsets_free,
+ sizeof(OffsetNumber), vc_cmp_offno);
vc_reappage(&Nvpl, vpc);
WriteBuffer(buf);
}
@@ -1167,7 +1553,7 @@ failed to add item with len = %u to page %u (free space %u, nusd %u, noff %u)",
}
/*
- * Clean uncleaned reapped pages from vacuum_pages list and set xmin
+ * Clean uncleaned reapped pages from vacuum_pages list list and set xmin
* committed for inserted tuples
*/
checked_moved = 0;
@@ -1178,16 +1564,10 @@ failed to add item with len = %u to page %u (free space %u, nusd %u, noff %u)",
page = BufferGetPage(buf);
if ((*vpp)->vpd_offsets_used == 0) /* this page was not used */
{
-
- /*
- * noff == 0 in empty pages only - such pages should be
- * re-used
- */
- Assert((*vpp)->vpd_offsets_free > 0);
- vc_vacpage(page, *vpp);
+ if (!PageIsEmpty(page))
+ vc_vacpage(page, *vpp);
}
- else
-/* this page was used */
+ else /* this page was used */
{
num_tuples = 0;
max_offset = PageGetMaxOffsetNumber(page);
@@ -1199,10 +1579,19 @@ failed to add item with len = %u to page %u (free space %u, nusd %u, noff %u)",
if (!ItemIdIsUsed(itemid))
continue;
tuple.t_data = (HeapTupleHeader) PageGetItem(page, itemid);
- if (TransactionIdEquals((TransactionId) tuple.t_data->t_xmin, myXID))
+ if (!(tuple.t_data->t_infomask & HEAP_XMIN_COMMITTED))
{
- tuple.t_data->t_infomask |= HEAP_XMIN_COMMITTED;
- num_tuples++;
+ if ((TransactionId)tuple.t_data->t_cmin != myXID)
+ elog(ERROR, "Invalid XID in t_cmin (2)");
+ if (tuple.t_data->t_infomask & HEAP_MOVED_IN)
+ {
+ tuple.t_data->t_infomask |= HEAP_XMIN_COMMITTED;
+ num_tuples++;
+ }
+ else if (tuple.t_data->t_infomask & HEAP_MOVED_OFF)
+ tuple.t_data->t_infomask |= HEAP_XMIN_INVALID;
+ else
+ elog(ERROR, "HEAP_MOVED_OFF/HEAP_MOVED_IN was expected (2)");
}
}
Assert((*vpp)->vpd_offsets_used == num_tuples);
@@ -1244,16 +1633,13 @@ Elapsed %u/%u sec.",
}
/*
- * clean moved tuples from last page in Nvpl list if some tuples
- * left there
+ * clean moved tuples from last page in Nvpl list
*/
- if (vpc->vpd_offsets_free > 0 && offnum <= maxoff)
+ if (vpc->vpd_blkno == blkno - 1 && vpc->vpd_offsets_free > 0)
{
- Assert(vpc->vpd_blkno == blkno - 1);
buf = ReadBuffer(onerel, vpc->vpd_blkno);
page = BufferGetPage(buf);
num_tuples = 0;
- maxoff = offnum;
for (offnum = FirstOffsetNumber;
offnum < maxoff;
offnum = OffsetNumberNext(offnum))
@@ -1262,9 +1648,20 @@ Elapsed %u/%u sec.",
if (!ItemIdIsUsed(itemid))
continue;
tuple.t_data = (HeapTupleHeader) PageGetItem(page, itemid);
- Assert(TransactionIdEquals((TransactionId) tuple.t_data->t_xmax, myXID));
- itemid->lp_flags &= ~LP_USED;
- num_tuples++;
+
+ if (!(tuple.t_data->t_infomask & HEAP_XMIN_COMMITTED))
+ {
+ if ((TransactionId)tuple.t_data->t_cmin != myXID)
+ elog(ERROR, "Invalid XID in t_cmin (3)");
+ if (tuple.t_data->t_infomask & HEAP_MOVED_OFF)
+ {
+ itemid->lp_flags &= ~LP_USED;
+ num_tuples++;
+ }
+ else
+ elog(ERROR, "HEAP_MOVED_OFF was expected");
+ }
+
}
Assert(vpc->vpd_offsets_free == num_tuples);
PageRepairFragmentation(page);
@@ -1298,6 +1695,8 @@ Elapsed %u/%u sec.",
}
pfree(vpc);
+ if (vacrelstats->vtlinks != NULL)
+ pfree(vacrelstats->vtlinks);
} /* vc_rpfheap */
@@ -1522,8 +1921,8 @@ vc_tidreapped(ItemPointer itemptr, VPageList vpl)
ioffno = ItemPointerGetOffsetNumber(itemptr);
vp = &vpd;
- vpp = (VPageDescr *) vc_find_eq((char *) (vpl->vpl_pagedesc),
- vpl->vpl_num_pages, sizeof(VPageDescr), (char *) &vp,
+ vpp = (VPageDescr *) vc_find_eq((void *) (vpl->vpl_pagedesc),
+ vpl->vpl_num_pages, sizeof(VPageDescr), (void *) &vp,
vc_cmp_blk);
if (vpp == (VPageDescr *) NULL)
@@ -1537,8 +1936,8 @@ vc_tidreapped(ItemPointer itemptr, VPageList vpl)
return vp;
}
- voff = (OffsetNumber *) vc_find_eq((char *) (vp->vpd_offsets),
- vp->vpd_offsets_free, sizeof(OffsetNumber), (char *) &ioffno,
+ voff = (OffsetNumber *) vc_find_eq((void *) (vp->vpd_offsets),
+ vp->vpd_offsets_free, sizeof(OffsetNumber), (void *) &ioffno,
vc_cmp_offno);
if (voff == (OffsetNumber *) NULL)
@@ -1998,8 +2397,9 @@ vc_free(VRelList vrl)
MemoryContextSwitchTo(old);
}
-static char *
-vc_find_eq(char *bot, int nelem, int size, char *elm, int (*compar) (char *, char *))
+static void *
+vc_find_eq(void *bot, int nelem, int size, void *elm,
+ int (*compar) (const void *, const void *))
{
int res;
int last = nelem - 1;
@@ -2053,7 +2453,7 @@ vc_find_eq(char *bot, int nelem, int size, char *elm, int (*compar) (char *, cha
} /* vc_find_eq */
static int
-vc_cmp_blk(char *left, char *right)
+vc_cmp_blk(const void *left, const void *right)
{
BlockNumber lblk,
rblk;
@@ -2070,7 +2470,7 @@ vc_cmp_blk(char *left, char *right)
} /* vc_cmp_blk */
static int
-vc_cmp_offno(char *left, char *right)
+vc_cmp_offno(const void *left, const void *right)
{
if (*(OffsetNumber *) left < *(OffsetNumber *) right)
@@ -2081,6 +2481,33 @@ vc_cmp_offno(char *left, char *right)
} /* vc_cmp_offno */
+static int
+vc_cmp_vtlinks(const void *left, const void *right)
+{
+
+ if (((VTupleLink)left)->new_tid.ip_blkid.bi_hi <
+ ((VTupleLink)right)->new_tid.ip_blkid.bi_hi)
+ return -1;
+ if (((VTupleLink)left)->new_tid.ip_blkid.bi_hi >
+ ((VTupleLink)right)->new_tid.ip_blkid.bi_hi)
+ return 1;
+ /* bi_hi-es are equal */
+ if (((VTupleLink)left)->new_tid.ip_blkid.bi_lo <
+ ((VTupleLink)right)->new_tid.ip_blkid.bi_lo)
+ return -1;
+ if (((VTupleLink)left)->new_tid.ip_blkid.bi_lo >
+ ((VTupleLink)right)->new_tid.ip_blkid.bi_lo)
+ return 1;
+ /* bi_lo-es are equal */
+ if (((VTupleLink)left)->new_tid.ip_posid <
+ ((VTupleLink)right)->new_tid.ip_posid)
+ return -1;
+ if (((VTupleLink)left)->new_tid.ip_posid >
+ ((VTupleLink)right)->new_tid.ip_posid)
+ return 1;
+ return 0;
+
+}
static void
vc_getindices(Oid relid, int *nindices, Relation **Irel)
@@ -2230,7 +2657,7 @@ vc_enough_space(VPageDescr vpd, Size len)
return true; /* and len <= free_space */
/* ok. noff_usd >= noff_free and so we'll have to allocate new itemid */
- if (len <= vpd->vpd_free - sizeof(ItemIdData))
+ if (len + DOUBLEALIGN(sizeof(ItemIdData)) <= vpd->vpd_free)
return true;
return false;