From: Cédric Villemain Date: Sun, 1 May 2011 20:44:29 +0000 (+0200) Subject: Add an extension to calculate OSCache X-Git-Url: http://git.postgresql.org/gitweb/static/main.js?a=commitdiff_plain;h=40cefa392974c73ec20deb3c15fb5111ed7fad17;p=users%2Fc2main%2Fpostgres.git Add an extension to calculate OSCache --- diff --git a/contrib/Makefile b/contrib/Makefile index 696776795e..47652d536b 100644 --- a/contrib/Makefile +++ b/contrib/Makefile @@ -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 index 0000000000..8d8dcc5dd4 --- /dev/null +++ b/contrib/oscache/Makefile @@ -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 index 0000000000..1ad7dc23b6 --- /dev/null +++ b/contrib/oscache/oscache.c @@ -0,0 +1,151 @@ +/*------------------------------------------------------------------------- + * + * oscache.c + * + * + * Copyright (c) 2011, PostgreSQL Global Development Group + * + * IDENTIFICATION + * contrib/oscache/oscache.c + * + *------------------------------------------------------------------------- + */ +/* { POSIX stuff */ +#include /* exit, calloc, free */ +#include /* stat, fstat */ +#include /* size_t, mincore */ +#include /* sysconf, close */ +#include /* 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 cedric@2ndQuadrant.fr 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)); +}