-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathpg_control_priority.c
180 lines (154 loc) · 4.14 KB
/
pg_control_priority.c
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
/*-------------------------------------------------------------------------
*
* pg_control_priority.c
* controls the priorities of PostgreSQL server processes
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include <sys/resource.h>
#include <unistd.h>
#include "funcapi.h"
#include "miscadmin.h"
#include "storage/proc.h"
#include "storage/procarray.h"
#include "utils/guc.h"
PG_MODULE_MAGIC;
/* GUC variable */
static int scheduling_priority = 0;
PG_FUNCTION_INFO_V1(pg_get_priority);
PG_FUNCTION_INFO_V1(pg_set_priority);
void _PG_init(void);
void _PG_fini(void);
static int GetProcessPriority(int pid, int elevel);
static void SetProcessPriority(int pid, int priority, int elevel);
static void CheckPostgresPid(int pid);
static bool IsAuxiliaryPid(int pid);
static void assign_scheduling_priority(int newval, void *extra);
static const char *show_scheduling_priority(void);
/*
* Module load callback
*/
void
_PG_init(void)
{
/* Define custom GUC variable */
/*
* We don't accept a priority value in range between -20 and -1 while
* setpriority(2) does. Because the default priority of a process is zero,
* and only root user may lower the priority but PostgreSQL is not allowed
* to run as root. Therefore we use zero as a minimum allowed setting
* value.
*
* The maximum priority value that setpriority(2) can set varies on
* systems, 19 in Linux but 20 in other systems like MacOS. Therefore we
* allow this parameter to accept 20 as a maximum priority. If 20 is set
* in Linux, 19 is used as the actual priority, instead.
*/
DefineCustomIntVariable("pg_control_priority.scheduling_priority",
"Set the scheduling priorities of PostgreSQL server processes.",
NULL,
&scheduling_priority,
0,
0,
20,
PGC_USERSET,
0,
NULL,
assign_scheduling_priority,
show_scheduling_priority);
EmitWarningsOnPlaceholders("pg_control_priority");
}
/*
* Module unload callback
*/
void
_PG_fini(void)
{
}
/*
* Get the scheduling priority of PostgreSQL server process.
*/
Datum
pg_get_priority(PG_FUNCTION_ARGS)
{
int pid = PG_GETARG_INT32(0);
int priority;
CheckPostgresPid(pid);
priority = GetProcessPriority(pid, ERROR);
PG_RETURN_INT32(priority);
}
/*
* Set the scheduling priority of PostgreSQL server process.
*/
Datum
pg_set_priority(PG_FUNCTION_ARGS)
{
int pid = PG_GETARG_INT32(0);
int priority = PG_GETARG_INT32(1);
CheckPostgresPid(pid);
SetProcessPriority(pid, priority, ERROR);
PG_RETURN_VOID();
}
/*
* Get the scheduling priority of the specified process.
*/
static int
GetProcessPriority(int pid, int elevel)
{
int priority = 0;
int save_errno = errno;
errno = 0;
priority = getpriority(PRIO_PROCESS, pid);
if (errno != 0)
ereport(elevel,
(errmsg("could not get the scheduling priority of process %d: %m", pid)));
errno = save_errno;
return priority;
}
/*
* Set the scheduling priority of the specified process.
*/
static void
SetProcessPriority(int pid, int priority, int elevel)
{
int save_errno = errno;
if (setpriority(PRIO_PROCESS, pid, priority) != 0)
ereport(elevel,
(errmsg("could not set the scheduling priority of process %d to %d: %m", pid, priority)));
errno = save_errno;
}
/*
* Check to see if a given pid is a running postmaster, backend, or
* auxiliary process.
*/
static void
CheckPostgresPid(int pid)
{
if (PostmasterPid != pid && !IsBackendPid(pid) && !IsAuxiliaryPid(pid))
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
(errmsg("PID %d is not a PostgreSQL server process", pid))));
}
/*
* Is a given pid a running auxiliary process?
*/
static bool
IsAuxiliaryPid(int pid)
{
return (AuxiliaryPidGetProc(pid) != NULL);
}
static void
assign_scheduling_priority(int newval, void *extra)
{
/* See comments in assign_tcp_keepalives_idle in PostgreSQL source */
SetProcessPriority(getpid(), newval, WARNING);
}
static const char *
show_scheduling_priority(void)
{
/* See comments in assign_tcp_keepalives_idle in PostgreSQL source */
static char nbuf[16];
snprintf(nbuf, sizeof(nbuf), "%d", GetProcessPriority(getpid(), WARNING));
return nbuf;
}