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 );
115113static List * getrels (const RangeVar * vacrel ,const char * stmttype );
116114static void vac_update_dbstats (Oid dbid ,
117115TransactionId vacuumXID ,
@@ -160,6 +158,8 @@ static bool enough_space(VacPage vacpage, Size len);
160158void
161159vacuum (VacuumStmt * vacstmt )
162160{
161+ MemoryContext anl_context ,
162+ old_context ;
163163const char * stmttype = vacstmt -> vacuum ?"VACUUM" :"ANALYZE" ;
164164List * 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 ())
182182elog (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 ))
186186elog (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)
203203ALLOCSET_DEFAULT_INITSIZE ,
204204ALLOCSET_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) */
207214vrl = 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)
225274if (vacstmt -> vacuum )
226275vacuum_rel (relid ,vacstmt ,RELKIND_RELATION );
227276if (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+
228284analyze_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 */
310322MemoryContextDelete (vac_context );
311323vac_context = NULL ;
324+
325+ if (vacstmt -> analyze && !vacstmt -> vacuum )
326+ MemoryContextDelete (anl_context );
327+
312328}
313329
314330/*