7
7
*
8
8
*
9
9
* IDENTIFICATION
10
- * $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.133 1999/12/29 10:13:20 momjian Exp $
10
+ * $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.134 2000/01/10 04:09:50 tgl Exp $
11
11
*
12
12
*-------------------------------------------------------------------------
13
13
*/
@@ -95,6 +95,8 @@ static int vc_cmp_blk(const void *left, const void *right);
95
95
static int vc_cmp_offno (const void * left , const void * right );
96
96
static int vc_cmp_vtlinks (const void * left , const void * right );
97
97
static bool vc_enough_space (VPageDescr vpd , Size len );
98
+ static char * vc_show_rusage (struct rusage * ru0 );
99
+
98
100
99
101
void
100
102
vacuum (char * vacrel , bool verbose , bool analyze , List * va_spec )
@@ -637,12 +639,11 @@ vc_scanheap(VRelStats *vacrelstats, Relation onerel,
637
639
Size min_tlen = MaxTupleSize ;
638
640
Size max_tlen = 0 ;
639
641
int32 i ;
640
- struct rusage ru0 ,
641
- ru1 ;
642
642
bool do_shrinking = true;
643
643
VTupleLink vtlinks = (VTupleLink ) palloc (100 * sizeof (VTupleLinkData ));
644
644
int num_vtlinks = 0 ;
645
645
int free_vtlinks = 100 ;
646
+ struct rusage ru0 ;
646
647
647
648
getrusage (RUSAGE_SELF , & ru0 );
648
649
@@ -987,25 +988,21 @@ vc_scanheap(VRelStats *vacrelstats, Relation onerel,
987
988
pfree (vtlinks );
988
989
}
989
990
990
- getrusage (RUSAGE_SELF , & ru1 );
991
-
992
991
elog (MESSAGE_LEVEL , "Pages %u: Changed %u, Reapped %u, Empty %u, New %u; \
993
992
Tup %u: Vac %u, Keep/VTL %u/%u, Crash %u, UnUsed %u, MinLen %u, MaxLen %u; \
994
- Re-using: Free/Avail. Space %u/%u; EndEmpty/Avail. Pages %u/%u. \
995
- Elapsed %u/%u sec." ,
993
+ Re-using: Free/Avail. Space %u/%u; EndEmpty/Avail. Pages %u/%u. %s" ,
996
994
nblocks , changed_pages , vacuum_pages -> vpl_num_pages , empty_pages ,
997
995
new_pages , num_tuples , tups_vacuumed ,
998
996
nkeep , vacrelstats -> num_vtlinks , ncrash ,
999
997
nunused , min_tlen , max_tlen , free_size , usable_free_size ,
1000
998
empty_end_pages , fraged_pages -> vpl_num_pages ,
1001
- ru1 .ru_stime .tv_sec - ru0 .ru_stime .tv_sec ,
1002
- ru1 .ru_utime .tv_sec - ru0 .ru_utime .tv_sec );
999
+ vc_show_rusage (& ru0 ));
1003
1000
1004
1001
} /* vc_scanheap */
1005
1002
1006
1003
1007
1004
/*
1008
- * vc_rpfheap() -- try to repaire relation' fragmentation
1005
+ * vc_rpfheap() -- try to repair relation's fragmentation
1009
1006
*
1010
1007
* This routine marks dead tuples as unused and tries re-use dead space
1011
1008
* by moving tuples (and inserting indices if needed). It constructs
@@ -1016,7 +1013,8 @@ Elapsed %u/%u sec.",
1016
1013
*/
1017
1014
static void
1018
1015
vc_rpfheap (VRelStats * vacrelstats , Relation onerel ,
1019
- VPageList vacuum_pages , VPageList fraged_pages , int nindices , Relation * Irel )
1016
+ VPageList vacuum_pages , VPageList fraged_pages ,
1017
+ int nindices , Relation * Irel )
1020
1018
{
1021
1019
TransactionId myXID ;
1022
1020
CommandId myCID ;
@@ -1040,14 +1038,13 @@ vc_rpfheap(VRelStats *vacrelstats, Relation onerel,
1040
1038
InsertIndexResult iresult ;
1041
1039
VPageListData Nvpl ;
1042
1040
VPageDescr cur_page = NULL ,
1043
- last_fraged_page ,
1044
1041
last_vacuum_page ,
1045
1042
vpc ,
1046
1043
* vpp ;
1047
1044
int cur_item = 0 ;
1048
1045
IndDesc * Idesc ,
1049
1046
* idcur ;
1050
- int last_fraged_block ,
1047
+ int last_move_dest_block = -1 ,
1051
1048
last_vacuum_block ,
1052
1049
i = 0 ;
1053
1050
Size tuple_len ;
@@ -1060,8 +1057,7 @@ vc_rpfheap(VRelStats *vacrelstats, Relation onerel,
1060
1057
bool isempty ,
1061
1058
dowrite ,
1062
1059
chain_tuple_moved ;
1063
- struct rusage ru0 ,
1064
- ru1 ;
1060
+ struct rusage ru0 ;
1065
1061
1066
1062
getrusage (RUSAGE_SELF , & ru0 );
1067
1063
@@ -1078,26 +1074,32 @@ vc_rpfheap(VRelStats *vacrelstats, Relation onerel,
1078
1074
1079
1075
Nvpl .vpl_num_pages = 0 ;
1080
1076
num_fraged_pages = fraged_pages -> vpl_num_pages ;
1081
- last_fraged_page = fraged_pages -> vpl_pagedesc [num_fraged_pages - 1 ];
1082
- last_fraged_block = last_fraged_page -> vpd_blkno ;
1083
1077
Assert (vacuum_pages -> vpl_num_pages > vacuum_pages -> vpl_empty_end_pages );
1084
1078
vacuumed_pages = vacuum_pages -> vpl_num_pages - vacuum_pages -> vpl_empty_end_pages ;
1085
1079
last_vacuum_page = vacuum_pages -> vpl_pagedesc [vacuumed_pages - 1 ];
1086
1080
last_vacuum_block = last_vacuum_page -> vpd_blkno ;
1087
- Assert (last_vacuum_block >= last_fraged_block );
1088
1081
cur_buffer = InvalidBuffer ;
1089
1082
num_moved = 0 ;
1090
1083
1091
1084
vpc = (VPageDescr ) palloc (sizeof (VPageDescrData ) + MaxOffsetNumber * sizeof (OffsetNumber ));
1092
1085
vpc -> vpd_offsets_used = vpc -> vpd_offsets_free = 0 ;
1093
1086
1087
+ /*
1088
+ * Scan pages backwards from the last nonempty page, trying to move
1089
+ * tuples down to lower pages. Quit when we reach a page that we
1090
+ * have moved any tuples onto. Note that if a page is still in the
1091
+ * fraged_pages list (list of candidate move-target pages) when we
1092
+ * reach it, we will remove it from the list. This ensures we never
1093
+ * move a tuple up to a higher page number.
1094
+ *
1095
+ * NB: this code depends on the vacuum_pages and fraged_pages lists
1096
+ * being in order, and on fraged_pages being a subset of vacuum_pages.
1097
+ */
1094
1098
nblocks = vacrelstats -> num_pages ;
1095
- for (blkno = nblocks - vacuum_pages -> vpl_empty_end_pages - 1 ;; blkno -- )
1099
+ for (blkno = nblocks - vacuum_pages -> vpl_empty_end_pages - 1 ;
1100
+ blkno > last_move_dest_block ;
1101
+ blkno -- )
1096
1102
{
1097
- /* if it's reapped page and it was used by me - quit */
1098
- if (blkno == last_fraged_block && last_fraged_page -> vpd_offsets_used > 0 )
1099
- break ;
1100
-
1101
1103
buf = ReadBuffer (onerel , blkno );
1102
1104
page = BufferGetPage (buf );
1103
1105
@@ -1117,21 +1119,24 @@ vc_rpfheap(VRelStats *vacrelstats, Relation onerel,
1117
1119
else
1118
1120
Assert (isempty );
1119
1121
-- vacuumed_pages ;
1120
- Assert (vacuumed_pages > 0 );
1121
- /* get prev reapped page from vacuum_pages */
1122
- last_vacuum_page = vacuum_pages -> vpl_pagedesc [vacuumed_pages - 1 ];
1123
- last_vacuum_block = last_vacuum_page -> vpd_blkno ;
1124
- if (blkno == last_fraged_block ) /* this page in
1125
- * fraged_pages too */
1122
+ if (vacuumed_pages > 0 )
1123
+ {
1124
+ /* get prev reapped page from vacuum_pages */
1125
+ last_vacuum_page = vacuum_pages -> vpl_pagedesc [vacuumed_pages - 1 ];
1126
+ last_vacuum_block = last_vacuum_page -> vpd_blkno ;
1127
+ }
1128
+ else
1126
1129
{
1130
+ last_vacuum_page = NULL ;
1131
+ last_vacuum_block = -1 ;
1132
+ }
1133
+ if (num_fraged_pages > 0 &&
1134
+ blkno ==
1135
+ fraged_pages -> vpl_pagedesc [num_fraged_pages - 1 ]-> vpd_blkno )
1136
+ {
1137
+ /* page is in fraged_pages too; remove it */
1127
1138
-- num_fraged_pages ;
1128
- Assert (num_fraged_pages > 0 );
1129
- Assert (last_fraged_page -> vpd_offsets_used == 0 );
1130
- /* get prev reapped page from fraged_pages */
1131
- last_fraged_page = fraged_pages -> vpl_pagedesc [num_fraged_pages - 1 ];
1132
- last_fraged_block = last_fraged_page -> vpd_blkno ;
1133
1139
}
1134
- Assert (last_fraged_block <= last_vacuum_block );
1135
1140
if (isempty )
1136
1141
{
1137
1142
ReleaseBuffer (buf );
@@ -1217,10 +1222,10 @@ vc_rpfheap(VRelStats *vacrelstats, Relation onerel,
1217
1222
HeapTupleData tp = tuple ;
1218
1223
Size tlen = tuple_len ;
1219
1224
VTupleMove vtmove = (VTupleMove )
1220
- palloc (100 * sizeof (VTupleMoveData ));
1225
+ palloc (100 * sizeof (VTupleMoveData ));
1221
1226
int num_vtmove = 0 ;
1222
1227
int free_vtmove = 100 ;
1223
- VPageDescr to_vpd = fraged_pages -> vpl_pagedesc [ 0 ] ;
1228
+ VPageDescr to_vpd = NULL ;
1224
1229
int to_item = 0 ;
1225
1230
bool freeCbuf = false;
1226
1231
int ti ;
@@ -1276,17 +1281,20 @@ vc_rpfheap(VRelStats *vacrelstats, Relation onerel,
1276
1281
/* first, can chain be moved ? */
1277
1282
for (;;)
1278
1283
{
1279
- if (!vc_enough_space (to_vpd , tlen ))
1284
+ if (to_vpd == NULL ||
1285
+ !vc_enough_space (to_vpd , tlen ))
1280
1286
{
1281
- if (to_vpd != last_fraged_page &&
1282
- !vc_enough_space (to_vpd , vacrelstats -> min_tlen ))
1287
+ /* if to_vpd no longer has enough free space to be
1288
+ * useful, remove it from fraged_pages list
1289
+ */
1290
+ if (to_vpd != NULL &&
1291
+ !vc_enough_space (to_vpd , vacrelstats -> min_tlen ))
1283
1292
{
1284
- Assert (num_fraged_pages > to_item + 1 );
1293
+ Assert (num_fraged_pages > to_item );
1285
1294
memmove (fraged_pages -> vpl_pagedesc + to_item ,
1286
- fraged_pages -> vpl_pagedesc + to_item + 1 ,
1287
- sizeof (VPageDescr * ) * (num_fraged_pages - to_item - 1 ));
1295
+ fraged_pages -> vpl_pagedesc + to_item + 1 ,
1296
+ sizeof (VPageDescr ) * (num_fraged_pages - to_item - 1 ));
1288
1297
num_fraged_pages -- ;
1289
- Assert (last_fraged_page == fraged_pages -> vpl_pagedesc [num_fraged_pages - 1 ]);
1290
1298
}
1291
1299
for (i = 0 ; i < num_fraged_pages ; i ++ )
1292
1300
{
@@ -1477,6 +1485,8 @@ moving chain: failed to add item with len = %u to page %u",
1477
1485
newtup .t_datamcxt = NULL ;
1478
1486
newtup .t_data = (HeapTupleHeader ) PageGetItem (ToPage , newitemid );
1479
1487
ItemPointerSet (& (newtup .t_self ), vtmove [ti ].vpd -> vpd_blkno , newoff );
1488
+ if (((int ) vtmove [ti ].vpd -> vpd_blkno ) > last_move_dest_block )
1489
+ last_move_dest_block = vtmove [ti ].vpd -> vpd_blkno ;
1480
1490
1481
1491
/*
1482
1492
* Set t_ctid pointing to itself for last tuple in
@@ -1545,23 +1555,17 @@ moving chain: failed to add item with len = %u to page %u",
1545
1555
{
1546
1556
WriteBuffer (cur_buffer );
1547
1557
cur_buffer = InvalidBuffer ;
1548
-
1549
1558
/*
1550
- * If no one tuple can't be added to this page -
1551
- * remove page from fraged_pages. - vadim 11/27/96
1552
- *
1553
- * But we can't remove last page - this is our
1554
- * "show-stopper" !!! - vadim 02/25/98
1559
+ * If previous target page is now too full to add
1560
+ * *any* tuple to it, remove it from fraged_pages.
1555
1561
*/
1556
- if (cur_page != last_fraged_page &&
1557
- !vc_enough_space (cur_page , vacrelstats -> min_tlen ))
1562
+ if (!vc_enough_space (cur_page , vacrelstats -> min_tlen ))
1558
1563
{
1559
- Assert (num_fraged_pages > cur_item + 1 );
1564
+ Assert (num_fraged_pages > cur_item );
1560
1565
memmove (fraged_pages -> vpl_pagedesc + cur_item ,
1561
1566
fraged_pages -> vpl_pagedesc + cur_item + 1 ,
1562
- sizeof (VPageDescr * ) * (num_fraged_pages - cur_item - 1 ));
1567
+ sizeof (VPageDescr ) * (num_fraged_pages - cur_item - 1 ));
1563
1568
num_fraged_pages -- ;
1564
- Assert (last_fraged_page == fraged_pages -> vpl_pagedesc [num_fraged_pages - 1 ]);
1565
1569
}
1566
1570
}
1567
1571
for (i = 0 ; i < num_fraged_pages ; i ++ )
@@ -1623,6 +1627,9 @@ failed to add item with len = %u to page %u (free space %u, nusd %u, noff %u)",
1623
1627
cur_page -> vpd_offsets_used ++ ;
1624
1628
num_moved ++ ;
1625
1629
cur_page -> vpd_free = ((PageHeader ) ToPage )-> pd_upper - ((PageHeader ) ToPage )-> pd_lower ;
1630
+ if (((int ) cur_page -> vpd_blkno ) > last_move_dest_block )
1631
+ last_move_dest_block = cur_page -> vpd_blkno ;
1632
+
1626
1633
vpc -> vpd_offsets [vpc -> vpd_offsets_free ++ ] = offnum ;
1627
1634
1628
1635
/* insert index' tuples if needed */
@@ -1789,14 +1796,10 @@ failed to add item with len = %u to page %u (free space %u, nusd %u, noff %u)",
1789
1796
}
1790
1797
Assert (num_moved == checked_moved );
1791
1798
1792
- getrusage (RUSAGE_SELF , & ru1 );
1793
-
1794
- elog (MESSAGE_LEVEL , "Rel %s: Pages: %u --> %u; Tuple(s) moved: %u. \
1795
- Elapsed %u/%u sec." ,
1799
+ elog (MESSAGE_LEVEL , "Rel %s: Pages: %u --> %u; Tuple(s) moved: %u. %s" ,
1796
1800
RelationGetRelationName (onerel ),
1797
1801
nblocks , blkno , num_moved ,
1798
- ru1 .ru_stime .tv_sec - ru0 .ru_stime .tv_sec ,
1799
- ru1 .ru_utime .tv_sec - ru0 .ru_utime .tv_sec );
1802
+ vc_show_rusage (& ru0 ));
1800
1803
1801
1804
if (Nvpl .vpl_num_pages > 0 )
1802
1805
{
@@ -1950,14 +1953,17 @@ vc_vacheap(VRelStats *vacrelstats, Relation onerel, VPageList vacuum_pages)
1950
1953
1951
1954
/*
1952
1955
* vc_vacpage() -- free dead tuples on a page
1953
- * and repaire its fragmentation.
1956
+ * and repair its fragmentation.
1954
1957
*/
1955
1958
static void
1956
1959
vc_vacpage (Page page , VPageDescr vpd )
1957
1960
{
1958
1961
ItemId itemid ;
1959
1962
int i ;
1960
1963
1964
+ /* There shouldn't be any tuples moved onto the page yet! */
1965
+ Assert (vpd -> vpd_offsets_used == 0 );
1966
+
1961
1967
for (i = 0 ; i < vpd -> vpd_offsets_free ; i ++ )
1962
1968
{
1963
1969
itemid = & (((PageHeader ) page )-> pd_linp [vpd -> vpd_offsets [i ] - 1 ]);
@@ -1978,8 +1984,7 @@ vc_scanoneind(Relation indrel, int num_tuples)
1978
1984
IndexScanDesc iscan ;
1979
1985
int nitups ;
1980
1986
int nipages ;
1981
- struct rusage ru0 ,
1982
- ru1 ;
1987
+ struct rusage ru0 ;
1983
1988
1984
1989
getrusage (RUSAGE_SELF , & ru0 );
1985
1990
@@ -2000,12 +2005,9 @@ vc_scanoneind(Relation indrel, int num_tuples)
2000
2005
nipages = RelationGetNumberOfBlocks (indrel );
2001
2006
vc_updstats (RelationGetRelid (indrel ), nipages , nitups , false, NULL );
2002
2007
2003
- getrusage (RUSAGE_SELF , & ru1 );
2004
-
2005
- elog (MESSAGE_LEVEL , "Index %s: Pages %u; Tuples %u. Elapsed %u/%u sec." ,
2008
+ elog (MESSAGE_LEVEL , "Index %s: Pages %u; Tuples %u. %s" ,
2006
2009
RelationGetRelationName (indrel ), nipages , nitups ,
2007
- ru1 .ru_stime .tv_sec - ru0 .ru_stime .tv_sec ,
2008
- ru1 .ru_utime .tv_sec - ru0 .ru_utime .tv_sec );
2010
+ vc_show_rusage (& ru0 ));
2009
2011
2010
2012
if (nitups != num_tuples )
2011
2013
elog (NOTICE , "Index %s: NUMBER OF INDEX' TUPLES (%u) IS NOT THE SAME AS HEAP' (%u).\
@@ -2036,8 +2038,7 @@ vc_vaconeind(VPageList vpl, Relation indrel, int num_tuples, int keep_tuples)
2036
2038
int num_index_tuples ;
2037
2039
int num_pages ;
2038
2040
VPageDescr vp ;
2039
- struct rusage ru0 ,
2040
- ru1 ;
2041
+ struct rusage ru0 ;
2041
2042
2042
2043
getrusage (RUSAGE_SELF , & ru0 );
2043
2044
@@ -2081,13 +2082,10 @@ vc_vaconeind(VPageList vpl, Relation indrel, int num_tuples, int keep_tuples)
2081
2082
num_pages = RelationGetNumberOfBlocks (indrel );
2082
2083
vc_updstats (RelationGetRelid (indrel ), num_pages , num_index_tuples , false, NULL );
2083
2084
2084
- getrusage (RUSAGE_SELF , & ru1 );
2085
-
2086
- elog (MESSAGE_LEVEL , "Index %s: Pages %u; Tuples %u: Deleted %u. Elapsed %u/%u sec." ,
2085
+ elog (MESSAGE_LEVEL , "Index %s: Pages %u; Tuples %u: Deleted %u. %s" ,
2087
2086
RelationGetRelationName (indrel ), num_pages ,
2088
2087
num_index_tuples - keep_tuples , tups_vacuumed ,
2089
- ru1 .ru_stime .tv_sec - ru0 .ru_stime .tv_sec ,
2090
- ru1 .ru_utime .tv_sec - ru0 .ru_utime .tv_sec );
2088
+ vc_show_rusage (& ru0 ));
2091
2089
2092
2090
if (num_index_tuples != num_tuples + keep_tuples )
2093
2091
elog (NOTICE , "Index %s: NUMBER OF INDEX' TUPLES (%u) IS NOT THE SAME AS HEAP' (%u).\
@@ -2905,3 +2903,39 @@ vc_enough_space(VPageDescr vpd, Size len)
2905
2903
return false;
2906
2904
2907
2905
} /* vc_enough_space */
2906
+
2907
+
2908
+ /*
2909
+ * Compute elapsed time since ru0 usage snapshot, and format into
2910
+ * a displayable string. Result is in a static string, which is
2911
+ * tacky, but no one ever claimed that the Postgres backend is
2912
+ * threadable...
2913
+ */
2914
+ static char *
2915
+ vc_show_rusage (struct rusage * ru0 )
2916
+ {
2917
+ static char result [64 ];
2918
+ struct rusage ru1 ;
2919
+
2920
+ getrusage (RUSAGE_SELF , & ru1 );
2921
+
2922
+ if (ru1 .ru_stime .tv_usec < ru0 -> ru_stime .tv_usec )
2923
+ {
2924
+ ru1 .ru_stime .tv_sec -- ;
2925
+ ru1 .ru_stime .tv_usec += 1000000 ;
2926
+ }
2927
+ if (ru1 .ru_utime .tv_usec < ru0 -> ru_utime .tv_usec )
2928
+ {
2929
+ ru1 .ru_utime .tv_sec -- ;
2930
+ ru1 .ru_utime .tv_usec += 1000000 ;
2931
+ }
2932
+
2933
+ snprintf (result , sizeof (result ),
2934
+ "CPU %d.%02ds/%d.%02du sec." ,
2935
+ (int ) (ru1 .ru_stime .tv_sec - ru0 -> ru_stime .tv_sec ),
2936
+ (int ) (ru1 .ru_stime .tv_usec - ru0 -> ru_stime .tv_usec ) / 10000 ,
2937
+ (int ) (ru1 .ru_utime .tv_sec - ru0 -> ru_utime .tv_sec ),
2938
+ (int ) (ru1 .ru_utime .tv_usec - ru0 -> ru_utime .tv_usec ) / 10000 );
2939
+
2940
+ return result ;
2941
+ }
0 commit comments