2929 *
3030 *
3131 * IDENTIFICATION
32- * $PostgreSQL: pgsql/src/backend/commands/vacuumlazy.c,v 1.129 2010/02/08 04:33:54 tgl Exp $
32+ * $PostgreSQL: pgsql/src/backend/commands/vacuumlazy.c,v 1.130 2010/02/09 00:28:30 tgl Exp $
3333 *
3434 *-------------------------------------------------------------------------
3535 */
@@ -123,7 +123,7 @@ static void lazy_cleanup_index(Relation indrel,
123123 LVRelStats * vacrelstats );
124124static int lazy_vacuum_page (Relation onerel , BlockNumber blkno , Buffer buffer ,
125125 int tupindex , LVRelStats * vacrelstats );
126- static void lazy_truncate_heap (Relation onerel , LVRelStats * vacrelstats );
126+ static bool lazy_truncate_heap (Relation onerel , LVRelStats * vacrelstats );
127127static BlockNumber count_nondeletable_pages (Relation onerel ,
128128 LVRelStats * vacrelstats );
129129static void lazy_space_alloc (LVRelStats * vacrelstats , BlockNumber relblocks );
@@ -143,7 +143,7 @@ static int vac_cmp_itemptr(const void *left, const void *right);
143143 * and locked the relation.
144144 *
145145 * The return value indicates whether this function has held off
146- * interrupts -- caller must RESUME_INTERRUPTS() after commit if true .
146+ * interrupts -- if true, caller must RESUME_INTERRUPTS() after commit.
147147 */
148148bool
149149lazy_vacuum_rel (Relation onerel , VacuumStmt * vacstmt ,
@@ -194,30 +194,24 @@ lazy_vacuum_rel(Relation onerel, VacuumStmt *vacstmt,
194194 /* Done with indexes */
195195 vac_close_indexes (nindexes , Irel , NoLock );
196196
197+ /* Vacuum the Free Space Map */
198+ FreeSpaceMapVacuum (onerel );
199+
197200 /*
198201 * Optionally truncate the relation.
199202 *
203+ * NB: there should be as little code as possible after this point,
204+ * to minimize the chance of failure as well as the time spent ignoring
205+ * cancel/die interrupts.
206+ *
200207 * Don't even think about it unless we have a shot at releasing a goodly
201208 * number of pages. Otherwise, the time taken isn't worth it.
202- *
203- * Note that after we've truncated the heap, it's too late to abort the
204- * transaction; doing so would lose the sinval messages needed to tell
205- * the other backends about the table being shrunk. We prevent interrupts
206- * in that case; caller is responsible for re-enabling them after
207- * committing the transaction.
208209 */
209210 possibly_freeable = vacrelstats -> rel_pages - vacrelstats -> nonempty_pages ;
210211 if (possibly_freeable > 0 &&
211212 (possibly_freeable >= REL_TRUNCATE_MINIMUM ||
212213 possibly_freeable >= vacrelstats -> rel_pages / REL_TRUNCATE_FRACTION ))
213- {
214- HOLD_INTERRUPTS ();
215- heldoff = true;
216- lazy_truncate_heap (onerel , vacrelstats );
217- }
218-
219- /* Vacuum the Free Space Map */
220- FreeSpaceMapVacuum (onerel );
214+ heldoff = lazy_truncate_heap (onerel , vacrelstats );
221215
222216 /*
223217 * Update statistics in pg_class. But only if we didn't skip any pages;
@@ -1002,8 +996,11 @@ lazy_cleanup_index(Relation indrel,
1002996
1003997/*
1004998 * lazy_truncate_heap - try to truncate off any empty pages at the end
999+ *
1000+ * The return value indicates whether this function has held off
1001+ * interrupts -- if true, caller must RESUME_INTERRUPTS() after commit.
10051002 */
1006- static void
1003+ static bool
10071004lazy_truncate_heap (Relation onerel , LVRelStats * vacrelstats )
10081005{
10091006 BlockNumber old_rel_pages = vacrelstats -> rel_pages ;
@@ -1019,7 +1016,7 @@ lazy_truncate_heap(Relation onerel, LVRelStats *vacrelstats)
10191016 * possible considering we already hold a lower-grade lock).
10201017 */
10211018 if (!ConditionalLockRelation (onerel , AccessExclusiveLock ))
1022- return ;
1019+ return false ;
10231020
10241021 /*
10251022 * Now that we have exclusive lock, look to see if the rel has grown
@@ -1032,7 +1029,7 @@ lazy_truncate_heap(Relation onerel, LVRelStats *vacrelstats)
10321029 /* might as well use the latest news when we update pg_class stats */
10331030 vacrelstats -> rel_pages = new_rel_pages ;
10341031 UnlockRelation (onerel , AccessExclusiveLock );
1035- return ;
1032+ return false ;
10361033 }
10371034
10381035 /*
@@ -1047,23 +1044,34 @@ lazy_truncate_heap(Relation onerel, LVRelStats *vacrelstats)
10471044 {
10481045 /* can't do anything after all */
10491046 UnlockRelation (onerel , AccessExclusiveLock );
1050- return ;
1047+ return false ;
10511048 }
10521049
10531050 /*
1054- * Okay to truncate.
1051+ * Prevent cancel/die interrupts from now till commit. Once we have
1052+ * truncated, it is essential that we send the sinval message before
1053+ * releasing exclusive lock on the relation; both of which will
1054+ * happen during commit. Other backends must receive the sinval
1055+ * message to reset their rd_targblock values before they can safely
1056+ * write to the table again. While we can't positively guarantee
1057+ * no error before commit, we can at least prevent cancel interrupts.
1058+ *
1059+ * XXX it would be better if we had a way to send the inval message
1060+ * nontransactionally; an error after the truncate will mean that the
1061+ * message is lost. Note however that turning this all into a critical
1062+ * section would not be an improvement. Making it critical would mean
1063+ * that an error forces PANIC, whereas losing the sinval will at worst
1064+ * cause unexpected nonfatal errors in other sessions.
10551065 */
1056- RelationTruncate ( onerel , new_rel_pages );
1066+ HOLD_INTERRUPTS ( );
10571067
10581068 /* force relcache inval so all backends reset their rd_targblock */
10591069 CacheInvalidateRelcache (onerel );
10601070
10611071 /*
1062- * Note: once we have truncated, we *must* keep the exclusive lock until
1063- * commit. The sinval message won't be sent until commit, and other
1064- * backends must see it and reset their rd_targblock values before they
1065- * can safely access the table again.
1072+ * Okay to truncate. Do as little as possible between here and commit.
10661073 */
1074+ RelationTruncate (onerel , new_rel_pages );
10671075
10681076 /* update statistics */
10691077 vacrelstats -> rel_pages = new_rel_pages ;
@@ -1075,6 +1083,8 @@ lazy_truncate_heap(Relation onerel, LVRelStats *vacrelstats)
10751083 old_rel_pages , new_rel_pages ),
10761084 errdetail ("%s." ,
10771085 pg_rusage_show (& ru0 ))));
1086+
1087+ return true; /* interrupts are held off */
10781088}
10791089
10801090/*
0 commit comments