Extract logic filling pg_stat_get_io()'s tuplestore into its own routine
authorMichael Paquier <michael@paquier.xyz>
Thu, 19 Dec 2024 01:16:02 +0000 (10:16 +0900)
committerMichael Paquier <michael@paquier.xyz>
Thu, 19 Dec 2024 01:16:02 +0000 (10:16 +0900)
This commit adds pg_stat_io_build_tuples(), a helper routine for
pg_stat_get_io(), that fills its result tuplestore based on the contents
of PgStat_BktypeIO.  This will be used in a follow-up commit that uses
the same structures as pg_stat_io for reporting, including the same
object types and contexts, but for a different statistics kind.

Author: Bertrand Drouvot, Michael Paquier
Discussion: https://postgr.es/m/ZtXR+CtkEVVE/LHF@ip-10-97-1-34.eu-west-3.compute.internal

src/backend/utils/adt/pgstatfuncs.c

index cdf37403e9d521793d1a60e05ec21214c5537c45..03dd8cd335a5ad1b34c40f7de4a3f822f4926e81 100644 (file)
@@ -1365,29 +1365,117 @@ pg_stat_us_to_ms(PgStat_Counter val_ms)
    return val_ms * (double) 0.001;
 }
 
+/*
+ * pg_stat_io_build_tuples
+ *
+ * Helper routine for pg_stat_get_io() filling a result tuplestore with one
+ * tuple for each object and each context supported by the caller, based on the
+ * contents of bktype_stats.
+ */
+static void
+pg_stat_io_build_tuples(ReturnSetInfo *rsinfo,
+                       PgStat_BktypeIO *bktype_stats,
+                       BackendType bktype,
+                       TimestampTz stat_reset_timestamp)
+{
+   Datum       bktype_desc = CStringGetTextDatum(GetBackendTypeDesc(bktype));
+
+   for (int io_obj = 0; io_obj < IOOBJECT_NUM_TYPES; io_obj++)
+   {
+       const char *obj_name = pgstat_get_io_object_name(io_obj);
+
+       for (int io_context = 0; io_context < IOCONTEXT_NUM_TYPES; io_context++)
+       {
+           const char *context_name = pgstat_get_io_context_name(io_context);
+
+           Datum       values[IO_NUM_COLUMNS] = {0};
+           bool        nulls[IO_NUM_COLUMNS] = {0};
+
+           /*
+            * Some combinations of BackendType, IOObject, and IOContext are
+            * not valid for any type of IOOp. In such cases, omit the entire
+            * row from the view.
+            */
+           if (!pgstat_tracks_io_object(bktype, io_obj, io_context))
+               continue;
+
+           values[IO_COL_BACKEND_TYPE] = bktype_desc;
+           values[IO_COL_CONTEXT] = CStringGetTextDatum(context_name);
+           values[IO_COL_OBJECT] = CStringGetTextDatum(obj_name);
+           if (stat_reset_timestamp != 0)
+               values[IO_COL_RESET_TIME] = TimestampTzGetDatum(stat_reset_timestamp);
+           else
+               nulls[IO_COL_RESET_TIME] = true;
+
+           /*
+            * Hard-code this to the value of BLCKSZ for now. Future values
+            * could include XLOG_BLCKSZ, once WAL IO is tracked, and constant
+            * multipliers, once non-block-oriented IO (e.g. temporary file
+            * IO) is tracked.
+            */
+           values[IO_COL_CONVERSION] = Int64GetDatum(BLCKSZ);
+
+           for (int io_op = 0; io_op < IOOP_NUM_TYPES; io_op++)
+           {
+               int         op_idx = pgstat_get_io_op_index(io_op);
+               int         time_idx = pgstat_get_io_time_index(io_op);
+
+               /*
+                * Some combinations of BackendType and IOOp, of IOContext and
+                * IOOp, and of IOObject and IOOp are not tracked. Set these
+                * cells in the view NULL.
+                */
+               if (pgstat_tracks_io_op(bktype, io_obj, io_context, io_op))
+               {
+                   PgStat_Counter count =
+                       bktype_stats->counts[io_obj][io_context][io_op];
+
+                   values[op_idx] = Int64GetDatum(count);
+               }
+               else
+                   nulls[op_idx] = true;
+
+               /* not every operation is timed */
+               if (time_idx == IO_COL_INVALID)
+                   continue;
+
+               if (!nulls[op_idx])
+               {
+                   PgStat_Counter time =
+                       bktype_stats->times[io_obj][io_context][io_op];
+
+                   values[time_idx] = Float8GetDatum(pg_stat_us_to_ms(time));
+               }
+               else
+                   nulls[time_idx] = true;
+           }
+
+           tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc,
+                                values, nulls);
+       }
+   }
+}
+
 Datum
 pg_stat_get_io(PG_FUNCTION_ARGS)
 {
    ReturnSetInfo *rsinfo;
    PgStat_IO  *backends_io_stats;
-   Datum       reset_time;
 
    InitMaterializedSRF(fcinfo, 0);
    rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
 
    backends_io_stats = pgstat_fetch_stat_io();
 
-   reset_time = TimestampTzGetDatum(backends_io_stats->stat_reset_timestamp);
-
    for (int bktype = 0; bktype < BACKEND_NUM_TYPES; bktype++)
    {
-       Datum       bktype_desc = CStringGetTextDatum(GetBackendTypeDesc(bktype));
        PgStat_BktypeIO *bktype_stats = &backends_io_stats->stats[bktype];
 
        /*
         * In Assert builds, we can afford an extra loop through all of the
-        * counters checking that only expected stats are non-zero, since it
-        * keeps the non-Assert code cleaner.
+        * counters (in pg_stat_io_build_tuples()), checking that only
+        * expected stats are non-zero, since it keeps the non-Assert code
+        * cleaner.
         */
        Assert(pgstat_bktype_io_stats_valid(bktype_stats, bktype));
 
@@ -1398,77 +1486,9 @@ pg_stat_get_io(PG_FUNCTION_ARGS)
        if (!pgstat_tracks_io_bktype(bktype))
            continue;
 
-       for (int io_obj = 0; io_obj < IOOBJECT_NUM_TYPES; io_obj++)
-       {
-           const char *obj_name = pgstat_get_io_object_name(io_obj);
-
-           for (int io_context = 0; io_context < IOCONTEXT_NUM_TYPES; io_context++)
-           {
-               const char *context_name = pgstat_get_io_context_name(io_context);
-
-               Datum       values[IO_NUM_COLUMNS] = {0};
-               bool        nulls[IO_NUM_COLUMNS] = {0};
-
-               /*
-                * Some combinations of BackendType, IOObject, and IOContext
-                * are not valid for any type of IOOp. In such cases, omit the
-                * entire row from the view.
-                */
-               if (!pgstat_tracks_io_object(bktype, io_obj, io_context))
-                   continue;
-
-               values[IO_COL_BACKEND_TYPE] = bktype_desc;
-               values[IO_COL_CONTEXT] = CStringGetTextDatum(context_name);
-               values[IO_COL_OBJECT] = CStringGetTextDatum(obj_name);
-               values[IO_COL_RESET_TIME] = reset_time;
-
-               /*
-                * Hard-code this to the value of BLCKSZ for now. Future
-                * values could include XLOG_BLCKSZ, once WAL IO is tracked,
-                * and constant multipliers, once non-block-oriented IO (e.g.
-                * temporary file IO) is tracked.
-                */
-               values[IO_COL_CONVERSION] = Int64GetDatum(BLCKSZ);
-
-               for (int io_op = 0; io_op < IOOP_NUM_TYPES; io_op++)
-               {
-                   int         op_idx = pgstat_get_io_op_index(io_op);
-                   int         time_idx = pgstat_get_io_time_index(io_op);
-
-                   /*
-                    * Some combinations of BackendType and IOOp, of IOContext
-                    * and IOOp, and of IOObject and IOOp are not tracked. Set
-                    * these cells in the view NULL.
-                    */
-                   if (pgstat_tracks_io_op(bktype, io_obj, io_context, io_op))
-                   {
-                       PgStat_Counter count =
-                           bktype_stats->counts[io_obj][io_context][io_op];
-
-                       values[op_idx] = Int64GetDatum(count);
-                   }
-                   else
-                       nulls[op_idx] = true;
-
-                   /* not every operation is timed */
-                   if (time_idx == IO_COL_INVALID)
-                       continue;
-
-                   if (!nulls[op_idx])
-                   {
-                       PgStat_Counter time =
-                           bktype_stats->times[io_obj][io_context][io_op];
-
-                       values[time_idx] = Float8GetDatum(pg_stat_us_to_ms(time));
-                   }
-                   else
-                       nulls[time_idx] = true;
-               }
-
-               tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc,
-                                    values, nulls);
-           }
-       }
+       /* save tuples with data from this PgStat_BktypeIO */
+       pg_stat_io_build_tuples(rsinfo, bktype_stats, bktype,
+                               backends_io_stats->stat_reset_timestamp);
    }
 
    return (Datum) 0;