13
13
*
14
14
*
15
15
* 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 $
17
17
*
18
18
*-------------------------------------------------------------------------
19
19
*/
@@ -110,8 +110,6 @@ static TransactionId initialFreezeLimit;
110
110
111
111
112
112
/* non-export function prototypes */
113
- static void vacuum_init (VacuumStmt * vacstmt );
114
- static void vacuum_shutdown (VacuumStmt * vacstmt );
115
113
static List * getrels (const RangeVar * vacrel ,const char * stmttype );
116
114
static void vac_update_dbstats (Oid dbid ,
117
115
TransactionId vacuumXID ,
@@ -160,6 +158,8 @@ static bool enough_space(VacPage vacpage, Size len);
160
158
void
161
159
vacuum (VacuumStmt * vacstmt )
162
160
{
161
+ MemoryContext anl_context ,
162
+ old_context ;
163
163
const char * stmttype = vacstmt -> vacuum ?"VACUUM" :"ANALYZE" ;
164
164
List * vrl ,
165
165
* cur ;
@@ -178,13 +178,13 @@ vacuum(VacuumStmt *vacstmt)
178
178
* user's transaction too, which would certainly not be the desired
179
179
* behavior.
180
180
*/
181
- if (IsTransactionBlock ())
181
+ if (vacstmt -> vacuum && IsTransactionBlock ())
182
182
elog (ERROR ,"%s cannot run inside a BEGIN/END block" ,stmttype );
183
183
184
184
/* Running VACUUM from a function would free the function context */
185
- if (!MemoryContextContains (QueryContext ,vacstmt ))
185
+ if (vacstmt -> vacuum && !MemoryContextContains (QueryContext ,vacstmt ))
186
186
elog (ERROR ,"%s cannot be executed from a function" ,stmttype );
187
-
187
+
188
188
/*
189
189
* Send info about dead objects to the statistics collector
190
190
*/
@@ -203,13 +203,62 @@ vacuum(VacuumStmt *vacstmt)
203
203
ALLOCSET_DEFAULT_INITSIZE ,
204
204
ALLOCSET_DEFAULT_MAXSIZE );
205
205
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
+
206
213
/* Build list of relations to process (note this lives in vac_context) */
207
214
vrl = getrels (vacstmt -> relation ,stmttype );
208
215
209
216
/*
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().
211
233
*/
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
+ }
213
262
214
263
/*
215
264
* Process each selected relation.We are careful to process each
@@ -225,81 +274,44 @@ vacuum(VacuumStmt *vacstmt)
225
274
if (vacstmt -> vacuum )
226
275
vacuum_rel (relid ,vacstmt ,RELKIND_RELATION );
227
276
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
+
228
284
analyze_rel (relid ,vacstmt );
285
+
286
+ if (vacstmt -> vacuum )
287
+ CommitTransactionCommand ();
288
+ else
289
+ {
290
+ MemoryContextResetAndDeleteChildren (anl_context );
291
+ MemoryContextSwitchTo (old_context );
292
+ }
293
+ }
229
294
}
230
295
231
296
/* 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 )
259
298
{
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 */
289
300
290
- /* matches the CommitTransaction in PostgresMain() */
291
- StartTransactionCommand ();
301
+ /* matches the CommitTransaction in PostgresMain() */
302
+ StartTransactionCommand ();
292
303
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
+ }
303
315
}
304
316
305
317
/*
@@ -309,6 +321,10 @@ vacuum_shutdown(VacuumStmt *vacstmt)
309
321
*/
310
322
MemoryContextDelete (vac_context );
311
323
vac_context = NULL ;
324
+
325
+ if (vacstmt -> analyze && !vacstmt -> vacuum )
326
+ MemoryContextDelete (anl_context );
327
+
312
328
}
313
329
314
330
/*