Re: reldesc does not exit - Mailing list pgsql-general

From Tom Lane
Subject Re: reldesc does not exit
Date
Msg-id 6542.970340224@sss.pgh.pa.us
Whole thread Raw
In response to Re: reldesc does not exit  (Tom Lane <tgl@sss.pgh.pa.us>)
List pgsql-general
I wrote:
> "Darrin Ladd" <dladd@newfoundcomm.net> writes:
>> Uh oh, yes, I do get the same notice when truncating other tables, even
>> tables not in the same database :(

> OK, so it's not so data-dependent after all.  Sounds like it's probably
> a flat-out bug associated with 64-bit-int machines.

No, I was guessing wrong.  Turns out it's a fundamental bug in TRUNCATE
that could show up on any machine, depending on chance behavior of
memory allocation, with consequences up to and including backend
coredump.  (TRUNCATE on a table with indexes would fail unless closing and
re-opening the relcache entry recreated the relcache entry at exactly
the same memory address it had before :-(.)

Apparently the RedHat LinuxAlpha distro is somewhat more likely than
other platforms to move things around in memory, for reasons not
immediately obvious; else we'd have seen this sooner on other machines.

I have fixed this for 7.0.3, due out soon.  If you need a fix now
the patch against 7.0.2 is attached.

            regards, tom lane

*** heap.c.orig    Thu May 25 17:25:32 2000
--- heap.c    Sat Sep 30 14:41:51 2000
***************
*** 1091,1134 ****
   * RelationTruncateIndexes - This routine is used to truncate all
   * indices associated with the heap relation to zero tuples.
   * The routine will truncate and then reconstruct the indices on
!  * the relation specified by the heapRelation parameter.
   * --------------------------------
   */
  static void
! RelationTruncateIndexes(Relation heapRelation)
  {
!     Relation    indexRelation,
!                 currentIndex;
      ScanKeyData entry;
      HeapScanDesc scan;
!     HeapTuple    indexTuple,
!                 procTuple,
!                 classTuple;
!     Form_pg_index index;
!     Oid            heapId,
!                 indexId,
!                 procId,
!                 accessMethodId;
!     Node       *oldPred = NULL;
!     PredInfo   *predInfo;
!     List       *cnfPred = NULL;
!     AttrNumber *attributeNumberA;
!     FuncIndexInfo fInfo,
!                *funcInfo = NULL;
!     int            i,
!                 numberOfAttributes;
!     char       *predString;
!
!     heapId = RelationGetRelid(heapRelation);
!
!     /* Scan pg_index to find indexes on heapRelation */

      indexRelation = heap_openr(IndexRelationName, AccessShareLock);
      ScanKeyEntryInitialize(&entry, 0, Anum_pg_index_indrelid, F_OIDEQ,
                             ObjectIdGetDatum(heapId));
      scan = heap_beginscan(indexRelation, false, SnapshotNow, 1, &entry);
      while (HeapTupleIsValid(indexTuple = heap_getnext(scan, 0)))
      {

          /*
           * For each index, fetch index attributes so we can apply
--- 1091,1132 ----
   * RelationTruncateIndexes - This routine is used to truncate all
   * indices associated with the heap relation to zero tuples.
   * The routine will truncate and then reconstruct the indices on
!  * the relation specified by the heapId parameter.
   * --------------------------------
   */
  static void
! RelationTruncateIndexes(Oid heapId)
  {
!     Relation    indexRelation;
      ScanKeyData entry;
      HeapScanDesc scan;
!     HeapTuple    indexTuple;

+     /* Scan pg_index to find indexes on specified heap */
      indexRelation = heap_openr(IndexRelationName, AccessShareLock);
      ScanKeyEntryInitialize(&entry, 0, Anum_pg_index_indrelid, F_OIDEQ,
                             ObjectIdGetDatum(heapId));
      scan = heap_beginscan(indexRelation, false, SnapshotNow, 1, &entry);
+
      while (HeapTupleIsValid(indexTuple = heap_getnext(scan, 0)))
      {
+         Relation    heapRelation,
+                     currentIndex;
+         HeapTuple    procTuple,
+                     classTuple;
+         Form_pg_index index;
+         Oid            indexId,
+                     procId,
+                     accessMethodId;
+         Node       *oldPred = NULL;
+         PredInfo   *predInfo;
+         List       *cnfPred = NULL;
+         AttrNumber *attributeNumberA;
+         FuncIndexInfo fInfo,
+                    *funcInfo = NULL;
+         int            i,
+                     numberOfAttributes;
+         char       *predString;

          /*
           * For each index, fetch index attributes so we can apply
***************
*** 1183,1192 ****
              elog(ERROR, "RelationTruncateIndexes: index access method not found");
          accessMethodId = ((Form_pg_class) GETSTRUCT(classTuple))->relam;

          /* Open our index relation */
          currentIndex = index_open(indexId);
-         if (currentIndex == NULL)
-             elog(ERROR, "RelationTruncateIndexes: can't open index relation");

          /* Obtain exclusive lock on it, just to be sure */
          LockRelation(currentIndex, AccessExclusiveLock);
--- 1181,1197 ----
              elog(ERROR, "RelationTruncateIndexes: index access method not found");
          accessMethodId = ((Form_pg_class) GETSTRUCT(classTuple))->relam;

+         /*
+          * We have to re-open the heap rel each time through this loop
+          * because index_build will close it again.  We need grab no lock,
+          * however, because we assume heap_truncate is holding an exclusive
+          * lock on the heap rel.
+          */
+         heapRelation = heap_open(heapId, NoLock);
+         Assert(heapRelation != NULL);
+
          /* Open our index relation */
          currentIndex = index_open(indexId);

          /* Obtain exclusive lock on it, just to be sure */
          LockRelation(currentIndex, AccessExclusiveLock);
***************
*** 1205,1220 ****
          InitIndexStrategy(numberOfAttributes, currentIndex, accessMethodId);
          index_build(heapRelation, currentIndex, numberOfAttributes,
                      attributeNumberA, 0, NULL, funcInfo, predInfo);
-
          /*
           * index_build will close both the heap and index relations (but
!          * not give up the locks we hold on them).    That's fine for the
!          * index, but we need to open the heap again.  We need no new
!          * lock, since this backend still has the exclusive lock grabbed
!          * by heap_truncate.
           */
-         heapRelation = heap_open(heapId, NoLock);
-         Assert(heapRelation != NULL);
      }

      /* Complete the scan and close pg_index */
--- 1210,1219 ----
          InitIndexStrategy(numberOfAttributes, currentIndex, accessMethodId);
          index_build(heapRelation, currentIndex, numberOfAttributes,
                      attributeNumberA, 0, NULL, funcInfo, predInfo);
          /*
           * index_build will close both the heap and index relations (but
!          * not give up the locks we hold on them).
           */
      }

      /* Complete the scan and close pg_index */
***************
*** 1270,1286 ****
      rel->rd_nblocks = 0;

      /* If this relation has indexes, truncate the indexes too */
!     RelationTruncateIndexes(rel);

      /*
       * Close the relation, but keep exclusive lock on it until commit.
       */
      heap_close(rel, NoLock);
-
-     /*
-      * Is this really necessary?
-      */
-     RelationForgetRelation(rid);
  }


--- 1269,1280 ----
      rel->rd_nblocks = 0;

      /* If this relation has indexes, truncate the indexes too */
!     RelationTruncateIndexes(rid);

      /*
       * Close the relation, but keep exclusive lock on it until commit.
       */
      heap_close(rel, NoLock);
  }



pgsql-general by date:

Previous
From: Stephan Szabo
Date:
Subject: Re: Checking number of entries
Next
From: Philip Warner
Date:
Subject: Re: Checking number of entries