Re: Reducing relcache memory usage: deduping index shapes

From: Matthias van de Meent <boekewurm+postgres(at)gmail(dot)com>
To: David Rowley <dgrowleyml(at)gmail(dot)com>
Cc: PostgreSQL Hackers <pgsql-hackers(at)lists(dot)postgresql(dot)org>, Andres Freund <andres(at)anarazel(dot)de>, David Geier <geidav(dot)pg(at)gmail(dot)com>
Subject: Re: Reducing relcache memory usage: deduping index shapes
Date: 2026-09-08 09:55:36
Message-ID: CAEze2WgqYJBch-VNshqxx8umQ7YZJKS-9RToYujW+gX0qHJZ8g@mail.gmail.com
Views: Whole Thread | Raw Message | Download mbox | Resend email
Thread:
Lists: pgsql-hackers

On Tue, 1 Sept 2026 at 09:18, David Rowley <dgrowleyml(at)gmail(dot)com> wrote:
>
> On Tue, 1 Sept 2026 at 11:10, Matthias van de Meent
> <boekewurm+postgres(at)gmail(dot)com> wrote:
> >
> > On Tue, 1 Sept 2026 at 00:04, David Rowley <dgrowleyml(at)gmail(dot)com> wrote:
> > > Shouldn't nchunks be uint64 anyway? Nothing guarantees Size is bigger
> > > than int, even on 64-bit.
> >
> > True. But AFAIK, Size must be able to contain the largest possible
> > pointer difference, and that implies that we can't have more than
> > SIZE_MAX allocated chunks. Using Size for maths in those cases seems
> > appropriate, to avoid requiring expensive oversized registers on
> > 32-bit builds.
>
> Pointer difference relates to the size of a chunk. We're talking about
> the number of chunks. If a 64-bit platform exists with a 32-bit
> size_t, and you create > 2^32 chunks, then the counter will wrap and
> you'll mistakenly raise a WARNING.

If size_t is 32-bit, then that means all possible object sizes
(including array sizes) for the platform fit in those 32 bits. I'm
fairly sure that we don't support 64-bit addressing platforms that
don't also support objects larger than 2^32, though I'm happy to be
pointed to a (supported!) counterexample.

> I also think it's better to just remove the chunks_allocated struct
> field. It's not testing any code that exists in
> non-MEMORY_CONTEXT_CHECKING. All that's happening is you're adding a
> bunch of new code in MEMORY_CONTEXT_CHECKING builds and verifying that
> new code is ok. If you didn't add it, you wouldn't need to check it.

I used it to verify that the linked list is maintained correctly. I'd
have used dclist instead if it was simple to switch to that
implementation in only MEMORY_CONTEXT_TRACKING mode.

> More reviewing of 0004:
>
> 1. These Asserts also seem strange as they check something that's
> already been checked:
>
> + Assert(total_allocated == context->mem_allocated);
> + Assert(chunks_allocated == ctx->chunks_allocated);

I've adjusted this.

> 2. I think ExternalChunkGetBlock should be called something else as it
> returns a pointer to a ProxyChunk. Maybe MemoryChunkGetProxyChunk? You
> should also document what the parameter is to that macro.

I've adjusted the name of the struct to match its role -- it's more
comparable to aset's Block, so I updated its name.

> 3. Is "#include <limits.h>" just for INT_MAX? Normally we'd use
> PG_INT32_MAX from c.h.

I've seen various uses of INT_MAX from <limits.h> directly around the
codebase, so I don't see much of an issue with it. But, in v2 this
include has become redundant I reworked the code a bit in v2, and now
this check isn't present anymore.

> 4. If you are keen to save more memory, you could move away from using
> MemoryChunk and write your own version that maintains the lower 4-bits
> for the MemoryContextMethodID and encodes the size in the remaining 60
> bits. That might be more trouble than it's worth, however.

I don't think that exact scheme is allowed, because the most bits you
can consume is 59: Four bits are used by the MemoryContextMethodID,
and one bit stores the "external" bit. But when the external bit is
set, mctx infra expects these 59 bits to contain MEMORYCHUNK_MAGIC;
and when the external bit isn't set, it should contain a valid
`length` field less than .
And yes, I think that'd be more trouble than it's worth.

> 5. It would be good to see proxy.c using set_sentinel() and sentinel_ok(),

Added.

-------

Attached is v2 of the patchset. Changelist below:

0001/0002: Unchanged.

0003 (Deduplication):
* New memory context "Relation shape cache" to hold all shape-related
allocations and contexts,
This is a child context under CacheMemoryContext
* Memory context per "relation shape" in the RelShapeHash
This allows faster freeing of all associated data
* Optimized default shape entry data allocations per shape
The minimum is now down to 2 allocations, from >3. This is
primarily useful once Proxy contexts are used; Key data is still
bulk-allocated.
* Some varlena macro-related fixes.
Some SIZE/SIZE_EXHDR confusion and related issues, identified by
the sanitizer CF builds.

0004 (Proxy context):
* Consistency checks have been adjusted, and sentinel checks have been
introduced.
* Code has been updated with aset as template for naming and flow
This should clean up David's comments.

Name change from Proxy to anything else gets a 0-vote from me: I'd
like to avoid the churn, but if people have strong feelings about it
I'll go through the motions.

0005 (Apply proxy):
* Added Proxy to the new per-"index shape" contexts.

Question for the crowd: Most memory contexts often get a text
identifier which describes their contents in more detail when we have
many of the same name. "index shape" contexts don't have a simple
natural identifier. Whilst they do have the shape key, formatting
that into a name would be a bit of effort (and quite a bit of effort
if we want to capture the whole key), and we'd spend more bytes per
index shape. Do we want/need this identifier even with the increase
in memory usage?

Kind regards,

Matthias van de Meent
Databricks (https://www.databricks.com)

Attachment Content-Type Size
v2-0003-Deduplicate-some-index-attributes-in-the-relcache.patch application/octet-stream 42.9 KB
v2-0001-rel.h-const-ify-opclass-related-fields-of-Relatio.patch application/octet-stream 4.4 KB
v2-0002-relcache-refactor-RelationInitIndexAccessInfo.patch application/octet-stream 5.6 KB
v2-0005-Relcache-Use-Proxy-contexts-for-index-info-and-in.patch application/octet-stream 2.5 KB
v2-0004-MemCTX-Add-minimal-proxy-context-type-that-just-d.patch application/octet-stream 20.1 KB

In response to

Browse pgsql-hackers by date

  From Date Subject
Next Message cca5507 2026-09-08 10:02:52 [PATCH] Report userid to PgBackendStatus for standalone backends
Previous Message Amit Kapila 2026-09-08 09:52:20 Re: Revert RI fast-path batching from REL_19_STABLE