From 3f29e53882cd64e4b103ceba6b687109fbe68613 Mon Sep 17 00:00:00 2001 From: Joe Conway Date: Wed, 26 Jan 2022 17:15:52 -0500 Subject: [PATCH] Fully support proc diskstats 14, 18, or 20 fields /proc/diskstats has 14 fields prior to kernel 4.18 and 18 fields prior to kernel 5.5. The lines from that file were being parsed correctly and checked for one of those lengths previously, however the last 6 fields were being unconditionally discarded. Now they are preserved in the output when present, and NULL values passed when they are not. Also add these fields to the recently committed pg_proctab compatibility function. In this case any NULL fields are COALESCE'd to 0, since that is what pg_proctab itself does. --- genutils.c | 2 +- pg_proctab--0.0.9-compat.sql | 29 +++++++++++++++++++++-------- pgnodemx--1.2--1.3.sql | 28 ++++++++++++++++++++++++++++ pgnodemx--1.3.sql | 20 +++++++++++++------- pgnodemx.c | 15 +++++++++------ procfunc.c | 25 ++++++++++++++----------- srfsigs.h | 5 +++-- 7 files changed, 89 insertions(+), 35 deletions(-) diff --git a/genutils.c b/genutils.c index 94009fe..14a9bf6 100644 --- a/genutils.c +++ b/genutils.c @@ -845,7 +845,7 @@ Datum pgnodemx_stat_file(PG_FUNCTION_ARGS) groupname = pstrdup(grp->gr_name); /* get mode string */ - snprintf(buf, INTEGER_LEN, "%jo", (uintmax_t) st_mode); + snprintf(buf, INTEGER_LEN, "%o", st_mode & (S_IRWXU | S_IRWXG | S_IRWXO)); modestr = pstrdup(buf); values[0] = (char **) palloc(ncol * sizeof(char *)); diff --git a/pg_proctab--0.0.9-compat.sql b/pg_proctab--0.0.9-compat.sql index 52a09b5..248e277 100644 --- a/pg_proctab--0.0.9-compat.sql +++ b/pg_proctab--0.0.9-compat.sql @@ -169,23 +169,36 @@ CREATE OR REPLACE FUNCTION pg_diskusage ( OUT writetime bigint, OUT current_io bigint, OUT iotime bigint, - OUT totaliotime bigint) + OUT totaliotime bigint, + OUT discards_completed bigint, + OUT discards_merged bigint, + OUT sectors_discarded bigint, + OUT discardtime bigint, + OUT flushes_completed bigint, + OUT flushtime bigint +) RETURNS SETOF record AS $$ SELECT major_number::smallint AS major, minor_number::smallint AS minor, device_name AS devname, - reads_completed_successfully AS reads_completed, - reads_merged AS reads_merged, - sectors_read AS sectors_read, + reads_completed_successfully::bigint AS reads_completed, + reads_merged::bigint AS reads_merged, + sectors_read::bigint AS sectors_read, time_spent_reading_ms AS readtime, - writes_completed AS writes_completed, - writes_merged AS writes_merged, - sectors_written AS sectors_written, + writes_completed::bigint AS writes_completed, + writes_merged::bigint AS writes_merged, + sectors_written::bigint AS sectors_written, time_spent_writing_ms AS writetime, ios_currently_in_progress AS current_io, time_spent_doing_ios_ms AS iotime, - weighted_time_spent_doing_ios_ms AS totaliotime + weighted_time_spent_doing_ios_ms AS totaliotime, + COALESCE(discards_completed_successfully, 0)::bigint AS discards_completed, + COALESCE(discards_merged, 0)::bigint AS discards_merged, + COALESCE(sectors_discarded, 0)::bigint AS sectors_discarded, + COALESCE(time_spent_discarding, 0) AS discardtime, + COALESCE(flush_requests_completed_successfully, 0)::bigint AS flushes_completed, + COALESCE(time_spent_flushing, 0) AS flushtime FROM proc_diskstats() $$ LANGUAGE sql; diff --git a/pgnodemx--1.2--1.3.sql b/pgnodemx--1.2--1.3.sql index f3c864b..3c60c81 100644 --- a/pgnodemx--1.2--1.3.sql +++ b/pgnodemx--1.2--1.3.sql @@ -128,3 +128,31 @@ CREATE OR REPLACE FUNCTION openssl_version() RETURNS TEXT AS 'MODULE_PATHNAME', 'pgnodemx_openssl_version' LANGUAGE C IMMUTABLE STRICT; + +DROP FUNCTION proc_diskstats(); +CREATE FUNCTION proc_diskstats +( + OUT major_number BIGINT, + OUT minor_number BIGINT, + OUT device_name TEXT, + OUT reads_completed_successfully NUMERIC, + OUT reads_merged NUMERIC, + OUT sectors_read NUMERIC, + OUT time_spent_reading_ms BIGINT, + OUT writes_completed NUMERIC, + OUT writes_merged NUMERIC, + OUT sectors_written NUMERIC, + OUT time_spent_writing_ms BIGINT, + OUT ios_currently_in_progress BIGINT, + OUT time_spent_doing_ios_ms BIGINT, + OUT weighted_time_spent_doing_ios_ms BIGINT, + OUT discards_completed_successfully NUMERIC, + OUT discards_merged NUMERIC, + OUT sectors_discarded NUMERIC, + OUT time_spent_discarding BIGINT, + OUT flush_requests_completed_successfully NUMERIC, + OUT time_spent_flushing BIGINT +) +RETURNS SETOF record +AS 'MODULE_PATHNAME', 'pgnodemx_proc_diskstats' +LANGUAGE C STABLE STRICT; diff --git a/pgnodemx--1.3.sql b/pgnodemx--1.3.sql index 9ed640a..6f51f1c 100644 --- a/pgnodemx--1.3.sql +++ b/pgnodemx--1.3.sql @@ -134,17 +134,23 @@ CREATE FUNCTION proc_diskstats OUT major_number BIGINT, OUT minor_number BIGINT, OUT device_name TEXT, - OUT reads_completed_successfully BIGINT, - OUT reads_merged BIGINT, - OUT sectors_read BIGINT, + OUT reads_completed_successfully NUMERIC, + OUT reads_merged NUMERIC, + OUT sectors_read NUMERIC, OUT time_spent_reading_ms BIGINT, - OUT writes_completed BIGINT, - OUT writes_merged BIGINT, - OUT sectors_written BIGINT, + OUT writes_completed NUMERIC, + OUT writes_merged NUMERIC, + OUT sectors_written NUMERIC, OUT time_spent_writing_ms BIGINT, OUT ios_currently_in_progress BIGINT, OUT time_spent_doing_ios_ms BIGINT, - OUT weighted_time_spent_doing_ios_ms BIGINT + OUT weighted_time_spent_doing_ios_ms BIGINT, + OUT discards_completed_successfully NUMERIC, + OUT discards_merged NUMERIC, + OUT sectors_discarded NUMERIC, + OUT time_spent_discarding BIGINT, + OUT flush_requests_completed_successfully NUMERIC, + OUT time_spent_flushing BIGINT ) RETURNS SETOF record AS 'MODULE_PATHNAME', 'pgnodemx_proc_diskstats' diff --git a/pgnodemx.c b/pgnodemx.c index 2b90360..4dc560c 100644 --- a/pgnodemx.c +++ b/pgnodemx.c @@ -75,17 +75,12 @@ Oid _2_numeric_text_9_numeric_text_sig[] = {NUMERICOID, NUMERICOID, TEXTOID, NUM NUMERICOID, NUMERICOID, NUMERICOID, TEXTOID}; Oid _4_bigint_6_text_sig[] = {INT8OID, INT8OID, INT8OID, INT8OID, TEXTOID, TEXTOID, TEXTOID, TEXTOID, TEXTOID, TEXTOID}; -Oid bigint_bigint_text_11_bigint_sig[] = {INT8OID, INT8OID, TEXTOID, - INT8OID, INT8OID, INT8OID, INT8OID, - INT8OID, INT8OID, INT8OID, INT8OID, - INT8OID, INT8OID, INT8OID}; Oid text_16_bigint_sig[] = {TEXTOID, INT8OID, INT8OID, INT8OID, INT8OID, INT8OID, INT8OID, INT8OID, INT8OID, INT8OID, INT8OID, INT8OID, INT8OID, INT8OID, INT8OID, INT8OID, INT8OID}; - Oid _5_bigint_sig[] = { INT8OID, INT8OID, INT8OID, INT8OID, INT8OID }; Oid int_7_numeric_sig[] = { INT4OID, NUMERICOID, NUMERICOID, NUMERICOID, @@ -93,6 +88,14 @@ Oid int_7_numeric_sig[] = { INT4OID, NUMERICOID, NUMERICOID, NUMERICOID, Oid int_text_int_text_sig[] = { INT4OID, TEXTOID, INT4OID, TEXTOID }; Oid load_avg_sig[] = { FLOAT8OID, FLOAT8OID, FLOAT8OID, INT4OID }; +/* proc_diskstats is unique enough to have its own sig */ +Oid proc_diskstats_sig[] = {INT8OID, INT8OID, TEXTOID, + NUMERICOID, NUMERICOID, NUMERICOID, INT8OID, + NUMERICOID, NUMERICOID, NUMERICOID, INT8OID, + INT8OID, INT8OID, INT8OID, + NUMERICOID, NUMERICOID, NUMERICOID, INT8OID, + NUMERICOID, INT8OID}; + /* proc_pid_stat is unique enough to have its own sig */ Oid proc_pid_stat_sig[] = {INT4OID, TEXTOID, TEXTOID, INT4OID, INT4OID, INT4OID, INT4OID, @@ -193,7 +196,7 @@ _PG_init(void) } /* force kdapi disabled if path does not exist */ - if (access(kdapi_path, F_OK) != 0) + if (kdapi_enabled && access(kdapi_path, F_OK) != 0) { /* * If kdapi_path does not exist, there is not diff --git a/procfunc.c b/procfunc.c index b78620a..2db641c 100644 --- a/procfunc.c +++ b/procfunc.c @@ -138,32 +138,30 @@ check_procfs(void) * 19 - flush requests completed successfully * 20 - time spent flushing * - * For now, validate either 14,18, or 20 fields found when - * parsing the lines, but only return the first 14. If there - * is demand for the other fields at some point, possibly - * add them then. + * Validate either 14,18, or 20 fields found when + * parsing the lines. Unused fields passed as NULL. */ PG_FUNCTION_INFO_V1(pgnodemx_proc_diskstats); Datum pgnodemx_proc_diskstats(PG_FUNCTION_ARGS) { int nrow = 0; - int ncol = 14; + int ncol = 20; char ***values = (char ***) palloc(0); char **lines; int nlines; if (!proc_enabled) - return form_srf(fcinfo, NULL, 0, ncol, bigint_bigint_text_11_bigint_sig); + return form_srf(fcinfo, NULL, 0, ncol, proc_diskstats_sig); /* read /proc/diskstats file */ lines = read_nlsv(diskstats, &nlines); /* * These files have either 14,18, or 20 fields per line. - * We will validate one of those lengths, but only use 14 of the - * space separated columns. The third column is the device name. - * Rest of the columns are bigints. + * Validate one of those lengths. The third column is the device name. + * Rest of the columns are unsigned long or unsigned int, which + * are mapped to postgres numeric or bigints respectively. */ if (nlines > 0) { @@ -187,7 +185,12 @@ pgnodemx_proc_diskstats(PG_FUNCTION_ARGS) ntok, diskstats, j + 1))); for (k = 0; k < ncol; ++k) - values[j][k] = pstrdup(toks[k]); + { + if (k < ntok) + values[j][k] = pstrdup(toks[k]); + else + values[j][k] = NULL; + } } } else @@ -195,7 +198,7 @@ pgnodemx_proc_diskstats(PG_FUNCTION_ARGS) (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), errmsg("pgnodemx: no data in file: %s ", diskstats))); - return form_srf(fcinfo, values, nrow, ncol, bigint_bigint_text_11_bigint_sig); + return form_srf(fcinfo, values, nrow, ncol, proc_diskstats_sig); } /* diff --git a/srfsigs.h b/srfsigs.h index dde40b2..0471f88 100644 --- a/srfsigs.h +++ b/srfsigs.h @@ -37,13 +37,14 @@ extern Oid text_text_bigint_sig[]; extern Oid text_text_float8_sig[]; extern Oid _2_numeric_text_9_numeric_text_sig[]; extern Oid _4_bigint_6_text_sig[]; -extern Oid bigint_bigint_text_11_bigint_sig[]; extern Oid text_16_bigint_sig[]; extern Oid _5_bigint_sig[]; extern Oid int_7_numeric_sig[]; extern Oid int_text_int_text_sig[]; +extern Oid num_text_num_2_text_sig[]; + extern Oid load_avg_sig[]; +extern Oid proc_diskstats_sig[]; extern Oid proc_pid_stat_sig[]; -extern Oid num_text_num_2_text_sig[]; #endif /* _SRFSIGS_H_ */