88 *
99 *
1010 * IDENTIFICATION
11- * $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.168 2000/10/16 17:08:05 momjian Exp $
11+ * $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.169 2000/10/22 19:49:43 tgl Exp $
1212 *
1313
1414 *-------------------------------------------------------------------------
@@ -669,6 +669,7 @@ scan_heap(VRelStats *vacrelstats, Relation onerel,
669669tuple .t_data -> t_cmin ))
670670{
671671tuple .t_data -> t_infomask |=HEAP_XMIN_INVALID ;
672+ pgchanged = true;
672673tupgone = true;
673674}
674675else
@@ -683,6 +684,7 @@ scan_heap(VRelStats *vacrelstats, Relation onerel,
683684tuple .t_data -> t_cmin ))
684685{
685686tuple .t_data -> t_infomask |=HEAP_XMIN_INVALID ;
687+ pgchanged = true;
686688tupgone = true;
687689}
688690else
@@ -730,8 +732,10 @@ scan_heap(VRelStats *vacrelstats, Relation onerel,
730732{
731733if (tuple .t_data -> t_infomask & HEAP_MARKED_FOR_UPDATE )
732734{
733- pgchanged = true;
734735tuple .t_data -> t_infomask |=HEAP_XMAX_INVALID ;
736+ tuple .t_data -> t_infomask &=
737+ ~(HEAP_XMAX_COMMITTED |HEAP_MARKED_FOR_UPDATE );
738+ pgchanged = true;
735739}
736740else
737741tupgone = true;
@@ -746,6 +750,8 @@ scan_heap(VRelStats *vacrelstats, Relation onerel,
746750if (tuple .t_data -> t_infomask & HEAP_MARKED_FOR_UPDATE )
747751{
748752tuple .t_data -> t_infomask |=HEAP_XMAX_INVALID ;
753+ tuple .t_data -> t_infomask &=
754+ ~(HEAP_XMAX_COMMITTED |HEAP_MARKED_FOR_UPDATE );
749755pgchanged = true;
750756}
751757else
@@ -759,6 +765,8 @@ scan_heap(VRelStats *vacrelstats, Relation onerel,
759765 * from crashed process. - vadim 06/02/97
760766 */
761767tuple .t_data -> t_infomask |=HEAP_XMAX_INVALID ;
768+ tuple .t_data -> t_infomask &=
769+ ~(HEAP_XMAX_COMMITTED |HEAP_MARKED_FOR_UPDATE );
762770pgchanged = true;
763771}
764772else
@@ -818,6 +826,14 @@ scan_heap(VRelStats *vacrelstats, Relation onerel,
818826{
819827ItemId lpp ;
820828
829+ /*
830+ * Here we are building a temporary copy of the page with
831+ * dead tuples removed. Below we will apply
832+ * PageRepairFragmentation to the copy, so that we can
833+ * determine how much space will be available after
834+ * removal of dead tuples. But note we are NOT changing
835+ * the real page yet...
836+ */
821837if (tempPage == (Page )NULL )
822838{
823839Size pageSize ;
@@ -827,14 +843,12 @@ scan_heap(VRelStats *vacrelstats, Relation onerel,
827843memmove (tempPage ,page ,pageSize );
828844}
829845
846+ /* mark it unused on the temp page */
830847lpp = & (((PageHeader )tempPage )-> pd_linp [offnum - 1 ]);
831-
832- /* mark it unused */
833848lpp -> lp_flags &= ~LP_USED ;
834849
835850vacpage -> offsets [vacpage -> offsets_free ++ ]= offnum ;
836851tups_vacuumed ++ ;
837-
838852}
839853else
840854{
@@ -1397,20 +1411,45 @@ repair_frag(VRelStats *vacrelstats, Relation onerel,
13971411tuple .t_datamcxt = NULL ;
13981412tuple .t_data = (HeapTupleHeader )PageGetItem (Cpage ,Citemid );
13991413tuple_len = tuple .t_len = ItemIdGetLength (Citemid );
1400- /* Get page to move in */
1414+
1415+ /*
1416+ * make a copy of the source tuple, and then mark the
1417+ * source tuple MOVED_OFF.
1418+ */
1419+ heap_copytuple_with_tuple (& tuple ,& newtup );
1420+
1421+ RelationInvalidateHeapTuple (onerel ,& tuple );
1422+
1423+ TransactionIdStore (myXID , (TransactionId * )& (tuple .t_data -> t_cmin ));
1424+ tuple .t_data -> t_infomask &=
1425+ ~(HEAP_XMIN_COMMITTED |HEAP_XMIN_INVALID |HEAP_MOVED_IN );
1426+ tuple .t_data -> t_infomask |=HEAP_MOVED_OFF ;
1427+
1428+ /* Get page to move to */
14011429cur_buffer = ReadBuffer (onerel ,destvacpage -> blkno );
14021430
14031431/*
14041432 * We should LockBuffer(cur_buffer) but don't, at the
1405- * moment. If you'll do LockBuffer then UNLOCK it
1406- * before index_insert: unique btree-s call heap_fetch
1407- * to get t_infomask of inserted heap tuple !!!
1433+ * moment. This should be safe enough, since we have
1434+ * exclusive lock on the whole relation.
1435+ * If you'll do LockBuffer then UNLOCK it before
1436+ * index_insert: unique btree-s call heap_fetch to get
1437+ * t_infomask of inserted heap tuple !!!
14081438 */
14091439ToPage = BufferGetPage (cur_buffer );
14101440
14111441/*
14121442 * If this page was not used before - clean it.
14131443 *
1444+ * NOTE: a nasty bug used to lurk here. It is possible
1445+ * for the source and destination pages to be the same
1446+ * (since this tuple-chain member can be on a page lower
1447+ * than the one we're currently processing in the outer
1448+ * loop). If that's true, then after vacuum_page() the
1449+ * source tuple will have been moved, and tuple.t_data
1450+ * will be pointing at garbage. Therefore we must do
1451+ * everything that uses tuple.t_data BEFORE this step!!
1452+ *
14141453 * This path is different from the other callers of
14151454 * vacuum_page, because we have already incremented the
14161455 * vacpage's offsets_used field to account for the
@@ -1428,8 +1467,11 @@ repair_frag(VRelStats *vacrelstats, Relation onerel,
14281467vacuum_page (ToPage ,destvacpage );
14291468destvacpage -> offsets_used = sv_offsets_used ;
14301469}
1431- heap_copytuple_with_tuple (& tuple ,& newtup );
1432- RelationInvalidateHeapTuple (onerel ,& tuple );
1470+
1471+ /*
1472+ * Update the state of the copied tuple, and store it
1473+ * on the destination page.
1474+ */
14331475TransactionIdStore (myXID , (TransactionId * )& (newtup .t_data -> t_cmin ));
14341476newtup .t_data -> t_infomask &=
14351477~(HEAP_XMIN_COMMITTED |HEAP_XMIN_INVALID |HEAP_MOVED_OFF );
@@ -1450,20 +1492,15 @@ repair_frag(VRelStats *vacrelstats, Relation onerel,
14501492last_move_dest_block = destvacpage -> blkno ;
14511493
14521494/*
1453- * Set t_ctid pointing to itself for last tuple in
1454- * chain and to next tuple in chain otherwise.
1495+ * Setnew tuple's t_ctid pointing to itself for last
1496+ *tuple in chain, and to next tuple in chain otherwise.
14551497 */
14561498if (!ItemPointerIsValid (& Ctid ))
14571499newtup .t_data -> t_ctid = newtup .t_self ;
14581500else
14591501newtup .t_data -> t_ctid = Ctid ;
14601502Ctid = newtup .t_self ;
14611503
1462- TransactionIdStore (myXID , (TransactionId * )& (tuple .t_data -> t_cmin ));
1463- tuple .t_data -> t_infomask &=
1464- ~(HEAP_XMIN_COMMITTED |HEAP_XMIN_INVALID |HEAP_MOVED_IN );
1465- tuple .t_data -> t_infomask |=HEAP_MOVED_OFF ;
1466-
14671504num_moved ++ ;
14681505
14691506/*
@@ -1504,10 +1541,7 @@ repair_frag(VRelStats *vacrelstats, Relation onerel,
15041541}
15051542}
15061543WriteBuffer (cur_buffer );
1507- if (Cbuf == buf )
1508- ReleaseBuffer (Cbuf );
1509- else
1510- WriteBuffer (Cbuf );
1544+ WriteBuffer (Cbuf );
15111545}
15121546cur_buffer = InvalidBuffer ;
15131547pfree (vtmove );