From fbee247f9ad419ec275a8ebb754a21c0d1cbf4e7 Mon Sep 17 00:00:00 2001 From: Andres Freund Date: Tue, 11 Feb 2025 14:24:31 -0500 Subject: [PATCH v2.4 09/29] aio: Basic subsystem initialization This is just separate to make it easier to review the tendrils into various places. --- src/include/storage/aio.h | 38 +++++++++++ src/include/storage/aio_subsys.h | 28 ++++++++ src/include/utils/guc.h | 1 + src/include/utils/guc_hooks.h | 2 + src/include/utils/resowner.h | 5 ++ src/backend/storage/aio/Makefile | 2 + src/backend/storage/aio/aio.c | 67 +++++++++++++++++++ src/backend/storage/aio/aio_init.c | 37 ++++++++++ src/backend/storage/aio/meson.build | 2 + src/backend/storage/ipc/ipci.c | 3 + src/backend/utils/init/postinit.c | 7 ++ src/backend/utils/misc/guc_tables.c | 23 +++++++ src/backend/utils/misc/postgresql.conf.sample | 6 ++ src/backend/utils/resowner/resowner.c | 29 ++++++++ doc/src/sgml/config.sgml | 51 ++++++++++++++ src/tools/pgindent/typedefs.list | 1 + 16 files changed, 302 insertions(+) create mode 100644 src/include/storage/aio.h create mode 100644 src/include/storage/aio_subsys.h create mode 100644 src/backend/storage/aio/aio.c create mode 100644 src/backend/storage/aio/aio_init.c diff --git a/src/include/storage/aio.h b/src/include/storage/aio.h new file mode 100644 index 00000000000..e79d5343038 --- /dev/null +++ b/src/include/storage/aio.h @@ -0,0 +1,38 @@ +/*------------------------------------------------------------------------- + * + * aio.h + * Main AIO interface + * + * + * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/storage/aio.h + * + *------------------------------------------------------------------------- + */ +#ifndef AIO_H +#define AIO_H + + + +/* Enum for io_method GUC. */ +typedef enum IoMethod +{ + IOMETHOD_SYNC = 0, +} IoMethod; + +/* We'll default to synchronous execution. */ +#define DEFAULT_IO_METHOD IOMETHOD_SYNC + + +struct dlist_node; +extern void pgaio_io_release_resowner(struct dlist_node *ioh_node, bool on_error); + + +/* GUCs */ +extern PGDLLIMPORT int io_method; +extern PGDLLIMPORT int io_max_concurrency; + + +#endif /* AIO_H */ diff --git a/src/include/storage/aio_subsys.h b/src/include/storage/aio_subsys.h new file mode 100644 index 00000000000..0b8aaaf00d3 --- /dev/null +++ b/src/include/storage/aio_subsys.h @@ -0,0 +1,28 @@ +/*------------------------------------------------------------------------- + * + * aio_subsys.h + * Interaction with AIO as a subsystem, rather than actually issuing AIO + * + * This header is for AIO related functionality that's being called by files + * that don't perform AIO but interact with it in some form. E.g. postmaster.c + * and shared memory initialization need to initialize AIO but don't perform + * AIO. + * + * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/storage/aio_subsys.h + * + *------------------------------------------------------------------------- + */ +#ifndef AIO_SUBSYS_H +#define AIO_SUBSYS_H + + +/* aio_init.c */ +extern Size AioShmemSize(void); +extern void AioShmemInit(void); + +extern void pgaio_init_backend(void); + +#endif /* AIO_SUBSYS_H */ diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index 1233e07d7da..de3bc37264f 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -318,6 +318,7 @@ extern PGDLLIMPORT bool optimize_bounded_sort; */ extern PGDLLIMPORT const struct config_enum_entry archive_mode_options[]; extern PGDLLIMPORT const struct config_enum_entry dynamic_shared_memory_options[]; +extern PGDLLIMPORT const struct config_enum_entry io_method_options[]; extern PGDLLIMPORT const struct config_enum_entry recovery_target_action_options[]; extern PGDLLIMPORT const struct config_enum_entry wal_level_options[]; extern PGDLLIMPORT const struct config_enum_entry wal_sync_method_options[]; diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 951451a9765..d1b49adc547 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -62,6 +62,8 @@ extern bool check_default_with_oids(bool *newval, void **extra, extern bool check_effective_io_concurrency(int *newval, void **extra, GucSource source); extern bool check_huge_page_size(int *newval, void **extra, GucSource source); +extern void assign_io_method(int newval, void *extra); +extern bool check_io_max_concurrency(int *newval, void **extra, GucSource source); extern const char *show_in_hot_standby(void); extern bool check_locale_messages(char **newval, void **extra, GucSource source); extern void assign_locale_messages(const char *newval, void *extra); diff --git a/src/include/utils/resowner.h b/src/include/utils/resowner.h index e8d452ca7ee..aede4bfc820 100644 --- a/src/include/utils/resowner.h +++ b/src/include/utils/resowner.h @@ -164,4 +164,9 @@ struct LOCALLOCK; extern void ResourceOwnerRememberLock(ResourceOwner owner, struct LOCALLOCK *locallock); extern void ResourceOwnerForgetLock(ResourceOwner owner, struct LOCALLOCK *locallock); +/* special support for AIO */ +struct dlist_node; +extern void ResourceOwnerRememberAioHandle(ResourceOwner owner, struct dlist_node *ioh_node); +extern void ResourceOwnerForgetAioHandle(ResourceOwner owner, struct dlist_node *ioh_node); + #endif /* RESOWNER_H */ diff --git a/src/backend/storage/aio/Makefile b/src/backend/storage/aio/Makefile index 2f29a9ec4d1..eaeaeeee8e3 100644 --- a/src/backend/storage/aio/Makefile +++ b/src/backend/storage/aio/Makefile @@ -9,6 +9,8 @@ top_builddir = ../../../.. include $(top_builddir)/src/Makefile.global OBJS = \ + aio.o \ + aio_init.o \ read_stream.o include $(top_srcdir)/src/backend/common.mk diff --git a/src/backend/storage/aio/aio.c b/src/backend/storage/aio/aio.c new file mode 100644 index 00000000000..8eb6a5f1292 --- /dev/null +++ b/src/backend/storage/aio/aio.c @@ -0,0 +1,67 @@ +/*------------------------------------------------------------------------- + * + * aio.c + * AIO - Core Logic + * + * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * IDENTIFICATION + * src/backend/storage/aio/aio.c + * + *------------------------------------------------------------------------- + */ + +#include "postgres.h" + +#include "lib/ilist.h" +#include "storage/aio.h" +#include "utils/guc.h" +#include "utils/guc_hooks.h" + + +/* Options for io_method. */ +const struct config_enum_entry io_method_options[] = { + {"sync", IOMETHOD_SYNC, false}, + {NULL, 0, false} +}; + +/* GUCs */ +int io_method = DEFAULT_IO_METHOD; +int io_max_concurrency = -1; + + + +void +assign_io_method(int newval, void *extra) +{ +} + +bool +check_io_max_concurrency(int *newval, void **extra, GucSource source) +{ + if (*newval == -1) + { + /* + * Auto-tuning will be applied later during startup, as auto-tuning + * depends on the value of various GUCs. + */ + return true; + } + else if (*newval == 0) + { + GUC_check_errdetail("Only -1 or values bigger than 0 are valid."); + return false; + } + + return true; +} + +/* + * Release IO handle during resource owner cleanup. + */ +void +pgaio_io_release_resowner(dlist_node *ioh_node, bool on_error) +{ + /* placeholder for later */ +} diff --git a/src/backend/storage/aio/aio_init.c b/src/backend/storage/aio/aio_init.c new file mode 100644 index 00000000000..aeacc144149 --- /dev/null +++ b/src/backend/storage/aio/aio_init.c @@ -0,0 +1,37 @@ +/*------------------------------------------------------------------------- + * + * aio_init.c + * AIO - Subsystem Initialization + * + * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * IDENTIFICATION + * src/backend/storage/aio/aio_init.c + * + *------------------------------------------------------------------------- + */ + +#include "postgres.h" + +#include "storage/aio_subsys.h" + + + +Size +AioShmemSize(void) +{ + Size sz = 0; + + return sz; +} + +void +AioShmemInit(void) +{ +} + +void +pgaio_init_backend(void) +{ +} diff --git a/src/backend/storage/aio/meson.build b/src/backend/storage/aio/meson.build index 8abe0eb4863..c822fd4ddf7 100644 --- a/src/backend/storage/aio/meson.build +++ b/src/backend/storage/aio/meson.build @@ -1,5 +1,7 @@ # Copyright (c) 2024-2025, PostgreSQL Global Development Group backend_sources += files( + 'aio.c', + 'aio_init.c', 'read_stream.c', ) diff --git a/src/backend/storage/ipc/ipci.c b/src/backend/storage/ipc/ipci.c index 174eed70367..2fa045e6b0f 100644 --- a/src/backend/storage/ipc/ipci.c +++ b/src/backend/storage/ipc/ipci.c @@ -37,6 +37,7 @@ #include "replication/slotsync.h" #include "replication/walreceiver.h" #include "replication/walsender.h" +#include "storage/aio_subsys.h" #include "storage/bufmgr.h" #include "storage/dsm.h" #include "storage/dsm_registry.h" @@ -148,6 +149,7 @@ CalculateShmemSize(int *num_semaphores) size = add_size(size, WaitEventCustomShmemSize()); size = add_size(size, InjectionPointShmemSize()); size = add_size(size, SlotSyncShmemSize()); + size = add_size(size, AioShmemSize()); /* include additional requested shmem from preload libraries */ size = add_size(size, total_addin_request); @@ -340,6 +342,7 @@ CreateOrAttachShmemStructs(void) StatsShmemInit(); WaitEventCustomShmemInit(); InjectionPointShmemInit(); + AioShmemInit(); } /* diff --git a/src/backend/utils/init/postinit.c b/src/backend/utils/init/postinit.c index b491d04de58..4410bbe602b 100644 --- a/src/backend/utils/init/postinit.c +++ b/src/backend/utils/init/postinit.c @@ -43,6 +43,7 @@ #include "replication/slot.h" #include "replication/slotsync.h" #include "replication/walsender.h" +#include "storage/aio_subsys.h" #include "storage/bufmgr.h" #include "storage/fd.h" #include "storage/ipc.h" @@ -626,6 +627,12 @@ BaseInit(void) */ pgstat_initialize(); + /* + * Initialize AIO before infrastructure that might need to actually + * execute AIO. + */ + pgaio_init_backend(); + /* Do local initialization of storage and buffer managers */ InitSync(); smgrinit(); diff --git a/src/backend/utils/misc/guc_tables.c b/src/backend/utils/misc/guc_tables.c index 3cde94a1759..b7c84d061e2 100644 --- a/src/backend/utils/misc/guc_tables.c +++ b/src/backend/utils/misc/guc_tables.c @@ -71,6 +71,7 @@ #include "replication/slot.h" #include "replication/slotsync.h" #include "replication/syncrep.h" +#include "storage/aio.h" #include "storage/bufmgr.h" #include "storage/bufpage.h" #include "storage/large_object.h" @@ -3252,6 +3253,18 @@ struct config_int ConfigureNamesInt[] = NULL, NULL, NULL }, + { + {"io_max_concurrency", + PGC_POSTMASTER, + RESOURCES_IO, + gettext_noop("Max number of IOs that one process can execute simultaneously."), + NULL, + }, + &io_max_concurrency, + -1, -1, 1024, + check_io_max_concurrency, NULL, NULL + }, + { {"backend_flush_after", PGC_USERSET, RESOURCES_IO, gettext_noop("Number of pages after which previously performed writes are flushed to disk."), @@ -5286,6 +5299,16 @@ struct config_enum ConfigureNamesEnum[] = NULL, NULL, NULL }, + { + {"io_method", PGC_POSTMASTER, RESOURCES_IO, + gettext_noop("Selects the method for executing asynchronous I/O."), + NULL + }, + &io_method, + DEFAULT_IO_METHOD, io_method_options, + NULL, assign_io_method, NULL + }, + /* End-of-list marker */ { {NULL, 0, 0, NULL, NULL}, NULL, 0, NULL, NULL, NULL, NULL diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample index 415f253096c..186bc47b700 100644 --- a/src/backend/utils/misc/postgresql.conf.sample +++ b/src/backend/utils/misc/postgresql.conf.sample @@ -199,6 +199,12 @@ #maintenance_io_concurrency = 10 # 1-1000; 0 disables prefetching #io_combine_limit = 128kB # usually 1-32 blocks (depends on OS) +#io_method = sync # sync (change requires restart) +#io_max_concurrency = -1 # Max number of IOs that one process + # can execute simultaneously + # -1 sets based on shared_buffers + # (change requires restart) + # - Worker Processes - #max_worker_processes = 8 # (change requires restart) diff --git a/src/backend/utils/resowner/resowner.c b/src/backend/utils/resowner/resowner.c index ac5ca4a765e..76b9cec1e26 100644 --- a/src/backend/utils/resowner/resowner.c +++ b/src/backend/utils/resowner/resowner.c @@ -47,6 +47,8 @@ #include "common/hashfn.h" #include "common/int.h" +#include "lib/ilist.h" +#include "storage/aio.h" #include "storage/ipc.h" #include "storage/predicate.h" #include "storage/proc.h" @@ -155,6 +157,12 @@ struct ResourceOwnerData /* The local locks cache. */ LOCALLOCK *locks[MAX_RESOWNER_LOCKS]; /* list of owned locks */ + + /* + * AIO handles need be registered in critical sections and therefore + * cannot use the normal ResoureElem mechanism. + */ + dlist_head aio_handles; }; @@ -425,6 +433,8 @@ ResourceOwnerCreate(ResourceOwner parent, const char *name) parent->firstchild = owner; } + dlist_init(&owner->aio_handles); + return owner; } @@ -725,6 +735,13 @@ ResourceOwnerReleaseInternal(ResourceOwner owner, * so issue warnings. In the abort case, just clean up quietly. */ ResourceOwnerReleaseAll(owner, phase, isCommit); + + while (!dlist_is_empty(&owner->aio_handles)) + { + dlist_node *node = dlist_head_node(&owner->aio_handles); + + pgaio_io_release_resowner(node, !isCommit); + } } else if (phase == RESOURCE_RELEASE_LOCKS) { @@ -1082,3 +1099,15 @@ ResourceOwnerForgetLock(ResourceOwner owner, LOCALLOCK *locallock) elog(ERROR, "lock reference %p is not owned by resource owner %s", locallock, owner->name); } + +void +ResourceOwnerRememberAioHandle(ResourceOwner owner, struct dlist_node *ioh_node) +{ + dlist_push_tail(&owner->aio_handles, ioh_node); +} + +void +ResourceOwnerForgetAioHandle(ResourceOwner owner, struct dlist_node *ioh_node) +{ + dlist_delete_from(&owner->aio_handles, ioh_node); +} diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml index 9eedcf6f0f4..0306827afbd 100644 --- a/doc/src/sgml/config.sgml +++ b/doc/src/sgml/config.sgml @@ -2618,6 +2618,57 @@ include_dir 'conf.d' + + + io_max_concurrency (integer) + + io_max_concurrency configuration parameter + + + + + Controls the maximum number of I/O operations that one process can + execute simultaneously. + + + The default setting of -1 selects a number based + on and the maximum number of + processes (, , and ), but not more than + 64. + + + This parameter can only be set at server start. + + + + + + io_method (enum) + + io_method configuration parameter + + + + + Selects the method for executing asynchronous I/O. + Possible values are: + + + + sync (execute asynchronous I/O synchronously) + + + + + + This parameter can only be set at server start. + + + + diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list index fb39c915d76..406c0893440 100644 --- a/src/tools/pgindent/typedefs.list +++ b/src/tools/pgindent/typedefs.list @@ -1267,6 +1267,7 @@ IntoClause InvalMessageArray InvalidationInfo InvalidationMsgsGroup +IoMethod IpcMemoryId IpcMemoryKey IpcMemoryState -- 2.48.1.76.g4e746b1a31.dirty