Re: REL_12_STABLE crashing with assertion failure in ExtractReplicaIdentity - Mailing list pgsql-hackers

From Tom Lane
Subject Re: REL_12_STABLE crashing with assertion failure in ExtractReplicaIdentity
Date
Msg-id 4422.1567373469@sss.pgh.pa.us
Whole thread Raw
In response to Re: REL_12_STABLE crashing with assertion failure in ExtractReplicaIdentity  (Tom Lane <tgl@sss.pgh.pa.us>)
Responses Re: REL_12_STABLE crashing with assertion failure in ExtractReplicaIdentity
List pgsql-hackers
I wrote:
> As far as 4) goes, I think the code in ExtractReplicaIdentity is pretty
> duff anyway, because it doesn't bother to check for the defined failure
> return for RelationIdGetRelation.  But if we're concerned about the
> cost of recalculating this stuff per-row, couldn't we cache it a little
> better?  It should be safe to assume the set of index columns isn't
> changing intra-query.
> ... in fact, isn't all the infrastructure for that present already?
> Why is this code looking directly at the index at all, rather than
> using the relcache's rd_idattr bitmap?

Here's a proposed patch along those lines.  It fixes Hadi's original
crash case and passes check-world.

I'm a bit suspicious of the exclusion for idattrs being empty, but
if I remove that, some of the contrib/test_decoding test results
change.  Anybody want to comment on that?  If that's actually an
expected situation, why is there an elog(DEBUG) in that path?

            regards, tom lane

diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c
index cb811d3..8a3c7dc 100644
--- a/src/backend/access/heap/heapam.c
+++ b/src/backend/access/heap/heapam.c
@@ -7594,18 +7594,20 @@ log_heap_new_cid(Relation relation, HeapTuple tup)
  *
  * Returns NULL if there's no need to log an identity or if there's no suitable
  * key in the Relation relation.
+ *
+ * *copy is set to true if the returned tuple is a modified copy rather than
+ * the same tuple that was passed in.
  */
 static HeapTuple
-ExtractReplicaIdentity(Relation relation, HeapTuple tp, bool key_changed, bool *copy)
+ExtractReplicaIdentity(Relation relation, HeapTuple tp, bool key_changed,
+                       bool *copy)
 {
     TupleDesc    desc = RelationGetDescr(relation);
-    Oid            replidindex;
-    Relation    idx_rel;
     char        replident = relation->rd_rel->relreplident;
-    HeapTuple    key_tuple = NULL;
+    Bitmapset  *idattrs;
+    HeapTuple    key_tuple;
     bool        nulls[MaxHeapAttributeNumber];
     Datum        values[MaxHeapAttributeNumber];
-    int            natt;

     *copy = false;

@@ -7624,7 +7626,7 @@ ExtractReplicaIdentity(Relation relation, HeapTuple tp, bool key_changed, bool *
         if (HeapTupleHasExternal(tp))
         {
             *copy = true;
-            tp = toast_flatten_tuple(tp, RelationGetDescr(relation));
+            tp = toast_flatten_tuple(tp, desc);
         }
         return tp;
     }
@@ -7633,41 +7635,37 @@ ExtractReplicaIdentity(Relation relation, HeapTuple tp, bool key_changed, bool *
     if (!key_changed)
         return NULL;

-    /* find the replica identity index */
-    replidindex = RelationGetReplicaIndex(relation);
-    if (!OidIsValid(replidindex))
+    /* find out the replica identity columns */
+    idattrs = RelationGetIndexAttrBitmap(relation,
+                                         INDEX_ATTR_BITMAP_IDENTITY_KEY);
+
+    if (bms_is_empty(idattrs))
     {
         elog(DEBUG4, "could not find configured replica identity for table \"%s\"",
              RelationGetRelationName(relation));
         return NULL;
     }

-    idx_rel = RelationIdGetRelation(replidindex);
-
-    Assert(CheckRelationLockedByMe(idx_rel, AccessShareLock, true));
-
-    /* deform tuple, so we have fast access to columns */
-    heap_deform_tuple(tp, desc, values, nulls);
-
-    /* set all columns to NULL, regardless of whether they actually are */
-    memset(nulls, 1, sizeof(nulls));
-
     /*
-     * Now set all columns contained in the index to NOT NULL, they cannot
-     * currently be NULL.
+     * Construct a new tuple containing only the replica identity columns,
+     * with nulls elsewhere.  While we're at it, assert that the replica
+     * identity columns aren't null.
      */
-    for (natt = 0; natt < IndexRelationGetNumberOfKeyAttributes(idx_rel); natt++)
-    {
-        int            attno = idx_rel->rd_index->indkey.values[natt];
+    heap_deform_tuple(tp, desc, values, nulls);

-        if (attno < 0)
-            elog(ERROR, "system column in index");
-        nulls[attno - 1] = false;
+    for (int i = 0; i < desc->natts; i++)
+    {
+        if (bms_is_member(i + 1 - FirstLowInvalidHeapAttributeNumber,
+                          idattrs))
+            Assert(!nulls[i]);
+        else
+            nulls[i] = true;
     }

     key_tuple = heap_form_tuple(desc, values, nulls);
     *copy = true;
-    RelationClose(idx_rel);
+
+    bms_free(idattrs);

     /*
      * If the tuple, which by here only contains indexed columns, still has
@@ -7680,7 +7678,7 @@ ExtractReplicaIdentity(Relation relation, HeapTuple tp, bool key_changed, bool *
     {
         HeapTuple    oldtup = key_tuple;

-        key_tuple = toast_flatten_tuple(oldtup, RelationGetDescr(relation));
+        key_tuple = toast_flatten_tuple(oldtup, desc);
         heap_freetuple(oldtup);
     }


pgsql-hackers by date:

Previous
From: Tom Lane
Date:
Subject: Re: REL_12_STABLE crashing with assertion failure in ExtractReplicaIdentity
Next
From: Euler Taveira
Date:
Subject: Re: row filtering for logical replication