Index: src/backend/commands/vacuum.c
===================================================================
RCS file: /home/alvherre/Code/cvs/pgsql/src/backend/commands/vacuum.c,v
retrieving revision 1.317.2.7
diff -c -p -r1.317.2.7 vacuum.c
*** src/backend/commands/vacuum.c	11 Feb 2008 19:14:45 -0000	1.317.2.7
--- src/backend/commands/vacuum.c	6 Nov 2009 17:15:40 -0000
*************** static void vac_update_dbstats(Oid dbid,
*** 206,215 ****
  static void vac_truncate_clog(TransactionId vacuumXID,
  				  TransactionId frozenXID);
  static bool vacuum_rel(Oid relid, VacuumStmt *vacstmt, char expected_relkind);
! static void full_vacuum_rel(Relation onerel, VacuumStmt *vacstmt);
  static void scan_heap(VRelStats *vacrelstats, Relation onerel,
  		  VacPageList vacuum_pages, VacPageList fraged_pages);
! static void repair_frag(VRelStats *vacrelstats, Relation onerel,
  			VacPageList vacuum_pages, VacPageList fraged_pages,
  			int nindexes, Relation *Irel);
  static void move_chain_tuple(Relation rel,
--- 206,215 ----
  static void vac_truncate_clog(TransactionId vacuumXID,
  				  TransactionId frozenXID);
  static bool vacuum_rel(Oid relid, VacuumStmt *vacstmt, char expected_relkind);
! static bool full_vacuum_rel(Relation onerel, VacuumStmt *vacstmt);
  static void scan_heap(VRelStats *vacrelstats, Relation onerel,
  		  VacPageList vacuum_pages, VacPageList fraged_pages);
! static bool repair_frag(VRelStats *vacrelstats, Relation onerel,
  			VacPageList vacuum_pages, VacPageList fraged_pages,
  			int nindexes, Relation *Irel);
  static void move_chain_tuple(Relation rel,
*************** vacuum_rel(Oid relid, VacuumStmt *vacstm
*** 963,968 ****
--- 963,969 ----
  	bool		result;
  	Oid			save_userid;
  	bool		save_secdefcxt;
+ 	bool		heldoff;
  
  	/* Begin a transaction for vacuuming this relation */
  	StartTransactionCommand();
*************** vacuum_rel(Oid relid, VacuumStmt *vacstm
*** 1085,1093 ****
  	 * Do the actual work --- either FULL or "lazy" vacuum
  	 */
  	if (vacstmt->full)
! 		full_vacuum_rel(onerel, vacstmt);
  	else
! 		lazy_vacuum_rel(onerel, vacstmt);
  
  	result = true;				/* did the vacuum */
  
--- 1086,1094 ----
  	 * Do the actual work --- either FULL or "lazy" vacuum
  	 */
  	if (vacstmt->full)
! 		heldoff = full_vacuum_rel(onerel, vacstmt);
  	else
! 		heldoff = lazy_vacuum_rel(onerel, vacstmt);
  
  	result = true;				/* did the vacuum */
  
*************** vacuum_rel(Oid relid, VacuumStmt *vacstm
*** 1103,1108 ****
--- 1104,1113 ----
  	StrategyHintVacuum(false);
  	CommitTransactionCommand();
  
+ 	/* now we can allow interrupts again, if disabled */
+ 	if (heldoff)
+ 		RESUME_INTERRUPTS();
+ 
  	/*
  	 * If the relation has a secondary toast rel, vacuum that too while we
  	 * still hold the session lock on the master table.  Note however that
*************** vacuum_rel(Oid relid, VacuumStmt *vacstm
*** 1141,1148 ****
   *
   *		At entry, we have already established a transaction and opened
   *		and locked the relation.
   */
! static void
  full_vacuum_rel(Relation onerel, VacuumStmt *vacstmt)
  {
  	VacPageListData vacuum_pages;		/* List of pages to vacuum and/or
--- 1146,1157 ----
   *
   *		At entry, we have already established a transaction and opened
   *		and locked the relation.
+  *
+  *		The return value indicates whether this function has held off
+  *		interrupts -- caller must call RESUME_INTERRUPTS() after commit if
+  *		it is true.
   */
! static bool
  full_vacuum_rel(Relation onerel, VacuumStmt *vacstmt)
  {
  	VacPageListData vacuum_pages;		/* List of pages to vacuum and/or
*************** full_vacuum_rel(Relation onerel, VacuumS
*** 1153,1158 ****
--- 1162,1168 ----
  	int			nindexes,
  				i;
  	VRelStats  *vacrelstats;
+ 	bool		heldoff = false;
  
  	vacuum_set_xid_limits(vacstmt, onerel->rd_rel->relisshared,
  						  &OldestXmin, &FreezeLimit);
*************** full_vacuum_rel(Relation onerel, VacuumS
*** 1194,1201 ****
  	if (fraged_pages.num_pages > 0)
  	{
  		/* Try to shrink heap */
! 		repair_frag(vacrelstats, onerel, &vacuum_pages, &fraged_pages,
! 					nindexes, Irel);
  		vac_close_indexes(nindexes, Irel, NoLock);
  	}
  	else
--- 1204,1211 ----
  	if (fraged_pages.num_pages > 0)
  	{
  		/* Try to shrink heap */
! 		heldoff = repair_frag(vacrelstats, onerel, &vacuum_pages, &fraged_pages,
! 						  	  nindexes, Irel);
  		vac_close_indexes(nindexes, Irel, NoLock);
  	}
  	else
*************** full_vacuum_rel(Relation onerel, VacuumS
*** 1218,1223 ****
--- 1228,1235 ----
  	/* report results to the stats collector, too */
  	pgstat_report_vacuum(RelationGetRelid(onerel), onerel->rd_rel->relisshared,
  						 vacstmt->analyze, vacrelstats->rel_tuples);
+ 
+ 	return heldoff;
  }
  
  
*************** scan_heap(VRelStats *vacrelstats, Relati
*** 1637,1644 ****
   *		for them after committing (in hack-manner - without losing locks
   *		and freeing memory!) current transaction. It truncates relation
   *		if some end-blocks are gone away.
   */
! static void
  repair_frag(VRelStats *vacrelstats, Relation onerel,
  			VacPageList vacuum_pages, VacPageList fraged_pages,
  			int nindexes, Relation *Irel)
--- 1649,1660 ----
   *		for them after committing (in hack-manner - without losing locks
   *		and freeing memory!) current transaction. It truncates relation
   *		if some end-blocks are gone away.
+  *
+  *		The return value indicates whether this function has held off
+  *		interrupts -- caller must call RESUME_INTERRUPTS() after commit if
+  *		it is true.
   */
! static bool
  repair_frag(VRelStats *vacrelstats, Relation onerel,
  			VacPageList vacuum_pages, VacPageList fraged_pages,
  			int nindexes, Relation *Irel)
*************** repair_frag(VRelStats *vacrelstats, Rela
*** 1662,1667 ****
--- 1678,1684 ----
  				vacuumed_pages;
  	int			keep_tuples = 0;
  	PGRUsage	ru0;
+ 	bool		heldoff = false;
  
  	pg_rusage_init(&ru0);
  
*************** repair_frag(VRelStats *vacrelstats, Rela
*** 2374,2379 ****
--- 2391,2398 ----
  		 * For now, a quick hack: record status of current transaction as
  		 * committed, and continue.
  		 */
+ 		HOLD_INTERRUPTS();
+ 		heldoff = true;
  		RecordTransactionCommit();
  	}
  
*************** repair_frag(VRelStats *vacrelstats, Rela
*** 2563,2568 ****
--- 2582,2589 ----
  		pfree(vacrelstats->vtlinks);
  
  	ExecContext_Finish(&ec);
+ 
+ 	return heldoff;
  }
  
  /*
Index: src/backend/commands/vacuumlazy.c
===================================================================
RCS file: /home/alvherre/Code/cvs/pgsql/src/backend/commands/vacuumlazy.c,v
retrieving revision 1.61.2.7
diff -c -p -r1.61.2.7 vacuumlazy.c
*** src/backend/commands/vacuumlazy.c	6 Jan 2009 14:55:56 -0000	1.61.2.7
--- src/backend/commands/vacuumlazy.c	6 Nov 2009 16:03:37 -0000
*************** static int	vac_cmp_page_spaces(const voi
*** 134,141 ****
   *
   *		At entry, we have already established a transaction and opened
   *		and locked the relation.
   */
! void
  lazy_vacuum_rel(Relation onerel, VacuumStmt *vacstmt)
  {
  	LVRelStats *vacrelstats;
--- 134,145 ----
   *
   *		At entry, we have already established a transaction and opened
   *		and locked the relation.
+  *
+  *		The return value indicates whether this function has held off
+  *		interrupts -- caller must call RESUME_INTERRUPTS() after commit if
+  *		it is true.
   */
! bool
  lazy_vacuum_rel(Relation onerel, VacuumStmt *vacstmt)
  {
  	LVRelStats *vacrelstats;
*************** lazy_vacuum_rel(Relation onerel, VacuumS
*** 143,148 ****
--- 147,153 ----
  	int			nindexes;
  	bool		hasindex;
  	BlockNumber possibly_freeable;
+ 	bool		heldoff;
  
  	if (vacstmt->verbose)
  		elevel = INFO;
*************** lazy_vacuum_rel(Relation onerel, VacuumS
*** 173,184 ****
--- 178,199 ----
  	 *
  	 * Don't even think about it unless we have a shot at releasing a goodly
  	 * number of pages.  Otherwise, the time taken isn't worth it.
+ 	 *
+ 	 * Note that after we've truncated the heap, it's too late to abort the
+ 	 * transaction; doing so would lose the sinval messages needed to tell
+ 	 * the other backends about the table being shrunk.  We hold off interrupts
+ 	 * in that case; the caller is responsible for releasing them after
+ 	 * committing the transaction.
  	 */
  	possibly_freeable = vacrelstats->rel_pages - vacrelstats->nonempty_pages;
  	if (possibly_freeable > 0 &&
  		(possibly_freeable >= REL_TRUNCATE_MINIMUM ||
  		 possibly_freeable >= vacrelstats->rel_pages / REL_TRUNCATE_FRACTION))
+ 	{
+ 		HOLD_INTERRUPTS();
+ 		heldoff = true;
  		lazy_truncate_heap(onerel, vacrelstats);
+ 	}
  
  	/* Update shared free space map with final free space info */
  	lazy_update_fsm(onerel, vacrelstats);
*************** lazy_vacuum_rel(Relation onerel, VacuumS
*** 192,197 ****
--- 207,214 ----
  	/* report results to the stats collector, too */
  	pgstat_report_vacuum(RelationGetRelid(onerel), onerel->rd_rel->relisshared,
  						 vacstmt->analyze, vacrelstats->rel_tuples);
+ 
+ 	return heldoff;
  }
  
  
Index: src/include/commands/vacuum.h
===================================================================
RCS file: /home/alvherre/Code/cvs/pgsql/src/include/commands/vacuum.h,v
retrieving revision 1.62
diff -c -p -r1.62 vacuum.h
*** src/include/commands/vacuum.h	15 Oct 2005 02:49:44 -0000	1.62
--- src/include/commands/vacuum.h	6 Nov 2009 14:21:04 -0000
*************** extern bool vac_is_partial_index(Relatio
*** 125,131 ****
  extern void vacuum_delay_point(void);
  
  /* in commands/vacuumlazy.c */
! extern void lazy_vacuum_rel(Relation onerel, VacuumStmt *vacstmt);
  
  /* in commands/analyze.c */
  extern void analyze_rel(Oid relid, VacuumStmt *vacstmt);
--- 125,131 ----
  extern void vacuum_delay_point(void);
  
  /* in commands/vacuumlazy.c */
! extern bool lazy_vacuum_rel(Relation onerel, VacuumStmt *vacstmt);
  
  /* in commands/analyze.c */
  extern void analyze_rel(Oid relid, VacuumStmt *vacstmt);
