Re: 7.4RC2 PANIC: insufficient room in FSM - Mailing list pgsql-bugs

From Tom Lane
Subject Re: 7.4RC2 PANIC: insufficient room in FSM
Date
Msg-id 17424.1069880110@sss.pgh.pa.us
Whole thread Raw
In response to 7.4RC2 PANIC: insufficient room in FSM  ("Arthur Ward" <award@dominionsciences.com>)
List pgsql-bugs
"Arthur Ward" <award@dominionsciences.com> writes:
> [ 7.4RC2 produced this: ]
> Nov 24 20:37:19 x postgres: [13904] PANIC:  insufficient room in FSM

After further study I've concluded that this means the fix I put in
place here:

2003-10-29 12:36  tgl

    * src/backend/storage/freespace/freespace.c: compact_fsm_storage()
    does need to handle the case where a relation's FSM data has to be
    both moved down and compressed.  Per report from Dror Matalon.

was incomplete, and that in fact there is no can't-happen case for this
routine.  I've applied the attached patch for 7.4.1.

            regards, tom lane


*** src/backend/storage/freespace/freespace.c.orig    Wed Oct 29 12:36:57 2003
--- src/backend/storage/freespace/freespace.c    Wed Nov 26 13:43:16 2003
***************
*** 1394,1399 ****
--- 1394,1400 ----
  compact_fsm_storage(void)
  {
      int            nextChunkIndex = 0;
+     bool        did_push = false;
      FSMRelation *fsmrel;

      for (fsmrel = FreeSpaceMap->firstRel;
***************
*** 1419,1434 ****
              newAllocPages = newAlloc * INDEXCHUNKPAGES;
          else
              newAllocPages = newAlloc * CHUNKPAGES;
-         newChunkIndex = nextChunkIndex;
-         nextChunkIndex += newAlloc;

          /*
           * Determine current size, current and new locations
           */
          curChunks = fsm_current_chunks(fsmrel);
          oldChunkIndex = fsmrel->firstChunk;
-         newLocation = FreeSpaceMap->arena + newChunkIndex * CHUNKBYTES;
          oldLocation = FreeSpaceMap->arena + oldChunkIndex * CHUNKBYTES;

          /*
           * It's possible that we have to move data down, not up, if the
--- 1420,1434 ----
              newAllocPages = newAlloc * INDEXCHUNKPAGES;
          else
              newAllocPages = newAlloc * CHUNKPAGES;

          /*
           * Determine current size, current and new locations
           */
          curChunks = fsm_current_chunks(fsmrel);
          oldChunkIndex = fsmrel->firstChunk;
          oldLocation = FreeSpaceMap->arena + oldChunkIndex * CHUNKBYTES;
+         newChunkIndex = nextChunkIndex;
+         newLocation = FreeSpaceMap->arena + newChunkIndex * CHUNKBYTES;

          /*
           * It's possible that we have to move data down, not up, if the
***************
*** 1440,1449 ****
           * more than once, so pack everything against the end of the arena
           * if so.
           *
!          * In corner cases where roundoff has affected our allocation, it's
!          * possible that we have to move down and compress our data too.
!          * Since this case is extremely infrequent, we do not try to be smart
!          * about it --- we just drop pages from the end of the rel's data.
           */
          if (newChunkIndex > oldChunkIndex)
          {
--- 1440,1455 ----
           * more than once, so pack everything against the end of the arena
           * if so.
           *
!          * In corner cases where we are on the short end of a roundoff choice
!          * that we were formerly on the long end of, it's possible that we
!          * have to move down and compress our data too.  In fact, even after
!          * pushing down the following rels, there might not be as much space
!          * as we computed for this rel above --- that would imply that some
!          * following rel(s) are also on the losing end of roundoff choices.
!          * We could handle this fairly by doing the per-rel compactions
!          * out-of-order, but that seems like way too much complexity to deal
!          * with a very infrequent corner case.  Instead, we simply drop pages
!          * from the end of the current rel's data until it fits.
           */
          if (newChunkIndex > oldChunkIndex)
          {
***************
*** 1455,1475 ****
                  fsmrel->storedPages = newAllocPages;
                  curChunks = fsm_current_chunks(fsmrel);
              }
              if (fsmrel->nextPhysical != NULL)
                  limitChunkIndex = fsmrel->nextPhysical->firstChunk;
              else
                  limitChunkIndex = FreeSpaceMap->totalChunks;
              if (newChunkIndex + curChunks > limitChunkIndex)
              {
!                 /* need to push down additional rels */
!                 push_fsm_rels_after(fsmrel);
!                 /* recheck for safety */
                  if (fsmrel->nextPhysical != NULL)
                      limitChunkIndex = fsmrel->nextPhysical->firstChunk;
                  else
                      limitChunkIndex = FreeSpaceMap->totalChunks;
                  if (newChunkIndex + curChunks > limitChunkIndex)
!                     elog(PANIC, "insufficient room in FSM");
              }
              memmove(newLocation, oldLocation, curChunks * CHUNKBYTES);
          }
--- 1461,1504 ----
                  fsmrel->storedPages = newAllocPages;
                  curChunks = fsm_current_chunks(fsmrel);
              }
+             /* is there enough space? */
              if (fsmrel->nextPhysical != NULL)
                  limitChunkIndex = fsmrel->nextPhysical->firstChunk;
              else
                  limitChunkIndex = FreeSpaceMap->totalChunks;
              if (newChunkIndex + curChunks > limitChunkIndex)
              {
!                 /* not enough space, push down following rels */
!                 if (!did_push)
!                 {
!                     push_fsm_rels_after(fsmrel);
!                     did_push = true;
!                 }
!                 /* now is there enough space? */
                  if (fsmrel->nextPhysical != NULL)
                      limitChunkIndex = fsmrel->nextPhysical->firstChunk;
                  else
                      limitChunkIndex = FreeSpaceMap->totalChunks;
                  if (newChunkIndex + curChunks > limitChunkIndex)
!                 {
!                     /* uh-oh, forcibly cut the allocation to fit */
!                     newAlloc = limitChunkIndex - newChunkIndex;
!                     /*
!                      * If newAlloc < 0 at this point, we are moving the rel's
!                      * firstChunk into territory currently assigned to a later
!                      * rel.  This is okay so long as we do not copy any data.
!                      * The rels will be back in nondecreasing firstChunk order
!                      * at completion of the compaction pass.
!                      */
!                     if (newAlloc < 0)
!                         newAlloc = 0;
!                     if (fsmrel->isIndex)
!                         newAllocPages = newAlloc * INDEXCHUNKPAGES;
!                     else
!                         newAllocPages = newAlloc * CHUNKPAGES;
!                     fsmrel->storedPages = newAllocPages;
!                     curChunks = fsm_current_chunks(fsmrel);
!                 }
              }
              memmove(newLocation, oldLocation, curChunks * CHUNKBYTES);
          }
***************
*** 1504,1509 ****
--- 1533,1539 ----
              memmove(newLocation, oldLocation, curChunks * CHUNKBYTES);
          }
          fsmrel->firstChunk = newChunkIndex;
+         nextChunkIndex += newAlloc;
      }
      Assert(nextChunkIndex <= FreeSpaceMap->totalChunks);
      FreeSpaceMap->usedChunks = nextChunkIndex;
***************
*** 1544,1551 ****
          oldChunkIndex = fsmrel->firstChunk;
          if (newChunkIndex < oldChunkIndex)
          {
!             /* trouble... */
!             elog(PANIC, "insufficient room in FSM");
          }
          else if (newChunkIndex > oldChunkIndex)
          {
--- 1574,1581 ----
          oldChunkIndex = fsmrel->firstChunk;
          if (newChunkIndex < oldChunkIndex)
          {
!             /* we're pushing down, how can it move up? */
!             elog(PANIC, "inconsistent entry sizes in FSM");
          }
          else if (newChunkIndex > oldChunkIndex)
          {
***************
*** 1758,1771 ****
  {
      int            chunkCount;

      /* Convert page count to chunk count */
      if (fsmrel->isIndex)
          chunkCount = (fsmrel->storedPages - 1) / INDEXCHUNKPAGES + 1;
      else
          chunkCount = (fsmrel->storedPages - 1) / CHUNKPAGES + 1;
-     /* Make sure storedPages==0 produces right answer */
-     if (chunkCount < 0)
-         chunkCount = 0;
      return chunkCount;
  }

--- 1788,1801 ----
  {
      int            chunkCount;

+     /* Make sure storedPages==0 produces right answer */
+     if (fsmrel->storedPages <= 0)
+         return 0;
      /* Convert page count to chunk count */
      if (fsmrel->isIndex)
          chunkCount = (fsmrel->storedPages - 1) / INDEXCHUNKPAGES + 1;
      else
          chunkCount = (fsmrel->storedPages - 1) / CHUNKPAGES + 1;
      return chunkCount;
  }

pgsql-bugs by date:

Previous
From: Bruce Momjian
Date:
Subject: Re: Fwd: Solaris build of 7.4 problem with
Next
From: Richard Huxton
Date:
Subject: Re: String index out of range - Postgresql 7.3.4, Resin & JDBC