88 *
99 *
1010 * IDENTIFICATION
11- * $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.148.2.1 2000/09/19 21: 01:04 tgl Exp $
11+ * $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.148.2.2 2000/10/17 01:39:56 tgl Exp $
1212 *
1313 *-------------------------------------------------------------------------
1414 */
@@ -815,6 +815,7 @@ vc_scanheap(VRelStats *vacrelstats, Relation onerel,
815815 tuple .t_data -> t_cmin ))
816816 {
817817 tuple .t_data -> t_infomask |= HEAP_XMIN_INVALID ;
818+ pgchanged = true;
818819 tupgone = true;
819820 }
820821 else
@@ -829,6 +830,7 @@ vc_scanheap(VRelStats *vacrelstats, Relation onerel,
829830 tuple .t_data -> t_cmin ))
830831 {
831832 tuple .t_data -> t_infomask |= HEAP_XMIN_INVALID ;
833+ pgchanged = true;
832834 tupgone = true;
833835 }
834836 else
@@ -876,8 +878,10 @@ vc_scanheap(VRelStats *vacrelstats, Relation onerel,
876878 {
877879 if (tuple .t_data -> t_infomask & HEAP_MARKED_FOR_UPDATE )
878880 {
879- pgchanged = true;
880881 tuple .t_data -> t_infomask |= HEAP_XMAX_INVALID ;
882+ tuple .t_data -> t_infomask &=
883+ ~(HEAP_XMAX_COMMITTED | HEAP_MARKED_FOR_UPDATE );
884+ pgchanged = true;
881885 }
882886 else
883887 tupgone = true;
@@ -892,6 +896,8 @@ vc_scanheap(VRelStats *vacrelstats, Relation onerel,
892896 if (tuple .t_data -> t_infomask & HEAP_MARKED_FOR_UPDATE )
893897 {
894898 tuple .t_data -> t_infomask |= HEAP_XMAX_INVALID ;
899+ tuple .t_data -> t_infomask &=
900+ ~(HEAP_XMAX_COMMITTED | HEAP_MARKED_FOR_UPDATE );
895901 pgchanged = true;
896902 }
897903 else
@@ -905,6 +911,8 @@ vc_scanheap(VRelStats *vacrelstats, Relation onerel,
905911 * from crashed process. - vadim 06/02/97
906912 */
907913 tuple .t_data -> t_infomask |= HEAP_XMAX_INVALID ;
914+ tuple .t_data -> t_infomask &=
915+ ~(HEAP_XMAX_COMMITTED | HEAP_MARKED_FOR_UPDATE );
908916 pgchanged = true;
909917 }
910918 else
@@ -964,6 +972,14 @@ vc_scanheap(VRelStats *vacrelstats, Relation onerel,
964972 {
965973 ItemId lpp ;
966974
975+ /*
976+ * Here we are building a temporary copy of the page with
977+ * dead tuples removed. Below we will apply
978+ * PageRepairFragmentation to the copy, so that we can
979+ * determine how much space will be available after
980+ * removal of dead tuples. But note we are NOT changing
981+ * the real page yet...
982+ */
967983 if (tempPage == (Page ) NULL )
968984 {
969985 Size pageSize ;
@@ -973,14 +989,12 @@ vc_scanheap(VRelStats *vacrelstats, Relation onerel,
973989 memmove (tempPage , page , pageSize );
974990 }
975991
992+ /* mark it unused on the temp page */
976993 lpp = & (((PageHeader ) tempPage )-> pd_linp [offnum - 1 ]);
977-
978- /* mark it unused */
979994 lpp -> lp_flags &= ~LP_USED ;
980995
981996 vpc -> vpd_offsets [vpc -> vpd_offsets_free ++ ] = offnum ;
982997 tups_vacuumed ++ ;
983-
984998 }
985999 else
9861000 {
@@ -1548,20 +1562,45 @@ vc_repair_frag(VRelStats *vacrelstats, Relation onerel,
15481562 tuple .t_datamcxt = NULL ;
15491563 tuple .t_data = (HeapTupleHeader ) PageGetItem (Cpage , Citemid );
15501564 tuple_len = tuple .t_len = ItemIdGetLength (Citemid );
1551- /* Get page to move in */
1565+
1566+ /*
1567+ * make a copy of the source tuple, and then mark the
1568+ * source tuple MOVED_OFF.
1569+ */
1570+ heap_copytuple_with_tuple (& tuple , & newtup );
1571+
1572+ RelationInvalidateHeapTuple (onerel , & tuple );
1573+
1574+ TransactionIdStore (myXID , (TransactionId * ) & (tuple .t_data -> t_cmin ));
1575+ tuple .t_data -> t_infomask &=
1576+ ~(HEAP_XMIN_COMMITTED | HEAP_XMIN_INVALID | HEAP_MOVED_IN );
1577+ tuple .t_data -> t_infomask |= HEAP_MOVED_OFF ;
1578+
1579+ /* Get page to move to */
15521580 cur_buffer = ReadBuffer (onerel , destvpd -> vpd_blkno );
15531581
15541582 /*
15551583 * We should LockBuffer(cur_buffer) but don't, at the
1556- * moment. If you'll do LockBuffer then UNLOCK it
1557- * before index_insert: unique btree-s call heap_fetch
1558- * to get t_infomask of inserted heap tuple !!!
1584+ * moment. This should be safe enough, since we have
1585+ * exclusive lock on the whole relation.
1586+ * If you'll do LockBuffer then UNLOCK it before
1587+ * index_insert: unique btree-s call heap_fetch to get
1588+ * t_infomask of inserted heap tuple !!!
15591589 */
15601590 ToPage = BufferGetPage (cur_buffer );
15611591
15621592 /*
15631593 * If this page was not used before - clean it.
15641594 *
1595+ * NOTE: a nasty bug used to lurk here. It is possible
1596+ * for the source and destination pages to be the same
1597+ * (since this tuple-chain member can be on a page lower
1598+ * than the one we're currently processing in the outer
1599+ * loop). If that's true, then after vc_vacpage() the
1600+ * source tuple will have been moved, and tuple.t_data
1601+ * will be pointing at garbage. Therefore we must do
1602+ * everything that uses tuple.t_data BEFORE this step!!
1603+ *
15651604 * This path is different from the other callers of
15661605 * vc_vacpage, because we have already incremented the
15671606 * vpd's vpd_offsets_used field to account for the
@@ -1579,8 +1618,11 @@ vc_repair_frag(VRelStats *vacrelstats, Relation onerel,
15791618 vc_vacpage (ToPage , destvpd );
15801619 destvpd -> vpd_offsets_used = sv_offsets_used ;
15811620 }
1582- heap_copytuple_with_tuple (& tuple , & newtup );
1583- RelationInvalidateHeapTuple (onerel , & tuple );
1621+
1622+ /*
1623+ * Update the state of the copied tuple, and store it
1624+ * on the destination page.
1625+ */
15841626 TransactionIdStore (myXID , (TransactionId * ) & (newtup .t_data -> t_cmin ));
15851627 newtup .t_data -> t_infomask &=
15861628 ~(HEAP_XMIN_COMMITTED | HEAP_XMIN_INVALID | HEAP_MOVED_OFF );
@@ -1601,20 +1643,15 @@ vc_repair_frag(VRelStats *vacrelstats, Relation onerel,
16011643 last_move_dest_block = destvpd -> vpd_blkno ;
16021644
16031645 /*
1604- * Set t_ctid pointing to itself for last tuple in
1605- * chain and to next tuple in chain otherwise.
1646+ * Set new tuple's t_ctid pointing to itself for last
1647+ * tuple in chain, and to next tuple in chain otherwise.
16061648 */
16071649 if (!ItemPointerIsValid (& Ctid ))
16081650 newtup .t_data -> t_ctid = newtup .t_self ;
16091651 else
16101652 newtup .t_data -> t_ctid = Ctid ;
16111653 Ctid = newtup .t_self ;
16121654
1613- TransactionIdStore (myXID , (TransactionId * ) & (tuple .t_data -> t_cmin ));
1614- tuple .t_data -> t_infomask &=
1615- ~(HEAP_XMIN_COMMITTED | HEAP_XMIN_INVALID | HEAP_MOVED_IN );
1616- tuple .t_data -> t_infomask |= HEAP_MOVED_OFF ;
1617-
16181655 num_moved ++ ;
16191656
16201657 /*
@@ -1648,10 +1685,7 @@ vc_repair_frag(VRelStats *vacrelstats, Relation onerel,
16481685 }
16491686 }
16501687 WriteBuffer (cur_buffer );
1651- if (Cbuf == buf )
1652- ReleaseBuffer (Cbuf );
1653- else
1654- WriteBuffer (Cbuf );
1688+ WriteBuffer (Cbuf );
16551689 }
16561690 cur_buffer = InvalidBuffer ;
16571691 pfree (vtmove );
0 commit comments