88 * Portions Copyright (c) 1994, Regents of the University of California
99 *
1010 * IDENTIFICATION
11- * $PostgreSQL: pgsql/src/backend/access/gist/gistvacuum.c,v 1.13 2006/02/1117:14:08 momjian Exp $
11+ * $PostgreSQL: pgsql/src/backend/access/gist/gistvacuum.c,v 1.14 2006/02/1123:31:33 tgl Exp $
1212 *
1313 *-------------------------------------------------------------------------
1414 */
2525#include "storage/freespace.h"
2626#include "storage/smgr.h"
2727
28- /* filled by gistbulkdelete, cleared by gistvacuumpcleanup */
29- static bool needFullVacuum = false;
3028
29+ typedef struct GistBulkDeleteResult
30+ {
31+ IndexBulkDeleteResult std ;/* common state */
32+ bool needFullVacuum ;
33+ }GistBulkDeleteResult ;
3134
3235typedef struct
3336{
3437GISTSTATE giststate ;
3538Relation index ;
3639MemoryContext opCtx ;
37- IndexBulkDeleteResult * result ;
40+ GistBulkDeleteResult * result ;
3841}GistVacuum ;
3942
4043typedef struct
@@ -44,6 +47,7 @@ typedef struct
4447bool emptypage ;
4548}ArrayTuple ;
4649
50+
4751static ArrayTuple
4852gistVacuumUpdate (GistVacuum * gv ,BlockNumber blkno ,bool needunion )
4953{
@@ -125,7 +129,7 @@ gistVacuumUpdate(GistVacuum *gv, BlockNumber blkno, bool needunion)
125129if (chldtuple .ituplen > 1 )
126130{
127131/*
128- * child wassplitted , so we need mark completion
132+ * child wassplit , so we need mark completion
129133 * insert(split)
130134 */
131135int j ;
@@ -262,7 +266,7 @@ gistVacuumUpdate(GistVacuum *gv, BlockNumber blkno, bool needunion)
262266needwrite = true;
263267res .emptypage = true;
264268GistPageSetDeleted (page );
265- gv -> result -> pages_deleted ++ ;
269+ gv -> result -> std . pages_deleted ++ ;
266270}
267271}
268272else
@@ -329,9 +333,9 @@ gistVacuumUpdate(GistVacuum *gv, BlockNumber blkno, bool needunion)
329333}
330334
331335/*
332- * Forusial vacuum just update FSM, for full vacuum
336+ * Forusual vacuum just update FSM, for full vacuum
333337 * reforms parent tuples if some of childs was deleted or changed,
334- * update invalid tuples (they canexsist from last crash recovery only),
338+ * update invalid tuples (they canexist from last crash recovery only),
335339 * tries to get smaller index
336340 */
337341
@@ -340,7 +344,7 @@ gistvacuumcleanup(PG_FUNCTION_ARGS)
340344{
341345Relation rel = (Relation )PG_GETARG_POINTER (0 );
342346IndexVacuumCleanupInfo * info = (IndexVacuumCleanupInfo * )PG_GETARG_POINTER (1 );
343- IndexBulkDeleteResult * stats = (IndexBulkDeleteResult * )PG_GETARG_POINTER (2 );
347+ GistBulkDeleteResult * stats = (GistBulkDeleteResult * )PG_GETARG_POINTER (2 );
344348BlockNumber npages ,
345349blkno ;
346350BlockNumber nFreePages ,
@@ -377,13 +381,11 @@ gistvacuumcleanup(PG_FUNCTION_ARGS)
377381freeGISTstate (& (gv .giststate ));
378382MemoryContextDelete (gv .opCtx );
379383}
380- else if (needFullVacuum )
384+ else if (stats -> needFullVacuum )
381385ereport (NOTICE ,
382386(errmsg ("index \"%s\" needs VACUUM FULL or REINDEX to finish crash recovery" ,
383387RelationGetRelationName (rel ))));
384388
385- needFullVacuum = false;
386-
387389if (info -> vacuum_full )
388390needLock = false;/* relation locked with AccessExclusiveLock */
389391else
@@ -438,23 +440,30 @@ gistvacuumcleanup(PG_FUNCTION_ARGS)
438440
439441if (lastBlock > lastFilledBlock )
440442RelationTruncate (rel ,lastFilledBlock + 1 );
441- stats -> pages_removed = lastBlock - lastFilledBlock ;
443+ stats -> std . pages_removed = lastBlock - lastFilledBlock ;
442444}
443445
444446RecordIndexFreeSpace (& rel -> rd_node ,nFreePages ,freePages );
445447pfree (freePages );
446448
447449/* return statistics */
448- stats -> pages_free = nFreePages ;
450+ stats -> std . pages_free = nFreePages ;
449451if (needLock )
450452LockRelationForExtension (rel ,ExclusiveLock );
451- stats -> num_pages = RelationGetNumberOfBlocks (rel );
453+ stats -> std . num_pages = RelationGetNumberOfBlocks (rel );
452454if (needLock )
453455UnlockRelationForExtension (rel ,ExclusiveLock );
454456
455457if (info -> vacuum_full )
456458UnlockRelation (rel ,AccessExclusiveLock );
457459
460+ /* if gistbulkdelete skipped the scan, use heap's tuple count */
461+ if (stats -> std .num_index_tuples < 0 )
462+ {
463+ Assert (info -> num_heap_tuples >=0 );
464+ stats -> std .num_index_tuples = info -> num_heap_tuples ;
465+ }
466+
458467PG_RETURN_POINTER (stats );
459468}
460469
@@ -500,15 +509,33 @@ gistbulkdelete(PG_FUNCTION_ARGS)
500509Relation rel = (Relation )PG_GETARG_POINTER (0 );
501510IndexBulkDeleteCallback callback = (IndexBulkDeleteCallback )PG_GETARG_POINTER (1 );
502511void * callback_state = (void * )PG_GETARG_POINTER (2 );
503- IndexBulkDeleteResult * result = ( IndexBulkDeleteResult * ) palloc0 ( sizeof ( IndexBulkDeleteResult )) ;
512+ GistBulkDeleteResult * result ;
504513GistBDItem * stack ,
505514* ptr ;
506515bool needLock ;
507516
508- stack = (GistBDItem * )palloc0 (sizeof (GistBDItem ));
517+ result = (GistBulkDeleteResult * )palloc0 (sizeof (GistBulkDeleteResult ));
509518
510- stack -> blkno = GIST_ROOT_BLKNO ;
511- needFullVacuum = false;
519+ /*
520+ * We can skip the scan entirely if there's nothing to delete (indicated
521+ * by callback_state == NULL) and the index isn't partial. For a partial
522+ * index we must scan in order to derive a trustworthy tuple count.
523+ *
524+ * XXX as of PG 8.2 this is dead code because GIST indexes are always
525+ * effectively partial ... but keep it anyway in case our null-handling
526+ * gets fixed.
527+ */
528+ if (callback_state || vac_is_partial_index (rel ))
529+ {
530+ stack = (GistBDItem * )palloc0 (sizeof (GistBDItem ));
531+ stack -> blkno = GIST_ROOT_BLKNO ;
532+ }
533+ else
534+ {
535+ /* skip scan and set flag for gistvacuumcleanup */
536+ stack = NULL ;
537+ result -> std .num_index_tuples = -1 ;
538+ }
512539
513540while (stack )
514541{
@@ -561,11 +588,11 @@ gistbulkdelete(PG_FUNCTION_ARGS)
561588i -- ;
562589maxoff -- ;
563590ntodelete ++ ;
564- result -> tuples_removed += 1 ;
591+ result -> std . tuples_removed += 1 ;
565592Assert (maxoff == PageGetMaxOffsetNumber (page ));
566593}
567594else
568- result -> num_index_tuples += 1 ;
595+ result -> std . num_index_tuples += 1 ;
569596}
570597
571598if (ntodelete )
@@ -615,7 +642,7 @@ gistbulkdelete(PG_FUNCTION_ARGS)
615642stack -> next = ptr ;
616643
617644if (GistTupleIsInvalid (idxtuple ))
618- needFullVacuum = true;
645+ result -> needFullVacuum = true;
619646}
620647}
621648
@@ -634,7 +661,7 @@ gistbulkdelete(PG_FUNCTION_ARGS)
634661
635662if (needLock )
636663LockRelationForExtension (rel ,ExclusiveLock );
637- result -> num_pages = RelationGetNumberOfBlocks (rel );
664+ result -> std . num_pages = RelationGetNumberOfBlocks (rel );
638665if (needLock )
639666UnlockRelationForExtension (rel ,ExclusiveLock );
640667