Hi,

On Fri, 17 Jul 2026 at 19:38, Álvaro Herrera <[email protected]> wrote:

> Hello,
>
> On 2026-Jul-17, Ayush Tiwari wrote:
> > I tried the "other way": keep the immediate parent OID on the relcache
> > entry (a lazily-filled rd_partparent), then use the existing walker above
> > that.  This avoids repeatedly scanning the leaf link and eliminates the
> > pg_inherits scan entirely for the common one-level hierarchy.  Patch
> > attached (fairly small).
>
> Hmm.  Why not cache the entire list of ancestors instead of just the
> immediate one?  You could have a union that's either a single
> OID (for the most common case where there's only one ancestor), or a
> pointer to an array of an arbitrary number of ancestors.  With such a
> system, you only have to scan pg_inherits for a relation once per
> invalidation, regardless of the number of ancestors.
>
> (Looking at pahole's output for RelationData it's obvious that nobody
> cares too much about how much memory that struct takes.)
>

The union is fine, but I don't think a full list cached on the index has
a valid invalidation.  AFAICT it depends on the *ancestors'* links, and
re-parenting an intermediate index doesn't invalidate the leaf:
pg_inherits changes send no relcache inval (only
pg_class/pg_attribute/pg_index/pg_constraint do), and IndexSetParentIndex
flips only the re-parented index's own pg_class row.

  -- 3-level r > m > l; warm l's index cache
  INSERT INTO r VALUES (1) ON CONFLICT (i) DO NOTHING;
    NOTICE: FILL l_pkey ancestors=[m_pkey r_pkey]
  ALTER TABLE r  DETACH PARTITION m;
  ALTER TABLE r2 ATTACH PARTITION m ...;      -- m_pkey now under r2_pkey
  INSERT INTO r2 VALUES (2) ON CONFLICT (i) DO NOTHING;
    NOTICE: HIT l_pkey cached=[m_pkey r_pkey] live=[m_pkey r2_pkey] <-STALE

l_pkey is never invalidated, so the cached list keeps r_pkey and
ExecInitPartitionInfo() would pick the wrong arbiter.  The
immediate-parent cache dodges this: it stores only the leaf's own parent
(invalidated when it changes) and walks the rest live.

To make a full list safe we'd need a new invalidation path that, on any
index re-parent, invalidates the whole descendant-index subtree rather
than just the re-parented index, and it only helps 3+ level
hierarchies. Should I explore that?

Regards,
Ayush

Reply via email to