29
29
*
30
30
*
31
31
* 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 $
33
33
*
34
34
*-------------------------------------------------------------------------
35
35
*/
@@ -123,7 +123,7 @@ static void lazy_cleanup_index(Relation indrel,
123
123
LVRelStats * vacrelstats );
124
124
static int lazy_vacuum_page (Relation onerel , BlockNumber blkno , Buffer buffer ,
125
125
int tupindex , LVRelStats * vacrelstats );
126
- static void lazy_truncate_heap (Relation onerel , LVRelStats * vacrelstats );
126
+ static bool lazy_truncate_heap (Relation onerel , LVRelStats * vacrelstats );
127
127
static BlockNumber count_nondeletable_pages (Relation onerel ,
128
128
LVRelStats * vacrelstats );
129
129
static void lazy_space_alloc (LVRelStats * vacrelstats , BlockNumber relblocks );
@@ -143,7 +143,7 @@ static int vac_cmp_itemptr(const void *left, const void *right);
143
143
* and locked the relation.
144
144
*
145
145
* 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.
147
147
*/
148
148
bool
149
149
lazy_vacuum_rel (Relation onerel , VacuumStmt * vacstmt ,
@@ -194,30 +194,24 @@ lazy_vacuum_rel(Relation onerel, VacuumStmt *vacstmt,
194
194
/* Done with indexes */
195
195
vac_close_indexes (nindexes , Irel , NoLock );
196
196
197
+ /* Vacuum the Free Space Map */
198
+ FreeSpaceMapVacuum (onerel );
199
+
197
200
/*
198
201
* Optionally truncate the relation.
199
202
*
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
+ *
200
207
* Don't even think about it unless we have a shot at releasing a goodly
201
208
* 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.
208
209
*/
209
210
possibly_freeable = vacrelstats -> rel_pages - vacrelstats -> nonempty_pages ;
210
211
if (possibly_freeable > 0 &&
211
212
(possibly_freeable >= REL_TRUNCATE_MINIMUM ||
212
213
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 );
221
215
222
216
/*
223
217
* Update statistics in pg_class. But only if we didn't skip any pages;
@@ -1002,8 +996,11 @@ lazy_cleanup_index(Relation indrel,
1002
996
1003
997
/*
1004
998
* 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.
1005
1002
*/
1006
- static void
1003
+ static bool
1007
1004
lazy_truncate_heap (Relation onerel , LVRelStats * vacrelstats )
1008
1005
{
1009
1006
BlockNumber old_rel_pages = vacrelstats -> rel_pages ;
@@ -1019,7 +1016,7 @@ lazy_truncate_heap(Relation onerel, LVRelStats *vacrelstats)
1019
1016
* possible considering we already hold a lower-grade lock).
1020
1017
*/
1021
1018
if (!ConditionalLockRelation (onerel , AccessExclusiveLock ))
1022
- return ;
1019
+ return false ;
1023
1020
1024
1021
/*
1025
1022
* 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)
1032
1029
/* might as well use the latest news when we update pg_class stats */
1033
1030
vacrelstats -> rel_pages = new_rel_pages ;
1034
1031
UnlockRelation (onerel , AccessExclusiveLock );
1035
- return ;
1032
+ return false ;
1036
1033
}
1037
1034
1038
1035
/*
@@ -1047,23 +1044,34 @@ lazy_truncate_heap(Relation onerel, LVRelStats *vacrelstats)
1047
1044
{
1048
1045
/* can't do anything after all */
1049
1046
UnlockRelation (onerel , AccessExclusiveLock );
1050
- return ;
1047
+ return false ;
1051
1048
}
1052
1049
1053
1050
/*
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.
1055
1065
*/
1056
- RelationTruncate ( onerel , new_rel_pages );
1066
+ HOLD_INTERRUPTS ( );
1057
1067
1058
1068
/* force relcache inval so all backends reset their rd_targblock */
1059
1069
CacheInvalidateRelcache (onerel );
1060
1070
1061
1071
/*
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.
1066
1073
*/
1074
+ RelationTruncate (onerel , new_rel_pages );
1067
1075
1068
1076
/* update statistics */
1069
1077
vacrelstats -> rel_pages = new_rel_pages ;
@@ -1075,6 +1083,8 @@ lazy_truncate_heap(Relation onerel, LVRelStats *vacrelstats)
1075
1083
old_rel_pages , new_rel_pages ),
1076
1084
errdetail ("%s." ,
1077
1085
pg_rusage_show (& ru0 ))));
1086
+
1087
+ return true; /* interrupts are held off */
1078
1088
}
1079
1089
1080
1090
/*
0 commit comments