├── uninstall_prioritize.sql ├── prioritize.control ├── prioritize.sql.in ├── Makefile ├── META.json ├── README.md └── prioritize.c /uninstall_prioritize.sql: -------------------------------------------------------------------------------- 1 | 2 | DROP FUNCTION set_backend_priority(integer, integer); 3 | DROP FUNCTION get_backend_priority(integer); 4 | -------------------------------------------------------------------------------- /prioritize.control: -------------------------------------------------------------------------------- 1 | # prioritize extension 2 | comment = 'get and set the priority of PostgreSQL backends' 3 | default_version = '1.0' 4 | module_pathname = '$libdir/prioritize' 5 | relocatable = true 6 | -------------------------------------------------------------------------------- /prioritize.sql.in: -------------------------------------------------------------------------------- 1 | CREATE OR REPLACE FUNCTION set_backend_priority(integer, integer) 2 | RETURNS boolean 3 | AS '$libdir/prioritize.so', 'set_backend_priority' 4 | LANGUAGE C VOLATILE; 5 | 6 | CREATE OR REPLACE FUNCTION get_backend_priority(integer) 7 | RETURNS integer 8 | AS '$libdir/prioritize.so', 'get_backend_priority' 9 | LANGUAGE C VOLATILE; 10 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | MODULES = prioritize 2 | EXTENSION = $(MODULES) 3 | EXTVERSION = 1.0 4 | EXTSQL = $(MODULES)--$(EXTVERSION).sql 5 | 6 | DATA_built = $(MODULES).sql 7 | DATA = uninstall_$(MODULES).sql 8 | DOCS = README.md 9 | REGRESS = $(MODULES) 10 | 11 | SQL_IN = $(MODULES).sql.in 12 | EXTRA_CLEAN = sql/$(MODULES).sql expected/$(MODULES).out 13 | 14 | USE_EXTENSION = $(shell pg_config --version | grep -qE " 8\.|9\.0" && echo no || echo yes) 15 | 16 | ifeq ($(USE_EXTENSION),yes) 17 | all: $(EXTSQL) 18 | 19 | $(EXTSQL): $(EXTENSION).sql 20 | cp $< $@ 21 | DATA = $(EXTSQL) 22 | EXTRA_CLEAN += $(EXTSQL) 23 | endif 24 | 25 | PG_CONFIG = pg_config 26 | PGXS := $(shell $(PG_CONFIG) --pgxs) 27 | include $(PGXS) 28 | -------------------------------------------------------------------------------- /META.json: -------------------------------------------------------------------------------- 1 | { 2 | "name":"prioritize", 3 | "abstract":"get/set priorities of PostgreSQL backends", 4 | "description":"This module provides methods to get and set the priorities of PostgreSQL backends.", 5 | "version":"1.0.4", 6 | "maintainer":"Josh Kupershmidt ", 7 | "license":"postgresql", 8 | "provides":{ 9 | "prioritize":{ 10 | "abstract":"get and set the priorities of backends", 11 | "version":"1.0.4", 12 | "file":"prioritize.sql", 13 | "docfile":"README.md" 14 | } 15 | }, 16 | "resources":{ 17 | "bugtracker":{ 18 | "web":"http://github.com/schmiddy/pg_prioritize/issues/" 19 | }, 20 | "repository":{ 21 | "url":"git://github.com/schmiddy/pg_prioritize.git", 22 | "web":"http://github.com/schmiddy/pg_prioritize", 23 | "type":"git" 24 | } 25 | }, 26 | "meta-spec":{ 27 | "version":"1.0.0", 28 | "url":"http://pgxn.org/meta/spec.txt" 29 | }, 30 | "tags":[ 31 | "priority", 32 | "prioritize", 33 | "nice", 34 | "renice" 35 | ] 36 | } 37 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | prioritize 2 | ================= 3 | This module implements an interface to getpriority() and setpriority() 4 | for PostgreSQL backends, callable from SQL functions. Essentially, 5 | this module allows users to `renice' their backends. 6 | 7 | Synopsis 8 | -------- 9 | 10 | SELECT get_backend_priority(pg_backend_pid()); 11 | 12 | SELECT set_backend_priority(pg_backend_pid(), 10); 13 | 14 | SELECT set_backend_priority(pid, get_backend_priority(pid) + 5) 15 | FROM pg_stat_activity 16 | WHERE usename = CURRENT_USER; 17 | 18 | Description 19 | ----------- 20 | This module allows users to query and set the priority of PostgreSQL 21 | backend processes. The priority values are used by getpriority() 22 | and setpriority(), which you may be familiar with from the `nice` or `renice` 23 | programs. 24 | 25 | 26 | 1) get_backend_priority(process_id integer) 27 | ---------------------------------------------- 28 | Returns the current priority of the selected backend. Any user may 29 | query the priority of any other user's backend. 30 | 31 | 2) set_backend_priority(process_id integer, priority_value integer) 32 | ---------------------------------------------- 33 | Set the priority of the given backend, specified by its process ID. 34 | 35 | Superusers are allowed to set the priority of any backends. Unprivileged 36 | users are only allowed to set the priority of backends with the same 37 | role. 38 | 39 | Note, it is only possible to adjust the priority of a process upwards 40 | (meaning, the process will run at a lower priority). This restriction 41 | arises from [SUSv1](http://www.opengroup.org/sud/sud1/xsh/getpriority.htm), 42 | which declares: 43 | 44 | > Only a process with appropriate privileges can raise its own priority 45 | > (that is, assign a lower numerical priority value). 46 | 47 | and UNIX-like platforms take this to mandate that only root users may 48 | adjust priority values downwards. Your PostgreSQL processes will (hopefully!) 49 | not be running under root, hence priority values may only be adjusted upwards. 50 | 51 | 52 | Installation 53 | ------- 54 | Installation should be a simple: 55 | 56 | $ make install 57 | $ CREATE EXTENSION prioritize; 58 | 59 | Support 60 | ------- 61 | 62 | This library is stored in an open [GitHub 63 | repository](https://github.com/schmiddy/pg_prioritize). 64 | Feel free to fork and contribute! Please file bug reports 65 | via [GitHub Issues](http://github.com/schmiddy/pg_prioritize/issues/). 66 | 67 | 68 | Author 69 | ------ 70 | [Josh Kupershmidt](mailto:schmiddy@gmail.com) 71 | 72 | 73 | Copyright and License 74 | --------------------- 75 | 76 | Copyright (c) Josh Kupershmidt 77 | 78 | This module is free software; you can redistribute it and/or modify it under 79 | the [PostgreSQL License](http://www.opensource.org/licenses/postgresql). 80 | 81 | Permission to use, copy, modify, and distribute this software and its 82 | documentation for any purpose, without fee, and without a written agreement is 83 | hereby granted, provided that the above copyright notice and this paragraph 84 | and the following two paragraphs appear in all copies. 85 | 86 | In no event shall Josh Kupershmidt be liable to any party for direct, 87 | indirect, special, incidental, or consequential damages, including 88 | lost profits, arising out of the use of this software and its documentation, 89 | even if Josh Kupershmidt has been advised of the possibility of such damage. 90 | 91 | Josh Kupershmidt specifically disclaims any warranties, 92 | including, but not limited to, the implied warranties of merchantability and 93 | fitness for a particular purpose. The software provided hereunder is on an "as 94 | is" basis, and Josh Kupershmidt has no obligations to provide maintenance, 95 | support, updates, enhancements, or modifications. 96 | -------------------------------------------------------------------------------- /prioritize.c: -------------------------------------------------------------------------------- 1 | #include "postgres.h" 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "fmgr.h" 8 | #include "miscadmin.h" 9 | #include "storage/proc.h" 10 | #include "storage/procarray.h" 11 | 12 | 13 | PG_MODULE_MAGIC; 14 | 15 | PG_FUNCTION_INFO_V1(set_backend_priority); 16 | PG_FUNCTION_INFO_V1(get_backend_priority); 17 | 18 | extern Datum get_backend_priority(PG_FUNCTION_ARGS); 19 | extern Datum set_backend_priority(PG_FUNCTION_ARGS); 20 | 21 | Datum 22 | get_backend_priority(PG_FUNCTION_ARGS) 23 | { 24 | int pid = PG_GETARG_INT32(0); 25 | int priority; 26 | int save_errno = errno; 27 | 28 | 29 | if (!IsBackendPid(pid)) { 30 | ereport(WARNING, 31 | (errmsg("PID %d is not a PostgreSQL server process", pid))); 32 | PG_RETURN_NULL(); 33 | } 34 | 35 | errno = 0; 36 | priority = getpriority(PRIO_PROCESS, pid); 37 | if (priority == -1) { 38 | /* We need to check errno to determine whether an error has occurred 39 | or if the priority of the process is just '-1'. 40 | */ 41 | if (errno == ESRCH || errno == EINVAL) { 42 | errno = save_errno; 43 | ereport(ERROR, 44 | (errcode(ERRCODE_IO_ERROR), 45 | (errmsg("getpriority() could not find the requested backend")))); 46 | } 47 | } 48 | errno = save_errno; 49 | PG_RETURN_INT32(priority); 50 | } 51 | 52 | 53 | /* Set the 'nice' priority of the given backend. The priority passed in should 54 | * typically be between 1 and 20, inclusive, since priorities may only 55 | * be adjusted upwards by non-root users. If the backend had been manually 56 | * set (by a root user) to a negative nice value, it may be possible to pass 57 | * in a greater-but-still-negative value as the new priority. 58 | */ 59 | Datum 60 | set_backend_priority(PG_FUNCTION_ARGS) 61 | { 62 | PGPROC *proc; 63 | int pid = PG_GETARG_INT32(0); 64 | int prio = PG_GETARG_INT32(1); 65 | int save_errno = errno; 66 | bool success = true; 67 | 68 | if (pid == MyProcPid) { 69 | /* Quick check: if we are setting the priority of our own backend, 70 | * skip permissions checks and chekcs of whether 'pid' is a valid 71 | * backend. 72 | */ 73 | } 74 | else if (!superuser()) { 75 | /* 76 | * Since the user is not superuser, check for matching roles. Trust 77 | * that BackendPidGetProc will return NULL if the pid isn't valid, 78 | * even though the check for whether it's a backend process is below. 79 | * The IsBackendPid check can't be relied on as definitive even if it 80 | * was first. The process might end between successive checks 81 | * regardless of their order. There's no way to acquire a lock on an 82 | * arbitrary process to prevent that. 83 | */ 84 | proc = BackendPidGetProc(pid); 85 | 86 | if (proc == NULL) { 87 | /* 88 | * This is just a warning so a loop-through-resultset will not 89 | * abort if one backend terminated on its own during the run 90 | */ 91 | ereport(WARNING, 92 | (errmsg("PID %d is not a PostgreSQL server process", pid))); 93 | success = false; 94 | } 95 | 96 | else if (proc->roleId != GetUserId()) 97 | ereport(ERROR, 98 | (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), 99 | (errmsg("must be superuser to nice arbitrary backends")))); 100 | 101 | /* Otherwise, the backend PID is valid and our user is allowed 102 | * to set its priority. 103 | */ 104 | } 105 | 106 | else if (!IsBackendPid(pid)) 107 | { 108 | ereport(WARNING, 109 | (errmsg("PID %d is not a PostgreSQL server process", pid))); 110 | success = false; 111 | } 112 | 113 | if (success) { 114 | errno = 0; 115 | if (setpriority(PRIO_PROCESS, pid, prio) == 0) { 116 | ereport(NOTICE, 117 | (errmsg("Set priority of backend %d to %d", pid, prio))); 118 | } 119 | else { 120 | if (errno == ESRCH || errno == EINVAL) { 121 | errno = save_errno; 122 | ereport(ERROR, 123 | (errcode(ERRCODE_IO_ERROR), 124 | (errmsg("setpriority(): could not find the requested backend")))); 125 | } 126 | else { 127 | /* Assume EPERM or EACCES */ 128 | ereport(WARNING, 129 | (errmsg("setpriority(): permission denied"))); 130 | success = false; 131 | } 132 | } 133 | } 134 | 135 | errno = save_errno; 136 | PG_RETURN_BOOL(success); 137 | } 138 | --------------------------------------------------------------------------------