7
7
*
8
8
*
9
9
* 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 $
11
11
*
12
12
*-------------------------------------------------------------------------
13
13
*/
@@ -87,7 +87,7 @@ static void vc_scanheap(VRelStats *vacrelstats, Relation onerel, VPageList vacuu
87
87
static void vc_rpfheap (VRelStats * vacrelstats ,Relation onerel ,VPageList vacuum_pages ,VPageList fraged_pages ,int nindices ,Relation * Irel );
88
88
static void vc_vacheap (VRelStats * vacrelstats ,Relation onerel ,VPageList vpl );
89
89
static 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 );
91
91
static void vc_scanoneind (Relation indrel ,int num_tuples );
92
92
static void vc_attrstats (Relation onerel ,VRelStats * vacrelstats ,HeapTuple tuple );
93
93
static 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)
541
541
if (vacuum_pages .vpl_num_pages > 0 )
542
542
{
543
543
for (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 );
545
545
}
546
546
else
547
547
/* just scan indices to update statistic */
@@ -1042,9 +1042,11 @@ vc_rpfheap(VRelStats *vacrelstats, Relation onerel,
1042
1042
num_fraged_pages ,
1043
1043
vacuumed_pages ;
1044
1044
int checked_moved ,
1045
- num_tuples ;
1045
+ num_tuples ,
1046
+ keep_tuples = 0 ;
1046
1047
bool isempty ,
1047
- dowrite ;
1048
+ dowrite ,
1049
+ chain_tuple_moved ;
1048
1050
struct rusage ru0 ,
1049
1051
ru1 ;
1050
1052
@@ -1126,6 +1128,7 @@ vc_rpfheap(VRelStats *vacrelstats, Relation onerel,
1126
1128
else
1127
1129
Assert (!isempty );
1128
1130
1131
+ chain_tuple_moved = false;/* no one chain-tuple was moved off this page, yet */
1129
1132
vpc -> vpd_blkno = blkno ;
1130
1133
maxoff = PageGetMaxOffsetNumber (page );
1131
1134
for (offnum = FirstOffsetNumber ;
@@ -1145,11 +1148,39 @@ vc_rpfheap(VRelStats *vacrelstats, Relation onerel,
1145
1148
{
1146
1149
if ((TransactionId )tuple .t_data -> t_cmin != myXID )
1147
1150
elog (ERROR ,"Invalid XID in t_cmin" );
1148
- if (tuple .t_data -> t_infomask & HEAP_MOVED_OFF )
1149
- continue ;/* already removed by me */
1150
1151
if (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" );
1153
1184
}
1154
1185
1155
1186
/*
@@ -1386,9 +1417,15 @@ moving chain: failed to add item with len = %u to page %u",
1386
1417
tuple .t_data -> t_infomask |=HEAP_MOVED_OFF ;
1387
1418
1388
1419
num_moved ++ ;
1420
+ /*
1421
+ * Remember that we moved tuple from the current page
1422
+ * (corresponding index tuple will be cleaned).
1423
+ */
1389
1424
if (Cbuf == buf )
1390
1425
vpc -> vpd_offsets [vpc -> vpd_offsets_free ++ ]=
1391
1426
ItemPointerGetOffsetNumber (& (tuple .t_self ));
1427
+ else
1428
+ keep_tuples ++ ;
1392
1429
1393
1430
if (Irel != (Relation * )NULL )
1394
1431
{
@@ -1418,6 +1455,7 @@ moving chain: failed to add item with len = %u to page %u",
1418
1455
}
1419
1456
cur_buffer = InvalidBuffer ;
1420
1457
pfree (vtmove );
1458
+ chain_tuple_moved = true;
1421
1459
continue ;
1422
1460
}
1423
1461
@@ -1532,10 +1570,58 @@ failed to add item with len = %u to page %u (free space %u, nusd %u, noff %u)",
1532
1570
1533
1571
}/* walk along page */
1534
1572
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
+
1535
1618
if (vpc -> vpd_offsets_free > 0 )/* some tuples were moved */
1536
1619
{
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 ,
1538
1623
sizeof (OffsetNumber ),vc_cmp_offno );
1624
+ }
1539
1625
vc_reappage (& Nvpl ,vpc );
1540
1626
WriteBuffer (buf );
1541
1627
}
@@ -1559,7 +1645,6 @@ failed to add item with len = %u to page %u (free space %u, nusd %u, noff %u)",
1559
1645
1560
1646
if (num_moved > 0 )
1561
1647
{
1562
-
1563
1648
/*
1564
1649
* We have to commit our tuple' movings before we'll truncate
1565
1650
* 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)",
1610
1695
else if (tuple .t_data -> t_infomask & HEAP_MOVED_OFF )
1611
1696
tuple .t_data -> t_infomask |=HEAP_XMIN_INVALID ;
1612
1697
else
1613
- elog (ERROR ,"HEAP_MOVED_OFF/HEAP_MOVED_IN was expected (2) " );
1698
+ elog (ERROR ,"HEAP_MOVED_OFF/HEAP_MOVED_IN was expected" );
1614
1699
}
1615
1700
}
1616
1701
Assert ((* vpp )-> vpd_offsets_used == num_tuples );
@@ -1647,8 +1732,10 @@ Elapsed %u/%u sec.",
1647
1732
* vpleft = * vpright ;
1648
1733
* vpright = vpsave ;
1649
1734
}
1735
+ Assert (keep_tuples >=0 );
1650
1736
for (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 );
1652
1739
}
1653
1740
1654
1741
/*
@@ -1678,7 +1765,7 @@ Elapsed %u/%u sec.",
1678
1765
num_tuples ++ ;
1679
1766
}
1680
1767
else
1681
- elog (ERROR ,"HEAP_MOVED_OFF was expected" );
1768
+ elog (ERROR ,"HEAP_MOVED_OFF was expected (2) " );
1682
1769
}
1683
1770
1684
1771
}
@@ -1854,7 +1941,7 @@ vc_scanoneind(Relation indrel, int num_tuples)
1854
1941
*pg_class.
1855
1942
*/
1856
1943
static void
1857
- vc_vaconeind (VPageList vpl ,Relation indrel ,int num_tuples )
1944
+ vc_vaconeind (VPageList vpl ,Relation indrel ,int num_tuples , int keep_tuples )
1858
1945
{
1859
1946
RetrieveIndexResult res ;
1860
1947
IndexScanDesc iscan ;
@@ -1911,11 +1998,12 @@ vc_vaconeind(VPageList vpl, Relation indrel, int num_tuples)
1911
1998
getrusage (RUSAGE_SELF ,& ru1 );
1912
1999
1913
2000
elog (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 ,
1915
2003
ru1 .ru_stime .tv_sec - ru0 .ru_stime .tv_sec ,
1916
2004
ru1 .ru_utime .tv_sec - ru0 .ru_utime .tv_sec );
1917
2005
1918
- if (num_index_tuples != num_tuples )
2006
+ if (num_index_tuples != num_tuples + keep_tuples )
1919
2007
elog (NOTICE ,"Index %s: NUMBER OF INDEX' TUPLES (%u) IS NOT THE SAME AS HEAP' (%u)" ,
1920
2008
indrel -> rd_rel -> relname .data ,num_index_tuples ,num_tuples );
1921
2009