Skip to content

Commit c66eb00

Browse files
committed
Allow ANALYZE to run in a transaction.
1 parent deec3cb commit c66eb00

File tree

2 files changed

+93
-96
lines changed

2 files changed

+93
-96
lines changed

src/backend/commands/analyze.c

Lines changed: 1 addition & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $Header: /cvsroot/pgsql/src/backend/commands/analyze.c,v 1.35 2002/05/24 18:57:55 tgl Exp $
11+
* $Header: /cvsroot/pgsql/src/backend/commands/analyze.c,v 1.36 2002/06/13 19:52:02 momjian Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -155,15 +155,6 @@ analyze_rel(Oid relid, VacuumStmt *vacstmt)
155155
else
156156
elevel = DEBUG1;
157157

158-
/*
159-
* Begin a transaction for analyzing this relation.
160-
*
161-
* Note: All memory allocated during ANALYZE will live in
162-
* TransactionCommandContext or a subcontext thereof, so it will all
163-
* be released by transaction commit at the end of this routine.
164-
*/
165-
StartTransactionCommand();
166-
167158
/*
168159
* Check for user-requested abort. Note we want this to be inside a
169160
* transaction, so xact.c doesn't issue useless WARNING.
@@ -177,10 +168,7 @@ analyze_rel(Oid relid, VacuumStmt *vacstmt)
177168
if (!SearchSysCacheExists(RELOID,
178169
ObjectIdGetDatum(relid),
179170
0, 0, 0))
180-
{
181-
CommitTransactionCommand();
182171
return;
183-
}
184172

185173
/*
186174
* Open the class, getting only a read lock on it, and check
@@ -196,7 +184,6 @@ analyze_rel(Oid relid, VacuumStmt *vacstmt)
196184
elog(WARNING, "Skipping \"%s\" --- only table or database owner can ANALYZE it",
197185
RelationGetRelationName(onerel));
198186
relation_close(onerel, AccessShareLock);
199-
CommitTransactionCommand();
200187
return;
201188
}
202189

@@ -211,7 +198,6 @@ analyze_rel(Oid relid, VacuumStmt *vacstmt)
211198
elog(WARNING, "Skipping \"%s\" --- can not process indexes, views or special system tables",
212199
RelationGetRelationName(onerel));
213200
relation_close(onerel, AccessShareLock);
214-
CommitTransactionCommand();
215201
return;
216202
}
217203

@@ -222,7 +208,6 @@ analyze_rel(Oid relid, VacuumStmt *vacstmt)
222208
strcmp(RelationGetRelationName(onerel), StatisticRelationName) == 0)
223209
{
224210
relation_close(onerel, AccessShareLock);
225-
CommitTransactionCommand();
226211
return;
227212
}
228213

@@ -283,7 +268,6 @@ analyze_rel(Oid relid, VacuumStmt *vacstmt)
283268
if (attr_cnt <= 0)
284269
{
285270
relation_close(onerel, NoLock);
286-
CommitTransactionCommand();
287271
return;
288272
}
289273

@@ -370,9 +354,6 @@ analyze_rel(Oid relid, VacuumStmt *vacstmt)
370354
* entries we made in pg_statistic.)
371355
*/
372356
relation_close(onerel, NoLock);
373-
374-
/* Commit and release working memory */
375-
CommitTransactionCommand();
376357
}
377358

378359
/*

src/backend/commands/vacuum.c

Lines changed: 92 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
*
1414
*
1515
* IDENTIFICATION
16-
* $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.226 2002/05/24 18:57:56 tgl Exp $
16+
* $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.227 2002/06/13 19:52:02 momjian Exp $
1717
*
1818
*-------------------------------------------------------------------------
1919
*/
@@ -110,8 +110,6 @@ static TransactionId initialFreezeLimit;
110110

111111

112112
/* non-export function prototypes */
113-
static void vacuum_init(VacuumStmt *vacstmt);
114-
static void vacuum_shutdown(VacuumStmt *vacstmt);
115113
static List *getrels(const RangeVar *vacrel, const char *stmttype);
116114
static void vac_update_dbstats(Oid dbid,
117115
TransactionId vacuumXID,
@@ -160,6 +158,8 @@ static bool enough_space(VacPage vacpage, Size len);
160158
void
161159
vacuum(VacuumStmt *vacstmt)
162160
{
161+
MemoryContext anl_context,
162+
old_context;
163163
const char *stmttype = vacstmt->vacuum ? "VACUUM" : "ANALYZE";
164164
List *vrl,
165165
*cur;
@@ -178,13 +178,13 @@ vacuum(VacuumStmt *vacstmt)
178178
* user's transaction too, which would certainly not be the desired
179179
* behavior.
180180
*/
181-
if (IsTransactionBlock())
181+
if (vacstmt->vacuum && IsTransactionBlock())
182182
elog(ERROR, "%s cannot run inside a BEGIN/END block", stmttype);
183183

184184
/* Running VACUUM from a function would free the function context */
185-
if (!MemoryContextContains(QueryContext, vacstmt))
185+
if (vacstmt->vacuum && !MemoryContextContains(QueryContext, vacstmt))
186186
elog(ERROR, "%s cannot be executed from a function", stmttype);
187-
187+
188188
/*
189189
* Send info about dead objects to the statistics collector
190190
*/
@@ -203,13 +203,62 @@ vacuum(VacuumStmt *vacstmt)
203203
ALLOCSET_DEFAULT_INITSIZE,
204204
ALLOCSET_DEFAULT_MAXSIZE);
205205

206+
if (vacstmt->analyze && !vacstmt->vacuum)
207+
anl_context = AllocSetContextCreate(QueryContext,
208+
"Analyze",
209+
ALLOCSET_DEFAULT_MINSIZE,
210+
ALLOCSET_DEFAULT_INITSIZE,
211+
ALLOCSET_DEFAULT_MAXSIZE);
212+
206213
/* Build list of relations to process (note this lives in vac_context) */
207214
vrl = getrels(vacstmt->relation, stmttype);
208215

209216
/*
210-
* Start up the vacuum cleaner.
217+
* Formerly, there was code here to prevent more than one VACUUM from
218+
* executing concurrently in the same database. However, there's no
219+
* good reason to prevent that, and manually removing lockfiles after
220+
* a vacuum crash was a pain for dbadmins. So, forget about lockfiles,
221+
* and just rely on the locks we grab on each target table
222+
* to ensure that there aren't two VACUUMs running on the same table
223+
* at the same time.
224+
*
225+
* The strangeness with committing and starting transactions in the
226+
* init and shutdown routines is due to the fact that the vacuum cleaner
227+
* is invoked via an SQL command, and so is already executing inside
228+
* a transaction. We need to leave ourselves in a predictable state
229+
* on entry and exit to the vacuum cleaner. We commit the transaction
230+
* started in PostgresMain() inside vacuum_init(), and start one in
231+
* vacuum_shutdown() to match the commit waiting for us back in
232+
* PostgresMain().
211233
*/
212-
vacuum_init(vacstmt);
234+
if (vacstmt->vacuum)
235+
{
236+
if (vacstmt->relation == NULL)
237+
{
238+
/*
239+
* Compute the initially applicable OldestXmin and FreezeLimit
240+
* XIDs, so that we can record these values at the end of the
241+
* VACUUM. Note that individual tables may well be processed with
242+
* newer values, but we can guarantee that no (non-shared)
243+
* relations are processed with older ones.
244+
*
245+
* It is okay to record non-shared values in pg_database, even though
246+
* we may vacuum shared relations with older cutoffs, because only
247+
* the minimum of the values present in pg_database matters. We
248+
* can be sure that shared relations have at some time been
249+
* vacuumed with cutoffs no worse than the global minimum; for, if
250+
* there is a backend in some other DB with xmin = OLDXMIN that's
251+
* determining the cutoff with which we vacuum shared relations,
252+
* it is not possible for that database to have a cutoff newer
253+
* than OLDXMIN recorded in pg_database.
254+
*/
255+
vacuum_set_xid_limits(vacstmt, false,
256+
&initialOldestXmin, &initialFreezeLimit);
257+
}
258+
259+
/* matches the StartTransaction in PostgresMain() */
260+
CommitTransactionCommand();
261+
}
213262

214263
/*
215264
* Process each selected relation. We are careful to process each
@@ -225,81 +274,44 @@ vacuum(VacuumStmt *vacstmt)
225274
if (vacstmt->vacuum)
226275
vacuum_rel(relid, vacstmt, RELKIND_RELATION);
227276
if (vacstmt->analyze)
277+
{
278+
/* If we vacuumed, use new transaction for analyze. */
279+
if (vacstmt->vacuum)
280+
StartTransactionCommand();
281+
else
282+
old_context = MemoryContextSwitchTo(anl_context);
283+
228284
analyze_rel(relid, vacstmt);
285+
286+
if (vacstmt->vacuum)
287+
CommitTransactionCommand();
288+
else
289+
{
290+
MemoryContextResetAndDeleteChildren(anl_context);
291+
MemoryContextSwitchTo(old_context);
292+
}
293+
}
229294
}
230295

231296
/* clean up */
232-
vacuum_shutdown(vacstmt);
233-
}
234-
235-
/*
236-
* vacuum_init(), vacuum_shutdown() -- start up and shut down the vacuum cleaner.
237-
*
238-
* Formerly, there was code here to prevent more than one VACUUM from
239-
* executing concurrently in the same database. However, there's no
240-
* good reason to prevent that, and manually removing lockfiles after
241-
* a vacuum crash was a pain for dbadmins. So, forget about lockfiles,
242-
* and just rely on the locks we grab on each target table
243-
* to ensure that there aren't two VACUUMs running on the same table
244-
* at the same time.
245-
*
246-
* The strangeness with committing and starting transactions in the
247-
* init and shutdown routines is due to the fact that the vacuum cleaner
248-
* is invoked via an SQL command, and so is already executing inside
249-
* a transaction. We need to leave ourselves in a predictable state
250-
* on entry and exit to the vacuum cleaner. We commit the transaction
251-
* started in PostgresMain() inside vacuum_init(), and start one in
252-
* vacuum_shutdown() to match the commit waiting for us back in
253-
* PostgresMain().
254-
*/
255-
static void
256-
vacuum_init(VacuumStmt *vacstmt)
257-
{
258-
if (vacstmt->vacuum && vacstmt->relation == NULL)
297+
if (vacstmt->vacuum)
259298
{
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 with
264-
* newer values, but we can guarantee that no (non-shared)
265-
* relations are processed with older ones.
266-
*
267-
* It is okay to record non-shared values in pg_database, even though
268-
* we may vacuum shared relations with older cutoffs, because only
269-
* the minimum of the values present in pg_database matters. We
270-
* can be sure that shared relations have at some time been
271-
* vacuumed with cutoffs no worse than the global minimum; for, if
272-
* there is a backend in some other DB with xmin = OLDXMIN that's
273-
* determining the cutoff with which we vacuum shared relations,
274-
* it is not possible for that database to have a cutoff newer
275-
* than OLDXMIN recorded in pg_database.
276-
*/
277-
vacuum_set_xid_limits(vacstmt, false,
278-
&initialOldestXmin, &initialFreezeLimit);
279-
}
280-
281-
/* matches the StartTransaction in PostgresMain() */
282-
CommitTransactionCommand();
283-
}
284-
285-
static void
286-
vacuum_shutdown(VacuumStmt *vacstmt)
287-
{
288-
/* on entry, we are not in a transaction */
299+
/* on entry, we are not in a transaction */
289300

290-
/* matches the CommitTransaction in PostgresMain() */
291-
StartTransactionCommand();
301+
/* matches the CommitTransaction in PostgresMain() */
302+
StartTransactionCommand();
292303

293-
/*
294-
* If we did a database-wide VACUUM, update the database's pg_database
295-
* row with info about the transaction IDs used, and try to truncate
296-
* pg_clog.
297-
*/
298-
if (vacstmt->vacuum && vacstmt->relation == NULL)
299-
{
300-
vac_update_dbstats(MyDatabaseId,
301-
initialOldestXmin, initialFreezeLimit);
302-
vac_truncate_clog(initialOldestXmin, initialFreezeLimit);
304+
/*
305+
* If we did a database-wide VACUUM, update the database's pg_database
306+
* row with info about the transaction IDs used, and try to truncate
307+
* pg_clog.
308+
*/
309+
if (vacstmt->relation == NULL)
310+
{
311+
vac_update_dbstats(MyDatabaseId,
312+
initialOldestXmin, initialFreezeLimit);
313+
vac_truncate_clog(initialOldestXmin, initialFreezeLimit);
314+
}
303315
}
304316

305317
/*
@@ -309,6 +321,10 @@ vacuum_shutdown(VacuumStmt *vacstmt)
309321
*/
310322
MemoryContextDelete(vac_context);
311323
vac_context = NULL;
324+
325+
if (vacstmt->analyze && !vacstmt->vacuum)
326+
MemoryContextDelete(anl_context);
327+
312328
}
313329

314330
/*

0 commit comments

Comments
 (0)