]> granicus.if.org Git - postgresql/commitdiff
Remove direct calls of index_insert(), instead use ExecInsertIndexTuples().
authorTom Lane <tgl@sss.pgh.pa.us>
Wed, 11 Jul 2001 18:38:07 +0000 (18:38 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Wed, 11 Jul 2001 18:38:07 +0000 (18:38 +0000)
This makes VACUUM work properly with partial indexes, and avoids memory
leakage with functional indexes.  Also, suppress complaint about fewer
index tuples than heap tuples when the index is a partial index.
From Martijn van Oosterhout.

src/backend/commands/vacuum.c

index df486de5120cbd3b74747bca07476b82a72124a8..888a50805542d14baaf511caec59eb61d6015979 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.201 2001/07/02 20:50:46 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.202 2001/07/11 18:38:07 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 #include "catalog/catalog.h"
 #include "catalog/catname.h"
 #include "catalog/index.h"
+#include "catalog/pg_index.h"
 #include "commands/vacuum.h"
+#include "executor/executor.h"
 #include "miscadmin.h"
 #include "nodes/execnodes.h"
 #include "storage/freespace.h"
 #include "storage/sinval.h"
 #include "storage/smgr.h"
+#include "tcop/pquery.h"
 #include "tcop/tcopprot.h"
 #include "utils/acl.h"
 #include "utils/builtins.h"
@@ -153,8 +156,7 @@ static VacPage copy_vac_page(VacPage vacpage);
 static void vpage_insert(VacPageList vacpagelist, VacPage vpnew);
 static void get_indices(Relation relation, int *nindices, Relation **Irel);
 static void close_indices(int nindices, Relation *Irel);
-static IndexInfo **get_index_desc(Relation onerel, int nindices,
-                          Relation *Irel);
+static bool is_partial_index(Relation indrel);
 static void *vac_bsearch(const void *key, const void *base,
                                                 size_t nelem, size_t size,
                                                 int (*compar) (const void *, const void *));
@@ -504,7 +506,7 @@ vacuum_rel(Oid relid)
                IsSystemRelationName(RelationGetRelationName(onerel)))
                reindex = true;
 
-       /* Now open indices */
+       /* Now open all indices of the relation */
        nindices = 0;
        Irel = (Relation *) NULL;
        get_indices(onerel, &nindices, &Irel);
@@ -524,8 +526,7 @@ vacuum_rel(Oid relid)
         */
        if (reindex)
        {
-               for (i = 0; i < nindices; i++)
-                       index_close(Irel[i]);
+               close_indices(nindices, Irel);
                Irel = (Relation *) NULL;
                activate_indexes_of_a_table(relid, false);
        }
@@ -553,11 +554,11 @@ vacuum_rel(Oid relid)
                /* Try to shrink heap */
                repair_frag(vacrelstats, onerel, &vacuum_pages, &fraged_pages,
                                        nindices, Irel);
+               close_indices(nindices, Irel);
        }
        else
        {
-               if (Irel != (Relation *) NULL)
-                       close_indices(nindices, Irel);
+               close_indices(nindices, Irel);
                if (vacuum_pages.num_pages > 0)
                {
                        /* Clean pages from vacuum_pages list */
@@ -1089,10 +1090,10 @@ repair_frag(VRelStats *vacrelstats, Relation onerel,
        HeapTupleData tuple,
                                newtup;
        TupleDesc       tupdesc;
-       IndexInfo **indexInfo = NULL;
-       Datum           idatum[INDEX_MAX_KEYS];
-       char            inulls[INDEX_MAX_KEYS];
-       InsertIndexResult iresult;
+       ResultRelInfo *resultRelInfo;
+       EState     *estate;
+       TupleTable      tupleTable;
+       TupleTableSlot *slot;
        VacPageListData Nvacpagelist;
        VacPage         cur_page = NULL,
                                last_vacuum_page,
@@ -1119,8 +1120,26 @@ repair_frag(VRelStats *vacrelstats, Relation onerel,
 
        tupdesc = RelationGetDescr(onerel);
 
-       if (Irel != (Relation *) NULL)          /* preparation for index' inserts */
-               indexInfo = get_index_desc(onerel, nindices, Irel);
+       /*
+        * We need a ResultRelInfo and an EState so we can use the regular
+        * executor's index-entry-making machinery.
+        */
+       resultRelInfo = makeNode(ResultRelInfo);
+       resultRelInfo->ri_RangeTableIndex = 1;          /* dummy */
+       resultRelInfo->ri_RelationDesc = onerel;
+       resultRelInfo->ri_TrigDesc = NULL;                      /* we don't fire triggers */
+
+       ExecOpenIndices(resultRelInfo);
+
+       estate = CreateExecutorState();
+       estate->es_result_relations = resultRelInfo;
+       estate->es_num_result_relations = 1;
+       estate->es_result_relation_info = resultRelInfo;
+
+       /* Set up a dummy tuple table too */
+       tupleTable = ExecCreateTupleTable(1);
+       slot = ExecAllocTableSlot(tupleTable);
+       ExecSetSlotDescriptor(slot, tupdesc, false);
 
        Nvacpagelist.num_pages = 0;
        num_fraged_pages = fraged_pages->num_pages;
@@ -1645,35 +1664,14 @@ repair_frag(VRelStats *vacrelstats, Relation onerel,
                                        if (cur_buffer != Cbuf)
                                                LockBuffer(Cbuf, BUFFER_LOCK_UNLOCK);
 
-                                       if (Irel != (Relation *) NULL)
+                                       /* Create index entries for the moved tuple */
+                                       if (resultRelInfo->ri_NumIndices > 0)
                                        {
-
-                                               /*
-                                                * XXX using CurrentMemoryContext here means
-                                                * intra-vacuum memory leak for functional
-                                                * indexes. Should fix someday.
-                                                *
-                                                * XXX This code fails to handle partial indexes!
-                                                * Probably should change it to use
-                                                * ExecOpenIndices.
-                                                */
-                                               for (i = 0; i < nindices; i++)
-                                               {
-                                                       FormIndexDatum(indexInfo[i],
-                                                                                  &newtup,
-                                                                                  tupdesc,
-                                                                                  CurrentMemoryContext,
-                                                                                  idatum,
-                                                                                  inulls);
-                                                       iresult = index_insert(Irel[i],
-                                                                                                  idatum,
-                                                                                                  inulls,
-                                                                                                  &newtup.t_self,
-                                                                                                  onerel);
-                                                       if (iresult)
-                                                               pfree(iresult);
-                                               }
+                                               ExecStoreTuple(&newtup, slot, InvalidBuffer, false);
+                                               ExecInsertIndexTuples(slot, &(newtup.t_self),
+                                                                                         estate, true);
                                        }
+
                                        WriteBuffer(cur_buffer);
                                        WriteBuffer(Cbuf);
                                }
@@ -1780,34 +1778,11 @@ repair_frag(VRelStats *vacrelstats, Relation onerel,
                        LockBuffer(buf, BUFFER_LOCK_UNLOCK);
 
                        /* insert index' tuples if needed */
-                       if (Irel != (Relation *) NULL)
+                       if (resultRelInfo->ri_NumIndices > 0)
                        {
-
-                               /*
-                                * XXX using CurrentMemoryContext here means intra-vacuum
-                                * memory leak for functional indexes. Should fix someday.
-                                *
-                                * XXX This code fails to handle partial indexes! Probably
-                                * should change it to use ExecOpenIndices.
-                                */
-                               for (i = 0; i < nindices; i++)
-                               {
-                                       FormIndexDatum(indexInfo[i],
-                                                                  &newtup,
-                                                                  tupdesc,
-                                                                  CurrentMemoryContext,
-                                                                  idatum,
-                                                                  inulls);
-                                       iresult = index_insert(Irel[i],
-                                                                                  idatum,
-                                                                                  inulls,
-                                                                                  &newtup.t_self,
-                                                                                  onerel);
-                                       if (iresult)
-                                               pfree(iresult);
-                               }
+                               ExecStoreTuple(&newtup, slot, InvalidBuffer, false);
+                               ExecInsertIndexTuples(slot, &(newtup.t_self), estate, true);
                        }
-
                }                                               /* walk along page */
 
                if (offnum < maxoff && keep_tuples > 0)
@@ -2095,15 +2070,14 @@ repair_frag(VRelStats *vacrelstats, Relation onerel,
                vacrelstats->rel_pages = blkno; /* set new number of blocks */
        }
 
-       if (Irel != (Relation *) NULL)          /* pfree index' allocations */
-       {
-               close_indices(nindices, Irel);
-               pfree(indexInfo);
-       }
-
+       /* clean up */
        pfree(vacpage);
        if (vacrelstats->vtlinks != NULL)
                pfree(vacrelstats->vtlinks);
+
+       ExecDropTupleTable(tupleTable, true);
+
+       ExecCloseIndices(resultRelInfo);
 }
 
 /*
@@ -2200,8 +2174,7 @@ vacuum_page(Relation onerel, Buffer buffer, VacPage vacpage)
 }
 
 /*
- *     _scan_index() -- scan one index relation to update statistic.
- *
+ *     scan_index() -- scan one index relation to update statistic.
  */
 static void
 scan_index(Relation indrel, double num_tuples)
@@ -2235,11 +2208,18 @@ scan_index(Relation indrel, double num_tuples)
                 RelationGetRelationName(indrel), nipages, nitups,
                 show_rusage(&ru0));
 
+       /*
+        * Check for tuple count mismatch.  If the index is partial, then
+        * it's OK for it to have fewer tuples than the heap; else we got trouble.
+        */
        if (nitups != num_tuples)
-               elog(NOTICE, "Index %s: NUMBER OF INDEX' TUPLES (%.0f) IS NOT THE SAME AS HEAP' (%.0f).\
+       {
+               if (nitups > num_tuples ||
+                       ! is_partial_index(indrel))
+                       elog(NOTICE, "Index %s: NUMBER OF INDEX' TUPLES (%.0f) IS NOT THE SAME AS HEAP' (%.0f).\
 \n\tRecreate the index.",
-                        RelationGetRelationName(indrel), nitups, num_tuples);
-
+                                RelationGetRelationName(indrel), nitups, num_tuples);
+       }
 }
 
 /*
@@ -2315,11 +2295,18 @@ vacuum_index(VacPageList vacpagelist, Relation indrel,
                 num_index_tuples - keep_tuples, tups_vacuumed,
                 show_rusage(&ru0));
 
+       /*
+        * Check for tuple count mismatch.  If the index is partial, then
+        * it's OK for it to have fewer tuples than the heap; else we got trouble.
+        */
        if (num_index_tuples != num_tuples + keep_tuples)
-               elog(NOTICE, "Index %s: NUMBER OF INDEX' TUPLES (%.0f) IS NOT THE SAME AS HEAP' (%.0f).\
+       {
+               if (num_index_tuples > num_tuples + keep_tuples ||
+                       ! is_partial_index(indrel))
+                       elog(NOTICE, "Index %s: NUMBER OF INDEX' TUPLES (%.0f) IS NOT THE SAME AS HEAP' (%.0f).\
 \n\tRecreate the index.",
-                 RelationGetRelationName(indrel), num_index_tuples, num_tuples);
-
+                                RelationGetRelationName(indrel), num_index_tuples, num_tuples);
+       }
 }
 
 /*
@@ -2640,42 +2627,34 @@ get_indices(Relation relation, int *nindices, Relation **Irel)
 static void
 close_indices(int nindices, Relation *Irel)
 {
-
        if (Irel == (Relation *) NULL)
                return;
 
        while (nindices--)
                index_close(Irel[nindices]);
        pfree(Irel);
-
 }
 
 
-/*
- * Obtain IndexInfo data for each index on the rel
- */
-static IndexInfo **
-get_index_desc(Relation onerel, int nindices, Relation *Irel)
+static bool
+is_partial_index(Relation indrel)
 {
-       IndexInfo **indexInfo;
-       int                     i;
+       bool            result;
        HeapTuple       cachetuple;
+       Form_pg_index indexStruct;
 
-       indexInfo = (IndexInfo **) palloc(nindices * sizeof(IndexInfo *));
+       cachetuple = SearchSysCache(INDEXRELID,
+                                                               ObjectIdGetDatum(RelationGetRelid(indrel)),
+                                                               0, 0, 0);
+       if (!HeapTupleIsValid(cachetuple))
+               elog(ERROR, "is_partial_index: index %u not found",
+                        RelationGetRelid(indrel));
+       indexStruct = (Form_pg_index) GETSTRUCT(cachetuple);
 
-       for (i = 0; i < nindices; i++)
-       {
-               cachetuple = SearchSysCache(INDEXRELID,
-                                                        ObjectIdGetDatum(RelationGetRelid(Irel[i])),
-                                                                       0, 0, 0);
-               if (!HeapTupleIsValid(cachetuple))
-                       elog(ERROR, "get_index_desc: index %u not found",
-                                RelationGetRelid(Irel[i]));
-               indexInfo[i] = BuildIndexInfo(cachetuple);
-               ReleaseSysCache(cachetuple);
-       }
+       result = (VARSIZE(&indexStruct->indpred) != 0);
 
-       return indexInfo;
+       ReleaseSysCache(cachetuple);
+       return result;
 }