1212 * Portions Copyright (c) 1994, Regents of the University of California
1313 *
1414 * IDENTIFICATION
15- * $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtree.c,v 1.99 2003/02/23 23:27:21 tgl Exp $
15+ * $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtree.c,v 1.100 2003/02/24 00:57:17 tgl Exp $
1616 *
1717 *-------------------------------------------------------------------------
1818 */
2424#include "catalog/index.h"
2525#include "miscadmin.h"
2626#include "storage/freespace.h"
27+ #include "storage/smgr.h"
2728
2829
2930/* Working state for btbuild and its callback */
@@ -673,11 +674,10 @@ btbulkdelete(PG_FUNCTION_ARGS)
673674 /* return statistics */
674675 num_pages = RelationGetNumberOfBlocks (rel );
675676
676- result = (IndexBulkDeleteResult * ) palloc (sizeof (IndexBulkDeleteResult ));
677+ result = (IndexBulkDeleteResult * ) palloc0 (sizeof (IndexBulkDeleteResult ));
677678 result -> num_pages = num_pages ;
678679 result -> num_index_tuples = num_index_tuples ;
679680 result -> tuples_removed = tuples_removed ;
680- result -> pages_free = 0 ; /* not computed here */
681681
682682 PG_RETURN_POINTER (result );
683683}
@@ -746,6 +746,12 @@ btvacuumcleanup(PG_FUNCTION_ARGS)
746746 pageSpaces [nFreePages ].avail = BLCKSZ - 1 ;
747747 nFreePages ++ ;
748748 }
749+ pages_deleted ++ ;
750+ }
751+ else if (P_ISDELETED (opaque ))
752+ {
753+ /* Already deleted, but can't recycle yet */
754+ pages_deleted ++ ;
749755 }
750756 else if ((opaque -> btpo_flags & BTP_HALF_DEAD ) ||
751757 P_FIRSTDATAKEY (opaque ) > PageGetMaxOffsetNumber (page ))
@@ -758,7 +764,10 @@ btvacuumcleanup(PG_FUNCTION_ARGS)
758764 oldcontext = MemoryContextSwitchTo (mycontext );
759765
760766 ndel = _bt_pagedel (rel , buf , info -> vacuum_full );
761- pages_deleted += ndel ;
767+
768+ /* count only this page, else may double-count parent */
769+ if (ndel )
770+ pages_deleted ++ ;
762771
763772 /*
764773 * During VACUUM FULL it's okay to recycle deleted pages
@@ -786,6 +795,50 @@ btvacuumcleanup(PG_FUNCTION_ARGS)
786795 _bt_relbuf (rel , buf );
787796 }
788797
798+ /*
799+ * During VACUUM FULL, we truncate off any recyclable pages at the
800+ * end of the index. In a normal vacuum it'd be unsafe to do this
801+ * except by acquiring exclusive lock on the index and then rechecking
802+ * all the pages; doesn't seem worth it.
803+ */
804+ if (info -> vacuum_full && nFreePages > 0 )
805+ {
806+ BlockNumber new_pages = num_pages ;
807+
808+ while (nFreePages > 0 &&
809+ pageSpaces [nFreePages - 1 ].blkno == new_pages - 1 )
810+ {
811+ new_pages -- ;
812+ pages_deleted -- ;
813+ nFreePages -- ;
814+ }
815+ if (new_pages != num_pages )
816+ {
817+ int i ;
818+
819+ /*
820+ * Okay to truncate.
821+ *
822+ * First, flush any shared buffers for the blocks we intend to
823+ * delete. FlushRelationBuffers is a bit more than we need for
824+ * this, since it will also write out dirty buffers for blocks we
825+ * aren't deleting, but it's the closest thing in bufmgr's API.
826+ */
827+ i = FlushRelationBuffers (rel , new_pages );
828+ if (i < 0 )
829+ elog (ERROR , "btvacuumcleanup: FlushRelationBuffers returned %d" ,
830+ i );
831+
832+ /*
833+ * Do the physical truncation.
834+ */
835+ new_pages = smgrtruncate (DEFAULT_SMGR , rel , new_pages );
836+ rel -> rd_nblocks = new_pages ; /* update relcache immediately */
837+ rel -> rd_targblock = InvalidBlockNumber ;
838+ num_pages = new_pages ;
839+ }
840+ }
841+
789842 /*
790843 * Update the shared Free Space Map with the info we now have about
791844 * free space in the index, discarding any old info the map may have.
@@ -797,13 +850,9 @@ btvacuumcleanup(PG_FUNCTION_ARGS)
797850
798851 MemoryContextDelete (mycontext );
799852
800- if (pages_deleted > 0 )
801- elog (info -> message_level , "Index %s: %u pages, deleted %u; %u now free" ,
802- RelationGetRelationName (rel ),
803- num_pages , pages_deleted , nFreePages );
804-
805853 /* update statistics */
806854 stats -> num_pages = num_pages ;
855+ stats -> pages_deleted = pages_deleted ;
807856 stats -> pages_free = nFreePages ;
808857
809858 PG_RETURN_POINTER (stats );
0 commit comments