--- /dev/null
+/*-------------------------------------------------------------------------
+ *
+ * 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));
+}