Add an extension to calculate OSCache
authorCédric Villemain <[email protected]>
Sun, 1 May 2011 20:44:29 +0000 (22:44 +0200)
committerCédric Villemain <[email protected]>
Sun, 1 May 2011 20:44:29 +0000 (22:44 +0200)
contrib/Makefile
contrib/oscache/Makefile [new file with mode: 0644]
contrib/oscache/oscache.c [new file with mode: 0644]

index 696776795e7a7db56fcbd4d785303e75c5745f20..47652d536b989b5daadedf072898dc12ca57a793 100644 (file)
@@ -27,6 +27,7 @@ SUBDIRS = \
                lo              \
                ltree           \
                oid2name        \
+               oscache \
                pageinspect     \
                passwordcheck   \
                pg_archivecleanup \
diff --git a/contrib/oscache/Makefile b/contrib/oscache/Makefile
new file mode 100644 (file)
index 0000000..8d8dcc5
--- /dev/null
@@ -0,0 +1,15 @@
+# contrib/oscache/Makefile
+
+MODULE_big = oscache
+OBJS = oscache.o
+
+ifdef USE_PGXS
+PG_CONFIG = pg_config
+PGXS := $(shell $(PG_CONFIG) --pgxs)
+include $(PGXS)
+else
+subdir = contrib/oscache
+top_builddir = ../..
+include $(top_builddir)/src/Makefile.global
+include $(top_srcdir)/contrib/contrib-global.mk
+endif
diff --git a/contrib/oscache/oscache.c b/contrib/oscache/oscache.c
new file mode 100644 (file)
index 0000000..1ad7dc2
--- /dev/null
@@ -0,0 +1,151 @@
+/*-------------------------------------------------------------------------
+ *
+ * oscache.c
+ *
+ *
+ * Copyright (c) 2011, PostgreSQL Global Development Group
+ *
+ * IDENTIFICATION
+ *       contrib/oscache/oscache.c
+ *
+ *-------------------------------------------------------------------------
+ */
+/* { POSIX stuff */
+#include <stdlib.h> /* exit, calloc, free */
+#include <sys/stat.h> /* stat, fstat */
+#include <sys/types.h> /* size_t, mincore */
+#include <unistd.h> /* sysconf, close */
+#include <sys/mman.h> /* mmap, mincore */
+/* } */
+
+/* { PostgreSQL stuff */
+#include "postgres.h" /* general Postgres declarations */
+#include "utils/rel.h" /* Relation */
+#include "storage/bufmgr.h"
+#include "catalog/catalog.h" /* relpath */
+/* } */
+
+PG_MODULE_MAGIC;
+
+void           _PG_init(void);
+
+float4 oscache(Relation, ForkNumber);
+
+/*
+ * Module load callback
+ */
+void
+_PG_init(void)
+{
+       /* Install hook. */
+       OSCache_hook = &oscache;
+}
+
+/*
+ * oscache process the os cache inspection for the relation.
+ * It returns the percentage of blocks in OS cache.
+ */
+float4
+oscache(Relation relation, ForkNumber forkNum)
+{
+       int  segment = 0;
+       char *relationpath;
+       char filename[MAXPGPATH];
+       int fd;
+       int64  total_block_disk = 0;
+       int64  total_block_mem  = 0;
+
+       /* OS things */
+       int64 pageSize  = sysconf(_SC_PAGESIZE); /* Page size */
+       register int64 pageIndex;
+
+       relationpath = relpathperm(relation->rd_node, forkNum);
+
+       /*
+        * For each segment of the relation
+        */
+       snprintf(filename, MAXPGPATH, "%s", relationpath);
+       while ((fd = open(filename, O_RDONLY)) != -1)
+       {
+               // for stat file
+               struct stat st;
+               // for mmap file
+               void *pa = (char *)0;
+               // for calloc file
+               unsigned char *vec = (unsigned char *)0;
+               int64  block_disk = 0;
+               int64  block_mem  = 0;
+
+               if (fstat(fd, &st) == -1)
+               {
+                       close(fd);
+                       elog(ERROR, "Can not stat object file : %s",
+                               filename);
+                       return 0;
+               }
+
+               /*
+               * if file ok
+               * then process
+               */
+               if (st.st_size != 0)
+               {
+                       /* number of block in the current file */
+                       block_disk = st.st_size/pageSize;
+
+                       /* TODO We need to split mmap size to be sure (?) to be able to mmap */
+                       pa = mmap(NULL, st.st_size, PROT_NONE, MAP_SHARED, fd, 0);
+                       if (pa == MAP_FAILED)
+                       {
+                               close(fd);
+                               elog(ERROR, "Can not mmap object file : %s, errno = %i,%s\nThis error can happen if there is not enought space in memory to do the projection. Please mail [email protected] with '[oscache] ENOMEM' as subject.",
+                                       filename, errno, strerror(errno));
+                               return 0;
+                       }
+
+                       /* Prepare our vector containing all blocks information */
+                       vec = calloc(1, (st.st_size+pageSize-1)/pageSize);
+                       if ((void *)0 == vec)
+                       {
+                               munmap(pa, st.st_size);
+                               close(fd);
+                               elog(ERROR, "Can not calloc object file : %s",
+                                       filename);
+                               return 0;
+                       }
+
+                       /* Affect vec with mincore */
+                       if (mincore(pa, st.st_size, vec) != 0)
+                       {
+                               free(vec);
+                               munmap(pa, st.st_size);
+                               close(fd);
+                               elog(ERROR, "mincore(%p, %lld, %p): %s\n",
+                                       pa, (int64)st.st_size, vec, strerror(errno));
+                               return 0;
+                       }
+
+                       /* handle the results */
+                       for (pageIndex = 0; pageIndex <= st.st_size/pageSize; pageIndex++)
+                       {
+                               // block in memory
+                               if (vec[pageIndex] & 1)
+                               {
+                                       block_mem++;
+                               }
+                       }
+               }
+               elog(DEBUG1, "oscache %s: %lld of %lld block in linux cache",
+                       filename, block_mem,  block_disk);
+
+               //   free things
+               free(vec);
+               munmap(pa, st.st_size);
+               close(fd);
+               total_block_mem += block_mem;
+               total_block_disk += block_disk;
+
+               snprintf(filename, MAXPGPATH, "%s.%u", relationpath, segment++);
+       }
+       return (float4)(total_block_mem*100/(total_block_disk+1));
+}