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
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
|
/* ----------
* pgstat.h
*
* Definitions for the PostgreSQL statistics collector daemon.
*
* Copyright (c) 2001, PostgreSQL Global Development Group
*
* $Id: pgstat.h,v 1.9 2001/10/25 05:49:54 momjian Exp $
* ----------
*/
#ifndef PGSTAT_H
#define PGSTAT_H
/* ----------
* Paths for the statistics files. The %s is replaced with the
* installations $PGDATA.
* ----------
*/
#define PGSTAT_STAT_FILENAME "%s/global/pgstat.stat"
#define PGSTAT_STAT_TMPFILE "%s/global/pgstat.tmp.%d"
/* ----------
* Timer definitions.
* ----------
*/
#define PGSTAT_STAT_INTERVAL 500 /* How often to write the status */
/* file, in milliseconds. */
#define PGSTAT_DESTROY_DELAY 10000 /* How long to keep destroyed */
/* objects known to give delayed */
/* UDP packets time to arrive, */
/* in milliseconds. */
#define PGSTAT_DESTROY_COUNT (PGSTAT_DESTROY_DELAY \
/ PGSTAT_STAT_INTERVAL)
/* ----------
* How much of the actual query string to send to the collector.
* ----------
*/
#define PGSTAT_ACTIVITY_SIZE 256
/* ----------
* The types of backend/postmaster -> collector messages
* ----------
*/
#define PGSTAT_MTYPE_DUMMY 0
#define PGSTAT_MTYPE_BESTART 1
#define PGSTAT_MTYPE_BETERM 2
#define PGSTAT_MTYPE_ACTIVITY 3
#define PGSTAT_MTYPE_TABSTAT 4
#define PGSTAT_MTYPE_TABPURGE 5
#define PGSTAT_MTYPE_DROPDB 6
#define PGSTAT_MTYPE_RESETCOUNTER 7
/* ----------
* Amount of space reserved in pgstat_recvbuffer().
* ----------
*/
#define PGSTAT_RECVBUFFERSZ ((int) (1024 * sizeof(PgStat_Msg)))
/* ----------
* The initial size hints for the hash tables used in the
* collector.
* ----------
*/
#define PGSTAT_DB_HASH_SIZE 16
#define PGSTAT_BE_HASH_SIZE 512
#define PGSTAT_TAB_HASH_SIZE 512
/* ----------
* The data type used for counters.
* ----------
*/
typedef int64 PgStat_Counter;
/* ------------------------------------------------------------
* Statistic collector data structures follow
* ------------------------------------------------------------
*/
/* ----------
* PgStat_StatDBEntry The collectors data per database
* ----------
*/
typedef struct PgStat_StatDBEntry
{
Oid databaseid;
HTAB *tables;
int n_backends;
PgStat_Counter n_connects;
PgStat_Counter n_xact_commit;
PgStat_Counter n_xact_rollback;
PgStat_Counter n_blocks_fetched;
PgStat_Counter n_blocks_hit;
int destroy;
} PgStat_StatDBEntry;
/* ----------
* PgStat_StatBeEntry The collectors data per backend
* ----------
*/
typedef struct PgStat_StatBeEntry
{
Oid databaseid;
Oid userid;
int procpid;
char activity[PGSTAT_ACTIVITY_SIZE];
} PgStat_StatBeEntry;
/* ----------
* PgStat_StatBeDead Because UDP packets can arrive out of
* order, we need to keep some information
* about backends that are known to be
* dead for some seconds. This info is held
* in a hash table of these structs.
* ----------
*/
typedef struct PgStat_StatBeDead
{
int procpid;
int backendid;
int destroy;
} PgStat_StatBeDead;
/* ----------
* PgStat_StatTabEntry The collectors data table data
* ----------
*/
typedef struct PgStat_StatTabEntry
{
Oid tableid;
PgStat_Counter numscans;
PgStat_Counter tuples_returned;
PgStat_Counter tuples_fetched;
PgStat_Counter tuples_inserted;
PgStat_Counter tuples_updated;
PgStat_Counter tuples_deleted;
PgStat_Counter blocks_fetched;
PgStat_Counter blocks_hit;
int destroy;
} PgStat_StatTabEntry;
/* ------------------------------------------------------------
* Message formats follow
* ------------------------------------------------------------
*/
/* ----------
* PgStat_MsgHdr The common message header
* ----------
*/
typedef struct PgStat_MsgHdr
{
int m_type;
int m_size;
int m_backendid;
int m_procpid;
Oid m_databaseid;
Oid m_userid;
} PgStat_MsgHdr;
/* ----------
* PgStat_TabEntry A table slot in a MsgTabstat
* ----------
*/
typedef struct PgStat_TableEntry
{
Oid t_id;
PgStat_Counter t_numscans;
PgStat_Counter t_tuples_returned;
PgStat_Counter t_tuples_fetched;
PgStat_Counter t_tuples_inserted;
PgStat_Counter t_tuples_updated;
PgStat_Counter t_tuples_deleted;
PgStat_Counter t_blocks_fetched;
PgStat_Counter t_blocks_hit;
} PgStat_TableEntry;
/* ----------
* PgStat_MsgDummy A dummy message, ignored by the collector
* ----------
*/
typedef struct PgStat_MsgDummy
{
PgStat_MsgHdr m_hdr;
char m_dummy[512];
} PgStat_MsgDummy;
/* ----------
* PgStat_MsgBestart Sent by the backend on startup
* ----------
*/
typedef struct PgStat_MsgBestart
{
PgStat_MsgHdr m_hdr;
} PgStat_MsgBestart;
/* ----------
* PgStat_MsgBeterm Sent by the postmaster after backend exit
* ----------
*/
typedef struct PgStat_MsgBeterm
{
PgStat_MsgHdr m_hdr;
} PgStat_MsgBeterm;
/* ----------
* PgStat_MsgActivity Sent by the backends when they start
* to parse a query.
* ----------
*/
typedef struct PgStat_MsgActivity
{
PgStat_MsgHdr m_hdr;
char m_what[PGSTAT_ACTIVITY_SIZE];
} PgStat_MsgActivity;
/* ----------
* How many table entries fit into a MsgTabstat. Actually,
* this will keep the UDP packets below 1K, what should fit
* unfragmented into the MTU of the lo interface on most
* platforms. Does anybody care for platforms where it doesn't?
* ----------
*/
#define PGSTAT_NUM_TABENTRIES ((1000 - sizeof(PgStat_MsgHdr)) \
/ sizeof(PgStat_TableEntry))
/* ----------
* PgStat_MsgTabstat Sent by the backend to report table
* and buffer access statistics.
* ----------
*/
typedef struct PgStat_MsgTabstat
{
PgStat_MsgHdr m_hdr;
int m_nentries;
int m_xact_commit;
int m_xact_rollback;
PgStat_TableEntry m_entry[PGSTAT_NUM_TABENTRIES];
} PgStat_MsgTabstat;
/* ----------
* How many Oid entries fit into a MsgTabpurge.
* ----------
*/
#define PGSTAT_NUM_TABPURGE ((1000 - sizeof(PgStat_MsgHdr)) \
/ sizeof(PgStat_TableEntry))
/* ----------
* PgStat_MsgTabpurge Sent by the backend to tell the collector
* about dead tables.
* ----------
*/
typedef struct PgStat_MsgTabpurge
{
PgStat_MsgHdr m_hdr;
int m_nentries;
Oid m_tableid[PGSTAT_NUM_TABPURGE];
} PgStat_MsgTabpurge;
/* ----------
* PgStat_MsgDropdb Sent by the backend to tell the collector
* about dropped database
* ----------
*/
typedef struct PgStat_MsgDropdb
{
PgStat_MsgHdr m_hdr;
Oid m_databaseid;
} PgStat_MsgDropdb;
/* ----------
* PgStat_MsgResetcounter Sent by the backend to tell the collector
* to reset counters
* ----------
*/
typedef struct PgStat_MsgResetcounter
{
PgStat_MsgHdr m_hdr;
} PgStat_MsgResetcounter;
/* ----------
* PgStat_Msg Union over all possible messages.
* ----------
*/
typedef union PgStat_Msg
{
PgStat_MsgHdr msg_hdr;
PgStat_MsgDummy msg_dummy;
PgStat_MsgBestart msg_bestart;
PgStat_MsgActivity msg_activity;
PgStat_MsgTabstat msg_tabstat;
PgStat_MsgTabpurge msg_tabpurge;
PgStat_MsgDropdb msg_dropdb;
PgStat_MsgResetcounter msg_resetcounter;
} PgStat_Msg;
/* ----------
* Global variables
* ----------
*/
extern bool pgstat_collect_startcollector;
extern bool pgstat_collect_resetonpmstart;
extern bool pgstat_collect_querystring;
extern bool pgstat_collect_tuplelevel;
extern bool pgstat_collect_blocklevel;
/* ----------
* Functions called from postmaster
* ----------
*/
extern int pgstat_init(void);
extern int pgstat_start(void);
extern int pgstat_ispgstat(int pid);
extern void pgstat_close_sockets(void);
extern void pgstat_beterm(int pid);
/* ----------
* Functions called from backends
* ----------
*/
extern void pgstat_bestart(void);
extern void pgstat_ping(void);
extern void pgstat_report_activity(char *what);
extern void pgstat_report_tabstat(void);
extern int pgstat_vacuum_tabstat(void);
extern void pgstat_reset_counters(void);
extern void pgstat_initstats(PgStat_Info *stats, Relation rel);
#define pgstat_reset_heap_scan(s) \
do { \
if (pgstat_collect_tuplelevel && (s)->tabentry != NULL) \
(s)->heap_scan_counted = FALSE; \
} while (0)
#define pgstat_count_heap_scan(s) \
do { \
if (pgstat_collect_tuplelevel && (s)->tabentry != NULL && \
!(s)->heap_scan_counted) { \
((PgStat_TableEntry *)((s)->tabentry))->t_numscans++; \
(s)->heap_scan_counted = TRUE; \
} \
} while (0)
#define pgstat_count_heap_getnext(s) \
do { \
if (pgstat_collect_tuplelevel && (s)->tabentry != NULL) \
((PgStat_TableEntry *)((s)->tabentry))->t_tuples_returned++; \
} while (0)
#define pgstat_count_heap_fetch(s) \
do { \
if (pgstat_collect_tuplelevel && (s)->tabentry != NULL) \
((PgStat_TableEntry *)((s)->tabentry))->t_tuples_fetched++; \
} while (0)
#define pgstat_count_heap_insert(s) \
do { \
if (pgstat_collect_tuplelevel && (s)->tabentry != NULL) \
((PgStat_TableEntry *)((s)->tabentry))->t_tuples_inserted++; \
} while (0)
#define pgstat_count_heap_update(s) \
do { \
if (pgstat_collect_tuplelevel && (s)->tabentry != NULL) \
((PgStat_TableEntry *)((s)->tabentry))->t_tuples_updated++; \
} while (0)
#define pgstat_count_heap_delete(s) \
do { \
if (pgstat_collect_tuplelevel && (s)->tabentry != NULL) \
((PgStat_TableEntry *)((s)->tabentry))->t_tuples_deleted++; \
} while (0)
#define pgstat_reset_index_scan(s) \
do { \
if (pgstat_collect_tuplelevel && (s)->tabentry != NULL) \
(s)->index_scan_counted = FALSE; \
} while (0)
#define pgstat_count_index_scan(s) \
do { \
if (pgstat_collect_tuplelevel && (s)->tabentry != NULL && \
!(s)->index_scan_counted) { \
((PgStat_TableEntry *)((s)->tabentry))->t_numscans++; \
(s)->index_scan_counted = TRUE; \
} \
} while (0)
#define pgstat_count_index_getnext(s) \
do { \
if (pgstat_collect_tuplelevel && (s)->tabentry != NULL) \
((PgStat_TableEntry *)((s)->tabentry))->t_tuples_returned++; \
} while (0)
#define pgstat_count_buffer_read(s,r) \
do { \
if (pgstat_collect_blocklevel && (s)->tabentry != NULL) \
((PgStat_TableEntry *)((s)->tabentry))->t_blocks_fetched++; \
else { \
if (pgstat_collect_blocklevel && !(s)->no_stats) { \
pgstat_initstats((s), (r)); \
if ((s)->tabentry != NULL) \
((PgStat_TableEntry *)((s)->tabentry))->t_blocks_fetched++; \
} \
} \
} while (0)
#define pgstat_count_buffer_hit(s,r) \
do { \
if (pgstat_collect_blocklevel && (s)->tabentry != NULL) \
((PgStat_TableEntry *)((s)->tabentry))->t_blocks_hit++; \
else { \
if (pgstat_collect_blocklevel && !(s)->no_stats) { \
pgstat_initstats((s), (r)); \
if ((s)->tabentry != NULL) \
((PgStat_TableEntry *)((s)->tabentry))->t_blocks_hit++; \
} \
} \
} while (0)
extern void pgstat_count_xact_commit(void);
extern void pgstat_count_xact_rollback(void);
/* ----------
* Support functions for the SQL-callable functions to
* generate the pgstat* views.
* ----------
*/
extern PgStat_StatDBEntry *pgstat_fetch_stat_dbentry(Oid dbid);
extern PgStat_StatTabEntry *pgstat_fetch_stat_tabentry(Oid relid);
extern PgStat_StatBeEntry *pgstat_fetch_stat_beentry(int beid);
extern int pgstat_fetch_stat_numbackends(void);
#endif /* PGSTAT_H */
|