Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit4d86ae4

Browse files
committed
For multi-table ANALYZE, use per-table transactions when possible
(ie, when not inside a transaction block), so that we can avoid holdinglocks longer than necessary. Per trouble report from Philip Warner.
1 parente26c403 commit4d86ae4

File tree

3 files changed

+124
-67
lines changed

3 files changed

+124
-67
lines changed

‎src/backend/access/transam/xact.c

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/access/transam/xact.c,v 1.166 2004/05/21 05:07:56 tgl Exp $
11+
* $PostgreSQL: pgsql/src/backend/access/transam/xact.c,v 1.167 2004/05/22 23:14:37 tgl Exp $
1212
*
1313
* NOTES
1414
*Transaction aborts can now occur two ways:
@@ -1417,7 +1417,7 @@ PreventTransactionChain(void *stmtNode, const char *stmtType)
14171417
errmsg("%s cannot be executed from a function",stmtType)));
14181418
/* If we got past IsTransactionBlock test, should be in default state */
14191419
if (CurrentTransactionState->blockState!=TBLOCK_DEFAULT&&
1420-
CurrentTransactionState->blockState!=TBLOCK_STARTED)
1420+
CurrentTransactionState->blockState!=TBLOCK_STARTED)
14211421
elog(ERROR,"cannot prevent transaction chain");
14221422
/* all okay */
14231423
}
@@ -1462,6 +1462,36 @@ RequireTransactionChain(void *stmtNode, const char *stmtType)
14621462
stmtType)));
14631463
}
14641464

1465+
/*
1466+
*IsInTransactionChain
1467+
*
1468+
*This routine is for statements that need to behave differently inside
1469+
*a transaction block than when running as single commands. ANALYZE is
1470+
*currently the only example.
1471+
*
1472+
*stmtNode: pointer to parameter block for statement; this is used in
1473+
*a very klugy way to determine whether we are inside a function.
1474+
*/
1475+
bool
1476+
IsInTransactionChain(void*stmtNode)
1477+
{
1478+
/*
1479+
* Return true on same conditions that would make PreventTransactionChain
1480+
* error out
1481+
*/
1482+
if (IsTransactionBlock())
1483+
return true;
1484+
1485+
if (!MemoryContextContains(QueryContext,stmtNode))
1486+
return true;
1487+
1488+
if (CurrentTransactionState->blockState!=TBLOCK_DEFAULT&&
1489+
CurrentTransactionState->blockState!=TBLOCK_STARTED)
1490+
return true;
1491+
1492+
return false;
1493+
}
1494+
14651495

14661496
/*
14671497
* Register or deregister callback functions for end-of-xact cleanup

‎src/backend/commands/vacuum.c

Lines changed: 90 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
*
1414
*
1515
* IDENTIFICATION
16-
* $PostgreSQL: pgsql/src/backend/commands/vacuum.c,v 1.276 2004/05/21 16:08:46 tgl Exp $
16+
* $PostgreSQL: pgsql/src/backend/commands/vacuum.c,v 1.277 2004/05/22 23:14:38 tgl Exp $
1717
*
1818
*-------------------------------------------------------------------------
1919
*/
@@ -161,7 +161,9 @@ vacuum(VacuumStmt *vacstmt)
161161
MemoryContextanl_context=NULL;
162162
TransactionIdinitialOldestXmin=InvalidTransactionId;
163163
TransactionIdinitialFreezeLimit=InvalidTransactionId;
164-
boolall_rels;
164+
boolall_rels,
165+
in_outer_xact,
166+
use_own_xacts;
165167
List*relations,
166168
*cur;
167169

@@ -177,10 +179,23 @@ vacuum(VacuumStmt *vacstmt)
177179
* Furthermore, the forced commit that occurs before truncating the
178180
* relation's file would have the effect of committing the rest of the
179181
* user's transaction too, which would certainly not be the desired
180-
* behavior.
182+
* behavior. (This only applies to VACUUM FULL, though. We could
183+
* in theory run lazy VACUUM inside a transaction block, but we choose
184+
* to disallow that case because we'd rather commit as soon as possible
185+
* after finishing the vacuum. This is mainly so that we can let go the
186+
* AccessExclusiveLock that we may be holding.)
187+
*
188+
* ANALYZE (without VACUUM) can run either way.
181189
*/
182190
if (vacstmt->vacuum)
191+
{
183192
PreventTransactionChain((void*)vacstmt,stmttype);
193+
in_outer_xact= false;
194+
}
195+
else
196+
{
197+
in_outer_xact=IsInTransactionChain((void*)vacstmt);
198+
}
184199

185200
/* Turn vacuum cost accounting on or off */
186201
VacuumCostActive= (VacuumCostNaptime>0);
@@ -205,81 +220,89 @@ vacuum(VacuumStmt *vacstmt)
205220
ALLOCSET_DEFAULT_INITSIZE,
206221
ALLOCSET_DEFAULT_MAXSIZE);
207222

208-
/*
209-
* If we are running only ANALYZE, we don't need per-table
210-
* transactions, but we still need a memory context with table
211-
* lifetime.
212-
*/
213-
if (vacstmt->analyze&& !vacstmt->vacuum)
214-
anl_context=AllocSetContextCreate(PortalContext,
215-
"Analyze",
216-
ALLOCSET_DEFAULT_MINSIZE,
217-
ALLOCSET_DEFAULT_INITSIZE,
218-
ALLOCSET_DEFAULT_MAXSIZE);
219-
220223
/* Assume we are processing everything unless one table is mentioned */
221224
all_rels= (vacstmt->relation==NULL);
222225

223226
/* Build list of relations to process (note this lives in vac_context) */
224227
relations=get_rel_oids(vacstmt->relation,stmttype);
225228

229+
if (vacstmt->vacuum&&all_rels)
230+
{
231+
/*
232+
* It's a database-wide VACUUM.
233+
*
234+
* Compute the initially applicable OldestXmin and FreezeLimit
235+
* XIDs, so that we can record these values at the end of the
236+
* VACUUM. Note that individual tables may well be processed
237+
* with newer values, but we can guarantee that no
238+
* (non-shared) relations are processed with older ones.
239+
*
240+
* It is okay to record non-shared values in pg_database, even
241+
* though we may vacuum shared relations with older cutoffs,
242+
* because only the minimum of the values present in
243+
* pg_database matters. We can be sure that shared relations
244+
* have at some time been vacuumed with cutoffs no worse than
245+
* the global minimum; for, if there is a backend in some
246+
* other DB with xmin = OLDXMIN that's determining the cutoff
247+
* with which we vacuum shared relations, it is not possible
248+
* for that database to have a cutoff newer than OLDXMIN
249+
* recorded in pg_database.
250+
*/
251+
vacuum_set_xid_limits(vacstmt, false,
252+
&initialOldestXmin,
253+
&initialFreezeLimit);
254+
}
255+
226256
/*
227-
* Formerly, there was code here to prevent more than one VACUUM from
228-
* executing concurrently in the same database. However, there's no
229-
* good reason to prevent that, and manually removing lockfiles after
230-
* a vacuum crash was a pain for dbadmins.So, forget about
231-
* lockfiles, and just rely on the locks we grab on each target table
232-
* to ensure that there aren't two VACUUMs running on the same table
233-
* at the same time.
257+
* Decide whether we need to start/commit our own transactions.
258+
*
259+
* For VACUUM (with or without ANALYZE): always do so, so that we
260+
* can release locks as soon as possible. (We could possibly use the
261+
* outer transaction for a one-table VACUUM, but handling TOAST tables
262+
* would be problematic.)
263+
*
264+
* For ANALYZE (no VACUUM): if inside a transaction block, we cannot
265+
* start/commit our own transactions. Also, there's no need to do so
266+
* if only processing one relation. For multiple relations when not
267+
* within a transaction block, use own transactions so we can release
268+
* locks sooner.
234269
*/
270+
if (vacstmt->vacuum)
271+
{
272+
use_own_xacts= true;
273+
}
274+
else
275+
{
276+
Assert(vacstmt->analyze);
277+
if (in_outer_xact)
278+
use_own_xacts= false;
279+
elseif (length(relations)>1)
280+
use_own_xacts= true;
281+
else
282+
use_own_xacts= false;
283+
}
284+
285+
/*
286+
* If we are running ANALYZE without per-table transactions, we'll
287+
* need a memory context with table lifetime.
288+
*/
289+
if (!use_own_xacts)
290+
anl_context=AllocSetContextCreate(PortalContext,
291+
"Analyze",
292+
ALLOCSET_DEFAULT_MINSIZE,
293+
ALLOCSET_DEFAULT_INITSIZE,
294+
ALLOCSET_DEFAULT_MAXSIZE);
235295

236296
/*
237-
* The strangeness with committing and starting transactions here is
238-
* due to wanting to run each table's VACUUM as a separate
239-
* transaction, so that we don't hold locks unnecessarily long. Also,
240-
* if we are doing VACUUM ANALYZE, the ANALYZE part runs as a separate
241-
* transaction from the VACUUM to further reduce locking.
242-
*
243297
* vacuum_rel expects to be entered with no transaction active; it will
244298
* start and commit its own transaction. But we are called by an SQL
245299
* command, and so we are executing inside a transaction already. We
246300
* commit the transaction started in PostgresMain() here, and start
247301
* another one before exiting to match the commit waiting for us back
248302
* in PostgresMain().
249-
*
250-
* In the case of an ANALYZE statement (no vacuum, just analyze) it's
251-
* okay to run the whole thing in the outer transaction, and so we
252-
* skip transaction start/stop operations.
253303
*/
254-
if (vacstmt->vacuum)
304+
if (use_own_xacts)
255305
{
256-
if (all_rels)
257-
{
258-
/*
259-
* It's a database-wide VACUUM.
260-
*
261-
* Compute the initially applicable OldestXmin and FreezeLimit
262-
* XIDs, so that we can record these values at the end of the
263-
* VACUUM. Note that individual tables may well be processed
264-
* with newer values, but we can guarantee that no
265-
* (non-shared) relations are processed with older ones.
266-
*
267-
* It is okay to record non-shared values in pg_database, even
268-
* though we may vacuum shared relations with older cutoffs,
269-
* because only the minimum of the values present in
270-
* pg_database matters. We can be sure that shared relations
271-
* have at some time been vacuumed with cutoffs no worse than
272-
* the global minimum; for, if there is a backend in some
273-
* other DB with xmin = OLDXMIN that's determining the cutoff
274-
* with which we vacuum shared relations, it is not possible
275-
* for that database to have a cutoff newer than OLDXMIN
276-
* recorded in pg_database.
277-
*/
278-
vacuum_set_xid_limits(vacstmt, false,
279-
&initialOldestXmin,
280-
&initialFreezeLimit);
281-
}
282-
283306
/* matches the StartTransaction in PostgresMain() */
284307
CommitTransactionCommand();
285308
}
@@ -301,13 +324,13 @@ vacuum(VacuumStmt *vacstmt)
301324
MemoryContextold_context=NULL;
302325

303326
/*
304-
* Ifwe vacuumed, use new transaction for analyze. Otherwise,
327+
* Ifusing separate xacts, start one for analyze. Otherwise,
305328
* we can use the outer transaction, but we still need to call
306329
* analyze_rel in a memory context that will be cleaned up on
307330
* return (else we leak memory while processing multiple
308331
* tables).
309332
*/
310-
if (vacstmt->vacuum)
333+
if (use_own_xacts)
311334
{
312335
StartTransactionCommand();
313336
SetQuerySnapshot();/* might be needed for functions
@@ -326,7 +349,7 @@ vacuum(VacuumStmt *vacstmt)
326349

327350
StrategyHintVacuum(false);
328351

329-
if (vacstmt->vacuum)
352+
if (use_own_xacts)
330353
CommitTransactionCommand();
331354
else
332355
{
@@ -339,7 +362,7 @@ vacuum(VacuumStmt *vacstmt)
339362
/*
340363
* Finish up processing.
341364
*/
342-
if (vacstmt->vacuum)
365+
if (use_own_xacts)
343366
{
344367
/* here, we are not in a transaction */
345368

@@ -348,7 +371,10 @@ vacuum(VacuumStmt *vacstmt)
348371
* PostgresMain().
349372
*/
350373
StartTransactionCommand();
374+
}
351375

376+
if (vacstmt->vacuum)
377+
{
352378
/*
353379
* If it was a database-wide VACUUM, print FSM usage statistics
354380
* (we don't make you be superuser to see these).

‎src/include/access/xact.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
88
* Portions Copyright (c) 1994, Regents of the University of California
99
*
10-
* $PostgreSQL: pgsql/src/include/access/xact.h,v 1.62 2004/04/05 03:11:39 momjian Exp $
10+
* $PostgreSQL: pgsql/src/include/access/xact.h,v 1.63 2004/05/22 23:14:38 tgl Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -145,6 +145,7 @@ extern void UserAbortTransactionBlock(void);
145145
externvoidAbortOutOfAnyTransaction(void);
146146
externvoidPreventTransactionChain(void*stmtNode,constchar*stmtType);
147147
externvoidRequireTransactionChain(void*stmtNode,constchar*stmtType);
148+
externboolIsInTransactionChain(void*stmtNode);
148149
externvoidRegisterEOXactCallback(EOXactCallbackcallback,void*arg);
149150
externvoidUnregisterEOXactCallback(EOXactCallbackcallback,void*arg);
150151

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp