Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1mOBat-0000wX-Mo for pgsql-hackers@arkaria.postgresql.org; Thu, 09 Sep 2021 04:23:23 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.92) (envelope-from ) id 1mOBas-0000Jn-Jl for pgsql-hackers@arkaria.postgresql.org; Thu, 09 Sep 2021 04:23:22 +0000 Received: from magus.postgresql.org ([2a02:c0:301:0:ffff::29]) by malur.postgresql.org with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1mOBas-0000Jf-9S for pgsql-hackers@lists.postgresql.org; Thu, 09 Sep 2021 04:23:22 +0000 Received: from out5-smtp.messagingengine.com ([66.111.4.29]) by magus.postgresql.org with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1mOBap-0005Q0-S8 for pgsql-hackers@postgresql.org; Thu, 09 Sep 2021 04:23:21 +0000 Received: from compute5.internal (compute5.nyi.internal [10.202.2.45]) by mailout.nyi.internal (Postfix) with ESMTP id 6A9CC5C0165; Thu, 9 Sep 2021 00:23:18 -0400 (EDT) Received: from mailfrontend1 ([10.202.2.162]) by compute5.internal (MEProxy); Thu, 09 Sep 2021 00:23:18 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=paquier.xyz; h= date:from:to:cc:subject:message-id:references:mime-version :content-type:in-reply-to; s=fm2; bh=xO879doIT6HFnTnlddunz9vWjIW 4/kUrYTOmXHVVwIk=; b=GkVOx50Nyn0WP5/Iesaezp0I71jNe/XIaQW3NGKioVD Yv3jkbY/xFffde5iFxD0egIOum5/fUgOE9mD/5eFuDwBOL4olqdsgceDPQ5ZkbHO 61Kh6iSQ7b6Zm6K8ybIciQNhvwmbpZs7Bed7jvtde2bRXfV2/oM976e9AtlRsOyB xKSKAOvkmDeiiP+ZSpen/bttYUJUAi31bkjQB4ZeoIiJCVGEAphQCm7TACQX1kVY HR+dT1+cbbGfWcnOatk7r24H7t+uWpaLLL83dIwtC2BLggFSw1AJoLL/c2DcCU/C psfbfzGP11ddjKzGqFKzQA6jAFc23QpGh68dF7rrW3A== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:content-type:date:from:in-reply-to :message-id:mime-version:references:subject:to:x-me-proxy :x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s=fm3; bh=xO879d oIT6HFnTnlddunz9vWjIW4/kUrYTOmXHVVwIk=; b=VB0mXvnu1EWxzoF5+UZCH5 VMJ2FlYFjnnxb1Qc1v3MsW//L8EtVVSxftlGIDyQtIMYpxbqH6TK75yCgsQ5egxy JqRwvZTGgh2SIuVidl1D1qk47Bkyd5dMcsoXXq7bJeY5YVTo1lR/TKsQiqSEVf2X 2Rp3PDsiKYPM1WB8PFwh09Y25u/alL9aOtIIlOfUEuxzjGFQ51YNV7Z4IusnILed qRacsC41X5K0B0cmp3melnwMkouGyqDjaLzgG6GOeexykea6y651+mDa77Z3vsUZ iDzo3FcPShtHXamMMIVN/FD8FG6GBRB55SRCqhrL0XtOzEOIOmZvL03uGwe3HOCA == X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedvtddrudefkedgkedvucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne gfrhhlucfvnfffucdljedtmdenucfjughrpeffhffvuffkfhggtggujgesghdtroertddt vdenucfhrhhomhepofhitghhrggvlhcurfgrqhhuihgvrhcuoehmihgthhgrvghlsehprg hquhhivghrrdighiiiqeenucggtffrrghtthgvrhhnpeehgedtueehkeetgeeuvedtleel keeggeefteefjeejgfekheeikeevjeehudejheenucevlhhushhtvghrufhiiigvpedtne curfgrrhgrmhepmhgrihhlfhhrohhmpehmihgthhgrvghlsehprghquhhivghrrdighiii X-ME-Proxy: Received: by mail.messagingengine.com (Postfix) with ESMTPA; Thu, 9 Sep 2021 00:23:14 -0400 (EDT) Date: Thu, 9 Sep 2021 13:23:10 +0900 From: Michael Paquier To: "Bossart, Nathan" Cc: Fujii Masao , Justin Pryzby , Andres Freund , Magnus Hagander , Mark Dilger , Don Seiler , "pgsql-hackers@postgresql.org" Subject: Re: Estimating HugePages Requirements? Message-ID: References: <7ED221D0-0D75-46F8-8D6C-8AF70D8EABE7@amazon.com> <89EFD5FB-3C28-459C-9D6D-C9F93F7C2A54@amazon.com> <578A8F79-FD13-4408-865F-4D31EE5D8123@amazon.com> <4cc5b434-b174-9aae-197b-737db6cac4e3@oss.nttdata.com> MIME-Version: 1.0 Content-Type: multipart/signed; micalg=pgp-sha256; protocol="application/pgp-signature"; boundary="HcnN3NUkb4APHLZD" Content-Disposition: inline In-Reply-To: List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk --HcnN3NUkb4APHLZD Content-Type: multipart/mixed; boundary="eWD6fSCFPDO7Mn1w" Content-Disposition: inline --eWD6fSCFPDO7Mn1w Content-Type: text/plain; charset=us-ascii Content-Disposition: inline On Thu, Sep 09, 2021 at 01:19:14PM +0900, Michael Paquier wrote: > I broke that again, so rebased as v9 attached. Well. -- Michael --eWD6fSCFPDO7Mn1w Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v9-0001-Introduce-huge_pages_required-GUC.patch" Content-Transfer-Encoding: quoted-printable =46rom 09b1f5a5e0e88a6d84bfc2f8a1bc410e21fb3775 Mon Sep 17 00:00:00 2001 =46rom: Michael Paquier Date: Thu, 9 Sep 2021 13:10:24 +0900 Subject: [PATCH v9 1/2] Introduce huge_pages_required GUC. This runtime-computed GUC shows the number of huge pages required for the server's main shared memory area. --- src/include/storage/pg_shmem.h | 1 + src/backend/port/sysv_shmem.c | 16 +++++++++++----- src/backend/port/win32_shmem.c | 14 ++++++++++++++ src/backend/storage/ipc/ipci.c | 14 ++++++++++++++ src/backend/utils/misc/guc.c | 12 ++++++++++++ doc/src/sgml/config.sgml | 21 +++++++++++++++++++++ 6 files changed, 73 insertions(+), 5 deletions(-) diff --git a/src/include/storage/pg_shmem.h b/src/include/storage/pg_shmem.h index 059df1b72c..518eb86065 100644 --- a/src/include/storage/pg_shmem.h +++ b/src/include/storage/pg_shmem.h @@ -87,5 +87,6 @@ extern PGShmemHeader *PGSharedMemoryCreate(Size size, PGShmemHeader **shim); extern bool PGSharedMemoryIsInUse(unsigned long id1, unsigned long id2); extern void PGSharedMemoryDetach(void); +extern void GetHugePageSize(Size *hugepagesize, int *mmap_flags); =20 #endif /* PG_SHMEM_H */ diff --git a/src/backend/port/sysv_shmem.c b/src/backend/port/sysv_shmem.c index 9de96edf6a..125e2d47ec 100644 --- a/src/backend/port/sysv_shmem.c +++ b/src/backend/port/sysv_shmem.c @@ -456,8 +456,6 @@ PGSharedMemoryAttach(IpcMemoryId shmId, return shmStat.shm_nattch =3D=3D 0 ? SHMSTATE_UNATTACHED : SHMSTATE_ATTAC= HED; } =20 -#ifdef MAP_HUGETLB - /* * Identify the huge page size to use, and compute the related mmap flags. * @@ -476,11 +474,19 @@ PGSharedMemoryAttach(IpcMemoryId shmId, * such as increasing shared_buffers to absorb the extra space. * * Returns the (real, assumed or config provided) page size into *hugepage= size, - * and the hugepage-related mmap flags to use into *mmap_flags. + * and the hugepage-related mmap flags to use into *mmap_flags. If huge p= ages + * is not supported, *hugepagesize and *mmap_flags will be set to 0. */ -static void +void GetHugePageSize(Size *hugepagesize, int *mmap_flags) { +#ifndef MAP_HUGETLB + + *hugepagesize =3D 0; + *mmap_flags =3D 0; + +#else + Size default_hugepagesize =3D 0; =20 /* @@ -553,9 +559,9 @@ GetHugePageSize(Size *hugepagesize, int *mmap_flags) *mmap_flags |=3D (shift & MAP_HUGE_MASK) << MAP_HUGE_SHIFT; } #endif -} =20 #endif /* MAP_HUGETLB */ +} =20 /* * Creates an anonymous mmap()ed shared memory segment. diff --git a/src/backend/port/win32_shmem.c b/src/backend/port/win32_shmem.c index d7a71992d8..90de2ab4e1 100644 --- a/src/backend/port/win32_shmem.c +++ b/src/backend/port/win32_shmem.c @@ -605,3 +605,17 @@ pgwin32_ReserveSharedMemoryRegion(HANDLE hChild) =20 return true; } + +/* + * This function is provided for consistency with sysv_shmem.c and does not + * provide any useful information for Windows. To obtain the large page s= ize, + * use GetLargePageMinimum() instead. + * + * This always sets *hugepagesize and *mmap_flags to 0. + */ +void +GetHugePageSize(Size *hugepagesize, int *mmap_flags) +{ + *hugepagesize =3D 0; + *mmap_flags =3D 0; +} diff --git a/src/backend/storage/ipc/ipci.c b/src/backend/storage/ipc/ipci.c index 13f3926ff6..91490653cf 100644 --- a/src/backend/storage/ipc/ipci.c +++ b/src/backend/storage/ipc/ipci.c @@ -326,6 +326,9 @@ InitializeShmemGUCs(void) char buf[64]; Size size_b; Size size_mb; + Size hp_size; + Size hp_required; + int unused; =20 /* * Calculate the shared memory size and round up to the nearest megabyte. @@ -334,4 +337,15 @@ InitializeShmemGUCs(void) size_mb =3D add_size(size_b, (1024 * 1024) - 1) / (1024 * 1024); sprintf(buf, "%zu", size_mb); SetConfigOption("shared_memory_size", buf, PGC_INTERNAL, PGC_S_OVERRIDE); + + /* + * Calculate the number of huge pages required. + */ + GetHugePageSize(&hp_size, &unused); + if (hp_size !=3D 0) + { + hp_required =3D (size_b / hp_size) + 1; + sprintf(buf, "%zu", hp_required); + SetConfigOption("huge_pages_required", buf, PGC_INTERNAL, PGC_S_OVERRIDE= ); + } } diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index fd4ca83be1..8edfd07340 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -665,6 +665,7 @@ static int max_identifier_length; static int block_size; static int segment_size; static int shared_memory_size_mb; +static int huge_pages_required; static int wal_block_size; static bool data_checksums; static bool integer_datetimes; @@ -2224,6 +2225,17 @@ static struct config_int ConfigureNamesInt[] =3D NULL, NULL, NULL }, =20 + { + {"huge_pages_required", PGC_INTERNAL, PRESET_OPTIONS, + gettext_noop("Shows the number of huge pages needed for the main shared= memory area."), + gettext_noop("-1 indicates that the value could not be determined."), + GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE + }, + &huge_pages_required, + -1, -1, INT_MAX, + NULL, NULL, NULL + }, + { /* This is PGC_SUSET to prevent hiding from log_lock_waits. */ {"deadlock_timeout", PGC_SUSET, LOCK_MANAGEMENT, diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml index ef0e2a7746..b27d8aff15 100644 --- a/doc/src/sgml/config.sgml +++ b/doc/src/sgml/config.sgml @@ -10101,6 +10101,27 @@ dynamic_library_path =3D 'C:\tools\postgresql;H:\m= y_project\lib;$libdir' =20 + + huge_pages_required (integer) + + huge_pages_required configuration param= eter + + + + + Reports the number of huge pages that are required for the main + shared memory area based on the specified + . If huge pages are not sup= ported, + this will be -1. + + + This setting is supported only on Linux. It is always set to + -1 on other platforms. For more details about = using + huge pages on Linux, see . + + + + integer_datetimes (boolean) --=20 2.33.0 --eWD6fSCFPDO7Mn1w Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v9-0002-Provide-useful-values-for-postgres-C-with-runtime.patch" Content-Transfer-Encoding: quoted-printable =46rom f4763273a7f4649d4c50699b590c0b4b8077cb95 Mon Sep 17 00:00:00 2001 =46rom: Michael Paquier Date: Thu, 9 Sep 2021 13:10:38 +0900 Subject: [PATCH v9 2/2] Provide useful values for 'postgres -C' with runtime-computed GUCs. The -C option is handled before a small subset of GUCs that are computed at runtime are initialized. Unfortunately, we cannot move this handling to after they are initialized without disallowing 'postgres -C' on a running server. One notable reason for this is that loadable libraries' _PG_init() functions are called before all runtime-computed GUCs are initialized, and this is not guaranteed to be safe to do on running servers. In order to provide useful values for 'postgres -C' for runtime- computed GUCs, this change adds a new section for handling just these GUCs just before shared memory is initialized. While users won't be able to use -C for runtime-computed GUCs on running servers, providing a useful value with this restriction seems better than not providing a useful value at all. --- src/include/utils/guc.h | 6 ++++ src/backend/postmaster/postmaster.c | 50 +++++++++++++++++++++++++---- src/backend/utils/misc/guc.c | 10 +++--- doc/src/sgml/ref/postgres-ref.sgml | 12 +++++-- doc/src/sgml/runtime.sgml | 33 +++++++------------ 5 files changed, 75 insertions(+), 36 deletions(-) diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index a7c3a4958e..aa18d304ac 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -229,6 +229,12 @@ typedef enum =20 #define GUC_EXPLAIN 0x100000 /* include in explain */ =20 +/* + * GUC_RUNTIME_COMPUTED is intended for runtime-computed GUCs that are only + * available via 'postgres -C' if the server is not running. + */ +#define GUC_RUNTIME_COMPUTED 0x200000 + #define GUC_UNIT (GUC_UNIT_MEMORY | GUC_UNIT_TIME) =20 =20 diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/p= ostmaster.c index b2fe420c3c..f601b9e5d1 100644 --- a/src/backend/postmaster/postmaster.c +++ b/src/backend/postmaster/postmaster.c @@ -896,15 +896,31 @@ PostmasterMain(int argc, char *argv[]) if (output_config_variable !=3D NULL) { /* - * "-C guc" was specified, so print GUC's value and exit. No extra - * permission check is needed because the user is reading inside the - * data dir. + * If this is a runtime-computed GUC, it hasn't yet been initialized, + * and the present value is not useful. However, this is a convenient + * place to print the value for most GUCs because it is safe to run + * postmaster startup to this point even if the server is already + * running. For the handful of runtime-computed GUCs that we can't + * provide meaningful values for yet, we wait until later in postmaster + * startup to print the value. We won't be able to use -C on running + * servers for those GUCs, but otherwise this option is unusable for + * them. */ - const char *config_val =3D GetConfigOption(output_config_variable, - false, false); + int flags =3D GetConfigOptionFlags(output_config_variable, true); =20 - puts(config_val ? config_val : ""); - ExitPostmaster(0); + if ((flags & GUC_RUNTIME_COMPUTED) =3D=3D 0) + { + /* + * "-C guc" was specified, so print GUC's value and exit. No extra + * permission check is needed because the user is reading inside + * the data dir. + */ + const char *config_val =3D GetConfigOption(output_config_variable, + false, false); + + puts(config_val ? config_val : ""); + ExitPostmaster(0); + } } =20 /* Verify that DataDir looks reasonable */ @@ -1033,6 +1049,26 @@ PostmasterMain(int argc, char *argv[]) */ InitializeShmemGUCs(); =20 + /* + * If -C was specified with a runtime-computed GUC, we held off printing + * the value earlier, as the GUC was not yet initialized. We handle -C f= or + * most GUCs before we lock the data directory so that the option may be + * used on a running server. However, a handful of GUCs are runtime- + * computed and do not have meaningful values until after locking the data + * directory, and we cannot safely calculate their values earlier on a + * running server. At this point, such GUCs should be properly + * initialized, and we haven't yet set up shared memory, so this is a good + * time to handle the -C option for these special GUCs. + */ + if (output_config_variable !=3D NULL) + { + const char *config_val =3D GetConfigOption(output_config_variable, + false, false); + + puts(config_val ? config_val : ""); + ExitPostmaster(0); + } + /* * Set up shared memory and semaphores. */ diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 8edfd07340..50e60b270b 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1984,7 +1984,7 @@ static struct config_bool ConfigureNamesBool[] =3D {"data_checksums", PGC_INTERNAL, PRESET_OPTIONS, gettext_noop("Shows whether data checksums are turned on for this clust= er."), NULL, - GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE + GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_RUNTIME_COMPUTED }, &data_checksums, false, @@ -2229,7 +2229,7 @@ static struct config_int ConfigureNamesInt[] =3D {"huge_pages_required", PGC_INTERNAL, PRESET_OPTIONS, gettext_noop("Shows the number of huge pages needed for the main shared= memory area."), gettext_noop("-1 indicates that the value could not be determined."), - GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE + GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_RUNTIME_COMPUTED }, &huge_pages_required, -1, -1, INT_MAX, @@ -2354,7 +2354,7 @@ static struct config_int ConfigureNamesInt[] =3D {"shared_memory_size", PGC_INTERNAL, PRESET_OPTIONS, gettext_noop("Shows the size of the server's main shared memory area (r= ounded up to the nearest MB)."), NULL, - GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_UNIT_MB + GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_UNIT_MB | GUC_RUNTIME_CO= MPUTED }, &shared_memory_size_mb, 0, 0, INT_MAX, @@ -2419,7 +2419,7 @@ static struct config_int ConfigureNamesInt[] =3D "in the form accepted by the chmod and umask system " "calls. (To use the customary octal format the number " "must start with a 0 (zero).)"), - GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE + GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_RUNTIME_COMPUTED }, &data_directory_mode, 0700, 0000, 0777, @@ -3243,7 +3243,7 @@ static struct config_int ConfigureNamesInt[] =3D {"wal_segment_size", PGC_INTERNAL, PRESET_OPTIONS, gettext_noop("Shows the size of write ahead log segments."), NULL, - GUC_UNIT_BYTE | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE + GUC_UNIT_BYTE | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_RUNTIME_= COMPUTED }, &wal_segment_size, DEFAULT_XLOG_SEG_SIZE, diff --git a/doc/src/sgml/ref/postgres-ref.sgml b/doc/src/sgml/ref/postgres= -ref.sgml index 4aaa7abe1a..89cc3cdb4e 100644 --- a/doc/src/sgml/ref/postgres-ref.sgml +++ b/doc/src/sgml/ref/postgres-ref.sgml @@ -133,13 +133,21 @@ PostgreSQL documentation Prints the value of the named run-time parameter, and exits. - (See the option above for details.) This can - be used on a running server, and returns values from + (See the option above for details.) This + returns values from postgresql.conf, modified by any parameters supplied in this invocation. It does not reflect parameters supplied when the cluster was started. =20 + + This can be used on a running server for most parameters. However, + the server must be shut down for some runtime-computed parameters + (e.g., , + , and + ). + + This option is meant for other programs that interact with a server instance, such as , to query configu= ration diff --git a/doc/src/sgml/runtime.sgml b/doc/src/sgml/runtime.sgml index f1cbc1d9e9..d955639900 100644 --- a/doc/src/sgml/runtime.sgml +++ b/doc/src/sgml/runtime.sgml @@ -1442,32 +1442,21 @@ export PG_OOM_ADJUST_VALUE=3D0 with CONFIG_HUGETLBFS=3Dy and CONFIG_HUGETLB_PAGE=3Dy. You will also have to conf= igure the operating system to provide enough huge pages of the desired size. - To estimate the number of huge pages needed, start - PostgreSQL without huge pages enabled and c= heck - the postmaster's anonymous shared memory segment size, as well as the - system's default and supported huge page sizes, using the - /proc and /sys file systems. - This might look like: + To estimate the number of huge pages needed, use the + postgres command to see the value of + . This might look like: -$ head -1 $PGDATA/postmaster.pid -4170 -$ pmap 4170 | awk '/rw-s/ && /zero/ {print $2}' -6490428K -$ grep ^Hugepagesize /proc/meminfo -Hugepagesize: 2048 kB -$ ls /sys/kernel/mm/hugepages -hugepages-1048576kB hugepages-2048kB +$ postgres -D $PGDATA -C huge_pages_required +3170 =20 - In this example the default is 2MB, but you can also explicitly reque= st - either 2MB or 1GB with . + Note that you can explicitly request either 2MB or 1GB huge pages with + . =20 - Assuming 2MB huge pages, - 6490428 / 2048 gives approximat= ely - 3169.154, so in this example we need at - least 3170 huge pages. A larger setting would be - appropriate if other programs on the machine also need huge pages. - We can set this with: + While we need at least 3170 huge pages in this + example, a larger setting would be appropriate if other programs on + the machine also need huge pages. We can allocate the huge pages + with: # sysctl -w vm.nr_hugepages=3D3170 --=20 2.33.0 --eWD6fSCFPDO7Mn1w-- --HcnN3NUkb4APHLZD Content-Type: application/pgp-signature; name="signature.asc" -----BEGIN PGP SIGNATURE----- iQIzBAEBCAAdFiEEG72nH6vTowiyblFKnvQgOdbyQH0FAmE5jC4ACgkQnvQgOdby QH2BShAAhezXFKJbrOHUjpB1aBD5E/VzJteGX0cuwyEk2m1BxHLHxwXOqjEq4U43 Faev5aisFvnu7PjUC8Fr/DTIMeSyGhvIHSwMwtednJxAPwahVZS2MtByEbCq8gUG dFWY1M26kh5toYEKmTYCHUF7gWkh0R+eQeDfDicQfK3FLmbS+lv2eVfGceoqCQD2 so4k5pKTw3WLe5BinXgsWBC8fJbZuJMgF3aXs74WdJdU8PH6wzBBT+IFRSdjS9up QCwoN6NONkg7NAOKGxveNFcrMvY17Ldt4eGQfMiL917b6YtJ7Vkl2tIHUslnzyTG ZTG1hAQmmqyDxRaAGIFCY1KyDsgdBZs5fQ0sSTdPJy95mvcpNAcLKCbiWHM6sxis BMVqHLpMRdn2xhGoylVONylg0RQxLFX7+Tk4RqopXAQQtoH/pmxWa1ZV8R9kD2o5 InLTXhtkD9K+FGatsjLcq985gDJfdfRae0K7ieAbZZejk7+j4b2PV8DzqzPaPTvs AeS4bXLcj0Iu+fl50/xS9VjgMdTIVG40KyeRwyyb/3zSUj+4O6CNBXTrkF2d7xG4 yfHkS9GggWyyxHddrWl0e4iXyEgUuxqCAYS4USZJZfT64xkxQCrAm4YHv9C+Hopk AUHCsT9P3+8n/AX3j9Fo8GrCd0yI/ZOgUp3VgoVcp1y5V7gOW7w= =N7Sl -----END PGP SIGNATURE----- --HcnN3NUkb4APHLZD--