Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1w9KKm-001Liy-2W for pgsql-hackers@arkaria.postgresql.org; Sun, 05 Apr 2026 10:04:01 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.96) (envelope-from ) id 1w9KKl-002Ife-0n for pgsql-hackers@arkaria.postgresql.org; Sun, 05 Apr 2026 10:03:59 +0000 Received: from magus.postgresql.org ([2a02:c0:301:0:ffff::29]) by malur.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1w9KKk-002IfW-2i for pgsql-hackers@lists.postgresql.org; Sun, 05 Apr 2026 10:03:59 +0000 Received: from lahtoruutu.iki.fi ([185.185.170.37]) by magus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.98.2) (envelope-from ) id 1w9KKi-00000000huY-3jkq for pgsql-hackers@postgresql.org; Sun, 05 Apr 2026 10:03:58 +0000 Received: from [10.0.2.15] (unknown [130.41.208.1]) (using TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits) key-exchange x25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) (Authenticated sender: hlinnaka) by lahtoruutu.iki.fi (Postfix) with ESMTPSA id 4fpSj22MFyz49PvR; Sun, 05 Apr 2026 13:03:50 +0300 (EEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=iki.fi; s=lahtoruutu; t=1775383431; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=BZLRb2om63JEv4hkwHupW67lFbzfDnBNjhtMkJG3mhw=; b=jAem60a2Bs00K3Mr8r/FMsIfJOoWmniUdqxWtXvxT9vGqCcm75Z05FTL/h5zuNoKO4eOWJ 0FEY86eyp3b9RBd4CAyeQEF7j6u+jk01fMq9Ni0iQGqIdnCluJ7XvVOkJPWxz5jIOZjawi 5Mb6gjNoAS680U9t3yFJ/hh/UyIiM9Gut5fqZHaJk4djbfT9SA2FP2SAMOMYBiacBNd1Zj zF2Fv462Kf82He9KdKuBSGtbHK2B16hYQGgZoe1Opmc2lzWrbQBUpv2tQzxmdJIziEy4iz fdDjPicit3tfxHFi8jtWNux2ZXKwXDxZ4PshZuct4/E/ASWzRn2DSvkFqNxxZQ== ARC-Seal: i=1; a=rsa-sha256; d=iki.fi; s=lahtoruutu; cv=none; t=1775383431; b=mn9qCKTlqkgGg9cSUdeAA/NdhVZRDIsXaE9lPwGgnxD64u74Ysz8IuEIM6/YZpC/nZuiQ7 TKALHW0fp6E1yuTRSyRl5frHMYfKgziEMM6mDX5GBy73xKIlrTHDNUOu8nwL7Sw/DeEEt0 UTa32uVtdsxAWQxrfJb6fR/yKJ9iYuHr5nwpruxYx51GnJMcQ7YZ4eNtMj1SxnTINh/zvi AMvhWd+hn/ogp0CPxx83rVjg1rLhAuY0Bq61K6hAXW91K9qHQz28abzxM9WFZao3UGTwCx CifL/4WlAQv4nUCsa+ripxJZimmvOwxHy2zIP8Q4YSPMVS7BoK8b2ca3pyV8cg== ARC-Authentication-Results: i=1; ORIGINATING; auth=pass smtp.auth=hlinnaka smtp.mailfrom=hlinnaka@iki.fi ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=iki.fi; s=lahtoruutu; t=1775383431; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=BZLRb2om63JEv4hkwHupW67lFbzfDnBNjhtMkJG3mhw=; b=ILi0yZDvsQ9wjmHUVO+ueMVgWFM6hLyMd7whUHgsRZfomObGOJTiIwK5Gq65CP5/MjggyJ TZACCNkwpin9Q+zdelwlA4VakDf+7tAV9uMY/Sr8YEbJps0Y5fCsE7KnLCnuYQmklv6iVx qIpY+Zd2k83Fhi0zJ8f1z2jGOO4VkTZoYgUkx9TVpAWw8uEAMeJxgQ3SwRvhI2uSClZz7M eFJqv0yW8Zjz8Rnf015mTcyrw4cGRy90i129+oTy2ovhSk6LZ+jF8NLdh6UnGbaoj1VEHr FKgSW/QOon3xQKgJbP9azocYecCluIWj7M9iKARotQ0p7XUWJ2J5qW6DHzP2jA== Message-ID: <249b4f57-bbb6-4030-a299-26013b9f7d44@iki.fi> Date: Sun, 5 Apr 2026 13:03:49 +0300 MIME-Version: 1.0 User-Agent: Mozilla Thunderbird Subject: Re: Better shared data structure management and resizable shared data structures From: Heikki Linnakangas To: Robert Haas Cc: Ashutosh Bapat , Andres Freund , pgsql-hackers , chaturvedipalak1911@gmail.com References: <26c766d6-db0f-43d3-a618-44f8d40a3121@iki.fi> <62b8dc23-8f6a-4cac-91ff-f74bb5bc159a@iki.fi> <8a6799be-bd42-49fb-8914-856c97bb1977@iki.fi> <113724ab-0028-493f-9605-6e8570f0939f@iki.fi> Content-Language: en-US In-Reply-To: Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 8bit List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk On 27/03/2026 02:51, Heikki Linnakangas wrote: > On 25/03/2026 20:37, Robert Haas wrote: >> On Sat, Mar 21, 2026 at 8:14 PM Heikki Linnakangas >> wrote:>> Shmem callbacks >>> --------------- >>> >>> I separated the request/init/fn callbacks from the structs. There's now >>> a concept of "shmem callbacks", which you register in _PG_init(). For >>> example: >>> >>> static void pgss_shmem_request(void *arg); >>> static void pgss_shmem_init(void *arg); >>> >>> static const ShmemCallbacks pgss_shmem_callbacks = { >>>       .request_fn = pgss_shmem_request, >>>       .init_fn = pgss_shmem_init, >>>       .attach_fn = NULL, /* no special attach actions needed */ >>> }; >> >> What's the advantage of coupling the functions together this way, vs. >> just registering each callback individually? > > One reason is to support allocations after postmaster startup. The > RegisterShmemCallbacks() call ties together all the resources requested > by the request_fn callback, with the the init_fn or attach_fn callbacks > that will later initialize/attach them. The init_fn/attach_fn callbacks > are called only after *all* the resources requested by the request_fn > callback have been initialized, and it holds a lock while doing all that. > > If the callbacks were registered separately, shmem.c wouldn't know when > to call the init_fn/attach_fn. There's no problem during postmaster or > backend startup, because we run all init_fn or attach_fn callbacks in > the whole system, after requesting all the resources, but after startup, > you must only call the callbacks related to the newly-requested resources. > > Aside from that after-startup allocation issue, though, IMO the > ShmemCallbacks struct makes it more clear that the callbacks are meant > to work together on the same resources. > > One way to think of this is that all the resources requested by the > request_fn callback are implicitly part of the same "subsystem", and > need to be initialized/attached to together. We discussed that before, > and I still wonder if we should make that concept of a subsystem more > explicit. If we just renamed ShmemCallbacks to ShmemSubsystem, and give > each subsystem a name, it'd look like this: > > static void pgss_shmem_request(void *arg); > static void pgss_shmem_init(void *arg); > > static const ShmemSubsystem pgss_shmem_subsystem = { >     .name = "pg_stat_statements" >     .request_fn = pgss_shmem_request, >     .init_fn = pgss_shmem_init, >     .attach_fn = NULL, /* no special attach actions needed */ > }; > > static void > pgss_shmem_request(void *arg) > { >     ShmemRequestStruct(&pgssSharedStateDesc, &(ShmemRequestStructOpts) { >          /* >           * name is optional in this design, subsystem's name is used if >           * not given >           */ >         .name = "pg_stat_statements", >         .size = sizeof(pgssSharedState), >         .ptr = (void **) &pgss, >     }); > } > > static void > pgss_shmem_init(void *arg) > { >     /* initialize contents of pgss */ >     ... > } > > void > _PG_init(void) > { >     RegisterShmemSubsystem(&pgss_shmem_subsystem); > } > > > > Thinking how this might work without such a struct, registering the > callbacks separately, here's an alternative design: > > static void pgss_shmem_request(void *arg); > static void pgss_shmem_init(void *arg); > > static void > pgss_shmem_request(void *arg) > { >     ShmemRequestStruct(&pgssSharedStateDesc, &(ShmemRequestStructOpts) { >         .name = "pg_stat_statements", >         .size = sizeof(pgssSharedState), >         .ptr = (void **) &pgss, >     }); > >     ShmemRegisterInitCallback(&pgss_shmem_init); >     /* no attach callback needed, but for illustration: */ >     ShmemRegisterInitCallback(&pgss_shmem_attach); > } > > static void > pgss_shmem_init(void *arg) > { >     /* initialize contents of pgss */ >     ... > } > > void > _PG_init(void) > { >     ShmemRegisterRequestCallback(&pgss_shmem_request); > } > > In this design, the ShmemRegisterRequestCallback() call still ties > together all the related resources. All the resources requested in the > request-callback are initialized together, and the fact that the init/ > attach callbacks are registered within the request callback associates > them with the resources. This feels a little Rube Goldbergian, with one > callback registering more callbacks, but would also work. Thinking about this some more, we could also just pass the callback functions directly as arguments to the ShmemRegisterCallback() function, without the ShmemCallbacks struct. If they're all passed in one call, that still ties them together. The shmem.c implementation would probably still need the ShmemCallbacks struct, but that would be a detail internal to shmem.c. It would look like this: static void pgss_shmem_request(void *arg); static void pgss_shmem_init(void *arg); static void pgss_shmem_request(void *arg) { ShmemRequestStruct( .name = "pg_stat_statements", .size = sizeof(pgssSharedState), .ptr = (void **) &pgss, ); } static void pgss_shmem_init(void *arg) { /* initialize contents of pgss */ ... } void _PG_init(void) { RegisterShmemSubsystem(pgss_shmem_request, pgss_shmem_init, NULL, /* no attach fn needed */ 0, /* flags */); } This is pretty much the same as what's in the latest patch version, but a little less boilerplate as you don't need the ShmemCallbacks struct. The struct would be useful if we had needs to add lots of optional options in the future, but I don't think we have such needs. - Heikki