Rearrange source code
authorMark Wong <markwkm@gmail.com>
Sat, 30 Mar 2013 05:07:50 +0000 (22:07 -0700)
committerMark Wong <markwkm@gmail.com>
Sat, 30 Mar 2013 05:07:50 +0000 (22:07 -0700)
Move all the source and SQL code into a single file.  It seems easier
to deal with with pgxn this way.

META.json
pg_proctab.control
sql/pg_cputime.sql [deleted file]
sql/pg_loadavg.sql [deleted file]
sql/pg_memusage.sql [deleted file]
sql/pg_proctab.sql
src/pg_cputime.c [deleted file]
src/pg_loadavg.c [deleted file]
src/pg_memusage.c [deleted file]
src/pg_proctab.c

index c0ce6162838eb0031b5c97deaf326adcabfb82ec..d6481236aef1ad6d299ede405c68bc758f74a0dc 100644 (file)
--- a/META.json
+++ b/META.json
@@ -2,27 +2,12 @@
    "name": "pg_proctab",
    "abstract": "Access operating system process tables from PostgreSQL",
    "description": "pg_proctab is a collection of stored functions that can access the operating systems process table so that system statitics can be queried through the database.",
-   "version": "0.0.4",
+   "version": "0.0.5",
    "maintainer": "Mark Wong",
    "license": {
       "PostgreSQL": "http://www.postgresql.org/about/licence"
    },
    "provides": {
-      "pg_cputime": {
-         "abstract": "Processor statitics",
-         "file": "sql/pg_proctab.sql",
-         "version": "0.0.1"
-      },
-      "pg_loadavg": {
-         "abstract": "System load averages",
-         "file": "sql/pg_loadavg.sql",
-         "version": "0.0.1"
-      },
-      "pg_memusage": {
-         "abstract": "Memory usage",
-         "file": "sql/pg_memusage.sql",
-         "version": "0.0.1"
-      },
       "pg_proctab": {
          "abstract": "Operating system process table",
          "file": "sql/pg_proctab.sql",
index b915d715d94acc0a246a7e83817959a8f3c335ea..4dd21e09dae8a3dc3cda5c49bebf84373f1d59ca 100644 (file)
@@ -1,5 +1,5 @@
 # pg_proctab extension
 comment = 'Access operating system process table'
-default_version = '0.0.4'
+default_version = '0.0.5'
 module_pathname = '$libdir/pg_proctab'
 relocatable = true
diff --git a/sql/pg_cputime.sql b/sql/pg_cputime.sql
deleted file mode 100644 (file)
index 495ec24..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
--- Copyright (C) 2008 Mark Wong
-CREATE OR REPLACE FUNCTION pg_cputime(
-               OUT "user" BIGINT,
-               OUT nice BIGINT,
-               OUT system BIGINT,
-               OUT idle BIGINT,
-               OUT iowait BIGINT)
-RETURNS SETOF record
-AS 'MODULE_PATHNAME', 'pg_cputime'
-LANGUAGE C IMMUTABLE STRICT;
diff --git a/sql/pg_loadavg.sql b/sql/pg_loadavg.sql
deleted file mode 100644 (file)
index 7d47d43..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
--- Copyright (C) 2008 Mark Wong
-CREATE OR REPLACE FUNCTION pg_loadavg(
-               OUT load1 FLOAT,
-               OUT load5 FLOAT,
-               OUT load15 FLOAT,
-               OUT last_pid INTEGER)
-RETURNS SETOF record
-AS 'MODULE_PATHNAME', 'pg_loadavg'
-LANGUAGE C IMMUTABLE STRICT;
diff --git a/sql/pg_memusage.sql b/sql/pg_memusage.sql
deleted file mode 100644 (file)
index 1b5011b..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
--- Copyright (C) 2008 Mark Wong
-CREATE OR REPLACE FUNCTION pg_memusage(
-               OUT memused BIGINT,
-               OUT memfree BIGINT,
-               OUT memshared BIGINT,
-               OUT membuffers BIGINT,
-               OUT memcached BIGINT,
-               OUT swapused BIGINT,
-               OUT swapfree BIGINT,
-               OUT swapcached BIGINT)
-RETURNS SETOF record
-AS 'MODULE_PATHNAME', 'pg_memusage'
-LANGUAGE C IMMUTABLE STRICT;
index c52987cb84c16c6773e05ddae1b8ca2f72e2a075..a1b0c998e6b5602a719b9576b8699600d95171f6 100644 (file)
@@ -42,3 +42,35 @@ CREATE OR REPLACE FUNCTION pg_proctab(
 RETURNS SETOF record
 AS 'MODULE_PATHNAME', 'pg_proctab'
 LANGUAGE C IMMUTABLE STRICT;
+
+CREATE OR REPLACE FUNCTION pg_cputime(
+               OUT "user" BIGINT,
+               OUT nice BIGINT,
+               OUT system BIGINT,
+               OUT idle BIGINT,
+               OUT iowait BIGINT)
+RETURNS SETOF record
+AS 'MODULE_PATHNAME', 'pg_cputime'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE OR REPLACE FUNCTION pg_loadavg(
+               OUT load1 FLOAT,
+               OUT load5 FLOAT,
+               OUT load15 FLOAT,
+               OUT last_pid INTEGER)
+RETURNS SETOF record
+AS 'MODULE_PATHNAME', 'pg_loadavg'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE OR REPLACE FUNCTION pg_memusage(
+               OUT memused BIGINT,
+               OUT memfree BIGINT,
+               OUT memshared BIGINT,
+               OUT membuffers BIGINT,
+               OUT memcached BIGINT,
+               OUT swapused BIGINT,
+               OUT swapfree BIGINT,
+               OUT swapcached BIGINT)
+RETURNS SETOF record
+AS 'MODULE_PATHNAME', 'pg_memusage'
+LANGUAGE C IMMUTABLE STRICT;
diff --git a/src/pg_cputime.c b/src/pg_cputime.c
deleted file mode 100644 (file)
index 8893340..0000000
+++ /dev/null
@@ -1,164 +0,0 @@
-/*
- * Copyright (C) 2008 Mark Wong
- */
-
-#include "postgres.h"
-#include <string.h>
-#include "fmgr.h"
-#include "funcapi.h"
-#include <sys/vfs.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <sys/param.h>
-#include <executor/spi.h>
-#include "pg_common.h"
-
-enum loadavg {i_user, i_nice, i_system, i_idle, i_iowait};
-
-int get_cputime(char **);
-Datum pg_cputime(PG_FUNCTION_ARGS);
-
-PG_FUNCTION_INFO_V1(pg_cputime);
-
-Datum pg_cputime(PG_FUNCTION_ARGS)
-{
-       FuncCallContext *funcctx;
-       int call_cntr;
-       int max_calls;
-       TupleDesc tupdesc;
-       AttInMetadata *attinmeta;
-
-       elog(DEBUG5, "pg_cputime: Entering stored function.");
-
-       /* stuff done only on the first call of the function */
-       if (SRF_IS_FIRSTCALL())
-       {
-               MemoryContext oldcontext;
-
-               /* create a function context for cross-call persistence */
-               funcctx = SRF_FIRSTCALL_INIT();
-
-               /* switch to memory context appropriate for multiple function calls */
-               oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
-
-               /* Build a tuple descriptor for our result type */
-               if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
-                       ereport(ERROR,
-                                       (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-                                       errmsg("function returning record called in context "
-                                                       "that cannot accept type record")));
-
-               /*
-                * generate attribute metadata needed later to produce tuples from raw
-                * C strings
-                */
-               attinmeta = TupleDescGetAttInMetadata(tupdesc);
-               funcctx->attinmeta = attinmeta;
-
-               funcctx->max_calls = 1;
-
-               MemoryContextSwitchTo(oldcontext);
-       }
-
-       /* stuff done on every call of the function */
-       funcctx = SRF_PERCALL_SETUP();
-
-       call_cntr = funcctx->call_cntr;
-       max_calls = funcctx->max_calls;
-       attinmeta = funcctx->attinmeta;
-
-       if (call_cntr < max_calls) /* do when there is more left to send */
-       {
-               HeapTuple tuple;
-               Datum result;
-
-               char **values = NULL;
-
-               values = (char **) palloc(5 * sizeof(char *));
-               values[i_user] = (char *) palloc((BIGINT_LEN + 1) * sizeof(char));
-               values[i_nice] = (char *) palloc((BIGINT_LEN + 1) * sizeof(char));
-               values[i_system] = (char *) palloc((BIGINT_LEN + 1) * sizeof(char));
-               values[i_idle] = (char *) palloc((BIGINT_LEN + 1) * sizeof(char));
-               values[i_iowait] = (char *) palloc((BIGINT_LEN + 1) * sizeof(char));
-
-               if (get_cputime(values) == 0)
-                       SRF_RETURN_DONE(funcctx);
-
-               /* build a tuple */
-               tuple = BuildTupleFromCStrings(attinmeta, values);
-
-               /* make the tuple into a datum */
-               result = HeapTupleGetDatum(tuple);
-
-               SRF_RETURN_NEXT(funcctx, result);
-       }
-       else /* do when there is no more left */
-       {
-               SRF_RETURN_DONE(funcctx);
-       }
-}
-
-int
-get_cputime(char **values)
-{
-#ifdef __linux__
-       struct statfs sb;
-       int fd;
-       int len;
-       char buffer[4096];
-       char *p;
-       char *q;
-
-       int length;
-
-       /* Check if /proc is mounted. */
-       if (statfs(PROCFS, &sb) < 0 || sb.f_type != PROC_SUPER_MAGIC)
-       {
-               elog(ERROR, "proc filesystem not mounted on " PROCFS "\n");
-               return 0;
-       }
-
-       snprintf(buffer, sizeof(buffer) - 1, "%s/stat", PROCFS);
-       fd = open(buffer, O_RDONLY);
-       if (fd == -1)
-       {
-               elog(ERROR, "'%s' not found", buffer);
-               return 0;
-       }
-       len = read(fd, buffer, sizeof(buffer) - 1);
-       close(fd);
-       buffer[len] = '\0';
-       elog(DEBUG5, "pg_cputime: %s", buffer);
-
-       p = buffer;
-
-       SKIP_TOKEN(p);                  /* skip cpu */
-
-       /* user */
-       GET_NEXT_VALUE(p, q, values[i_user], length, "user not found", ' ');
-
-       /* nice */
-       GET_NEXT_VALUE(p, q, values[i_nice], length, "nice not found", ' ');
-
-       /* system */
-       GET_NEXT_VALUE(p, q, values[i_system], length, "system not found", ' ');
-
-       /* idle */
-       GET_NEXT_VALUE(p, q, values[i_idle], length, "idle not found", ' ');
-
-       /* iowait */
-       GET_NEXT_VALUE(p, q, values[i_iowait], length, "iowait not found", ' ');
-#endif /* __linux__ */
-
-       elog(DEBUG5, "pg_cputime: [%d] user = %s", (int) i_user, values[i_user]);
-       elog(DEBUG5, "pg_cputime: [%d] nice = %s", (int) i_nice, values[i_nice]);
-       elog(DEBUG5, "pg_cputime: [%d] system = %s", (int) i_system,
-                       values[i_system]);
-       elog(DEBUG5, "pg_cputime: [%d] idle = %s", (int) i_idle, values[i_idle]);
-       elog(DEBUG5, "pg_cputime: [%d] iowait = %s", (int) i_iowait,
-                       values[i_iowait]);
-
-       return 1;
-}
diff --git a/src/pg_loadavg.c b/src/pg_loadavg.c
deleted file mode 100644 (file)
index fab7fcb..0000000
+++ /dev/null
@@ -1,177 +0,0 @@
-/*
- * Copyright (C) 2008 Mark Wong
- */
-
-#include "postgres.h"
-#include <string.h>
-#include "fmgr.h"
-#include "funcapi.h"
-#include <sys/vfs.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <sys/param.h>
-#include <executor/spi.h>
-#include "pg_common.h"
-
-enum loadavg {i_load1, i_load5, i_load15, i_last_pid};
-
-int get_loadavg(char **);
-
-Datum pg_loadavg(PG_FUNCTION_ARGS);
-
-PG_FUNCTION_INFO_V1(pg_loadavg);
-
-Datum pg_loadavg(PG_FUNCTION_ARGS)
-{
-       FuncCallContext *funcctx;
-       int call_cntr;
-       int max_calls;
-       TupleDesc tupdesc;
-       AttInMetadata *attinmeta;
-
-       elog(DEBUG5, "pg_loadavg: Entering stored function.");
-
-       /* stuff done only on the first call of the function */
-       if (SRF_IS_FIRSTCALL())
-       {
-               MemoryContext oldcontext;
-
-               /* create a function context for cross-call persistence */
-               funcctx = SRF_FIRSTCALL_INIT();
-
-               /* switch to memory context appropriate for multiple function calls */
-               oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
-
-               /* Build a tuple descriptor for our result type */
-               if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
-                       ereport(ERROR,
-                                       (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-                                       errmsg("function returning record called in context "
-                                                       "that cannot accept type record")));
-
-               /*
-                * generate attribute metadata needed later to produce tuples from raw
-                * C strings
-                */
-               attinmeta = TupleDescGetAttInMetadata(tupdesc);
-               funcctx->attinmeta = attinmeta;
-
-               funcctx->max_calls = 1;
-
-               MemoryContextSwitchTo(oldcontext);
-       }
-
-       /* stuff done on every call of the function */
-       funcctx = SRF_PERCALL_SETUP();
-
-       call_cntr = funcctx->call_cntr;
-       max_calls = funcctx->max_calls;
-       attinmeta = funcctx->attinmeta;
-
-       if (call_cntr < max_calls) /* do when there is more left to send */
-       {
-               HeapTuple tuple;
-               Datum result;
-
-               char **values = NULL;
-
-               values = (char **) palloc(4 * sizeof(char *));
-               values[i_load1] = (char *) palloc((FLOAT_LEN + 1) * sizeof(char));
-               values[i_load5] = (char *) palloc((FLOAT_LEN + 1) * sizeof(char));
-               values[i_load15] = (char *) palloc((FLOAT_LEN + 1) * sizeof(char));
-               values[i_last_pid] = (char *) palloc((INTEGER_LEN + 1) * sizeof(char));
-
-               if (get_loadavg(values) == 0)
-                       SRF_RETURN_DONE(funcctx);
-
-               /* build a tuple */
-               tuple = BuildTupleFromCStrings(attinmeta, values);
-
-               /* make the tuple into a datum */
-               result = HeapTupleGetDatum(tuple);
-
-               SRF_RETURN_NEXT(funcctx, result);
-       }
-       else /* do when there is no more left */
-       {
-               SRF_RETURN_DONE(funcctx);
-       }
-}
-
-int
-get_loadavg(char **values)
-{
-#ifdef __linux__
-       int length;
-
-       struct statfs sb;
-       int fd;
-       int len;
-       char buffer[4096];
-       char *p;
-       char *q;
-
-       /* Check if /proc is mounted. */
-       if (statfs(PROCFS, &sb) < 0 || sb.f_type != PROC_SUPER_MAGIC)
-       {
-               elog(ERROR, "proc filesystem not mounted on " PROCFS "\n");
-               return 0;
-       }
-
-       snprintf(buffer, sizeof(buffer) - 1, "%s/loadavg", PROCFS);
-       fd = open(buffer, O_RDONLY);
-       if (fd == -1)
-       {
-               elog(ERROR, "'%s' not found", buffer);
-               return 0;
-       }
-       len = read(fd, buffer, sizeof(buffer) - 1);
-       close(fd);
-       buffer[len] = '\0';
-       elog(DEBUG5, "pg_loadavg: %s", buffer);
-
-       p = buffer;
-
-       /* load1 */
-       GET_NEXT_VALUE(p, q, values[i_load1], length, "load1 not found", ' ');
-
-       /* load5 */
-       GET_NEXT_VALUE(p, q, values[i_load5], length, "load5 not found", ' ');
-
-       /* load15 */
-       GET_NEXT_VALUE(p, q, values[i_load15], length, "load15 not found", ' ');
-
-       SKIP_TOKEN(p);                  /* skip running/tasks */
-
-       /* last_pid */
-       /*
-        * It appears sometimes this is the last item in /proc/PID/stat and
-        * sometimes it's not, depending on the version of the kernel and
-        * possibly the architecture.  So first test if it is the last item
-        * before determining how to deliminate it.
-        */
-       if (strchr(p, ' ') == NULL)
-       {
-               GET_NEXT_VALUE(p, q, values[i_last_pid], length,
-                               "last_pid not found", '\n');
-       }
-       else
-       {
-               GET_NEXT_VALUE(p, q, values[i_last_pid], length,
-                               "last_pid not found", ' ');
-       }
-#endif /* __linux__ */
-
-       elog(DEBUG5, "pg_loadavg: [%d] load1 = %s", (int) i_load1,
-                       values[i_load1]);
-       elog(DEBUG5, "pg_loadavg: [%d] load5 = %s", (int) i_load5,
-                       values[i_load5]);
-       elog(DEBUG5, "pg_loadavg: [%d] load15 = %s", (int) i_load15,
-                       values[i_load15]);
-       elog(DEBUG5, "pg_loadavg: [%d] last_pid = %s", (int) i_last_pid,
-                       values[i_last_pid]);
-
-       return 1;
-}
diff --git a/src/pg_memusage.c b/src/pg_memusage.c
deleted file mode 100644 (file)
index 4676087..0000000
+++ /dev/null
@@ -1,227 +0,0 @@
-/*
- * Copyright (C) 2008 Mark Wong
- */
-
-#include "postgres.h"
-#include <string.h>
-#include "fmgr.h"
-#include "funcapi.h"
-#include <sys/vfs.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <sys/param.h>
-#include <executor/spi.h>
-#include "pg_common.h"
-
-enum loadavg {i_memused, i_memfree, i_memshared, i_membuffers, i_memcached,
-               i_swapused, i_swapfree, i_swapcached};
-
-int get_memusage(char **);
-
-Datum pg_memusage(PG_FUNCTION_ARGS);
-
-PG_FUNCTION_INFO_V1(pg_memusage);
-
-Datum pg_memusage(PG_FUNCTION_ARGS)
-{
-       FuncCallContext *funcctx;
-       int call_cntr;
-       int max_calls;
-       TupleDesc tupdesc;
-       AttInMetadata *attinmeta;
-
-
-       elog(DEBUG5, "pg_memusage: Entering stored function.");
-
-       /* stuff done only on the first call of the function */
-       if (SRF_IS_FIRSTCALL())
-       {
-               MemoryContext oldcontext;
-
-               /* create a function context for cross-call persistence */
-               funcctx = SRF_FIRSTCALL_INIT();
-
-               /* switch to memory context appropriate for multiple function calls */
-               oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
-
-               /* Build a tuple descriptor for our result type */
-               if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
-                       ereport(ERROR,
-                                       (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-                                       errmsg("function returning record called in context "
-                                                       "that cannot accept type record")));
-
-               /*
-                * generate attribute metadata needed later to produce tuples from raw
-                * C strings
-                */
-               attinmeta = TupleDescGetAttInMetadata(tupdesc);
-               funcctx->attinmeta = attinmeta;
-
-               funcctx->max_calls = 1;
-
-               MemoryContextSwitchTo(oldcontext);
-       }
-
-       /* stuff done on every call of the function */
-       funcctx = SRF_PERCALL_SETUP();
-
-       call_cntr = funcctx->call_cntr;
-       max_calls = funcctx->max_calls;
-       attinmeta = funcctx->attinmeta;
-
-       if (call_cntr < max_calls) /* do when there is more left to send */
-       {
-               HeapTuple tuple;
-               Datum result;
-
-               char **values = NULL;
-
-               values = (char **) palloc(8 * sizeof(char *));
-               values[i_memused] = (char *) palloc((BIGINT_LEN + 1) * sizeof(char));
-               values[i_memfree] = (char *) palloc((BIGINT_LEN + 1) * sizeof(char));
-               values[i_memshared] = (char *) palloc((BIGINT_LEN + 1) * sizeof(char));
-               values[i_membuffers] =
-                               (char *) palloc((BIGINT_LEN + 1) * sizeof(char));
-               values[i_memcached] = (char *) palloc((BIGINT_LEN + 1) * sizeof(char));
-               values[i_swapused] = (char *) palloc((BIGINT_LEN + 1) * sizeof(char));
-               values[i_swapfree] = (char *) palloc((BIGINT_LEN + 1) * sizeof(char));
-               values[i_swapcached] =
-                               (char *) palloc((BIGINT_LEN + 1) * sizeof(char));
-
-               if (get_memusage(values) == 0)
-                       SRF_RETURN_DONE(funcctx);
-
-               /* build a tuple */
-               tuple = BuildTupleFromCStrings(attinmeta, values);
-
-               /* make the tuple into a datum */
-               result = HeapTupleGetDatum(tuple);
-
-               SRF_RETURN_NEXT(funcctx, result);
-       }
-       else /* do when there is no more left */
-       {
-               SRF_RETURN_DONE(funcctx);
-       }
-}
-
-int
-get_memusage(char **values)
-{
-#ifdef __linux__
-       int length;
-       unsigned long memfree = 0;
-       unsigned long memtotal = 0;
-       unsigned long swapfree = 0;
-       unsigned long swaptotal = 0;
-
-       struct statfs sb;
-       int fd;
-       int len;
-       char buffer[4096];
-       char *p;
-       char *q;
-
-       /* Check if /proc is mounted. */
-       if (statfs(PROCFS, &sb) < 0 || sb.f_type != PROC_SUPER_MAGIC)
-       {
-               elog(ERROR, "proc filesystem not mounted on " PROCFS "\n");
-               return 0;
-       }
-
-       snprintf(buffer, sizeof(buffer) - 1, "%s/meminfo", PROCFS);
-       fd = open(buffer, O_RDONLY);
-       if (fd == -1)
-       {
-               elog(ERROR, "'%s' not found", buffer);
-               return 0;
-       }
-       len = read(fd, buffer, sizeof(buffer) - 1);
-       close(fd);
-       buffer[len] = '\0';
-       elog(DEBUG5, "pg_memusage: %s", buffer);
-
-       p = buffer - 1;
-
-       values[i_memshared][0] = '0';
-       values[i_memshared][1] = '\0';
-
-       while (p != NULL) {
-               ++p;
-               if (strncmp(p, "Buffers:", 8) == 0)
-               {
-                       SKIP_TOKEN(p);
-                       GET_NEXT_VALUE(p, q, values[i_membuffers], length,
-                                       "Buffers not found", ' ');
-               }
-               else if (strncmp(p, "Cached:", 7) == 0)
-               {
-                       SKIP_TOKEN(p);
-                       GET_NEXT_VALUE(p, q, values[i_memcached], length,
-                                       "Cached not found", ' ');
-               }
-               else if (strncmp(p, "MemFree:", 8) == 0)
-               {
-                       SKIP_TOKEN(p);
-                       memfree = strtoul(p, &p, 10);
-                       snprintf(values[i_memused], BIGINT_LEN, "%lu", memtotal - memfree);
-                       snprintf(values[i_memfree], BIGINT_LEN, "%lu", memfree);
-               }
-               else if (strncmp(p, "MemShared:", 10) == 0)
-               {
-                       SKIP_TOKEN(p);
-                       GET_NEXT_VALUE(p, q, values[i_memshared], length,
-                                       "MemShared not found", ' ');
-               }
-               else if (strncmp(p, "MemTotal:", 9) == 0)
-               {
-                       SKIP_TOKEN(p);
-                       memtotal = strtoul(p, &p, 10);
-                       elog(DEBUG5, "pg_memusage: MemTotal = %lu", memtotal);
-               }
-               else if (strncmp(p, "SwapFree:", 9) == 0)
-               {
-                       SKIP_TOKEN(p);
-                       swapfree = strtoul(p, &p, 10);
-                       snprintf(values[i_swapused], BIGINT_LEN, "%lu",
-                                       swaptotal - swapfree);
-                       snprintf(values[i_swapfree], BIGINT_LEN, "%lu", swapfree);
-               }
-               else if (strncmp(p, "SwapCached:", 11) == 0)
-               {
-                       SKIP_TOKEN(p);
-                       GET_NEXT_VALUE(p, q, values[i_swapcached], length,
-                                       "SwapCached not found", ' ');
-               }
-               else if (strncmp(p, "SwapTotal:", 10) == 0)
-               {
-                       SKIP_TOKEN(p);
-                       swaptotal = strtoul(p, &p, 10);
-                       elog(DEBUG5, "pg_memusage: SwapTotal = %lu", swaptotal);
-               }
-               p = strchr(p, '\n');
-       }
-#endif /* __linux__ */
-
-       elog(DEBUG5, "pg_memusage: [%d] Buffers = %s", (int) i_membuffers,
-                       values[i_membuffers]);
-       elog(DEBUG5, "pg_memusage: [%d] Cached = %s", (int) i_memcached,
-                       values[i_memcached]);
-       elog(DEBUG5, "pg_memusage: [%d] MemFree = %s", (int) i_memfree,
-                       values[i_memfree]);
-       elog(DEBUG5, "pg_memusage: [%d] MemUsed = %s", (int) i_memused,
-                       values[i_memused]);
-       elog(DEBUG5, "pg_memusage: [%d] MemShared = %s", (int) i_memshared,
-                       values[i_memshared]);
-       elog(DEBUG5, "pg_memusage: [%d] SwapCached = %s", (int) i_swapcached,
-                       values[i_swapcached]);
-       elog(DEBUG5, "pg_memusage: [%d] SwapFree = %s", (int) i_swapfree,
-                       values[i_swapfree]);
-       elog(DEBUG5, "pg_memusage: [%d] SwapUsed = %s", (int) i_swapused,
-                       values[i_swapused]);
-
-       return 1;
-}
index 9315c1c1ce15074b5a6b787f7f3dde16b6a4bbe4..4867321d061aa8b194e21eefccc908a845e17f81 100644 (file)
@@ -49,12 +49,25 @@ enum proctab {i_pid, i_comm, i_fullcomm, i_state, i_ppid, i_pgrp, i_session,
                i_exit_signal, i_processor, i_rt_priority, i_policy,
                i_delayacct_blkio_ticks, i_uid, i_username, i_rchar, i_wchar, i_syscr,
                i_syscw, i_reads, i_writes, i_cwrites};
+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};
 
 int get_proctab(FuncCallContext *, char **);
+int get_cputime(char **);
+int get_loadavg(char **);
+int get_memusage(char **);
 
 Datum pg_proctab(PG_FUNCTION_ARGS);
+Datum pg_cputime(PG_FUNCTION_ARGS);
+Datum pg_loadavg(PG_FUNCTION_ARGS);
+Datum pg_memusage(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);
 
 Datum pg_proctab(PG_FUNCTION_ARGS)
 {
@@ -551,3 +564,499 @@ get_proctab(FuncCallContext *funcctx, char **values)
 
        return 1;
 }
+
+Datum pg_cputime(PG_FUNCTION_ARGS)
+{
+       FuncCallContext *funcctx;
+       int call_cntr;
+       int max_calls;
+       TupleDesc tupdesc;
+       AttInMetadata *attinmeta;
+
+       elog(DEBUG5, "pg_cputime: Entering stored function.");
+
+       /* stuff done only on the first call of the function */
+       if (SRF_IS_FIRSTCALL())
+       {
+               MemoryContext oldcontext;
+
+               /* create a function context for cross-call persistence */
+               funcctx = SRF_FIRSTCALL_INIT();
+
+               /* switch to memory context appropriate for multiple function calls */
+               oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
+
+               /* Build a tuple descriptor for our result type */
+               if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
+                       ereport(ERROR,
+                                       (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+                                       errmsg("function returning record called in context "
+                                                       "that cannot accept type record")));
+
+               /*
+                * generate attribute metadata needed later to produce tuples from raw
+                * C strings
+                */
+               attinmeta = TupleDescGetAttInMetadata(tupdesc);
+               funcctx->attinmeta = attinmeta;
+
+               funcctx->max_calls = 1;
+
+               MemoryContextSwitchTo(oldcontext);
+       }
+
+       /* stuff done on every call of the function */
+       funcctx = SRF_PERCALL_SETUP();
+
+       call_cntr = funcctx->call_cntr;
+       max_calls = funcctx->max_calls;
+       attinmeta = funcctx->attinmeta;
+
+       if (call_cntr < max_calls) /* do when there is more left to send */
+       {
+               HeapTuple tuple;
+               Datum result;
+
+               char **values = NULL;
+
+               values = (char **) palloc(5 * sizeof(char *));
+               values[i_user] = (char *) palloc((BIGINT_LEN + 1) * sizeof(char));
+               values[i_nice_c] = (char *) palloc((BIGINT_LEN + 1) * sizeof(char));
+               values[i_system] = (char *) palloc((BIGINT_LEN + 1) * sizeof(char));
+               values[i_idle] = (char *) palloc((BIGINT_LEN + 1) * sizeof(char));
+               values[i_iowait] = (char *) palloc((BIGINT_LEN + 1) * sizeof(char));
+
+               if (get_cputime(values) == 0)
+                       SRF_RETURN_DONE(funcctx);
+
+               /* build a tuple */
+               tuple = BuildTupleFromCStrings(attinmeta, values);
+
+               /* make the tuple into a datum */
+               result = HeapTupleGetDatum(tuple);
+
+               SRF_RETURN_NEXT(funcctx, result);
+       }
+       else /* do when there is no more left */
+       {
+               SRF_RETURN_DONE(funcctx);
+       }
+}
+
+int
+get_cputime(char **values)
+{
+#ifdef __linux__
+       struct statfs sb;
+       int fd;
+       int len;
+       char buffer[4096];
+       char *p;
+       char *q;
+
+       int length;
+
+       /* Check if /proc is mounted. */
+       if (statfs(PROCFS, &sb) < 0 || sb.f_type != PROC_SUPER_MAGIC)
+       {
+               elog(ERROR, "proc filesystem not mounted on " PROCFS "\n");
+               return 0;
+       }
+
+       snprintf(buffer, sizeof(buffer) - 1, "%s/stat", PROCFS);
+       fd = open(buffer, O_RDONLY);
+       if (fd == -1)
+       {
+               elog(ERROR, "'%s' not found", buffer);
+               return 0;
+       }
+       len = read(fd, buffer, sizeof(buffer) - 1);
+       close(fd);
+       buffer[len] = '\0';
+       elog(DEBUG5, "pg_cputime: %s", buffer);
+
+       p = buffer;
+
+       SKIP_TOKEN(p);                  /* skip cpu */
+
+       /* user */
+       GET_NEXT_VALUE(p, q, values[i_user], length, "user not found", ' ');
+
+       /* nice */
+       GET_NEXT_VALUE(p, q, values[i_nice_c], length, "nice not found", ' ');
+
+       /* system */
+       GET_NEXT_VALUE(p, q, values[i_system], length, "system not found", ' ');
+
+       /* idle */
+       GET_NEXT_VALUE(p, q, values[i_idle], length, "idle not found", ' ');
+
+       /* iowait */
+       GET_NEXT_VALUE(p, q, values[i_iowait], length, "iowait not found", ' ');
+#endif /* __linux__ */
+
+       elog(DEBUG5, "pg_cputime: [%d] user = %s", (int) i_user, values[i_user]);
+       elog(DEBUG5, "pg_cputime: [%d] nice = %s", (int) i_nice_c, values[i_nice_c]);
+       elog(DEBUG5, "pg_cputime: [%d] system = %s", (int) i_system,
+                       values[i_system]);
+       elog(DEBUG5, "pg_cputime: [%d] idle = %s", (int) i_idle, values[i_idle]);
+       elog(DEBUG5, "pg_cputime: [%d] iowait = %s", (int) i_iowait,
+                       values[i_iowait]);
+
+       return 1;
+}
+
+Datum pg_loadavg(PG_FUNCTION_ARGS)
+{
+       FuncCallContext *funcctx;
+       int call_cntr;
+       int max_calls;
+       TupleDesc tupdesc;
+       AttInMetadata *attinmeta;
+
+       elog(DEBUG5, "pg_loadavg: Entering stored function.");
+
+       /* stuff done only on the first call of the function */
+       if (SRF_IS_FIRSTCALL())
+       {
+               MemoryContext oldcontext;
+
+               /* create a function context for cross-call persistence */
+               funcctx = SRF_FIRSTCALL_INIT();
+
+               /* switch to memory context appropriate for multiple function calls */
+               oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
+
+               /* Build a tuple descriptor for our result type */
+               if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
+                       ereport(ERROR,
+                                       (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+                                       errmsg("function returning record called in context "
+                                                       "that cannot accept type record")));
+
+               /*
+                * generate attribute metadata needed later to produce tuples from raw
+                * C strings
+                */
+               attinmeta = TupleDescGetAttInMetadata(tupdesc);
+               funcctx->attinmeta = attinmeta;
+
+               funcctx->max_calls = 1;
+
+               MemoryContextSwitchTo(oldcontext);
+       }
+
+       /* stuff done on every call of the function */
+       funcctx = SRF_PERCALL_SETUP();
+
+       call_cntr = funcctx->call_cntr;
+       max_calls = funcctx->max_calls;
+       attinmeta = funcctx->attinmeta;
+
+       if (call_cntr < max_calls) /* do when there is more left to send */
+       {
+               HeapTuple tuple;
+               Datum result;
+
+               char **values = NULL;
+
+               values = (char **) palloc(4 * sizeof(char *));
+               values[i_load1] = (char *) palloc((FLOAT_LEN + 1) * sizeof(char));
+               values[i_load5] = (char *) palloc((FLOAT_LEN + 1) * sizeof(char));
+               values[i_load15] = (char *) palloc((FLOAT_LEN + 1) * sizeof(char));
+               values[i_last_pid] = (char *) palloc((INTEGER_LEN + 1) * sizeof(char));
+
+               if (get_loadavg(values) == 0)
+                       SRF_RETURN_DONE(funcctx);
+
+               /* build a tuple */
+               tuple = BuildTupleFromCStrings(attinmeta, values);
+
+               /* make the tuple into a datum */
+               result = HeapTupleGetDatum(tuple);
+
+               SRF_RETURN_NEXT(funcctx, result);
+       }
+       else /* do when there is no more left */
+       {
+               SRF_RETURN_DONE(funcctx);
+       }
+}
+
+int
+get_loadavg(char **values)
+{
+#ifdef __linux__
+       int length;
+
+       struct statfs sb;
+       int fd;
+       int len;
+       char buffer[4096];
+       char *p;
+       char *q;
+
+       /* Check if /proc is mounted. */
+       if (statfs(PROCFS, &sb) < 0 || sb.f_type != PROC_SUPER_MAGIC)
+       {
+               elog(ERROR, "proc filesystem not mounted on " PROCFS "\n");
+               return 0;
+       }
+
+       snprintf(buffer, sizeof(buffer) - 1, "%s/loadavg", PROCFS);
+       fd = open(buffer, O_RDONLY);
+       if (fd == -1)
+       {
+               elog(ERROR, "'%s' not found", buffer);
+               return 0;
+       }
+       len = read(fd, buffer, sizeof(buffer) - 1);
+       close(fd);
+       buffer[len] = '\0';
+       elog(DEBUG5, "pg_loadavg: %s", buffer);
+
+       p = buffer;
+
+       /* load1 */
+       GET_NEXT_VALUE(p, q, values[i_load1], length, "load1 not found", ' ');
+
+       /* load5 */
+       GET_NEXT_VALUE(p, q, values[i_load5], length, "load5 not found", ' ');
+
+       /* load15 */
+       GET_NEXT_VALUE(p, q, values[i_load15], length, "load15 not found", ' ');
+
+       SKIP_TOKEN(p);                  /* skip running/tasks */
+
+       /* last_pid */
+       /*
+        * It appears sometimes this is the last item in /proc/PID/stat and
+        * sometimes it's not, depending on the version of the kernel and
+        * possibly the architecture.  So first test if it is the last item
+        * before determining how to deliminate it.
+        */
+       if (strchr(p, ' ') == NULL)
+       {
+               GET_NEXT_VALUE(p, q, values[i_last_pid], length,
+                               "last_pid not found", '\n');
+       }
+       else
+       {
+               GET_NEXT_VALUE(p, q, values[i_last_pid], length,
+                               "last_pid not found", ' ');
+       }
+#endif /* __linux__ */
+
+       elog(DEBUG5, "pg_loadavg: [%d] load1 = %s", (int) i_load1,
+                       values[i_load1]);
+       elog(DEBUG5, "pg_loadavg: [%d] load5 = %s", (int) i_load5,
+                       values[i_load5]);
+       elog(DEBUG5, "pg_loadavg: [%d] load15 = %s", (int) i_load15,
+                       values[i_load15]);
+       elog(DEBUG5, "pg_loadavg: [%d] last_pid = %s", (int) i_last_pid,
+                       values[i_last_pid]);
+
+       return 1;
+}
+
+Datum pg_memusage(PG_FUNCTION_ARGS)
+{
+       FuncCallContext *funcctx;
+       int call_cntr;
+       int max_calls;
+       TupleDesc tupdesc;
+       AttInMetadata *attinmeta;
+
+
+       elog(DEBUG5, "pg_memusage: Entering stored function.");
+
+       /* stuff done only on the first call of the function */
+       if (SRF_IS_FIRSTCALL())
+       {
+               MemoryContext oldcontext;
+
+               /* create a function context for cross-call persistence */
+               funcctx = SRF_FIRSTCALL_INIT();
+
+               /* switch to memory context appropriate for multiple function calls */
+               oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
+
+               /* Build a tuple descriptor for our result type */
+               if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
+                       ereport(ERROR,
+                                       (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+                                       errmsg("function returning record called in context "
+                                                       "that cannot accept type record")));
+
+               /*
+                * generate attribute metadata needed later to produce tuples from raw
+                * C strings
+                */
+               attinmeta = TupleDescGetAttInMetadata(tupdesc);
+               funcctx->attinmeta = attinmeta;
+
+               funcctx->max_calls = 1;
+
+               MemoryContextSwitchTo(oldcontext);
+       }
+
+       /* stuff done on every call of the function */
+       funcctx = SRF_PERCALL_SETUP();
+
+       call_cntr = funcctx->call_cntr;
+       max_calls = funcctx->max_calls;
+       attinmeta = funcctx->attinmeta;
+
+       if (call_cntr < max_calls) /* do when there is more left to send */
+       {
+               HeapTuple tuple;
+               Datum result;
+
+               char **values = NULL;
+
+               values = (char **) palloc(8 * sizeof(char *));
+               values[i_memused] = (char *) palloc((BIGINT_LEN + 1) * sizeof(char));
+               values[i_memfree] = (char *) palloc((BIGINT_LEN + 1) * sizeof(char));
+               values[i_memshared] = (char *) palloc((BIGINT_LEN + 1) * sizeof(char));
+               values[i_membuffers] =
+                               (char *) palloc((BIGINT_LEN + 1) * sizeof(char));
+               values[i_memcached] = (char *) palloc((BIGINT_LEN + 1) * sizeof(char));
+               values[i_swapused] = (char *) palloc((BIGINT_LEN + 1) * sizeof(char));
+               values[i_swapfree] = (char *) palloc((BIGINT_LEN + 1) * sizeof(char));
+               values[i_swapcached] =
+                               (char *) palloc((BIGINT_LEN + 1) * sizeof(char));
+
+               if (get_memusage(values) == 0)
+                       SRF_RETURN_DONE(funcctx);
+
+               /* build a tuple */
+               tuple = BuildTupleFromCStrings(attinmeta, values);
+
+               /* make the tuple into a datum */
+               result = HeapTupleGetDatum(tuple);
+
+               SRF_RETURN_NEXT(funcctx, result);
+       }
+       else /* do when there is no more left */
+       {
+               SRF_RETURN_DONE(funcctx);
+       }
+}
+
+int
+get_memusage(char **values)
+{
+#ifdef __linux__
+       int length;
+       unsigned long memfree = 0;
+       unsigned long memtotal = 0;
+       unsigned long swapfree = 0;
+       unsigned long swaptotal = 0;
+
+       struct statfs sb;
+       int fd;
+       int len;
+       char buffer[4096];
+       char *p;
+       char *q;
+
+       /* Check if /proc is mounted. */
+       if (statfs(PROCFS, &sb) < 0 || sb.f_type != PROC_SUPER_MAGIC)
+       {
+               elog(ERROR, "proc filesystem not mounted on " PROCFS "\n");
+               return 0;
+       }
+
+       snprintf(buffer, sizeof(buffer) - 1, "%s/meminfo", PROCFS);
+       fd = open(buffer, O_RDONLY);
+       if (fd == -1)
+       {
+               elog(ERROR, "'%s' not found", buffer);
+               return 0;
+       }
+       len = read(fd, buffer, sizeof(buffer) - 1);
+       close(fd);
+       buffer[len] = '\0';
+       elog(DEBUG5, "pg_memusage: %s", buffer);
+
+       p = buffer - 1;
+
+       values[i_memshared][0] = '0';
+       values[i_memshared][1] = '\0';
+
+       while (p != NULL) {
+               ++p;
+               if (strncmp(p, "Buffers:", 8) == 0)
+               {
+                       SKIP_TOKEN(p);
+                       GET_NEXT_VALUE(p, q, values[i_membuffers], length,
+                                       "Buffers not found", ' ');
+               }
+               else if (strncmp(p, "Cached:", 7) == 0)
+               {
+                       SKIP_TOKEN(p);
+                       GET_NEXT_VALUE(p, q, values[i_memcached], length,
+                                       "Cached not found", ' ');
+               }
+               else if (strncmp(p, "MemFree:", 8) == 0)
+               {
+                       SKIP_TOKEN(p);
+                       memfree = strtoul(p, &p, 10);
+                       snprintf(values[i_memused], BIGINT_LEN, "%lu", memtotal - memfree);
+                       snprintf(values[i_memfree], BIGINT_LEN, "%lu", memfree);
+               }
+               else if (strncmp(p, "MemShared:", 10) == 0)
+               {
+                       SKIP_TOKEN(p);
+                       GET_NEXT_VALUE(p, q, values[i_memshared], length,
+                                       "MemShared not found", ' ');
+               }
+               else if (strncmp(p, "MemTotal:", 9) == 0)
+               {
+                       SKIP_TOKEN(p);
+                       memtotal = strtoul(p, &p, 10);
+                       elog(DEBUG5, "pg_memusage: MemTotal = %lu", memtotal);
+               }
+               else if (strncmp(p, "SwapFree:", 9) == 0)
+               {
+                       SKIP_TOKEN(p);
+                       swapfree = strtoul(p, &p, 10);
+                       snprintf(values[i_swapused], BIGINT_LEN, "%lu",
+                                       swaptotal - swapfree);
+                       snprintf(values[i_swapfree], BIGINT_LEN, "%lu", swapfree);
+               }
+               else if (strncmp(p, "SwapCached:", 11) == 0)
+               {
+                       SKIP_TOKEN(p);
+                       GET_NEXT_VALUE(p, q, values[i_swapcached], length,
+                                       "SwapCached not found", ' ');
+               }
+               else if (strncmp(p, "SwapTotal:", 10) == 0)
+               {
+                       SKIP_TOKEN(p);
+                       swaptotal = strtoul(p, &p, 10);
+                       elog(DEBUG5, "pg_memusage: SwapTotal = %lu", swaptotal);
+               }
+               p = strchr(p, '\n');
+       }
+#endif /* __linux__ */
+
+       elog(DEBUG5, "pg_memusage: [%d] Buffers = %s", (int) i_membuffers,
+                       values[i_membuffers]);
+       elog(DEBUG5, "pg_memusage: [%d] Cached = %s", (int) i_memcached,
+                       values[i_memcached]);
+       elog(DEBUG5, "pg_memusage: [%d] MemFree = %s", (int) i_memfree,
+                       values[i_memfree]);
+       elog(DEBUG5, "pg_memusage: [%d] MemUsed = %s", (int) i_memused,
+                       values[i_memused]);
+       elog(DEBUG5, "pg_memusage: [%d] MemShared = %s", (int) i_memshared,
+                       values[i_memshared]);
+       elog(DEBUG5, "pg_memusage: [%d] SwapCached = %s", (int) i_swapcached,
+                       values[i_swapcached]);
+       elog(DEBUG5, "pg_memusage: [%d] SwapFree = %s", (int) i_swapfree,
+                       values[i_swapfree]);
+       elog(DEBUG5, "pg_memusage: [%d] SwapUsed = %s", (int) i_swapused,
+                       values[i_swapused]);
+
+       return 1;
+}