77 *
88 *
99 * IDENTIFICATION
10- * $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.102 1999/05/10 00:44:59 momjian Exp $
10+ * $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.103 1999/05/23 09:10:24 vadim Exp $
1111 *
1212 *-------------------------------------------------------------------------
1313 */
@@ -87,7 +87,7 @@ static void vc_scanheap(VRelStats *vacrelstats, Relation onerel, VPageList vacuu
8787static void vc_rpfheap (VRelStats * vacrelstats ,Relation onerel ,VPageList vacuum_pages ,VPageList fraged_pages ,int nindices ,Relation * Irel );
8888static void vc_vacheap (VRelStats * vacrelstats ,Relation onerel ,VPageList vpl );
8989static void vc_vacpage (Page page ,VPageDescr vpd );
90- static void vc_vaconeind (VPageList vpl ,Relation indrel ,int num_tuples );
90+ static void vc_vaconeind (VPageList vpl ,Relation indrel ,int num_tuples , int keep_tuples );
9191static void vc_scanoneind (Relation indrel ,int num_tuples );
9292static void vc_attrstats (Relation onerel ,VRelStats * vacrelstats ,HeapTuple tuple );
9393static void vc_bucketcpy (Form_pg_attribute attr ,Datum value ,Datum * bucket ,int16 * bucket_len );
@@ -541,7 +541,7 @@ vc_vacone(Oid relid, bool analyze, List *va_cols)
541541if (vacuum_pages .vpl_num_pages > 0 )
542542{
543543for (i = 0 ;i < nindices ;i ++ )
544- vc_vaconeind (& vacuum_pages ,Irel [i ],vacrelstats -> num_tuples );
544+ vc_vaconeind (& vacuum_pages ,Irel [i ],vacrelstats -> num_tuples , 0 );
545545}
546546else
547547/* just scan indices to update statistic */
@@ -1042,9 +1042,11 @@ vc_rpfheap(VRelStats *vacrelstats, Relation onerel,
10421042num_fraged_pages ,
10431043vacuumed_pages ;
10441044int checked_moved ,
1045- num_tuples ;
1045+ num_tuples ,
1046+ keep_tuples = 0 ;
10461047bool isempty ,
1047- dowrite ;
1048+ dowrite ,
1049+ chain_tuple_moved ;
10481050struct rusage ru0 ,
10491051ru1 ;
10501052
@@ -1126,6 +1128,7 @@ vc_rpfheap(VRelStats *vacrelstats, Relation onerel,
11261128else
11271129Assert (!isempty );
11281130
1131+ chain_tuple_moved = false;/* no one chain-tuple was moved off this page, yet */
11291132vpc -> vpd_blkno = blkno ;
11301133maxoff = PageGetMaxOffsetNumber (page );
11311134for (offnum = FirstOffsetNumber ;
@@ -1145,11 +1148,39 @@ vc_rpfheap(VRelStats *vacrelstats, Relation onerel,
11451148{
11461149if ((TransactionId )tuple .t_data -> t_cmin != myXID )
11471150elog (ERROR ,"Invalid XID in t_cmin" );
1148- if (tuple .t_data -> t_infomask & HEAP_MOVED_OFF )
1149- continue ;/* already removed by me */
11501151if (tuple .t_data -> t_infomask & HEAP_MOVED_IN )
1151- break ;
1152- elog (ERROR ,"HEAP_MOVED_OFF/HEAP_MOVED_IN was expected" );
1152+ elog (ERROR ,"HEAP_MOVED_IN was not expected" );
1153+ /*
1154+ * If this (chain) tuple is moved by me already then
1155+ * I have to check is it in vpc or not - i.e. is it
1156+ * moved while cleaning this page or some previous one.
1157+ */
1158+ if (tuple .t_data -> t_infomask & HEAP_MOVED_OFF )
1159+ {
1160+ if (keep_tuples == 0 )
1161+ continue ;
1162+ if (chain_tuple_moved )/* some chains was moved while */
1163+ {/* cleaning this page */
1164+ Assert (vpc -> vpd_offsets_free > 0 );
1165+ for (i = 0 ;i < vpc -> vpd_offsets_free ;i ++ )
1166+ {
1167+ if (vpc -> vpd_offsets [i ]== offnum )
1168+ break ;
1169+ }
1170+ if (i >=vpc -> vpd_offsets_free )/* not found */
1171+ {
1172+ vpc -> vpd_offsets [vpc -> vpd_offsets_free ++ ]= offnum ;
1173+ keep_tuples -- ;
1174+ }
1175+ }
1176+ else
1177+ {
1178+ vpc -> vpd_offsets [vpc -> vpd_offsets_free ++ ]= offnum ;
1179+ keep_tuples -- ;
1180+ }
1181+ continue ;
1182+ }
1183+ elog (ERROR ,"HEAP_MOVED_OFF was expected" );
11531184}
11541185
11551186/*
@@ -1386,9 +1417,15 @@ moving chain: failed to add item with len = %u to page %u",
13861417tuple .t_data -> t_infomask |=HEAP_MOVED_OFF ;
13871418
13881419num_moved ++ ;
1420+ /*
1421+ * Remember that we moved tuple from the current page
1422+ * (corresponding index tuple will be cleaned).
1423+ */
13891424if (Cbuf == buf )
13901425vpc -> vpd_offsets [vpc -> vpd_offsets_free ++ ]=
13911426ItemPointerGetOffsetNumber (& (tuple .t_self ));
1427+ else
1428+ keep_tuples ++ ;
13921429
13931430if (Irel != (Relation * )NULL )
13941431{
@@ -1418,6 +1455,7 @@ moving chain: failed to add item with len = %u to page %u",
14181455}
14191456cur_buffer = InvalidBuffer ;
14201457pfree (vtmove );
1458+ chain_tuple_moved = true;
14211459continue ;
14221460}
14231461
@@ -1532,10 +1570,58 @@ failed to add item with len = %u to page %u (free space %u, nusd %u, noff %u)",
15321570
15331571}/* walk along page */
15341572
1573+ if (offnum < maxoff && keep_tuples > 0 )
1574+ {
1575+ OffsetNumber off ;
1576+
1577+ for (off = OffsetNumberNext (offnum );
1578+ off <=maxoff ;
1579+ off = OffsetNumberNext (off ))
1580+ {
1581+ itemid = PageGetItemId (page ,off );
1582+ if (!ItemIdIsUsed (itemid ))
1583+ continue ;
1584+ tuple .t_data = (HeapTupleHeader )PageGetItem (page ,itemid );
1585+ if (tuple .t_data -> t_infomask & HEAP_XMIN_COMMITTED )
1586+ continue ;
1587+ if ((TransactionId )tuple .t_data -> t_cmin != myXID )
1588+ elog (ERROR ,"Invalid XID in t_cmin (4)" );
1589+ if (tuple .t_data -> t_infomask & HEAP_MOVED_IN )
1590+ elog (ERROR ,"HEAP_MOVED_IN was not expected (2)" );
1591+ if (tuple .t_data -> t_infomask & HEAP_MOVED_OFF )
1592+ {
1593+ if (chain_tuple_moved )/* some chains was moved while */
1594+ {/* cleaning this page */
1595+ Assert (vpc -> vpd_offsets_free > 0 );
1596+ for (i = 0 ;i < vpc -> vpd_offsets_free ;i ++ )
1597+ {
1598+ if (vpc -> vpd_offsets [i ]== off )
1599+ break ;
1600+ }
1601+ if (i >=vpc -> vpd_offsets_free )/* not found */
1602+ {
1603+ vpc -> vpd_offsets [vpc -> vpd_offsets_free ++ ]= off ;
1604+ Assert (keep_tuples > 0 );
1605+ keep_tuples -- ;
1606+ }
1607+ }
1608+ else
1609+ {
1610+ vpc -> vpd_offsets [vpc -> vpd_offsets_free ++ ]= off ;
1611+ Assert (keep_tuples > 0 );
1612+ keep_tuples -- ;
1613+ }
1614+ }
1615+ }
1616+ }
1617+
15351618if (vpc -> vpd_offsets_free > 0 )/* some tuples were moved */
15361619{
1537- qsort ((char * ) (vpc -> vpd_offsets ),vpc -> vpd_offsets_free ,
1620+ if (chain_tuple_moved )/* else - they are ordered */
1621+ {
1622+ qsort ((char * ) (vpc -> vpd_offsets ),vpc -> vpd_offsets_free ,
15381623sizeof (OffsetNumber ),vc_cmp_offno );
1624+ }
15391625vc_reappage (& Nvpl ,vpc );
15401626WriteBuffer (buf );
15411627}
@@ -1559,7 +1645,6 @@ failed to add item with len = %u to page %u (free space %u, nusd %u, noff %u)",
15591645
15601646if (num_moved > 0 )
15611647{
1562-
15631648/*
15641649 * We have to commit our tuple' movings before we'll truncate
15651650 * relation, but we shouldn't lose our locks. And so - quick hack:
@@ -1610,7 +1695,7 @@ failed to add item with len = %u to page %u (free space %u, nusd %u, noff %u)",
16101695else if (tuple .t_data -> t_infomask & HEAP_MOVED_OFF )
16111696tuple .t_data -> t_infomask |=HEAP_XMIN_INVALID ;
16121697else
1613- elog (ERROR ,"HEAP_MOVED_OFF/HEAP_MOVED_IN was expected (2) " );
1698+ elog (ERROR ,"HEAP_MOVED_OFF/HEAP_MOVED_IN was expected" );
16141699}
16151700}
16161701Assert ((* vpp )-> vpd_offsets_used == num_tuples );
@@ -1647,8 +1732,10 @@ Elapsed %u/%u sec.",
16471732* vpleft = * vpright ;
16481733* vpright = vpsave ;
16491734}
1735+ Assert (keep_tuples >=0 );
16501736for (i = 0 ;i < nindices ;i ++ )
1651- vc_vaconeind (& Nvpl ,Irel [i ],vacrelstats -> num_tuples );
1737+ vc_vaconeind (& Nvpl ,Irel [i ],
1738+ vacrelstats -> num_tuples ,keep_tuples );
16521739}
16531740
16541741/*
@@ -1678,7 +1765,7 @@ Elapsed %u/%u sec.",
16781765num_tuples ++ ;
16791766}
16801767else
1681- elog (ERROR ,"HEAP_MOVED_OFF was expected" );
1768+ elog (ERROR ,"HEAP_MOVED_OFF was expected (2) " );
16821769}
16831770
16841771}
@@ -1854,7 +1941,7 @@ vc_scanoneind(Relation indrel, int num_tuples)
18541941 *pg_class.
18551942 */
18561943static void
1857- vc_vaconeind (VPageList vpl ,Relation indrel ,int num_tuples )
1944+ vc_vaconeind (VPageList vpl ,Relation indrel ,int num_tuples , int keep_tuples )
18581945{
18591946RetrieveIndexResult res ;
18601947IndexScanDesc iscan ;
@@ -1911,11 +1998,12 @@ vc_vaconeind(VPageList vpl, Relation indrel, int num_tuples)
19111998getrusage (RUSAGE_SELF ,& ru1 );
19121999
19132000elog (MESSAGE_LEVEL ,"Index %s: Pages %u; Tuples %u: Deleted %u. Elapsed %u/%u sec." ,
1914- indrel -> rd_rel -> relname .data ,num_pages ,num_index_tuples ,tups_vacuumed ,
2001+ indrel -> rd_rel -> relname .data ,num_pages ,
2002+ num_index_tuples - keep_tuples ,tups_vacuumed ,
19152003ru1 .ru_stime .tv_sec - ru0 .ru_stime .tv_sec ,
19162004ru1 .ru_utime .tv_sec - ru0 .ru_utime .tv_sec );
19172005
1918- if (num_index_tuples != num_tuples )
2006+ if (num_index_tuples != num_tuples + keep_tuples )
19192007elog (NOTICE ,"Index %s: NUMBER OF INDEX' TUPLES (%u) IS NOT THE SAME AS HEAP' (%u)" ,
19202008indrel -> rd_rel -> relname .data ,num_index_tuples ,num_tuples );
19212009