Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 95289e4

Browse files
committed
Rearrange lazy-vacuum code a little bit to reduce the window between
truncating the table and transaction commit. This isn't really making it safe, but at least there is no good reason to do free space map cleanup within the risk window. Don't lock out cancel interrupts until we have to, either.
1 parent d5768dc commit 95289e4

File tree

1 file changed

+37
-27
lines changed

1 file changed

+37
-27
lines changed

src/backend/commands/vacuumlazy.c

Lines changed: 37 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
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);
124124
static 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);
127127
static BlockNumber count_nondeletable_pages(Relation onerel,
128128
LVRelStats *vacrelstats);
129129
static 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
*/
148148
bool
149149
lazy_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
10071004
lazy_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

Comments
 (0)