Re: Support for REINDEX CONCURRENTLY - Mailing list pgsql-hackers

From Andres Freund
Subject Re: Support for REINDEX CONCURRENTLY
Date
Msg-id 20130618093510.GC5646@awork2.anarazel.de
Whole thread Raw
In response to Re: Support for REINDEX CONCURRENTLY  (Michael Paquier <michael.paquier@gmail.com>)
Responses Re: Support for REINDEX CONCURRENTLY
Re: Support for REINDEX CONCURRENTLY
List pgsql-hackers
Hi,

On 2013-06-18 10:53:25 +0900, Michael Paquier wrote:
> diff --git a/contrib/pg_upgrade/info.c b/contrib/pg_upgrade/info.c
> index c381f11..3a6342c 100644
> --- a/contrib/pg_upgrade/info.c
> +++ b/contrib/pg_upgrade/info.c
> @@ -321,12 +321,17 @@ get_rel_infos(ClusterInfo *cluster, DbInfo *dbinfo)
>                                "INSERT INTO info_rels "
>                                "SELECT reltoastrelid "
>                                "FROM info_rels i JOIN pg_catalog.pg_class c "
> -                              "        ON i.reloid = c.oid"));
> +                              "        ON i.reloid = c.oid "
> +                              "        AND c.reltoastrelid != %u", InvalidOid));
>      PQclear(executeQueryOrDie(conn,
>                                "INSERT INTO info_rels "
> -                              "SELECT reltoastidxid "
> -                              "FROM info_rels i JOIN pg_catalog.pg_class c "
> -                              "        ON i.reloid = c.oid"));
> +                              "SELECT indexrelid "
> +                              "FROM pg_index "
> +                              "WHERE indrelid IN (SELECT reltoastrelid "
> +                              "          FROM pg_class "
> +                              "          WHERE oid >= %u "
> +                              "             AND reltoastrelid != %u)",
> +                              FirstNormalObjectId, InvalidOid));

What's the idea behind the >= here?

I think we should ignore the invalid indexes in that SELECT?


> @@ -1392,19 +1390,62 @@ swap_relation_files(Oid r1, Oid r2, bool target_is_pg_class,
>      }
>  
>      /*
> -     * If we're swapping two toast tables by content, do the same for their
> -     * indexes.
> +     * If we're swapping two toast tables by content, do the same for all of
> +     * their indexes. The swap can actually be safely done only if the
> +     * relations have indexes.
>       */
>      if (swap_toast_by_content &&
> -        relform1->reltoastidxid && relform2->reltoastidxid)
> -        swap_relation_files(relform1->reltoastidxid,
> -                            relform2->reltoastidxid,
> -                            target_is_pg_class,
> -                            swap_toast_by_content,
> -                            is_internal,
> -                            InvalidTransactionId,
> -                            InvalidMultiXactId,
> -                            mapped_tables);
> +        relform1->reltoastrelid &&
> +        relform2->reltoastrelid)
> +    {
> +        Relation toastRel1, toastRel2;
> +
> +        /* Open relations */
> +        toastRel1 = heap_open(relform1->reltoastrelid, AccessExclusiveLock);
> +        toastRel2 = heap_open(relform2->reltoastrelid, AccessExclusiveLock);
> +
> +        /* Obtain index list */
> +        RelationGetIndexList(toastRel1);
> +        RelationGetIndexList(toastRel2);
> +
> +        /* Check if the swap is possible for all the toast indexes */
> +        if (list_length(toastRel1->rd_indexlist) == 1 &&
> +            list_length(toastRel2->rd_indexlist) == 1)
> +        {
> +            ListCell *lc1, *lc2;
> +
> +            /* Now swap each couple */
> +            lc2 = list_head(toastRel2->rd_indexlist);
> +            foreach(lc1, toastRel1->rd_indexlist)
> +            {
> +                Oid indexOid1 = lfirst_oid(lc1);
> +                Oid indexOid2 = lfirst_oid(lc2);
> +                swap_relation_files(indexOid1,
> +                                    indexOid2,
> +                                    target_is_pg_class,
> +                                    swap_toast_by_content,
> +                                    is_internal,
> +                                    InvalidTransactionId,
> +                                    InvalidMultiXactId,
> +                                    mapped_tables);
> +                lc2 = lnext(lc2);
> +            }

Why are you iterating over the indexlists after checking they are both
of length == 1? Looks like the code would be noticeably shorter without
that.

> +        }
> +        else
> +        {
> +            /*
> +             * As this code path is only taken by shared catalogs, who cannot
> +             * have multiple indexes on their toast relation, simply return
> +             * an error.
> +             */
> +            ereport(ERROR,
> +                    (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
> +                     errmsg("cannot swap relation files of a shared catalog with multiple indexes on toast
relation")));
> +        }
> +

Absolutely minor thing, using an elog() seems to be better here since
that uses the appropriate error code for some codepath that's not
expected to be executed.

>      /* Clean up. */
>      heap_freetuple(reltup1);
> @@ -1529,12 +1570,13 @@ finish_heap_swap(Oid OIDOldHeap, Oid OIDNewHeap,
>          if (OidIsValid(newrel->rd_rel->reltoastrelid))
>          {
>              Relation    toastrel;
> -            Oid            toastidx;
>              char        NewToastName[NAMEDATALEN];
> +            ListCell   *lc;
> +            int            count = 0;
>  
>              toastrel = relation_open(newrel->rd_rel->reltoastrelid,
>                                       AccessShareLock);
> -            toastidx = toastrel->rd_rel->reltoastidxid;
> +            RelationGetIndexList(toastrel);
>              relation_close(toastrel, AccessShareLock);
>  
>              /* rename the toast table ... */
> @@ -1543,11 +1585,23 @@ finish_heap_swap(Oid OIDOldHeap, Oid OIDNewHeap,
>              RenameRelationInternal(newrel->rd_rel->reltoastrelid,
>                                     NewToastName, true);
>  
> -            /* ... and its index too */
> -            snprintf(NewToastName, NAMEDATALEN, "pg_toast_%u_index",
> -                     OIDOldHeap);
> -            RenameRelationInternal(toastidx,
> -                                   NewToastName, true);
> +            /* ... and its indexes too */
> +            foreach(lc, toastrel->rd_indexlist)
> +            {
> +                /*
> +                 * The first index keeps the former toast name and the
> +                 * following entries have a suffix appended.
> +                 */
> +                if (count == 0)
> +                    snprintf(NewToastName, NAMEDATALEN, "pg_toast_%u_index",
> +                             OIDOldHeap);
> +                else
> +                    snprintf(NewToastName, NAMEDATALEN, "pg_toast_%u_index_%d",
> +                             OIDOldHeap, count);
> +                RenameRelationInternal(lfirst_oid(lc),
> +                                       NewToastName, true);
> +                count++;
> +            }
>          }
>          relation_close(newrel, NoLock);
>      }

Is it actually possible to get here with multiple toast indexes?


> diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
> index ec956ad..ac42389 100644
> --- a/src/bin/pg_dump/pg_dump.c
> +++ b/src/bin/pg_dump/pg_dump.c
> @@ -2781,16 +2781,16 @@ binary_upgrade_set_pg_class_oids(Archive *fout,
>      Oid            pg_class_reltoastidxid;
>  
>      appendPQExpBuffer(upgrade_query,
> -                      "SELECT c.reltoastrelid, t.reltoastidxid "
> +                      "SELECT c.reltoastrelid, t.indexrelid "
>                        "FROM pg_catalog.pg_class c LEFT JOIN "
> -                      "pg_catalog.pg_class t ON (c.reltoastrelid = t.oid) "
> -                      "WHERE c.oid = '%u'::pg_catalog.oid;",
> +                      "pg_catalog.pg_index t ON (c.reltoastrelid = t.indrelid) "
> +                      "WHERE c.oid = '%u'::pg_catalog.oid AND t.indisvalid;",
>                        pg_class_oid);

This possibly needs a version qualification due to querying
indisalid. How far back do we support pg_upgrade?

> diff --git a/src/include/utils/relcache.h b/src/include/utils/relcache.h
> index 8ac2549..31309ed 100644
> --- a/src/include/utils/relcache.h
> +++ b/src/include/utils/relcache.h
> @@ -29,6 +29,16 @@ typedef struct RelationData *Relation;
>  typedef Relation *RelationPtr;
>  
>  /*
> + * RelationGetIndexListIfValid
> + * Get index list of relation without recomputing it.
> + */
> +#define RelationGetIndexListIfValid(rel) \
> +do { \
> +    if (rel->rd_indexvalid == 0) \
> +        RelationGetIndexList(rel); \
> +} while(0)

Isn't this function misnamed and should be
RelationGetIndexListIfInValid?

Going to do some performance tests now.

Greetings,

Andres Freund

-- Andres Freund                       http://www.2ndQuadrant.com/PostgreSQL Development, 24x7 Support, Training &
Services



pgsql-hackers by date:

Previous
From: Markus Wanner
Date:
Subject: Re: Change authentication error message (patch)
Next
From: Andres Freund
Date:
Subject: Re: A minor correction in comment in heaptuple.c