OSDN Git Service

Performance improvement for MultiRecordFreeSpace on large relations ---
authorTom Lane <tgl@sss.pgh.pa.us>
Fri, 20 Sep 2002 19:56:01 +0000 (19:56 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Fri, 20 Sep 2002 19:56:01 +0000 (19:56 +0000)
avoid O(N^2) behavior.  Problem noted and fixed by Stephen Marshall <smarshall@wsicorp.com>,
with some help from Tom Lane.

src/backend/commands/vacuum.c
src/backend/commands/vacuumlazy.c
src/backend/storage/freespace/freespace.c
src/backend/storage/smgr/smgr.c
src/include/storage/freespace.h

index a9b2e42..d2e7e25 100644 (file)
@@ -13,7 +13,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.237 2002/09/04 20:31:16 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.238 2002/09/20 19:56:01 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1321,9 +1321,10 @@ scan_heap(VRelStats *vacrelstats, Relation onerel,
                pfree(vtlinks);
        }
 
-       elog(elevel, "Pages %u: Changed %u, reaped %u, Empty %u, New %u; \
-Tup %.0f: Vac %.0f, Keep/VTL %.0f/%u, UnUsed %.0f, MinLen %lu, MaxLen %lu; \
-Re-using: Free/Avail. Space %.0f/%.0f; EndEmpty/Avail. Pages %u/%u.\n\t%s",
+       elog(elevel, "Pages %u: Changed %u, reaped %u, Empty %u, New %u; "
+                "Tup %.0f: Vac %.0f, Keep/VTL %.0f/%u, UnUsed %.0f, MinLen %lu, "
+                "MaxLen %lu; Re-using: Free/Avail. Space %.0f/%.0f; "
+                "EndEmpty/Avail. Pages %u/%u.\n\t%s",
                 nblocks, changed_pages, vacuum_pages->num_pages, empty_pages,
                 new_pages, num_tuples, tups_vacuumed,
                 nkeep, vacrelstats->num_vtlinks,
@@ -2597,8 +2598,8 @@ scan_index(Relation indrel, double num_tuples)
        {
                if (stats->num_index_tuples > num_tuples ||
                        !vac_is_partial_index(indrel))
-                       elog(WARNING, "Index %s: NUMBER OF INDEX' TUPLES (%.0f) IS NOT THE SAME AS HEAP' (%.0f).\
-\n\tRecreate the index.",
+                       elog(WARNING, "Index %s: NUMBER OF INDEX' TUPLES (%.0f) IS NOT THE SAME AS HEAP' (%.0f)."
+                                "\n\tRecreate the index.",
                                 RelationGetRelationName(indrel),
                                 stats->num_index_tuples, num_tuples);
        }
@@ -2651,8 +2652,8 @@ vacuum_index(VacPageList vacpagelist, Relation indrel,
        {
                if (stats->num_index_tuples > num_tuples + keep_tuples ||
                        !vac_is_partial_index(indrel))
-                       elog(WARNING, "Index %s: NUMBER OF INDEX' TUPLES (%.0f) IS NOT THE SAME AS HEAP' (%.0f).\
-\n\tRecreate the index.",
+                       elog(WARNING, "Index %s: NUMBER OF INDEX' TUPLES (%.0f) IS NOT THE SAME AS HEAP' (%.0f)."
+                                "\n\tRecreate the index.",
                                 RelationGetRelationName(indrel),
                                 stats->num_index_tuples, num_tuples);
        }
@@ -2731,35 +2732,32 @@ vac_update_fsm(Relation onerel, VacPageList fraged_pages,
 {
        int                     nPages = fraged_pages->num_pages;
        int                     i;
-       BlockNumber *pages;
-       Size       *spaceAvail;
+       PageFreeSpaceInfo *pageSpaces;
 
        /* +1 to avoid palloc(0) */
-       pages = (BlockNumber *) palloc((nPages + 1) * sizeof(BlockNumber));
-       spaceAvail = (Size *) palloc((nPages + 1) * sizeof(Size));
+       pageSpaces = (PageFreeSpaceInfo *)
+               palloc((nPages + 1) * sizeof(PageFreeSpaceInfo));
 
        for (i = 0; i < nPages; i++)
        {
-               pages[i] = fraged_pages->pagedesc[i]->blkno;
-               spaceAvail[i] = fraged_pages->pagedesc[i]->free;
+               pageSpaces[i].blkno = fraged_pages->pagedesc[i]->blkno;
+               pageSpaces[i].avail = fraged_pages->pagedesc[i]->free;
 
                /*
                 * fraged_pages may contain entries for pages that we later
                 * decided to truncate from the relation; don't enter them into
-                * the map!
+                * the free space map!
                 */
-               if (pages[i] >= rel_pages)
+               if (pageSpaces[i].blkno >= rel_pages)
                {
                        nPages = i;
                        break;
                }
        }
 
-       MultiRecordFreeSpace(&onerel->rd_node,
-                                                0, MaxBlockNumber,
-                                                nPages, pages, spaceAvail);
-       pfree(pages);
-       pfree(spaceAvail);
+       MultiRecordFreeSpace(&onerel->rd_node, 0, nPages, pageSpaces);
+
+       pfree(pageSpaces);
 }
 
 /* Copy a VacPage structure */
index 023472e..9495301 100644 (file)
@@ -31,7 +31,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/commands/vacuumlazy.c,v 1.19 2002/09/04 20:31:17 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/commands/vacuumlazy.c,v 1.20 2002/09/20 19:56:01 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -87,9 +87,8 @@ typedef struct LVRelStats
        /* We use a simple array until it fills up, then convert to heap */
        bool            fs_is_heap;             /* are we using heap organization? */
        int                     num_free_pages; /* current # of entries */
-       int                     max_free_pages; /* # slots allocated in arrays */
-       BlockNumber *free_pages;        /* array or heap of block numbers */
-       Size       *free_spaceavail;    /* array or heap of available space */
+       int                     max_free_pages; /* # slots allocated in array */
+       PageFreeSpaceInfo *free_pages;  /* array or heap of blkno/avail */
 } LVRelStats;
 
 
@@ -119,6 +118,7 @@ static bool lazy_tid_reaped(ItemPointer itemptr, void *state);
 static bool dummy_tid_reaped(ItemPointer itemptr, void *state);
 static void lazy_update_fsm(Relation onerel, LVRelStats *vacrelstats);
 static int     vac_cmp_itemptr(const void *left, const void *right);
+static int     vac_cmp_page_spaces(const void *left, const void *right);
 
 
 /*
@@ -432,8 +432,7 @@ lazy_scan_heap(Relation onerel, LVRelStats *vacrelstats,
                        lazy_scan_index(Irel[i], vacrelstats);
        }
 
-       elog(elevel, "Pages %u: Changed %u, Empty %u; \
-Tup %.0f: Vac %.0f, Keep %.0f, UnUsed %.0f.\n\tTotal %s",
+       elog(elevel, "Pages %u: Changed %u, Empty %u; Tup %.0f: Vac %.0f, Keep %.0f, UnUsed %.0f.\n\tTotal %s",
                 nblocks, changed_pages, empty_pages,
                 num_tuples, tups_vacuumed, nkeep, nunused,
                 vac_show_rusage(&ru0));
@@ -662,8 +661,7 @@ lazy_truncate_heap(Relation onerel, LVRelStats *vacrelstats)
 {
        BlockNumber old_rel_pages = vacrelstats->rel_pages;
        BlockNumber new_rel_pages;
-       BlockNumber *pages;
-       Size       *spaceavail;
+       PageFreeSpaceInfo *pageSpaces;
        int                     n;
        int                     i,
                                j;
@@ -736,20 +734,20 @@ lazy_truncate_heap(Relation onerel, LVRelStats *vacrelstats)
         * Drop free-space info for removed blocks; these must not get entered
         * into the FSM!
         */
-       pages = vacrelstats->free_pages;
-       spaceavail = vacrelstats->free_spaceavail;
+       pageSpaces = vacrelstats->free_pages;
        n = vacrelstats->num_free_pages;
        j = 0;
        for (i = 0; i < n; i++)
        {
-               if (pages[i] < new_rel_pages)
+               if (pageSpaces[i].blkno < new_rel_pages)
                {
-                       pages[j] = pages[i];
-                       spaceavail[j] = spaceavail[i];
+                       pageSpaces[j] = pageSpaces[i];
                        j++;
                }
        }
        vacrelstats->num_free_pages = j;
+       /* We destroyed the heap ordering, so mark array unordered */
+       vacrelstats->fs_is_heap = false;
 
        /*
         * We keep the exclusive lock until commit (perhaps not necessary)?
@@ -913,10 +911,8 @@ lazy_space_alloc(LVRelStats *vacrelstats, BlockNumber relblocks)
        vacrelstats->fs_is_heap = false;
        vacrelstats->num_free_pages = 0;
        vacrelstats->max_free_pages = maxpages;
-       vacrelstats->free_pages = (BlockNumber *)
-               palloc(maxpages * sizeof(BlockNumber));
-       vacrelstats->free_spaceavail = (Size *)
-               palloc(maxpages * sizeof(Size));
+       vacrelstats->free_pages = (PageFreeSpaceInfo *)
+               palloc(maxpages * sizeof(PageFreeSpaceInfo));
 }
 
 /*
@@ -946,8 +942,7 @@ lazy_record_free_space(LVRelStats *vacrelstats,
                                           BlockNumber page,
                                           Size avail)
 {
-       BlockNumber *pages;
-       Size       *spaceavail;
+       PageFreeSpaceInfo *pageSpaces;
        int                     n;
 
        /* Ignore pages with little free space */
@@ -955,15 +950,14 @@ lazy_record_free_space(LVRelStats *vacrelstats,
                return;
 
        /* Copy pointers to local variables for notational simplicity */
-       pages = vacrelstats->free_pages;
-       spaceavail = vacrelstats->free_spaceavail;
+       pageSpaces = vacrelstats->free_pages;
        n = vacrelstats->max_free_pages;
 
        /* If we haven't filled the array yet, just keep adding entries */
        if (vacrelstats->num_free_pages < n)
        {
-               pages[vacrelstats->num_free_pages] = page;
-               spaceavail[vacrelstats->num_free_pages] = avail;
+               pageSpaces[vacrelstats->num_free_pages].blkno = page;
+               pageSpaces[vacrelstats->num_free_pages].avail = avail;
                vacrelstats->num_free_pages++;
                return;
        }
@@ -971,7 +965,7 @@ lazy_record_free_space(LVRelStats *vacrelstats,
        /*----------
         * The rest of this routine works with "heap" organization of the
         * free space arrays, wherein we maintain the heap property
-        *                      spaceavail[(j-1) div 2] <= spaceavail[j]  for 0 < j < n.
+        *                      avail[(j-1) div 2] <= avail[j]  for 0 < j < n.
         * In particular, the zero'th element always has the smallest available
         * space and can be discarded to make room for a new page with more space.
         * See Knuth's discussion of heap-based priority queues, sec 5.2.3;
@@ -991,8 +985,8 @@ lazy_record_free_space(LVRelStats *vacrelstats,
 
                while (--l >= 0)
                {
-                       BlockNumber R = pages[l];
-                       Size            K = spaceavail[l];
+                       BlockNumber R = pageSpaces[l].blkno;
+                       Size            K = pageSpaces[l].avail;
                        int                     i;              /* i is where the "hole" is */
 
                        i = l;
@@ -1002,23 +996,22 @@ lazy_record_free_space(LVRelStats *vacrelstats,
 
                                if (j >= n)
                                        break;
-                               if (j + 1 < n && spaceavail[j] > spaceavail[j + 1])
+                               if (j + 1 < n && pageSpaces[j].avail > pageSpaces[j + 1].avail)
                                        j++;
-                               if (K <= spaceavail[j])
+                               if (K <= pageSpaces[j].avail)
                                        break;
-                               pages[i] = pages[j];
-                               spaceavail[i] = spaceavail[j];
+                               pageSpaces[i] = pageSpaces[j];
                                i = j;
                        }
-                       pages[i] = R;
-                       spaceavail[i] = K;
+                       pageSpaces[i].blkno = R;
+                       pageSpaces[i].avail = K;
                }
 
                vacrelstats->fs_is_heap = true;
        }
 
        /* If new page has more than zero'th entry, insert it into heap */
-       if (avail > spaceavail[0])
+       if (avail > pageSpaces[0].avail)
        {
                /*
                 * Notionally, we replace the zero'th entry with the new data, and
@@ -1034,16 +1027,15 @@ lazy_record_free_space(LVRelStats *vacrelstats,
 
                        if (j >= n)
                                break;
-                       if (j + 1 < n && spaceavail[j] > spaceavail[j + 1])
+                       if (j + 1 < n && pageSpaces[j].avail > pageSpaces[j + 1].avail)
                                j++;
-                       if (avail <= spaceavail[j])
+                       if (avail <= pageSpaces[j].avail)
                                break;
-                       pages[i] = pages[j];
-                       spaceavail[i] = spaceavail[j];
+                       pageSpaces[i] = pageSpaces[j];
                        i = j;
                }
-               pages[i] = page;
-               spaceavail[i] = avail;
+               pageSpaces[i].blkno = page;
+               pageSpaces[i].avail = avail;
        }
 }
 
@@ -1085,16 +1077,17 @@ dummy_tid_reaped(ItemPointer itemptr, void *state)
 static void
 lazy_update_fsm(Relation onerel, LVRelStats *vacrelstats)
 {
+       PageFreeSpaceInfo *pageSpaces = vacrelstats->free_pages;
+       int                     nPages = vacrelstats->num_free_pages;
+
        /*
-        * Since MultiRecordFreeSpace doesn't currently impose any
-        * restrictions on the ordering of the input, we can just pass it the
-        * arrays as-is, whether they are in heap or linear order.
+        * Sort data into order, as required by MultiRecordFreeSpace.
         */
-       MultiRecordFreeSpace(&onerel->rd_node,
-                                                0, MaxBlockNumber,
-                                                vacrelstats->num_free_pages,
-                                                vacrelstats->free_pages,
-                                                vacrelstats->free_spaceavail);
+       if (nPages > 1)
+               qsort(pageSpaces, nPages, sizeof(PageFreeSpaceInfo),
+                         vac_cmp_page_spaces);
+
+       MultiRecordFreeSpace(&onerel->rd_node, 0, nPages, pageSpaces);
 }
 
 /*
@@ -1126,3 +1119,16 @@ vac_cmp_itemptr(const void *left, const void *right)
 
        return 0;
 }
+
+static int
+vac_cmp_page_spaces(const void *left, const void *right)
+{
+       PageFreeSpaceInfo *linfo = (PageFreeSpaceInfo *) left;
+       PageFreeSpaceInfo *rinfo = (PageFreeSpaceInfo *) right;
+
+       if (linfo->blkno < rinfo->blkno)
+               return -1;
+       else if (linfo->blkno > rinfo->blkno)
+               return 1;
+       return 0;
+}
index 7dc91a4..b8fe0a3 100644 (file)
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/storage/freespace/freespace.c,v 1.13 2002/09/04 20:31:25 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/storage/freespace/freespace.c,v 1.14 2002/09/20 19:56:01 tgl Exp $
  *
  *
  * NOTES:
@@ -99,6 +99,7 @@ struct FSMRelation
                                                                 * about */
        int                     numChunks;              /* number of FSMChunks allocated to rel */
        FSMChunk   *relChunks;          /* linked list of page info chunks */
+       FSMChunk   *lastChunk;          /* last chunk in linked list */
 };
 
 /*
@@ -142,6 +143,7 @@ static bool lookup_fsm_page_entry(FSMRelation *fsmrel, BlockNumber page,
 static bool insert_fsm_page_entry(FSMRelation *fsmrel,
                                          BlockNumber page, Size spaceAvail,
                                          FSMChunk *chunk, int chunkRelIndex);
+static bool append_fsm_chunk(FSMRelation *fsmrel);
 static bool push_fsm_page_entry(BlockNumber page, Size spaceAvail,
                                        FSMChunk *chunk, int chunkRelIndex);
 static void delete_fsm_page_entry(FSMRelation *fsmrel, FSMChunk *chunk,
@@ -359,21 +361,20 @@ RecordAndGetPageWithFreeSpace(RelFileNode *rel,
  * MultiRecordFreeSpace - record available-space info about multiple pages
  *             of a relation in one call.
  *
- * First, if minPage <= maxPage, the FSM must discard any entries it has for
- * pages in that page number range (inclusive).  This allows obsolete info
- * to be discarded.  Second, if nPages > 0, record the page numbers and free
- * space amounts in the given arrays.  As with RecordFreeSpace, the FSM is at
- * liberty to discard some of the information. However, it *must* discard
- * previously stored info in the minPage..maxPage range (for example, this
- * case is used to remove info about deleted pages during relation truncation).
+ * First, the FSM must discard any entries it has for pages >= minPage.
+ * This allows obsolete info to be discarded (for example, it is used when
+ * truncating a relation).  Any entries before minPage should be kept.
+ *
+ * Second, if nPages > 0, record the page numbers and free space amounts in
+ * the given pageSpaces[] array.  As with RecordFreeSpace, the FSM is at
+ * liberty to discard some of this information.  The pageSpaces[] array must
+ * be sorted in order by blkno, and may not contain entries before minPage.
  */
 void
 MultiRecordFreeSpace(RelFileNode *rel,
                                         BlockNumber minPage,
-                                        BlockNumber maxPage,
                                         int nPages,
-                                        BlockNumber *pages,
-                                        Size *spaceAvail)
+                                        PageFreeSpaceInfo *pageSpaces)
 {
        FSMRelation *fsmrel;
        int                     i;
@@ -383,59 +384,64 @@ MultiRecordFreeSpace(RelFileNode *rel,
        if (fsmrel)
        {
                /*
-                * Remove entries in specified range
+                * Remove entries >= minPage
                 */
-               if (minPage <= maxPage)
+               FSMChunk   *chunk;
+               int                     chunkRelIndex;
+
+               /* Use lookup to locate first entry >= minPage */
+               lookup_fsm_page_entry(fsmrel, minPage, &chunk, &chunkRelIndex);
+               /* Set free space to 0 for each page >= minPage */
+               while (chunk)
                {
-                       FSMChunk   *chunk;
-                       int                     chunkRelIndex;
-                       bool            done;
-
-                       /* Use lookup to locate first entry >= minPage */
-                       lookup_fsm_page_entry(fsmrel, minPage, &chunk, &chunkRelIndex);
-                       /* Set free space to 0 for each page within range */
-                       done = false;
-                       while (chunk && !done)
-                       {
-                               int                     numPages = chunk->numPages;
+                       int                     numPages = chunk->numPages;
 
-                               for (; chunkRelIndex < numPages; chunkRelIndex++)
-                               {
-                                       if (chunk->pages[chunkRelIndex] > maxPage)
-                                       {
-                                               done = true;
-                                               break;
-                                       }
-                                       chunk->bytes[chunkRelIndex] = 0;
-                               }
-                               chunk = chunk->next;
-                               chunkRelIndex = 0;
-                       }
-                       /* Now compact out the zeroed entries */
-                       compact_fsm_page_list(fsmrel);
+                       for (i = chunkRelIndex; i < numPages; i++)
+                               chunk->bytes[i] = 0;
+                       chunk = chunk->next;
+                       chunkRelIndex = 0;
                }
+               /* Now compact out the zeroed entries, along with any other junk */
+               compact_fsm_page_list(fsmrel);
 
                /*
                 * Add new entries, if appropriate.
                 *
-                * XXX we could probably be smarter about this than doing it
-                * completely separately for each one.  FIXME later.
-                *
-                * One thing we can do is short-circuit the process entirely if a
-                * page (a) has too little free space to be recorded, and (b) is
-                * within the minPage..maxPage range --- then we deleted any old
-                * entry above, and we aren't going to make a new one. This is
-                * particularly useful since in most cases, all the passed pages
-                * will in fact be in the minPage..maxPage range.
+                * This can be much cheaper than a full fsm_record_free_space()
+                * call because we know we are appending to the end of the relation.
                 */
                for (i = 0; i < nPages; i++)
                {
-                       BlockNumber page = pages[i];
-                       Size            avail = spaceAvail[i];
+                       BlockNumber page = pageSpaces[i].blkno;
+                       Size            avail = pageSpaces[i].avail;
+                       FSMChunk   *chunk;
+
+                       /* Check caller provides sorted data */
+                       if (i > 0 ? (page <= pageSpaces[i-1].blkno) : (page < minPage))
+                               elog(ERROR, "MultiRecordFreeSpace: data not in page order");
+
+                       /* Ignore pages too small to fit */
+                       if (avail < fsmrel->threshold)
+                               continue;
+
+                       /* Get another chunk if needed */
+                       /* We may need to loop if acquire_fsm_free_space() fails */
+                       while ((chunk = fsmrel->lastChunk) == NULL ||
+                                  chunk->numPages >= CHUNKPAGES)
+                       {
+                               if (!append_fsm_chunk(fsmrel))
+                                       acquire_fsm_free_space();
+                       }
+
+                       /* Recheck in case threshold was raised by acquire */
+                       if (avail < fsmrel->threshold)
+                               continue;
 
-                       if (avail >= fsmrel->threshold ||
-                               page < minPage || page > maxPage)
-                               fsm_record_free_space(fsmrel, page, avail);
+                       /* Okay to store */
+                       chunk->pages[chunk->numPages] = page;
+                       chunk->bytes[chunk->numPages] = (ItemLength) avail;
+                       chunk->numPages++;
+                       fsmrel->numPages++;
                }
        }
        LWLockRelease(FreeSpaceLock);
@@ -538,6 +544,7 @@ create_fsm_rel(RelFileNode *rel)
                fsmrel->numPages = 0;
                fsmrel->numChunks = 0;
                fsmrel->relChunks = NULL;
+               fsmrel->lastChunk = NULL;
                /* Discard lowest-priority existing rel, if we are over limit */
                if (FreeSpaceMap->numRels >= MaxFSMRelations)
                        delete_fsm_rel(FreeSpaceMap->relListTail);
@@ -847,29 +854,12 @@ insert_fsm_page_entry(FSMRelation *fsmrel, BlockNumber page, Size spaceAvail,
                if (fsmrel->numPages >= fsmrel->numChunks * CHUNKPAGES)
                {
                        /* No free space within chunk list, so need another chunk */
-                       FSMChunk   *newChunk;
-
-                       if ((newChunk = FreeSpaceMap->freeChunks) == NULL)
+                       if (!append_fsm_chunk(fsmrel))
                                return false;   /* can't do it */
-                       FreeSpaceMap->freeChunks = newChunk->next;
-                       FreeSpaceMap->numFreeChunks--;
-                       newChunk->next = NULL;
-                       newChunk->numPages = 0;
-                       if (fsmrel->relChunks == NULL)
-                               fsmrel->relChunks = newChunk;
-                       else
-                       {
-                               FSMChunk   *priorChunk = fsmrel->relChunks;
-
-                               while (priorChunk->next != NULL)
-                                       priorChunk = priorChunk->next;
-                               priorChunk->next = newChunk;
-                       }
-                       fsmrel->numChunks++;
                        if (chunk == NULL)
                        {
                                /* Original search found that new page belongs at end */
-                               chunk = newChunk;
+                               chunk = fsmrel->lastChunk;
                                chunkRelIndex = 0;
                        }
                }
@@ -901,6 +891,38 @@ insert_fsm_page_entry(FSMRelation *fsmrel, BlockNumber page, Size spaceAvail,
 }
 
 /*
+ * Add one chunk to a FSMRelation's chunk list, if possible.
+ *
+ * Returns TRUE if successful, FALSE if no space available.  Note that on
+ * success, the new chunk is easily accessible via fsmrel->lastChunk.
+ */
+static bool
+append_fsm_chunk(FSMRelation *fsmrel)
+{
+       FSMChunk   *newChunk;
+
+       /* Remove a chunk from the freelist */
+       if ((newChunk = FreeSpaceMap->freeChunks) == NULL)
+               return false;                   /* can't do it */
+       FreeSpaceMap->freeChunks = newChunk->next;
+       FreeSpaceMap->numFreeChunks--;
+
+       /* Initialize chunk to empty */
+       newChunk->next = NULL;
+       newChunk->numPages = 0;
+
+       /* Link it into FSMRelation */
+       if (fsmrel->relChunks == NULL)
+               fsmrel->relChunks = newChunk;
+       else
+               fsmrel->lastChunk->next = newChunk;
+       fsmrel->lastChunk = newChunk;
+       fsmrel->numChunks++;
+
+       return true;
+}
+
+/*
  * Auxiliary routine for insert_fsm_page_entry: try to push entries to the
  * right to insert at chunk/chunkRelIndex.     Return TRUE if successful.
  * Note that the FSMRelation's own fields are not updated.
@@ -1016,6 +1038,7 @@ compact_fsm_page_list(FSMRelation *fsmrel)
                fsmrel->numPages = 0;
                fsmrel->numChunks = 0;
                fsmrel->relChunks = NULL;
+               fsmrel->lastChunk = NULL;
                free_chunk_chain(dstChunk);
        }
        else
@@ -1026,6 +1049,7 @@ compact_fsm_page_list(FSMRelation *fsmrel)
                dstChunk->numPages = dstIndex;
                free_chunk_chain(dstChunk->next);
                dstChunk->next = NULL;
+               fsmrel->lastChunk = dstChunk;
        }
 }
 
index 8b05fdf..b20873b 100644 (file)
@@ -11,7 +11,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/storage/smgr/smgr.c,v 1.60 2002/09/04 20:31:26 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/storage/smgr/smgr.c,v 1.61 2002/09/20 19:56:01 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -410,9 +410,7 @@ smgrtruncate(int16 which, Relation reln, BlockNumber nblocks)
                 * for the about-to-be-deleted blocks.  We want to be sure it
                 * won't return bogus block numbers later on.
                 */
-               MultiRecordFreeSpace(&reln->rd_node,
-                                                        nblocks, MaxBlockNumber,
-                                                        0, NULL, NULL);
+               MultiRecordFreeSpace(&reln->rd_node, nblocks, 0, NULL);
 
                newblks = (*(smgrsw[which].smgr_truncate)) (reln, nblocks);
                if (newblks == InvalidBlockNumber)
index 339759f..428898b 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: freespace.h,v 1.7 2002/06/20 20:29:52 momjian Exp $
+ * $Id: freespace.h,v 1.8 2002/09/20 19:56:01 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 #include "storage/relfilenode.h"
 
 
+/*
+ * exported types
+ */
+typedef struct PageFreeSpaceInfo
+{
+       BlockNumber             blkno;          /* which page in relation */
+       Size                    avail;          /* space available on this page */
+} PageFreeSpaceInfo;
+
+
 extern int     MaxFSMRelations;
 extern int     MaxFSMPages;
 
@@ -37,10 +47,8 @@ extern BlockNumber RecordAndGetPageWithFreeSpace(RelFileNode *rel,
                                                          Size spaceNeeded);
 extern void MultiRecordFreeSpace(RelFileNode *rel,
                                         BlockNumber minPage,
-                                        BlockNumber maxPage,
                                         int nPages,
-                                        BlockNumber *pages,
-                                        Size *spaceAvail);
+                                        PageFreeSpaceInfo *pageSpaces);
 extern void FreeSpaceMapForgetRel(RelFileNode *rel);
 extern void FreeSpaceMapForgetDatabase(Oid dbid);