From c31435a09a7098cd8b443c995b3fb75a0654023b Mon Sep 17 00:00:00 2001 From: Thomas Reiss Date: Fri, 26 Jun 2015 16:21:24 +0200 Subject: [PATCH] Add pg_diskusage function Uses the tuplestore interface, so the code layout is slighly different from the original. --- sql/{pg_proctab.sql => pg_proctab--0.0.5.sql} | 0 src/pg_proctab.c | 116 ++++++++++++++++++ 2 files changed, 116 insertions(+) rename sql/{pg_proctab.sql => pg_proctab--0.0.5.sql} (100%) diff --git a/sql/pg_proctab.sql b/sql/pg_proctab--0.0.5.sql similarity index 100% rename from sql/pg_proctab.sql rename to sql/pg_proctab--0.0.5.sql diff --git a/src/pg_proctab.c b/src/pg_proctab.c index 4867321..978cc53 100644 --- a/src/pg_proctab.c +++ b/src/pg_proctab.c @@ -6,6 +6,11 @@ #include #include "fmgr.h" #include "funcapi.h" +#include "miscadmin.h" +#include "access/htup_details.h" +#include "utils/tuplestore.h" +#include "storage/fd.h" +#include "utils/builtins.h" #include #include #include @@ -53,6 +58,10 @@ enum cputime {i_user, i_nice_c, i_system, i_idle, i_iowait}; enum loadavg {i_load1, i_load5, i_load15, i_last_pid}; enum memusage {i_memused, i_memfree, i_memshared, i_membuffers, i_memcached, i_swapused, i_swapfree, i_swapcached}; +enum diskusage {i_major, i_minor, i_devname, + i_reads_completed, i_reads_merged, i_sectors_read, i_readtime, + i_writes_completed, i_writes_merged, i_sectors_written, i_writetime, + i_current_io, i_iotime,i_totaliotime}; int get_proctab(FuncCallContext *, char **); int get_cputime(char **); @@ -63,11 +72,13 @@ Datum pg_proctab(PG_FUNCTION_ARGS); Datum pg_cputime(PG_FUNCTION_ARGS); Datum pg_loadavg(PG_FUNCTION_ARGS); Datum pg_memusage(PG_FUNCTION_ARGS); +Datum pg_diskusage(PG_FUNCTION_ARGS); PG_FUNCTION_INFO_V1(pg_proctab); PG_FUNCTION_INFO_V1(pg_cputime); PG_FUNCTION_INFO_V1(pg_loadavg); PG_FUNCTION_INFO_V1(pg_memusage); +PG_FUNCTION_INFO_V1(pg_diskusage); Datum pg_proctab(PG_FUNCTION_ARGS) { @@ -1060,3 +1071,108 @@ get_memusage(char **values) return 1; } + +Datum pg_diskusage(PG_FUNCTION_ARGS) +{ + ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo; + MemoryContext per_query_ctx; + MemoryContext oldcontext; + TupleDesc tupleDesc; + Tuplestorestate *tupleStore; + + Datum values[14]; + bool nulls[14]; + + char device_name[4096]; + struct statfs sb; + FILE *fd; + int ret; + + int major = 0; + int minor = 0; + int64 reads_completed = 0; + int64 reads_merged = 0; + int64 sectors_read = 0; + int64 readtime = 0; + int64 writes_completed = 0; + int64 writes_merged = 0; + int64 sectors_written = 0; + int64 writetime = 0; + int64 current_io = 0; + int64 iotime = 0; + int64 totaliotime = 0; + + elog(DEBUG5, "pg_diskusage: Entering stored function."); + + if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo)) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg + ("set-valued function called in context that cannot accept a set"))); + if (!(rsinfo->allowedModes & SFRM_Materialize)) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("materialize mode required, but it is not " + "allowed in this context"))); + + per_query_ctx = rsinfo->econtext->ecxt_per_query_memory; + oldcontext = MemoryContextSwitchTo(per_query_ctx); + + /* + Build a tuple descriptor for our result type + */ + if (get_call_result_type(fcinfo, NULL, &tupleDesc) != TYPEFUNC_COMPOSITE) + elog(ERROR, "return type must be a row type"); + + tupleStore = tuplestore_begin_heap(true, false, work_mem); + rsinfo->returnMode = SFRM_Materialize; + rsinfo->setResult = tupleStore; + rsinfo->setDesc = tupleDesc; + + MemoryContextSwitchTo(oldcontext); + + memset(nulls, 0, sizeof(nulls)); + memset(values, 0, sizeof(values)); + +#ifdef __linux__ + if (statfs("/proc", &sb) < 0 || sb.f_type != PROC_SUPER_MAGIC) + { + elog(ERROR, "proc filesystem not mounted on /proc\n"); + return (Datum) 0; + } + if ((fd = AllocateFile("/proc/diskstats", PG_BINARY_R)) == NULL) + { + elog(ERROR, "File not found: '/proc/diskstats'"); + return (Datum) 0; + } + + while ((ret = + fscanf(fd, "%d %d %s %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu", + &major, &minor, device_name, &reads_completed, + &reads_merged, §ors_read, &readtime, &writes_completed, + &writes_merged, §ors_written, &writetime, ¤t_io, + &iotime, &totaliotime)) != EOF) + { + values[i_major] = Int32GetDatum(major); + values[i_minor] = Int32GetDatum(minor); + values[i_devname] = CStringGetTextDatum(device_name); + values[i_reads_completed] = Int64GetDatumFast(reads_completed); + values[i_reads_merged] = Int64GetDatumFast(reads_merged); + values[i_sectors_read] = Int64GetDatumFast(sectors_read); + values[i_readtime] = Int64GetDatumFast(readtime); + values[i_writes_completed] = Int64GetDatumFast(writes_completed); + values[i_writes_merged] = Int64GetDatumFast(writes_merged); + values[i_sectors_written] = Int64GetDatumFast(sectors_written); + values[i_writetime] = Int64GetDatumFast(writetime); + values[i_current_io] = Int64GetDatumFast(current_io); + values[i_iotime] = Int64GetDatumFast(iotime); + values[i_totaliotime] = Int64GetDatumFast(totaliotime); + tuplestore_putvalues(tupleStore, tupleDesc, values, nulls); + } + FreeFile(fd); +#endif /* __linux */ + + tuplestore_donestoring(tupleStore); + + return (Datum) 0; +} -- 2.39.5