Skip to content

Commit

Permalink
Fully support proc diskstats 14, 18, or 20 fields
Browse files Browse the repository at this point in the history
/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.
  • Loading branch information
jconway committed Jan 26, 2022
1 parent b01ea84 commit 3f29e53
Show file tree
Hide file tree
Showing 7 changed files with 89 additions and 35 deletions.
2 changes: 1 addition & 1 deletion genutils.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 *));
Expand Down
29 changes: 21 additions & 8 deletions pg_proctab--0.0.9-compat.sql
Original file line number Diff line number Diff line change
Expand Up @@ -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;
28 changes: 28 additions & 0 deletions pgnodemx--1.2--1.3.sql
Original file line number Diff line number Diff line change
Expand Up @@ -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;
20 changes: 13 additions & 7 deletions pgnodemx--1.3.sql
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down
15 changes: 9 additions & 6 deletions pgnodemx.c
Original file line number Diff line number Diff line change
Expand Up @@ -75,24 +75,27 @@ 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,
NUMERICOID, 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,
Expand Down Expand Up @@ -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
Expand Down
25 changes: 14 additions & 11 deletions procfunc.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand All @@ -187,15 +185,20 @@ 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
ereport(ERROR,
(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);
}

/*
Expand Down
5 changes: 3 additions & 2 deletions srfsigs.h
Original file line number Diff line number Diff line change
Expand Up @@ -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_ */

0 comments on commit 3f29e53

Please sign in to comment.