LCOV - code coverage report
Current view: top level - src/backend/storage/aio - aio_init.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 91.1 % 79 72
Test Date: 2026-04-06 02:16:11 Functions: 90.0 % 10 9
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /*-------------------------------------------------------------------------
       2              :  *
       3              :  * aio_init.c
       4              :  *    AIO - Subsystem Initialization
       5              :  *
       6              :  * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
       7              :  * Portions Copyright (c) 1994, Regents of the University of California
       8              :  *
       9              :  * IDENTIFICATION
      10              :  *    src/backend/storage/aio/aio_init.c
      11              :  *
      12              :  *-------------------------------------------------------------------------
      13              :  */
      14              : 
      15              : #include "postgres.h"
      16              : 
      17              : #include "miscadmin.h"
      18              : #include "storage/aio.h"
      19              : #include "storage/aio_internal.h"
      20              : #include "storage/aio_subsys.h"
      21              : #include "storage/bufmgr.h"
      22              : #include "storage/io_worker.h"
      23              : #include "storage/ipc.h"
      24              : #include "storage/proc.h"
      25              : #include "storage/shmem.h"
      26              : #include "storage/subsystems.h"
      27              : #include "utils/guc.h"
      28              : 
      29              : 
      30              : static void AioShmemRequest(void *arg);
      31              : static void AioShmemInit(void *arg);
      32              : static void AioShmemAttach(void *arg);
      33              : 
      34              : const ShmemCallbacks AioShmemCallbacks = {
      35              :     .request_fn = AioShmemRequest,
      36              :     .init_fn = AioShmemInit,
      37              :     .attach_fn = AioShmemAttach,
      38              : };
      39              : 
      40              : static PgAioBackend *AioBackendShmemPtr;
      41              : static PgAioHandle *AioHandleShmemPtr;
      42              : static struct iovec *AioHandleIOVShmemPtr;
      43              : static uint64 *AioHandleDataShmemPtr;
      44              : 
      45              : static uint32
      46       192592 : AioProcs(void)
      47              : {
      48              :     /*
      49              :      * While AIO workers don't need their own AIO context, we can't currently
      50              :      * guarantee that nothing gets assigned to an IO worker's ProcNumber if we
      51              :      * just subtracted MAX_IO_WORKERS.
      52              :      */
      53       192592 :     return MaxBackends + NUM_AUXILIARY_PROCS;
      54              : }
      55              : 
      56              : static Size
      57         1227 : AioBackendShmemSize(void)
      58              : {
      59         1227 :     return mul_size(AioProcs(), sizeof(PgAioBackend));
      60              : }
      61              : 
      62              : static Size
      63         1227 : AioHandleShmemSize(void)
      64              : {
      65              :     Size        sz;
      66              : 
      67              :     /* verify AioChooseMaxConcurrency() did its thing */
      68              :     Assert(io_max_concurrency > 0);
      69              : 
      70              :     /* io handles */
      71         1227 :     sz = mul_size(AioProcs(),
      72              :                   mul_size(io_max_concurrency, sizeof(PgAioHandle)));
      73              : 
      74         1227 :     return sz;
      75              : }
      76              : 
      77              : static Size
      78         1227 : AioHandleIOVShmemSize(void)
      79              : {
      80              :     /* each IO handle can have up to io_max_combine_limit iovec objects */
      81         1227 :     return mul_size(sizeof(struct iovec),
      82         1227 :                     mul_size(mul_size(io_max_combine_limit, AioProcs()),
      83              :                              io_max_concurrency));
      84              : }
      85              : 
      86              : static Size
      87         1227 : AioHandleDataShmemSize(void)
      88              : {
      89              :     /* each buffer referenced by an iovec can have associated data */
      90         1227 :     return mul_size(sizeof(uint64),
      91         1227 :                     mul_size(mul_size(io_max_combine_limit, AioProcs()),
      92              :                              io_max_concurrency));
      93              : }
      94              : 
      95              : /*
      96              :  * Choose a suitable value for io_max_concurrency.
      97              :  *
      98              :  * It's unlikely that we could have more IOs in flight than buffers that we
      99              :  * would be allowed to pin.
     100              :  *
     101              :  * On the upper end, apply a cap too - just because shared_buffers is large,
     102              :  * it doesn't make sense have millions of buffers undergo IO concurrently.
     103              :  */
     104              : static int
     105         1221 : AioChooseMaxConcurrency(void)
     106              : {
     107              :     uint32      max_backends;
     108              :     int         max_proportional_pins;
     109              : 
     110              :     /* Similar logic to LimitAdditionalPins() */
     111         1221 :     max_backends = MaxBackends + NUM_AUXILIARY_PROCS;
     112         1221 :     max_proportional_pins = NBuffers / max_backends;
     113              : 
     114         1221 :     max_proportional_pins = Max(max_proportional_pins, 1);
     115              : 
     116              :     /* apply upper limit */
     117         1221 :     return Min(max_proportional_pins, 64);
     118              : }
     119              : 
     120              : /*
     121              :  * Register AIO subsystem's shared memory needs.
     122              :  */
     123              : static void
     124         1227 : AioShmemRequest(void *arg)
     125              : {
     126              :     /*
     127              :      * Resolve io_max_concurrency if not already done
     128              :      *
     129              :      * We prefer to report this value's source as PGC_S_DYNAMIC_DEFAULT.
     130              :      * However, if the DBA explicitly set io_max_concurrency = -1 in the
     131              :      * config file, then PGC_S_DYNAMIC_DEFAULT will fail to override that and
     132              :      * we must force the matter with PGC_S_OVERRIDE.
     133              :      */
     134         1227 :     if (io_max_concurrency == -1)
     135              :     {
     136              :         char        buf[32];
     137              : 
     138         1221 :         snprintf(buf, sizeof(buf), "%d", AioChooseMaxConcurrency());
     139         1221 :         SetConfigOption("io_max_concurrency", buf, PGC_POSTMASTER,
     140              :                         PGC_S_DYNAMIC_DEFAULT);
     141         1221 :         if (io_max_concurrency == -1)   /* failed to apply it? */
     142            0 :             SetConfigOption("io_max_concurrency", buf, PGC_POSTMASTER,
     143              :                             PGC_S_OVERRIDE);
     144              :     }
     145              : 
     146         1227 :     ShmemRequestStruct(.name = "AioCtl",
     147              :                        .size = sizeof(PgAioCtl),
     148              :                        .ptr = (void **) &pgaio_ctl,
     149              :         );
     150              : 
     151         1227 :     ShmemRequestStruct(.name = "AioBackend",
     152              :                        .size = AioBackendShmemSize(),
     153              :                        .ptr = (void **) &AioBackendShmemPtr,
     154              :         );
     155              : 
     156         1227 :     ShmemRequestStruct(.name = "AioHandle",
     157              :                        .size = AioHandleShmemSize(),
     158              :                        .ptr = (void **) &AioHandleShmemPtr,
     159              :         );
     160              : 
     161         1227 :     ShmemRequestStruct(.name = "AioHandleIOV",
     162              :                        .size = AioHandleIOVShmemSize(),
     163              :                        .ptr = (void **) &AioHandleIOVShmemPtr,
     164              :         );
     165              : 
     166         1227 :     ShmemRequestStruct(.name = "AioHandleData",
     167              :                        .size = AioHandleDataShmemSize(),
     168              :                        .ptr = (void **) &AioHandleDataShmemPtr,
     169              :         );
     170              : 
     171         1227 :     if (pgaio_method_ops->shmem_callbacks.request_fn)
     172         1220 :         pgaio_method_ops->shmem_callbacks.request_fn(pgaio_method_ops->shmem_callbacks.opaque_arg);
     173         1227 : }
     174              : 
     175              : /*
     176              :  * Initialize AIO shared memory during postmaster startup.
     177              :  */
     178              : static void
     179         1224 : AioShmemInit(void *arg)
     180              : {
     181         1224 :     uint32      io_handle_off = 0;
     182         1224 :     uint32      iovec_off = 0;
     183         1224 :     uint32      per_backend_iovecs = io_max_concurrency * io_max_combine_limit;
     184              : 
     185         1224 :     pgaio_ctl->io_handle_count = AioProcs() * io_max_concurrency;
     186         1224 :     pgaio_ctl->iovec_count = AioProcs() * per_backend_iovecs;
     187              : 
     188         1224 :     pgaio_ctl->backend_state = AioBackendShmemPtr;
     189         1224 :     pgaio_ctl->io_handles = AioHandleShmemPtr;
     190         1224 :     pgaio_ctl->iovecs = AioHandleIOVShmemPtr;
     191         1224 :     pgaio_ctl->handle_data = AioHandleDataShmemPtr;
     192              : 
     193       162533 :     for (int procno = 0; procno < AioProcs(); procno++)
     194              :     {
     195       161309 :         PgAioBackend *bs = &pgaio_ctl->backend_state[procno];
     196              : 
     197       161309 :         bs->io_handle_off = io_handle_off;
     198       161309 :         io_handle_off += io_max_concurrency;
     199              : 
     200       161309 :         dclist_init(&bs->idle_ios);
     201       161309 :         memset(bs->staged_ios, 0, sizeof(PgAioHandle *) * PGAIO_SUBMIT_BATCH_SIZE);
     202       161309 :         dclist_init(&bs->in_flight_ios);
     203              : 
     204              :         /* initialize per-backend IOs */
     205      7831291 :         for (int i = 0; i < io_max_concurrency; i++)
     206              :         {
     207      7669982 :             PgAioHandle *ioh = &pgaio_ctl->io_handles[bs->io_handle_off + i];
     208              : 
     209      7669982 :             ioh->generation = 1;
     210      7669982 :             ioh->owner_procno = procno;
     211      7669982 :             ioh->iovec_off = iovec_off;
     212      7669982 :             ioh->handle_data_len = 0;
     213      7669982 :             ioh->report_return = NULL;
     214      7669982 :             ioh->resowner = NULL;
     215      7669982 :             ioh->num_callbacks = 0;
     216      7669982 :             ioh->distilled_result.status = PGAIO_RS_UNKNOWN;
     217      7669982 :             ioh->flags = 0;
     218              : 
     219      7669982 :             ConditionVariableInit(&ioh->cv);
     220              : 
     221      7669982 :             dclist_push_tail(&bs->idle_ios, &ioh->node);
     222      7669982 :             iovec_off += io_max_combine_limit;
     223              :         }
     224              :     }
     225              : 
     226         1224 :     if (pgaio_method_ops->shmem_callbacks.init_fn)
     227         1217 :         pgaio_method_ops->shmem_callbacks.init_fn(pgaio_method_ops->shmem_callbacks.opaque_arg);
     228         1224 : }
     229              : 
     230              : static void
     231            0 : AioShmemAttach(void *arg)
     232              : {
     233            0 :     if (pgaio_method_ops->shmem_callbacks.attach_fn)
     234            0 :         pgaio_method_ops->shmem_callbacks.attach_fn(pgaio_method_ops->shmem_callbacks.opaque_arg);
     235            0 : }
     236              : 
     237              : void
     238        24608 : pgaio_init_backend(void)
     239              : {
     240              :     /* shouldn't be initialized twice */
     241              :     Assert(!pgaio_my_backend);
     242              : 
     243        24608 :     if (MyBackendType == B_IO_WORKER)
     244         1905 :         return;
     245              : 
     246        22703 :     if (MyProc == NULL || MyProcNumber >= AioProcs())
     247            0 :         elog(ERROR, "aio requires a normal PGPROC");
     248              : 
     249        22703 :     pgaio_my_backend = &pgaio_ctl->backend_state[MyProcNumber];
     250              : 
     251        22703 :     if (pgaio_method_ops->init_backend)
     252            0 :         pgaio_method_ops->init_backend();
     253              : 
     254        22703 :     before_shmem_exit(pgaio_shutdown, 0);
     255              : }
        

Generated by: LCOV version 2.0-1