8
8
*
9
9
*
10
10
* 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 $
12
12
*
13
13
*-------------------------------------------------------------------------
14
14
*/
@@ -815,6 +815,7 @@ vc_scanheap(VRelStats *vacrelstats, Relation onerel,
815
815
tuple .t_data -> t_cmin ))
816
816
{
817
817
tuple .t_data -> t_infomask |=HEAP_XMIN_INVALID ;
818
+ pgchanged = true;
818
819
tupgone = true;
819
820
}
820
821
else
@@ -829,6 +830,7 @@ vc_scanheap(VRelStats *vacrelstats, Relation onerel,
829
830
tuple .t_data -> t_cmin ))
830
831
{
831
832
tuple .t_data -> t_infomask |=HEAP_XMIN_INVALID ;
833
+ pgchanged = true;
832
834
tupgone = true;
833
835
}
834
836
else
@@ -876,8 +878,10 @@ vc_scanheap(VRelStats *vacrelstats, Relation onerel,
876
878
{
877
879
if (tuple .t_data -> t_infomask & HEAP_MARKED_FOR_UPDATE )
878
880
{
879
- pgchanged = true;
880
881
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;
881
885
}
882
886
else
883
887
tupgone = true;
@@ -892,6 +896,8 @@ vc_scanheap(VRelStats *vacrelstats, Relation onerel,
892
896
if (tuple .t_data -> t_infomask & HEAP_MARKED_FOR_UPDATE )
893
897
{
894
898
tuple .t_data -> t_infomask |=HEAP_XMAX_INVALID ;
899
+ tuple .t_data -> t_infomask &=
900
+ ~(HEAP_XMAX_COMMITTED |HEAP_MARKED_FOR_UPDATE );
895
901
pgchanged = true;
896
902
}
897
903
else
@@ -905,6 +911,8 @@ vc_scanheap(VRelStats *vacrelstats, Relation onerel,
905
911
* from crashed process. - vadim 06/02/97
906
912
*/
907
913
tuple .t_data -> t_infomask |=HEAP_XMAX_INVALID ;
914
+ tuple .t_data -> t_infomask &=
915
+ ~(HEAP_XMAX_COMMITTED |HEAP_MARKED_FOR_UPDATE );
908
916
pgchanged = true;
909
917
}
910
918
else
@@ -964,6 +972,14 @@ vc_scanheap(VRelStats *vacrelstats, Relation onerel,
964
972
{
965
973
ItemId lpp ;
966
974
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
+ */
967
983
if (tempPage == (Page )NULL )
968
984
{
969
985
Size pageSize ;
@@ -973,14 +989,12 @@ vc_scanheap(VRelStats *vacrelstats, Relation onerel,
973
989
memmove (tempPage ,page ,pageSize );
974
990
}
975
991
992
+ /* mark it unused on the temp page */
976
993
lpp = & (((PageHeader )tempPage )-> pd_linp [offnum - 1 ]);
977
-
978
- /* mark it unused */
979
994
lpp -> lp_flags &= ~LP_USED ;
980
995
981
996
vpc -> vpd_offsets [vpc -> vpd_offsets_free ++ ]= offnum ;
982
997
tups_vacuumed ++ ;
983
-
984
998
}
985
999
else
986
1000
{
@@ -1548,20 +1562,45 @@ vc_repair_frag(VRelStats *vacrelstats, Relation onerel,
1548
1562
tuple .t_datamcxt = NULL ;
1549
1563
tuple .t_data = (HeapTupleHeader )PageGetItem (Cpage ,Citemid );
1550
1564
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 */
1552
1580
cur_buffer = ReadBuffer (onerel ,destvpd -> vpd_blkno );
1553
1581
1554
1582
/*
1555
1583
* 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 !!!
1559
1589
*/
1560
1590
ToPage = BufferGetPage (cur_buffer );
1561
1591
1562
1592
/*
1563
1593
* If this page was not used before - clean it.
1564
1594
*
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
+ *
1565
1604
* This path is different from the other callers of
1566
1605
* vc_vacpage, because we have already incremented the
1567
1606
* vpd's vpd_offsets_used field to account for the
@@ -1579,8 +1618,11 @@ vc_repair_frag(VRelStats *vacrelstats, Relation onerel,
1579
1618
vc_vacpage (ToPage ,destvpd );
1580
1619
destvpd -> vpd_offsets_used = sv_offsets_used ;
1581
1620
}
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
+ */
1584
1626
TransactionIdStore (myXID , (TransactionId * )& (newtup .t_data -> t_cmin ));
1585
1627
newtup .t_data -> t_infomask &=
1586
1628
~(HEAP_XMIN_COMMITTED |HEAP_XMIN_INVALID |HEAP_MOVED_OFF );
@@ -1601,20 +1643,15 @@ vc_repair_frag(VRelStats *vacrelstats, Relation onerel,
1601
1643
last_move_dest_block = destvpd -> vpd_blkno ;
1602
1644
1603
1645
/*
1604
- * Set t_ctid pointing to itself for last tuple in
1605
- * chain and to next tuple in chain otherwise.
1646
+ * Setnew tuple's t_ctid pointing to itself for last
1647
+ *tuple in chain, and to next tuple in chain otherwise.
1606
1648
*/
1607
1649
if (!ItemPointerIsValid (& Ctid ))
1608
1650
newtup .t_data -> t_ctid = newtup .t_self ;
1609
1651
else
1610
1652
newtup .t_data -> t_ctid = Ctid ;
1611
1653
Ctid = newtup .t_self ;
1612
1654
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
-
1618
1655
num_moved ++ ;
1619
1656
1620
1657
/*
@@ -1648,10 +1685,7 @@ vc_repair_frag(VRelStats *vacrelstats, Relation onerel,
1648
1685
}
1649
1686
}
1650
1687
WriteBuffer (cur_buffer );
1651
- if (Cbuf == buf )
1652
- ReleaseBuffer (Cbuf );
1653
- else
1654
- WriteBuffer (Cbuf );
1688
+ WriteBuffer (Cbuf );
1655
1689
}
1656
1690
cur_buffer = InvalidBuffer ;
1657
1691
pfree (vtmove );