Thread: relcache reference leak on refresh materialized view concurrently

relcache reference leak on refresh materialized view concurrently

From
yamamoto@valinux.co.jp (YAMAMOTO Takashi)
Date:
the following patch fixes missing index_close in case
the mv has non-unique indexes.

YAMAMOTO Takashi

diff --git a/src/backend/commands/matview.c b/src/backend/commands/matview.c
index d64f165..83efab1 100644
--- a/src/backend/commands/matview.c
+++ b/src/backend/commands/matview.c
@@ -611,6 +611,8 @@ refresh_by_match_merge(Oid matviewOid, Oid tempOid)
         Relation    indexRel;
         HeapTuple    indexTuple;
         Form_pg_index indexStruct;
+        int            numatts;
+        int            i;

         indexRel = index_open(indexoid, RowExclusiveLock);
         indexTuple = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(indexoid));
@@ -619,61 +621,63 @@ refresh_by_match_merge(Oid matviewOid, Oid tempOid)
         indexStruct = (Form_pg_index) GETSTRUCT(indexTuple);

         /* We're only interested if it is unique and valid. */
-        if (indexStruct->indisunique && IndexIsValid(indexStruct))
+        if (!indexStruct->indisunique || !IndexIsValid(indexStruct))
         {
-            int            numatts = indexStruct->indnatts;
-            int            i;
-
-            /* Skip any index on an expression. */
-            if (RelationGetIndexExpressions(indexRel) != NIL)
-            {
-                index_close(indexRel, NoLock);
-                ReleaseSysCache(indexTuple);
-                continue;
-            }
+            index_close(indexRel, NoLock);
+            ReleaseSysCache(indexTuple);
+            continue;
+        }

-            /* Skip partial indexes. */
-            if (RelationGetIndexPredicate(indexRel) != NIL)
-            {
-                index_close(indexRel, NoLock);
-                ReleaseSysCache(indexTuple);
-                continue;
-            }
+        /* Skip any index on an expression. */
+        if (RelationGetIndexExpressions(indexRel) != NIL)
+        {
+            index_close(indexRel, NoLock);
+            ReleaseSysCache(indexTuple);
+            continue;
+        }

-            /* Hold the locks, since we're about to run DML which needs them. */
+        /* Skip partial indexes. */
+        if (RelationGetIndexPredicate(indexRel) != NIL)
+        {
             index_close(indexRel, NoLock);
+            ReleaseSysCache(indexTuple);
+            continue;
+        }

-            /* Add quals for all columns from this index. */
-            for (i = 0; i < numatts; i++)
-            {
-                int            attnum = indexStruct->indkey.values[i];
-                Oid            type;
-                Oid            op;
-                const char *colname;
-
-                /*
-                 * Only include the column once regardless of how many times
-                 * it shows up in how many indexes.
-                 */
-                if (usedForQual[attnum - 1])
-                    continue;
-                usedForQual[attnum - 1] = true;
-
-                /*
-                 * Actually add the qual, ANDed with any others.
-                 */
-                if (foundUniqueIndex)
-                    appendStringInfoString(&querybuf, " AND ");
-
-                colname = quote_identifier(NameStr((tupdesc->attrs[attnum - 1])->attname));
-                appendStringInfo(&querybuf, "newdata.%s ", colname);
-                type = attnumTypeId(matviewRel, attnum);
-                op = lookup_type_cache(type, TYPECACHE_EQ_OPR)->eq_opr;
-                mv_GenerateOper(&querybuf, op);
-                appendStringInfo(&querybuf, " mv.%s", colname);
-
-                foundUniqueIndex = true;
-            }
+        /* Hold the locks, since we're about to run DML which needs them. */
+        index_close(indexRel, NoLock);
+
+        /* Add quals for all columns from this index. */
+        numatts = indexStruct->indnatts;
+        for (i = 0; i < numatts; i++)
+        {
+            int            attnum = indexStruct->indkey.values[i];
+            Oid            type;
+            Oid            op;
+            const char *colname;
+
+            /*
+             * Only include the column once regardless of how many times
+             * it shows up in how many indexes.
+             */
+            if (usedForQual[attnum - 1])
+                continue;
+            usedForQual[attnum - 1] = true;
+
+            /*
+             * Actually add the qual, ANDed with any others.
+             */
+            if (foundUniqueIndex)
+                appendStringInfoString(&querybuf, " AND ");
+
+            colname = quote_identifier(NameStr((tupdesc->attrs[attnum - 1])->attname));
+            appendStringInfo(&querybuf, "newdata.%s ", colname);
+            type = attnumTypeId(matviewRel, attnum);
+            op = lookup_type_cache(type, TYPECACHE_EQ_OPR)->eq_opr;
+            mv_GenerateOper(&querybuf, op);
+            appendStringInfo(&querybuf, " mv.%s", colname);
+
+            foundUniqueIndex = true;
         }
         ReleaseSysCache(indexTuple);
     }

Re: relcache reference leak on refresh materialized view concurrently

From
Tom Lane
Date:
yamamoto@valinux.co.jp (YAMAMOTO Takashi) writes:
> the following patch fixes missing index_close in case
> the mv has non-unique indexes.

Hm ... I see the leak, I think, but isn't this an extraordinarily
complex patch?  Looks like adding

    else
    {
        index_close(indexRel, NoLock);
    }

at the bottom of the "if" would also fix the problem, and would be
far easier to verify.

            regards, tom lane

Re: relcache reference leak on refresh materialized view concurrently

From
yamamoto@valinux.co.jp (YAMAMOTO Takashi)
Date:
> yamamoto@valinux.co.jp (YAMAMOTO Takashi) writes:
>> the following patch fixes missing index_close in case
>> the mv has non-unique indexes.
>
> Hm ... I see the leak, I think, but isn't this an extraordinarily
> complex patch?  Looks like adding

i tend to think it's simpler, but it's a matter of taste.

>
>     else
>     {
>         index_close(indexRel, NoLock);
>     }
>
> at the bottom of the "if" would also fix the problem, and would be
> far easier to verify.

yes, it's probably the physically smallest patch.

YAMAMOTO Takashi

>
>             regards, tom lane