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.94.2) (envelope-from ) id 1rOlYI-006uPs-Dd for pgsql-hackers@arkaria.postgresql.org; Sat, 13 Jan 2024 21:28:27 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.94.2) (envelope-from ) id 1rOlYH-009ZKS-A4 for pgsql-hackers@arkaria.postgresql.org; Sat, 13 Jan 2024 21:28:25 +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.94.2) (envelope-from ) id 1rOlYG-009ZKJ-TX for pgsql-hackers@lists.postgresql.org; Sat, 13 Jan 2024 21:28:25 +0000 Received: from mail-io1-xd2b.google.com ([2607:f8b0:4864:20::d2b]) by magus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (Exim 4.94.2) (envelope-from ) id 1rOlYC-001ccM-Sk for pgsql-hackers@postgresql.org; Sat, 13 Jan 2024 21:28:24 +0000 Received: by mail-io1-xd2b.google.com with SMTP id ca18e2360f4ac-7bc32b0fdadso280799439f.2 for ; Sat, 13 Jan 2024 13:28:20 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1705181298; x=1705786098; darn=postgresql.org; h=in-reply-to:content-disposition:mime-version:references:message-id :subject:cc:to:from:date:from:to:cc:subject:date:message-id:reply-to; bh=kTbxwnhcc7hWeKhdmnV1MAmkw+aX7xyx3hXCcGSSZ5Y=; b=acRu8G432vUnosny35e8c0SOEojuUE9+K2rqMTWRDk0EODtSCoYPbezUAHLjtbZph2 7Am+SxTIJaWsT+9j8ARIVCSrQx0b3JnYhM1l0CTIRYjW4CKI9wAeBU4kzdu+BJqkKL6n 9rRt0ZslI1ZRvnp1njNZCuv7Jb5e9K5I1E3P9BDWiF6VNb2VNBI6BRbcJjr4nL1Y/8wE U0MEDJmkY+FfU0ukEEvZvnO2z8Gtf2sC9k14tA0B9VWD2FhnFOgo29LPTqPKEOQ+PS11 qgIWd6J4HZ57wpFhobx5/n6MFf/FQdMd01sMSuRkKpVmj/tkMpF5XQTFCvEIigV5PpaL sHhQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1705181298; x=1705786098; h=in-reply-to:content-disposition:mime-version:references:message-id :subject:cc:to:from:date:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to; bh=kTbxwnhcc7hWeKhdmnV1MAmkw+aX7xyx3hXCcGSSZ5Y=; b=SzNicHTU3oZqweSmmdSn5ceb/OvLndqO4CcSiT3PonJ176XvEThpsG0S5ZrZNXLrh9 UHo8dEj6d+mVCRzXpMNuhEzLnvQZHSk5tvsCbLllcHtbnJPDmfLxHcesN1Wa/HLCJ2Kl MbN+VE/wt4QnSIUfdye9M63pubssVPVK8UVgzRg3Fxkb4u4MTaRpPBhlGeOqE1T98SGC CbLtpiGPqFAu2FH9CIkCcim6N9iRFVoTM+jtLi0MkL/hHMYUU889RBevWeQATR7vF22t aJeyfC1VzQr4nyqfpTLZdn/76AxkfT/I3k3ZcYEWI9aYLlKxInutmkJRF8dxP5A0xURn eXrA== X-Gm-Message-State: AOJu0YygKxwvYBDF27mPfpxiuJWLd3Eqj72bDxToJzwMUa0CGBP5n2aB Df8hWAQCn/iR6FDOPK4OdJI= X-Google-Smtp-Source: AGHT+IG3E17zqgnbzD1bmGpw2O+MKBGGhtYszSCMD/72rrZB+DGFa5Uob0LO4ViuJ0jnm/M5My/u0A== X-Received: by 2002:a5e:a907:0:b0:7bf:39fc:86bd with SMTP id c7-20020a5ea907000000b007bf39fc86bdmr247485iod.19.1705181298370; Sat, 13 Jan 2024 13:28:18 -0800 (PST) Received: from nathanxps13 (162-195-168-172.lightspeed.stlsmo.sbcglobal.net. [162.195.168.172]) by smtp.gmail.com with ESMTPSA id l22-20020a02ccf6000000b0046e2ea26aa4sm1590782jaq.52.2024.01.13.13.28.17 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 13 Jan 2024 13:28:17 -0800 (PST) Date: Sat, 13 Jan 2024 15:28:15 -0600 From: Nathan Bossart To: Aleksander Alekseev Cc: pgsql-hackers@postgresql.org Subject: Re: reorganize "Shared Memory and LWLocks" section of docs Message-ID: <20240113212815.GA4065002@nathanxps13> References: <20240112041430.GA3557928@nathanxps13> <20240112154650.GA3565306@nathanxps13> <20240112172350.GB3803561@nathanxps13> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="HcAYCG3uE/tztfnV" Content-Disposition: inline In-Reply-To: List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk --HcAYCG3uE/tztfnV Content-Type: text/plain; charset=us-ascii Content-Disposition: inline On Sat, Jan 13, 2024 at 01:49:08PM +0300, Aleksander Alekseev wrote: > That's much better, thanks. > > I think the patch could use another pair of eyes, ideally from a > native English speaker. But if no one will express any objections for > a while I suggest merging it. Great. I've attached a v3 with a couple of fixes suggested in the other thread [0]. I'll wait a little while longer in case anyone else wants to take a look. [0] https://postgr.es/m/ZaF6UpYImGqVIhVp%40toroid.org -- Nathan Bossart Amazon Web Services: https://aws.amazon.com --HcAYCG3uE/tztfnV Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v3-0001-reorganize-shared-memory-and-lwlocks-documentatio.patch" From b56931edc4488a7376b27ba0e5519cc3a61b4899 Mon Sep 17 00:00:00 2001 From: Nathan Bossart Date: Thu, 11 Jan 2024 21:55:25 -0600 Subject: [PATCH v3 1/1] reorganize shared memory and lwlocks documentation --- doc/src/sgml/xfunc.sgml | 182 +++++++++++++++++++++++++--------------- 1 file changed, 114 insertions(+), 68 deletions(-) diff --git a/doc/src/sgml/xfunc.sgml b/doc/src/sgml/xfunc.sgml index 89116ae74c..82e1dadcca 100644 --- a/doc/src/sgml/xfunc.sgml +++ b/doc/src/sgml/xfunc.sgml @@ -3397,90 +3397,136 @@ CREATE FUNCTION make_array(anyelement) RETURNS anyarray - Shared Memory and LWLocks + Shared Memory - - Add-ins can reserve LWLocks and an allocation of shared memory on server - startup. The add-in's shared library must be preloaded by specifying - it in - shared_preload_libraries. - The shared library should register a shmem_request_hook - in its _PG_init function. This - shmem_request_hook can reserve LWLocks or shared memory. - Shared memory is reserved by calling: + + Requesting Shared Memory at Startup + + + Add-ins can reserve shared memory on server startup. To do so, the + add-in's shared library must be preloaded by specifying it in + shared_preload_libraries. + The shared library should also register a + shmem_request_hook in its + _PG_init function. This + shmem_request_hook can reserve shared memory by + calling: void RequestAddinShmemSpace(int size) - from your shmem_request_hook. - - - LWLocks are reserved by calling: + Each backend should obtain a pointer to the reserved shared memory by + calling: + +void *ShmemInitStruct(const char *name, Size size, bool *foundPtr) + + If this function sets foundPtr to + false, the caller should proceed to initialize the + contents of the reserved shared memory. If foundPtr + is set to true, the shared memory was already + initialized by another backend, and the caller need not initialize + further. + + + + To avoid race conditions, each backend should use the LWLock + AddinShmemInitLock when initializing its allocation + of shared memory, as shown here: + +static mystruct *ptr = NULL; +bool found; + +LWLockAcquire(AddinShmemInitLock, LW_EXCLUSIVE); +ptr = ShmemInitStruct("my struct name", size, &found); +if (!found) +{ + ... initialize contents of shared memory ... + ptr->locks = GetNamedLWLockTranche("my tranche name"); +} +LWLockRelease(AddinShmemInitLock); + + shmem_startup_hook provides a convenient place for the + initialization code, but it is not strictly required that all such code + be placed in this hook. Each backend will execute the registered + shmem_startup_hook shortly after it attaches to shared + memory. Note that add-ins should still acquire + AddinShmemInitLock within this hook, as shown in the + example above. + + + + An example of a shmem_request_hook and + shmem_startup_hook can be found in + contrib/pg_stat_statements/pg_stat_statements.c in + the PostgreSQL source tree. + + + + + + LWLocks + + + Requesting LWLocks at Startup + + + Add-ins can reserve LWLocks on server startup. As with shared memory, + the add-in's shared library must be preloaded by specifying it in + shared_preload_libraries, + and the shared library should register a + shmem_request_hook in its + _PG_init function. This + shmem_request_hook can reserve LWLocks by calling: void RequestNamedLWLockTranche(const char *tranche_name, int num_lwlocks) - from your shmem_request_hook. This will ensure that an array of - num_lwlocks LWLocks is available under the name - tranche_name. Use GetNamedLWLockTranche - to get a pointer to this array. - - - An example of a shmem_request_hook can be found in - contrib/pg_stat_statements/pg_stat_statements.c in the - PostgreSQL source tree. - - - There is another, more flexible method of obtaining LWLocks. First, - allocate a tranche_id from a shared counter by - calling: + This ensures that an array of num_lwlocks LWLocks is + available under the name tranche_name. A pointer to + this array can be obtained by calling: -int LWLockNewTrancheId(void) +LWLockPadded *GetNamedLWLockTranche(const char *tranche_name) - Next, each individual process using the tranche_id - should associate it with a tranche_name by calling: + + + + + Requesting LWLocks After Startup + + + There is another, more flexible method of obtaining LWLocks that can be + done after server startup and outside a + shmem_request_hook. To do so, first allocate a + tranche_id by calling: -void LWLockRegisterTranche(int tranche_id, const char *tranche_name) +int LWLockNewTrancheId(void) - It is also required to call LWLockInitialize once - per LWLock, passing the tranche_id as argument: + Next, initialize each LWLock, passing the new + tranche_id as an argument: void LWLockInitialize(LWLock *lock, int tranche_id) - A complete usage example of LWLockNewTrancheId, - LWLockInitialize and - LWLockRegisterTranche can be found in - contrib/pg_prewarm/autoprewarm.c in the - PostgreSQL source tree. - - - To avoid possible race-conditions, each backend should use the LWLock - AddinShmemInitLock when connecting to and initializing - its allocation of shared memory, as shown here: - -static mystruct *ptr = NULL; + Similar to shared memory, each backend should ensure that only one + process allocates a new tranche_id and initializes + each new LWLock. One way to do this is to only call these functions in + your shared memory initialization code with the + AddinShmemInitLock held exclusively. + -if (!ptr) -{ - bool found; - - LWLockAcquire(AddinShmemInitLock, LW_EXCLUSIVE); - ptr = ShmemInitStruct("my struct name", size, &found); - if (!found) - { - initialize contents of shmem area; - acquire any requested LWLocks using: - ptr->locks = GetNamedLWLockTranche("my tranche name"); - } - LWLockRelease(AddinShmemInitLock); -} + + Finally, each backend using the tranche_id should + associate it with a tranche_name by calling: + +void LWLockRegisterTranche(int tranche_id, const char *tranche_name) - - - It is convenient to use shmem_startup_hook which allows - placing all the code responsible for initializing shared memory in one - place. When using shmem_startup_hook the extension - still needs to acquire AddinShmemInitLock in order to - work properly on all the supported platforms. - + + + + A complete usage example of LWLockNewTrancheId, + LWLockInitialize, and + LWLockRegisterTranche can be found in + contrib/pg_prewarm/autoprewarm.c in the + PostgreSQL source tree. + + -- 2.25.1 --HcAYCG3uE/tztfnV--