1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
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 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));
}
|