aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/src/sgml/indexam.sgml8
-rw-r--r--src/backend/access/gist/gistvacuum.c73
-rw-r--r--src/backend/access/hash/hash.c14
-rw-r--r--src/backend/access/index/indexam.c6
-rw-r--r--src/backend/access/nbtree/nbtree.c25
-rw-r--r--src/backend/commands/vacuum.c4
-rw-r--r--src/backend/commands/vacuumlazy.c6
-rw-r--r--src/include/access/genam.h3
8 files changed, 108 insertions, 31 deletions
diff --git a/doc/src/sgml/indexam.sgml b/doc/src/sgml/indexam.sgml
index 7480c98a15b..d766467bdb4 100644
--- a/doc/src/sgml/indexam.sgml
+++ b/doc/src/sgml/indexam.sgml
@@ -1,5 +1,5 @@
<!--
-$PostgreSQL: pgsql/doc/src/sgml/indexam.sgml,v 2.7 2005/11/04 23:14:00 petere Exp $
+$PostgreSQL: pgsql/doc/src/sgml/indexam.sgml,v 2.8 2006/02/11 23:31:32 tgl Exp $
-->
<chapter id="indexam">
@@ -201,6 +201,12 @@ ambulkdelete (Relation indexRelation,
</para>
<para>
+ If <literal>callback_state</> is NULL then no tuples are to be deleted.
+ The index AM may choose to optimize this case (eg by not scanning the
+ index) but it is still expected to deliver accurate statistics.
+ </para>
+
+ <para>
<programlisting>
IndexBulkDeleteResult *
amvacuumcleanup (Relation indexRelation,
diff --git a/src/backend/access/gist/gistvacuum.c b/src/backend/access/gist/gistvacuum.c
index afd743a5a26..b96d84fd024 100644
--- a/src/backend/access/gist/gistvacuum.c
+++ b/src/backend/access/gist/gistvacuum.c
@@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/access/gist/gistvacuum.c,v 1.13 2006/02/11 17:14:08 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/access/gist/gistvacuum.c,v 1.14 2006/02/11 23:31:33 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -25,16 +25,19 @@
#include "storage/freespace.h"
#include "storage/smgr.h"
-/* filled by gistbulkdelete, cleared by gistvacuumpcleanup */
-static bool needFullVacuum = false;
+typedef struct GistBulkDeleteResult
+{
+ IndexBulkDeleteResult std; /* common state */
+ bool needFullVacuum;
+} GistBulkDeleteResult;
typedef struct
{
GISTSTATE giststate;
Relation index;
MemoryContext opCtx;
- IndexBulkDeleteResult *result;
+ GistBulkDeleteResult *result;
} GistVacuum;
typedef struct
@@ -44,6 +47,7 @@ typedef struct
bool emptypage;
} ArrayTuple;
+
static ArrayTuple
gistVacuumUpdate(GistVacuum *gv, BlockNumber blkno, bool needunion)
{
@@ -125,7 +129,7 @@ gistVacuumUpdate(GistVacuum *gv, BlockNumber blkno, bool needunion)
if (chldtuple.ituplen > 1)
{
/*
- * child was splitted, so we need mark completion
+ * child was split, so we need mark completion
* insert(split)
*/
int j;
@@ -262,7 +266,7 @@ gistVacuumUpdate(GistVacuum *gv, BlockNumber blkno, bool needunion)
needwrite = true;
res.emptypage = true;
GistPageSetDeleted(page);
- gv->result->pages_deleted++;
+ gv->result->std.pages_deleted++;
}
}
else
@@ -329,9 +333,9 @@ gistVacuumUpdate(GistVacuum *gv, BlockNumber blkno, bool needunion)
}
/*
- * For usial vacuum just update FSM, for full vacuum
+ * For usual vacuum just update FSM, for full vacuum
* reforms parent tuples if some of childs was deleted or changed,
- * update invalid tuples (they can exsist from last crash recovery only),
+ * update invalid tuples (they can exist from last crash recovery only),
* tries to get smaller index
*/
@@ -340,7 +344,7 @@ gistvacuumcleanup(PG_FUNCTION_ARGS)
{
Relation rel = (Relation) PG_GETARG_POINTER(0);
IndexVacuumCleanupInfo *info = (IndexVacuumCleanupInfo *) PG_GETARG_POINTER(1);
- IndexBulkDeleteResult *stats = (IndexBulkDeleteResult *) PG_GETARG_POINTER(2);
+ GistBulkDeleteResult *stats = (GistBulkDeleteResult *) PG_GETARG_POINTER(2);
BlockNumber npages,
blkno;
BlockNumber nFreePages,
@@ -377,13 +381,11 @@ gistvacuumcleanup(PG_FUNCTION_ARGS)
freeGISTstate(&(gv.giststate));
MemoryContextDelete(gv.opCtx);
}
- else if (needFullVacuum)
+ else if (stats->needFullVacuum)
ereport(NOTICE,
(errmsg("index \"%s\" needs VACUUM FULL or REINDEX to finish crash recovery",
RelationGetRelationName(rel))));
- needFullVacuum = false;
-
if (info->vacuum_full)
needLock = false; /* relation locked with AccessExclusiveLock */
else
@@ -438,23 +440,30 @@ gistvacuumcleanup(PG_FUNCTION_ARGS)
if (lastBlock > lastFilledBlock)
RelationTruncate(rel, lastFilledBlock + 1);
- stats->pages_removed = lastBlock - lastFilledBlock;
+ stats->std.pages_removed = lastBlock - lastFilledBlock;
}
RecordIndexFreeSpace(&rel->rd_node, nFreePages, freePages);
pfree(freePages);
/* return statistics */
- stats->pages_free = nFreePages;
+ stats->std.pages_free = nFreePages;
if (needLock)
LockRelationForExtension(rel, ExclusiveLock);
- stats->num_pages = RelationGetNumberOfBlocks(rel);
+ stats->std.num_pages = RelationGetNumberOfBlocks(rel);
if (needLock)
UnlockRelationForExtension(rel, ExclusiveLock);
if (info->vacuum_full)
UnlockRelation(rel, AccessExclusiveLock);
+ /* if gistbulkdelete skipped the scan, use heap's tuple count */
+ if (stats->std.num_index_tuples < 0)
+ {
+ Assert(info->num_heap_tuples >= 0);
+ stats->std.num_index_tuples = info->num_heap_tuples;
+ }
+
PG_RETURN_POINTER(stats);
}
@@ -500,15 +509,33 @@ gistbulkdelete(PG_FUNCTION_ARGS)
Relation rel = (Relation) PG_GETARG_POINTER(0);
IndexBulkDeleteCallback callback = (IndexBulkDeleteCallback) PG_GETARG_POINTER(1);
void *callback_state = (void *) PG_GETARG_POINTER(2);
- IndexBulkDeleteResult *result = (IndexBulkDeleteResult *) palloc0(sizeof(IndexBulkDeleteResult));
+ GistBulkDeleteResult *result;
GistBDItem *stack,
*ptr;
bool needLock;
- stack = (GistBDItem *) palloc0(sizeof(GistBDItem));
+ result = (GistBulkDeleteResult *) palloc0(sizeof(GistBulkDeleteResult));
- stack->blkno = GIST_ROOT_BLKNO;
- needFullVacuum = false;
+ /*
+ * We can skip the scan entirely if there's nothing to delete (indicated
+ * by callback_state == NULL) and the index isn't partial. For a partial
+ * index we must scan in order to derive a trustworthy tuple count.
+ *
+ * XXX as of PG 8.2 this is dead code because GIST indexes are always
+ * effectively partial ... but keep it anyway in case our null-handling
+ * gets fixed.
+ */
+ if (callback_state || vac_is_partial_index(rel))
+ {
+ stack = (GistBDItem *) palloc0(sizeof(GistBDItem));
+ stack->blkno = GIST_ROOT_BLKNO;
+ }
+ else
+ {
+ /* skip scan and set flag for gistvacuumcleanup */
+ stack = NULL;
+ result->std.num_index_tuples = -1;
+ }
while (stack)
{
@@ -561,11 +588,11 @@ gistbulkdelete(PG_FUNCTION_ARGS)
i--;
maxoff--;
ntodelete++;
- result->tuples_removed += 1;
+ result->std.tuples_removed += 1;
Assert(maxoff == PageGetMaxOffsetNumber(page));
}
else
- result->num_index_tuples += 1;
+ result->std.num_index_tuples += 1;
}
if (ntodelete)
@@ -615,7 +642,7 @@ gistbulkdelete(PG_FUNCTION_ARGS)
stack->next = ptr;
if (GistTupleIsInvalid(idxtuple))
- needFullVacuum = true;
+ result->needFullVacuum = true;
}
}
@@ -634,7 +661,7 @@ gistbulkdelete(PG_FUNCTION_ARGS)
if (needLock)
LockRelationForExtension(rel, ExclusiveLock);
- result->num_pages = RelationGetNumberOfBlocks(rel);
+ result->std.num_pages = RelationGetNumberOfBlocks(rel);
if (needLock)
UnlockRelationForExtension(rel, ExclusiveLock);
diff --git a/src/backend/access/hash/hash.c b/src/backend/access/hash/hash.c
index cb82a38d901..ca0d6ec96dd 100644
--- a/src/backend/access/hash/hash.c
+++ b/src/backend/access/hash/hash.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/access/hash/hash.c,v 1.85 2006/02/11 17:14:08 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/access/hash/hash.c,v 1.86 2006/02/11 23:31:33 tgl Exp $
*
* NOTES
* This file contains only the public interface routines.
@@ -517,6 +517,18 @@ hashbulkdelete(PG_FUNCTION_ARGS)
cur_maxbucket = orig_maxbucket;
loop_top:
+
+ /*
+ * If we don't have anything to delete, skip the scan, and report the
+ * number of tuples shown in the metapage. (Unlike btree and gist,
+ * we can trust this number even for a partial index.)
+ */
+ if (!callback_state)
+ {
+ cur_bucket = cur_maxbucket + 1;
+ num_index_tuples = local_metapage.hashm_ntuples;
+ }
+
while (cur_bucket <= cur_maxbucket)
{
BlockNumber bucket_blkno;
diff --git a/src/backend/access/index/indexam.c b/src/backend/access/index/indexam.c
index 6a681192caf..69c9ecb9189 100644
--- a/src/backend/access/index/indexam.c
+++ b/src/backend/access/index/indexam.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/access/index/indexam.c,v 1.89 2006/02/11 17:14:08 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/access/index/indexam.c,v 1.90 2006/02/11 23:31:33 tgl Exp $
*
* INTERFACE ROUTINES
* index_open - open an index relation by relation OID
@@ -685,6 +685,10 @@ index_getmulti(IndexScanDesc scan,
* callback routine tells whether a given main-heap tuple is
* to be deleted
*
+ * if callback_state is NULL then there are no tuples to be deleted;
+ * index AM can choose to avoid work in this case, but must still
+ * follow the protocol of returning statistical info.
+ *
* return value is an optional palloc'd struct of statistics
* ----------------
*/
diff --git a/src/backend/access/nbtree/nbtree.c b/src/backend/access/nbtree/nbtree.c
index 4fb70302d7a..e28faef141d 100644
--- a/src/backend/access/nbtree/nbtree.c
+++ b/src/backend/access/nbtree/nbtree.c
@@ -12,7 +12,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/access/nbtree/nbtree.c,v 1.138 2006/02/11 17:14:08 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/access/nbtree/nbtree.c,v 1.139 2006/02/11 23:31:33 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -564,8 +564,22 @@ btbulkdelete(PG_FUNCTION_ARGS)
* further to its right, which the indexscan will have no pin on.) We can
* skip obtaining exclusive lock on empty pages though, since no indexscan
* could be stopped on those.
+ *
+ * We can skip the scan entirely if there's nothing to delete (indicated
+ * by callback_state == NULL) and the index isn't partial. For a partial
+ * index we must scan in order to derive a trustworthy tuple count.
*/
- buf = _bt_get_endpoint(rel, 0, false);
+ if (callback_state || vac_is_partial_index(rel))
+ {
+ buf = _bt_get_endpoint(rel, 0, false);
+ }
+ else
+ {
+ /* skip scan and set flag for btvacuumcleanup */
+ buf = InvalidBuffer;
+ num_index_tuples = -1;
+ }
+
if (BufferIsValid(buf)) /* check for empty index */
{
for (;;)
@@ -836,6 +850,13 @@ btvacuumcleanup(PG_FUNCTION_ARGS)
stats->pages_deleted = pages_deleted;
stats->pages_free = nFreePages;
+ /* if btbulkdelete skipped the scan, use heap's tuple count */
+ if (stats->num_index_tuples < 0)
+ {
+ Assert(info->num_heap_tuples >= 0);
+ stats->num_index_tuples = info->num_heap_tuples;
+ }
+
PG_RETURN_POINTER(stats);
}
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index d60c433095d..3153a0a559a 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -13,7 +13,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/vacuum.c,v 1.323 2006/02/11 17:14:09 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/vacuum.c,v 1.324 2006/02/11 23:31:33 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -2955,6 +2955,7 @@ scan_index(Relation indrel, double num_tuples)
/* Do post-VACUUM cleanup, even though we deleted nothing */
vcinfo.vacuum_full = true;
vcinfo.message_level = elevel;
+ vcinfo.num_heap_tuples = num_tuples;
stats = index_vacuum_cleanup(indrel, &vcinfo, stats);
@@ -3022,6 +3023,7 @@ vacuum_index(VacPageList vacpagelist, Relation indrel,
/* Do post-VACUUM cleanup */
vcinfo.vacuum_full = true;
vcinfo.message_level = elevel;
+ vcinfo.num_heap_tuples = num_tuples + keep_tuples;
stats = index_vacuum_cleanup(indrel, &vcinfo, stats);
diff --git a/src/backend/commands/vacuumlazy.c b/src/backend/commands/vacuumlazy.c
index a65c269fc8c..2c1ba517638 100644
--- a/src/backend/commands/vacuumlazy.c
+++ b/src/backend/commands/vacuumlazy.c
@@ -31,7 +31,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/vacuumlazy.c,v 1.65 2006/02/11 17:14:09 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/vacuumlazy.c,v 1.66 2006/02/11 23:31:34 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -625,6 +625,7 @@ lazy_scan_index(Relation indrel, LVRelStats *vacrelstats)
/* Do post-VACUUM cleanup, even though we deleted nothing */
vcinfo.vacuum_full = false;
vcinfo.message_level = elevel;
+ vcinfo.num_heap_tuples = vacrelstats->rel_tuples;
stats = index_vacuum_cleanup(indrel, &vcinfo, stats);
@@ -697,6 +698,9 @@ lazy_vacuum_index(Relation indrel,
/* Do post-VACUUM cleanup */
vcinfo.vacuum_full = false;
vcinfo.message_level = elevel;
+ /* We don't yet know rel_tuples, so pass -1 */
+ /* index_bulk_delete can't have skipped scan anyway ... */
+ vcinfo.num_heap_tuples = -1;
stats = index_vacuum_cleanup(indrel, &vcinfo, stats);
diff --git a/src/include/access/genam.h b/src/include/access/genam.h
index 859c4e53b29..eace51db0e6 100644
--- a/src/include/access/genam.h
+++ b/src/include/access/genam.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/access/genam.h,v 1.56 2006/02/11 17:14:09 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/access/genam.h,v 1.57 2006/02/11 23:31:34 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -51,6 +51,7 @@ typedef struct IndexVacuumCleanupInfo
{
bool vacuum_full; /* VACUUM FULL (we have exclusive lock) */
int message_level; /* ereport level for progress messages */
+ double num_heap_tuples; /* tuples remaining in heap */
} IndexVacuumCleanupInfo;
/* Struct for heap-or-index scans of system tables */