<para>
<!--
The directory where the UNIX domain socket accepting connections for
- PCP process will be
- created. Default is <literal>/tmp</literal>. Be aware that
+ PCP process will be created. Multiple sockets can be created
+ by listing multiple directories separated by commas.
+ Default is <literal>/tmp</literal>. Be aware that
this socket might be deleted by a cron job. We recommend
to set this value to <literal>/var/run</literal> or such
directory.
-->
PCPプロセスが接続を受け付けるUNIXドメインソケットを置くディレクトリです。
+ コンマで区切った複数のディレクトリのリストを設定すると複数のUNIXドメインソケットファイルを作成します。
デフォルト値は<literal>/tmp</literal>です。
このソケットは、cron によって削除されることがあるので注意してください。
<literal>/var/run</literal>などのディレクトリに変更することをお勧めします。
<listitem>
<para>
The directory where the UNIX domain socket accepting
- connections for PCP process will be created. Default
- is <literal>/tmp</literal>. Be aware that this socket
+ connections for PCP process will be created. Multiple sockets
+ can be created by listing multiple directories separated by commas.
+ Default is <literal>/tmp</literal>. Be aware that this socket
might be deleted by a cron job. We recommend to set this
value to <literal>/var/run</literal> or such directory.
</para>
NULL, NULL, NULL, NULL
},
- {
- {"pcp_socket_dir", CFGCXT_INIT, CONNECTION_CONFIG,
- "The directory to create the UNIX domain socket for accepting pgpool-II PCP connections.",
- CONFIG_VAR_TYPE_STRING, false, 0
- },
- &g_pool_config.pcp_socket_dir,
- DEFAULT_SOCKET_DIR,
- NULL, NULL, NULL, NULL
- },
-
{
{"wd_ipc_socket_dir", CFGCXT_INIT, CONNECTION_CONFIG,
"The directory to create the UNIX domain socket for accepting pgpool-II watchdog IPC connections.",
NULL, NULL, NULL
},
+ {
+ {"pcp_socket_dir", CFGCXT_INIT, CONNECTION_CONFIG,
+ "The directories to create the UNIX domain socket for accepting pgpool-II PCP connections.",
+ CONFIG_VAR_TYPE_STRING_LIST, false, 0
+ },
+ &g_pool_config.pcp_socket_dir,
+ &g_pool_config.num_pcp_socket_directories,
+ (const char *) default_unix_socket_directories_list,
+ ",",
+ false,
+ NULL, NULL, NULL
+ },
+
{
{"read_only_function_list", CFGCXT_RELOAD, CONNECTION_POOL_CONFIG,
"list of functions that does not writes to database.",
char *unix_socket_group; /* owner group of pgpool sockets */
int unix_socket_permissions; /* pgpool sockets permissions */
char *wd_ipc_socket_dir; /* watchdog command IPC socket directory */
- char *pcp_socket_dir; /* PCP socket directory */
+ char **pcp_socket_dir; /* PCP socket directory */
int num_init_children; /* Maximum number of child to
* accept connections */
int min_spare_children; /* Minimum number of idle children */
int num_listen_addresses; /* number of entries in listen_addresses */
int num_pcp_listen_addresses; /* number of entries in pcp_listen_addresses */
int num_unix_socket_directories; /* number of entries in unix_socket_directories */
+ int num_pcp_socket_directories; /* number of entries in pcp_socket_dir */
int num_read_only_function_list; /* number of functions in
* read_only_function_list */
int num_write_function_list; /* number of functions in
static int select_victim_processes(int *process_info_idxs, int count);
static struct sockaddr_un *un_addrs; /* unix domain socket path */
-static struct sockaddr_un pcp_un_addr; /* unix domain socket path for PCP */
+static struct sockaddr_un *pcp_un_addrs; /* unix domain socket path for PCP */
ProcessInfo *process_info = NULL; /* Per child info table on shmem */
volatile User1SignalSlot *user1SignalSlot = NULL; /* User 1 signal slot on
* shmem */
{
int num_inet_fds = 0;
int num_unix_fds = 0;
+ int num_pcp_fds = 0;
int *unix_fds;
int *inet_fds;
- int pcp_unix_fd;
+ int *pcp_unix_fds;
int *pcp_inet_fds;
int i;
char unix_domain_socket_path[UNIXSOCK_PATH_BUFLEN + 1024];
}
/* set unix domain socket path for pgpool PCP communication */
- memset(unix_domain_socket_path, 0, sizeof(unix_domain_socket_path));
- snprintf(unix_domain_socket_path, sizeof(unix_domain_socket_path), "%s/.s.PGSQL.%d",
- pool_config->pcp_socket_dir,
- pool_config->pcp_port);
+ for (i = 0; i < pool_config->num_pcp_socket_directories; i++)
+ {
+ memset(unix_domain_socket_path, 0, sizeof(unix_domain_socket_path));
+ snprintf(unix_domain_socket_path, sizeof(unix_domain_socket_path), "%s/.s.PGSQL.%d",
+ pool_config->pcp_socket_dir[i],
+ pool_config->pcp_port);
- if (strlen(unix_domain_socket_path) >= UNIXSOCK_PATH_BUFLEN)
+ if (strlen(unix_domain_socket_path) >= UNIXSOCK_PATH_BUFLEN)
+ {
+ ereport(WARNING,
+ (errmsg("PCP Unix-domain socket path \"%s\" is too long (maximum %d bytes)",
+ unix_domain_socket_path,
+ (int) (UNIXSOCK_PATH_BUFLEN - 1))));
+ continue;
+ }
+ pcp_un_addrs = realloc(pcp_un_addrs, sizeof(struct sockaddr_un) * (num_pcp_fds + 1));
+ if (pcp_un_addrs == NULL)
+ ereport(FATAL,
+ (errmsg("failed to allocate memory in startup process")));
+
+ snprintf(pcp_un_addrs[i].sun_path, sizeof(pcp_un_addrs[i].sun_path), "%s", unix_domain_socket_path);
+ num_pcp_fds++;
+ }
+
+ if (num_pcp_fds == 0)
{
ereport(FATAL,
- (errmsg("could not create PCP Unix-domain sockets"),
- errdetail("PCP Unix-domain socket path \"%s\" is too long (maximum %d bytes)",
- unix_domain_socket_path,
- (int) (UNIXSOCK_PATH_BUFLEN - 1))));
+ (errmsg("could not create any PCP Unix-domain sockets")));
}
- snprintf(pcp_un_addr.sun_path, sizeof(pcp_un_addr.sun_path), "%s", unix_domain_socket_path);
/* set up signal handlers */
pool_signal(SIGPIPE, SIG_IGN);
-
/* start the log collector if enabled */
pgpool_logger_pid = SysLogger_Start();
/*
}
/* create pcp unix domain socket */
- num_unix_fds = 1;
num_inet_fds = 0;
- pcp_unix_fd = create_unix_domain_socket(pcp_un_addr, "", 0777);
- on_proc_exit(FileUnlink, (Datum) pcp_un_addr.sun_path);
-
- pcp_fds = malloc(sizeof(int) * (num_unix_fds + 1));
+ pcp_unix_fds = create_unix_domain_sockets_by_list(pcp_un_addrs, "", 0777, num_pcp_fds);
+ for (i = 0; i < num_pcp_fds; i++)
+ {
+ on_proc_exit(FileUnlink, (Datum) pcp_un_addrs[i].sun_path);
+ }
+ pcp_fds = malloc(sizeof(int) * (num_pcp_fds + 1));
if (pcp_fds == NULL)
ereport(FATAL,
(errmsg("failed to allocate memory in startup process")));
- pcp_fds[0] = pcp_unix_fd;
- pcp_fds[num_unix_fds] = -1;
+ memcpy(pcp_fds, pcp_unix_fds, sizeof(int) * num_pcp_fds);
+ pcp_fds[num_pcp_fds] = -1;
+ free(pcp_unix_fds);
/* create inet domain socket if any */
pcp_inet_fds = create_inet_domain_sockets_by_list(pool_config->pcp_listen_addresses,
if (num_inet_fds > 0)
{
- pcp_fds = realloc(pcp_fds, sizeof(int) * (num_inet_fds + num_unix_fds + 1));
+ pcp_fds = realloc(pcp_fds, sizeof(int) * (num_inet_fds + num_pcp_fds + 1));
if (pcp_fds == NULL)
ereport(FATAL,
(errmsg("failed to expand memory for pcp_fds")));
- memcpy(&pcp_fds[num_unix_fds], pcp_inet_fds, sizeof(int) * num_inet_fds);
- pcp_fds[num_inet_fds + num_unix_fds] = -1;
+ memcpy(&pcp_fds[num_pcp_fds], pcp_inet_fds, sizeof(int) * num_inet_fds);
+ pcp_fds[num_inet_fds + num_pcp_fds] = -1;
free(pcp_inet_fds);
}
/*
- * Create UNIX domain sockets by unix_socket_directories, which is an array of
- string. The number of elements is
+ * Create UNIX domain sockets by unix_socket_directories/pcp_socket_dir,
+ * which is an array of string. The number of elements is
* "n_listen_addresses". "port" is the port number. A socket array is returned.
* The number of elements in the socket array is "n_sockets".
*/
for (i = 0; i < n_sockets; i++)
{
ereport(LOG,
- (errmsg("unix_socket_directories[%d]: %s", i, un_addrs[i].sun_path)));
+ (errmsg("create socket files[%d]: %s", i, un_addrs[i].sun_path)));
sockets[i] = create_unix_domain_socket(un_addrs[i], group, permissions);
}
static void pcp_child_will_die(int code, Datum arg);
static void pcp_kill_all_children(int sig);
static void reaper(void);
+static bool pcp_unix_fds_not_isset(int *fds, int num_pcp_fds, fd_set* opt);
#define CHECK_RESTART_REQUEST \
* Set no delay if AF_INET socket. Not sure if this is really necessary
* but PostgreSQL does this.
*/
- if (!FD_ISSET(fds[0], &rmask)) /* fds[0] is UNIX domain socket */
+ if (pcp_unix_fds_not_isset(fds, pool_config->num_pcp_socket_directories, &rmask)) /* fds are UNIX domain socket for pcp process */
{
int on;
return afd;
}
+static bool
+pcp_unix_fds_not_isset(int* fds, int num_pcp_fds, fd_set* opt)
+{
+ int i;
+ for (i = 0; i < num_pcp_fds; i++)
+ {
+ if (!FD_ISSET(fds[i], opt))
+ continue;
+
+ return false;
+ }
+ return true;
+}
+
/*
* forks a new pcp worker child
*/
# Port number for pcp
# (change requires restart)
#pcp_socket_dir = '/tmp'
- # Unix domain socket path for pcp
+ # Unix domain socket path(s) for pcp
# The Debian package defaults to
# /var/run/postgresql
# (change requires restart)
#!/usr/bin/env bash
#-------------------------------------------------------------------
-# test script for unix_socket_directories, unix_socket_group and unix_socket_permissions.
+# test script for unix_socket_directories, unix_socket_group, unix_socket_permissions
+# and pcp_socket_dir.
# unix_socket_group test works if UNIX_SOCK_GROUP exists and the user running
# this test belongs to it. Therefore, we usually comment out it.
#
source $TESTLIBS
TESTDIR=testdir
PSQL=$PGBIN/psql
+PGPOOLBIN=$PGPOOL_INSTALL_DIR/bin
+PCP_PORT=11001
for mode in s
do
source ./bashrc.ports
dir=`pwd`
UNIX_SOCK_PATH1=/tmp
+ PCP_SOCK_PATH1=/tmp
if [ -d $HOME/tmp ];then
UNIX_SOCK_PATH2=$HOME/tmp
+ PCP_SOCK_PATH2=$HOME/tmp
else
UNIX_SOCK_PATH2=$HOME
+ PCP_SOCK_PATH2=$HOME
fi
UNIX_SOCK_FILE=.s.PGSQL.$PGPOOL_PORT
+ PCP_SOCK_FILE=.s.PGSQL.$PCP_PORT
UNIX_SOCK_GROUP=wheel
USER=`whoami`
echo "unix_socket_directories = '$UNIX_SOCK_PATH1,$UNIX_SOCK_PATH2'" >> etc/pgpool.conf
+ echo "pcp_socket_dir = '$PCP_SOCK_PATH1,$PCP_SOCK_PATH2'" >> etc/pgpool.conf
<<COMMENT_OUT
echo "unix_socket_group = '$UNIX_SOCK_GROUP'" >> etc/pgpool.conf
COMMENT_OUT
echo "unix_socket_permissions = 0770" >> etc/pgpool.conf
+ sed -i 's/localhost/*/g' ./pcppass
./startall
export PGPORT=$PGPOOL_PORT
+ export PCPPASSFILE=./pcppass
wait_for_pgpool_startup
echo ok: socket files permission
echo ok: unix_socket_directories and related parameters are working.
+ echo check: multiple unix domain sokets for pcp connections
+ if [ ! -e $PCP_SOCK_PATH1/$PCP_SOCK_FILE ]; then
+ echo "fail: not exist $PCP_SOCK_PATH1/$PCP_SOCK_FILE"
+ ./shutdownall
+ exit 1
+ fi
+
+ if [ ! -e $PCP_SOCK_PATH2/$PCP_SOCK_FILE ]; then
+ echo "fail: not exist $PCP_SOCK_PATH2/$PCP_SOCK_FILE"
+ ./shutdownall
+ exit 1
+ fi
+ echo ok: multiple unix domain sockets for pcp connections
+
+ echo check: pcp command connection to unix domain sockets
+ res=`$PGPOOLBIN/pcp_node_info -h $PCP_SOCK_PATH1 -w -p $PCP_PORT|egrep "primary|standby"|wc -l`
+ if [ $res -ne 2 ]; then
+ echo "fail: cannot connect to $PCP_SOCK_PATH1/$PCP_SOCK_FILE"
+ ./shutdownall
+ exit 1
+ fi
+
+ res=`$PGPOOLBIN/pcp_node_info -h $PCP_SOCK_PATH2 -w -p $PCP_PORT|egrep "primary|standby"|wc -l`
+ if [ $res -ne 2 ]; then
+ echo "fail: cannot connect to $PCP_SOCK_PATH2/$PCP_SOCK_FILE"
+ ./shutdownall
+ exit 1
+ fi
+ echo ok: pcp commmand connection to unix domain sockets
+
./shutdownall
done
i++;
StrNCpy(status[i].name, "pcp_socket_dir", POOLCONFIG_MAXNAMELEN);
- snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->pcp_socket_dir);
+ *(status[i].value) = '\0';
+ for (j = 0; j < pool_config->num_pcp_socket_directories; j++)
+ {
+ len = POOLCONFIG_MAXVALLEN - strlen(status[i].value);
+ strncat(status[i].value, pool_config->pcp_socket_dir[j], len);
+ len = POOLCONFIG_MAXVALLEN - strlen(status[i].value);
+ if (j != pool_config->num_pcp_socket_directories - 1)
+ strncat(status[i].value, ",", len);
+ }
StrNCpy(status[i].desc, "PCP socket directory", POOLCONFIG_MAXDESCLEN);
i++;