8
8
*
9
9
*
10
10
* IDENTIFICATION
11
- * $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.177 2000/12/08 06:43:44 inoue Exp $
11
+ * $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.178 2000/12/22 00:51:53 tgl Exp $
12
12
*
13
13
*-------------------------------------------------------------------------
14
14
*/
@@ -61,7 +61,7 @@ static void vacuum_init(void);
61
61
static void vacuum_shutdown (void );
62
62
static void vac_vacuum (NameData * VacRelP , bool analyze , List * anal_cols2 );
63
63
static VRelList getrels (NameData * VacRelP );
64
- static void vacuum_rel (Oid relid , bool is_toastrel );
64
+ static void vacuum_rel (Oid relid );
65
65
static void scan_heap (VRelStats * vacrelstats , Relation onerel , VacPageList vacuum_pages , VacPageList fraged_pages );
66
66
static void repair_frag (VRelStats * vacrelstats , Relation onerel , VacPageList vacuum_pages , VacPageList fraged_pages , int nindices , Relation * Irel );
67
67
static void vacuum_heap (VRelStats * vacrelstats , Relation onerel , VacPageList vacpagelist );
@@ -239,7 +239,7 @@ vac_vacuum(NameData *VacRelP, bool analyze, List *anal_cols2)
239
239
/* vacuum each heap relation */
240
240
for (cur = vrl ; cur != (VRelList ) NULL ; cur = cur -> vrl_next )
241
241
{
242
- vacuum_rel (cur -> vrl_relid , false );
242
+ vacuum_rel (cur -> vrl_relid );
243
243
/* analyze separately so locking is minimized */
244
244
if (analyze )
245
245
analyze_rel (cur -> vrl_relid , anal_cols2 , MESSAGE_LEVEL );
@@ -308,7 +308,7 @@ getrels(NameData *VacRelP)
308
308
309
309
if (rkind != RELKIND_RELATION )
310
310
{
311
- elog (NOTICE , "Vacuum: can not process indecies , views and certain system tables" );
311
+ elog (NOTICE , "Vacuum: can not process indices , views and certain system tables" );
312
312
continue ;
313
313
}
314
314
@@ -342,32 +342,34 @@ getrels(NameData *VacRelP)
342
342
* vacuum_rel() -- vacuum one heap relation
343
343
*
344
344
* This routine vacuums a single heap, cleans out its indices, and
345
- * updates its statistics num_pages and num_tuples statistics.
345
+ * updates its num_pages and num_tuples statistics.
346
346
*
347
347
* Doing one heap at a time incurs extra overhead, since we need to
348
348
* check that the heap exists again just before we vacuum it. The
349
349
* reason that we do this is so that vacuuming can be spread across
350
350
* many small transactions. Otherwise, two-phase locking would require
351
351
* us to lock the entire database during one pass of the vacuum cleaner.
352
+ *
353
+ * At entry and exit, we are not inside a transaction.
352
354
*/
353
355
static void
354
- vacuum_rel (Oid relid , bool is_toastrel )
356
+ vacuum_rel (Oid relid )
355
357
{
356
358
Relation onerel ;
359
+ LockRelId onerelid ;
357
360
VacPageListData vacuum_pages ; /* List of pages to vacuum and/or clean
358
- * indices */
361
+ * indices */
359
362
VacPageListData fraged_pages ; /* List of pages with space enough for
360
- * re-using */
361
- VacPage * vacpage ;
363
+ * re-using */
362
364
Relation * Irel ;
363
365
int32 nindices ,
364
366
i ;
365
367
VRelStats * vacrelstats ;
366
368
bool reindex = false;
367
369
Oid toast_relid ;
368
370
369
- if (! is_toastrel )
370
- StartTransactionCommand ();
371
+ /* Begin a transaction for vacuuming this relation */
372
+ StartTransactionCommand ();
371
373
372
374
/*
373
375
* Check for user-requested abort. Note we want this to be inside a
@@ -384,8 +386,7 @@ vacuum_rel(Oid relid, bool is_toastrel)
384
386
ObjectIdGetDatum (relid ),
385
387
0 , 0 , 0 ))
386
388
{
387
- if (!is_toastrel )
388
- CommitTransactionCommand ();
389
+ CommitTransactionCommand ();
389
390
return ;
390
391
}
391
392
@@ -403,13 +404,25 @@ vacuum_rel(Oid relid, bool is_toastrel)
403
404
elog (NOTICE , "Skipping \"%s\" --- only table owner can VACUUM it" ,
404
405
RelationGetRelationName (onerel ));
405
406
heap_close (onerel , AccessExclusiveLock );
406
- if (!is_toastrel )
407
- CommitTransactionCommand ();
407
+ CommitTransactionCommand ();
408
408
return ;
409
409
}
410
410
411
411
/*
412
- * Remember the relation'ss TOAST relation for later
412
+ * Get a session-level exclusive lock too. This will protect our
413
+ * exclusive access to the relation across multiple transactions,
414
+ * so that we can vacuum the relation's TOAST table (if any) secure
415
+ * in the knowledge that no one is diddling the parent relation.
416
+ *
417
+ * NOTE: this cannot block, even if someone else is waiting for access,
418
+ * because the lock manager knows that both lock requests are from the
419
+ * same process.
420
+ */
421
+ onerelid = onerel -> rd_lockInfo .lockRelId ;
422
+ LockRelationForSession (& onerelid , AccessExclusiveLock );
423
+
424
+ /*
425
+ * Remember the relation's TOAST relation for later
413
426
*/
414
427
toast_relid = onerel -> rd_rel -> reltoastrelid ;
415
428
@@ -500,21 +513,6 @@ vacuum_rel(Oid relid, bool is_toastrel)
500
513
if (reindex )
501
514
activate_indexes_of_a_table (relid , true);
502
515
503
- /*
504
- * ok - free vacuum_pages list of reaped pages
505
- *
506
- * Isn't this a waste of code? Upcoming commit should free memory, no?
507
- */
508
- if (vacuum_pages .num_pages > 0 )
509
- {
510
- vacpage = vacuum_pages .pagedesc ;
511
- for (i = 0 ; i < vacuum_pages .num_pages ; i ++ , vacpage ++ )
512
- pfree (* vacpage );
513
- pfree (vacuum_pages .pagedesc );
514
- if (fraged_pages .num_pages > 0 )
515
- pfree (fraged_pages .pagedesc );
516
- }
517
-
518
516
/* all done with this class, but hold lock until commit */
519
517
heap_close (onerel , NoLock );
520
518
@@ -523,19 +521,25 @@ vacuum_rel(Oid relid, bool is_toastrel)
523
521
vacrelstats -> num_tuples , vacrelstats -> hasindex ,
524
522
vacrelstats );
525
523
524
+ /*
525
+ * Complete the transaction and free all temporary memory used.
526
+ */
527
+ CommitTransactionCommand ();
528
+
526
529
/*
527
530
* If the relation has a secondary toast one, vacuum that too
528
- * while we still hold the lock on the master table. We don't
529
- * need to propagate "analyze" to it, because the toaster
531
+ * while we still hold the session lock on the master table.
532
+ * We don't need to propagate "analyze" to it, because the toaster
530
533
* always uses hardcoded index access and statistics are
531
534
* totally unimportant for toast relations
532
535
*/
533
536
if (toast_relid != InvalidOid )
534
- vacuum_rel (toast_relid , true );
537
+ vacuum_rel (toast_relid );
535
538
536
- /* next command frees attribute stats */
537
- if (!is_toastrel )
538
- CommitTransactionCommand ();
539
+ /*
540
+ * Now release the session-level lock on the master table.
541
+ */
542
+ UnlockRelationForSession (& onerelid , AccessExclusiveLock );
539
543
}
540
544
541
545
/*
@@ -1786,9 +1790,13 @@ failed to add item with len = %lu to page %u (free space %lu, nusd %u, noff %u)"
1786
1790
if (num_moved > 0 )
1787
1791
{
1788
1792
/*
1789
- * We have to commit our tuple' movings before we'll truncate
1790
- * relation, but we shouldn't lose our locks. And so - quick hack:
1791
- * record status of current transaction as committed, and continue.
1793
+ * We have to commit our tuple movings before we truncate the
1794
+ * relation. Ideally we should do Commit/StartTransactionCommand
1795
+ * here, relying on the session-level table lock to protect our
1796
+ * exclusive access to the relation. However, that would require
1797
+ * a lot of extra code to close and re-open the relation, indices,
1798
+ * etc. For now, a quick hack: record status of current transaction
1799
+ * as committed, and continue.
1792
1800
*/
1793
1801
RecordTransactionCommit ();
1794
1802
}
@@ -1852,7 +1860,7 @@ failed to add item with len = %lu to page %u (free space %lu, nusd %u, noff %u)"
1852
1860
/*
1853
1861
* Reflect the motion of system tuples to catalog cache here.
1854
1862
*/
1855
- CommandCounterIncrement ();
1863
+ CommandCounterIncrement ();
1856
1864
1857
1865
if (Nvacpagelist .num_pages > 0 )
1858
1866
{
0 commit comments