/* -*-pgsql-c-*- */ /* * * $Header$ * * pgpool: a language independent connection pool server for PostgreSQL * written by Tatsuo Ishii * * Copyright (c) 2003-2021 PgPool Global Development Group * * Permission to use, copy, modify, and distribute this software and * its documentation for any purpose and without fee is hereby * granted, provided that the above copyright notice appear in all * copies and that both that copyright notice and this permission * notice appear in supporting documentation, and that the name of the * author not be used in advertising or publicity pertaining to * distribution of the software without specific, written prior * permission. The author makes no representations about the * suitability of this software for any purpose. It is provided "as * is" without express or implied warranty. * */ #include #include #include #include "pool.h" #include "utils/elog.h" #include "context/pool_process_context.h" #include "pool_config.h" /* remove me afterwards */ static POOL_PROCESS_CONTEXT process_context_d; static POOL_PROCESS_CONTEXT * process_context; /* * Initialize per process context */ void pool_init_process_context(void) { process_context = &process_context_d; if (!process_info) ereport(FATAL, (return_code(1), errmsg("process info is not set"))); process_context->process_info = process_info; if (!pool_config->backend_desc) ereport(FATAL, (return_code(1), errmsg("backend desc is not set"))); process_context->backend_desc = pool_config->backend_desc; process_context->proc_id = my_proc_id; process_context->local_session_id = 0; /* initialize local session * counter */ process_context->last_alarm_handler = SIG_IGN; process_context->last_alarm_time = 0; process_context->last_alarm_second = 0; process_context->undo_alarm_second = 0; } /* * Return process context */ POOL_PROCESS_CONTEXT * pool_get_process_context(void) { return process_context; } /* * Return my process info */ ProcessInfo * pool_get_my_process_info(void) { if (!process_context) ereport(FATAL, (return_code(1), errmsg("process context is not initialized"))); return &process_context->process_info[process_context->proc_id]; } /* * Increment local session id */ void pool_increment_local_session_id(void) { POOL_PROCESS_CONTEXT *p = pool_get_process_context(); if (!p) ereport(ERROR, (errmsg("failed to get process context"))); p->local_session_id++; } /* * Return byte size of connection info(ConnectionInfo) on shmem. */ size_t pool_coninfo_size(void) { size_t size; size = pool_config->num_init_children * pool_config->max_pool * MAX_NUM_BACKENDS * sizeof(ConnectionInfo); ereport(DEBUG1, (errmsg("pool_coninfo_size: num_init_children (%d) * max_pool (%d) * MAX_NUM_BACKENDS (%d) * sizeof(ConnectionInfo) (%zu) = %zu bytes requested for shared memory", pool_config->num_init_children, pool_config->max_pool, MAX_NUM_BACKENDS, sizeof(ConnectionInfo), size))); return size; } /* * Return number of elements of connection info(ConnectionInfo) on shmem. */ int pool_coninfo_num(void) { int nelm; nelm = pool_config->num_init_children * pool_config->max_pool * MAX_NUM_BACKENDS; return nelm; } /* * Return pointer to i th child, j th connection pool and k th backend * of connection info on shmem. */ ConnectionInfo * pool_coninfo(int child, int connection_pool, int backend) { if (child < 0 || child >= pool_config->num_init_children) { ereport(WARNING, (errmsg("failed to get connection info, invalid child number: %d", child))); return NULL; } if (connection_pool < 0 || connection_pool >= pool_config->max_pool) { ereport(WARNING, (errmsg("failed to get connection info, invalid connection pool number: %d", connection_pool))); return NULL; } if (backend < 0 || backend >= MAX_NUM_BACKENDS) { ereport(WARNING, (errmsg("failed to get connection info, invalid backend number: %d", backend))); return NULL; } return &con_info[child * pool_config->max_pool * MAX_NUM_BACKENDS + connection_pool * MAX_NUM_BACKENDS + backend]; } /* * Return pointer to child which has OS process id pid, j th connection * pool and k th backend of connection info on shmem. */ ConnectionInfo * pool_coninfo_pid(int pid, int connection_pool, int backend) { int child = -1; int i; for (i = 0; i < pool_config->num_init_children; i++) { if (process_info[i].pid == pid) { child = i; break; } } if (child < 0) elog(ERROR, "failed to get child pid, invalid child PID:%d", pid); if (child < 0 || child >= pool_config->num_init_children) elog(ERROR, "failed to get child pid, invalid child no:%d", child); if (connection_pool < 0 || connection_pool >= pool_config->max_pool) elog(ERROR, "failed to get child pid, invalid connection pool no:%d", connection_pool); if (backend < 0 || backend >= MAX_NUM_BACKENDS) elog(ERROR, "failed to get child pid, invalid backend no:%d", backend); return &con_info[child * pool_config->max_pool * MAX_NUM_BACKENDS + connection_pool * MAX_NUM_BACKENDS + backend]; } /* * locate and return the shared memory ConnectionInfo having the * backend connection with the pid * if the connection is found the *backend_node_id contains the backend node id * of the backend node that has the connection */ ConnectionInfo * pool_coninfo_backend_pid(int backend_pid, int *backend_node_id) { int child; /* * look for the child process that has the backend with the pid */ ereport(DEBUG1, (errmsg("searching for the connection with backend pid:%d", backend_pid))); for (child = 0; child < pool_config->num_init_children; child++) { int pool; if (process_info[child].pid) { ProcessInfo *pi = pool_get_process_info(process_info[child].pid); for (pool = 0; pool < pool_config->max_pool; pool++) { int backend_id; for (backend_id = 0; backend_id < NUM_BACKENDS; backend_id++) { int poolBE = pool * MAX_NUM_BACKENDS + backend_id; if (ntohl(pi->connection_info[poolBE].pid) == backend_pid) { ereport(DEBUG1, (errmsg("found the connection with backend pid:%d on backend node %d", backend_pid, backend_id))); *backend_node_id = backend_id; return &pi->connection_info[poolBE]; } } } } } return NULL; } /* * sets the flag to mark that the connection will be terminated by the * backend and it should not be considered as a backend node failure. * This flag is used to handle pg_terminate_backend() */ void pool_set_connection_will_be_terminated(ConnectionInfo * connInfo) { connInfo->swallow_termination = 1; } void pool_unset_connection_will_be_terminated(ConnectionInfo * connInfo) { connInfo->swallow_termination = 0; } /* * Set frontend connected flag */ void pool_coninfo_set_frontend_connected(int proc_id, int pool_index) { ConnectionInfo *con; int i; for (i = 0; i < NUM_BACKENDS; i++) { if (!VALID_BACKEND(i)) continue; con = pool_coninfo(proc_id, pool_index, i); if (con == NULL) { elog(WARNING, "failed to get connection info while marking the frontend is connected for pool"); return; } con->connected = true; con->client_connection_time = time(NULL); } } /* * Unset frontend connected flag */ void pool_coninfo_unset_frontend_connected(int proc_id, int pool_index) { ConnectionInfo *con; int i; for (i = 0; i < NUM_BACKENDS; i++) { if (!VALID_BACKEND(i)) continue; con = pool_coninfo(proc_id, pool_index, i); if (con == NULL) { elog(WARNING, "failed to get connection info while marking the frontend is not connected for pool"); return; } con->connected = false; con->client_disconnection_time = time(NULL); } } /* * Set an alarm clock and a signal handler. * For pool_alarm_undo(), the alarm second and the old handler * are saved, and the remaining time is calculated. */ void pool_alarm(pool_sighandler_t handler, unsigned int second) { POOL_PROCESS_CONTEXT *p = pool_get_process_context(); time_t now = time(NULL); alarm(second); p->last_alarm_handler = pool_signal(SIGALRM, handler); if (p->last_alarm_second) { p->undo_alarm_second = p->last_alarm_second - (now - p->last_alarm_time); if (p->undo_alarm_second <= 0) p->undo_alarm_second = 1; } p->last_alarm_time = now; p->last_alarm_second = second; } /* * Undo the alarm signal handler using the remaining time. */ void pool_undo_alarm(void) { POOL_PROCESS_CONTEXT *p = pool_get_process_context(); if (p->undo_alarm_second) { alarm(p->undo_alarm_second); pool_signal(SIGALRM, p->last_alarm_handler); p->undo_alarm_second = 0; } else { alarm(0); pool_signal(SIGALRM, SIG_IGN); } }