prestogres 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +4 -0
- data/Gemfile +2 -0
- data/Gemfile.lock +20 -0
- data/LICENSE +202 -0
- data/NOTICE +22 -0
- data/README.md +217 -0
- data/Rakefile +13 -0
- data/VERSION +1 -0
- data/bin/prestogres +254 -0
- data/config/pcp.conf.sample +28 -0
- data/config/pgpool.conf +678 -0
- data/config/pool_hba.conf +84 -0
- data/config/pool_passwd +0 -0
- data/config/postgresql.conf +2 -0
- data/ext/.gitignore +6 -0
- data/ext/depend +26 -0
- data/ext/extconf.rb +4 -0
- data/ext/prestogres_config.c +12 -0
- data/pgpool2/.gitignore +36 -0
- data/pgpool2/AUTHORS +4 -0
- data/pgpool2/COPYING +12 -0
- data/pgpool2/ChangeLog +1 -0
- data/pgpool2/INSTALL +1 -0
- data/pgpool2/Makefile.am +159 -0
- data/pgpool2/Makefile.in +1187 -0
- data/pgpool2/NEWS +4960 -0
- data/pgpool2/README +1 -0
- data/pgpool2/README.euc_jp +1 -0
- data/pgpool2/README.online-recovery +62 -0
- data/pgpool2/TODO +103 -0
- data/pgpool2/ac_func_accept_argtypes.m4 +85 -0
- data/pgpool2/aclocal.m4 +1088 -0
- data/pgpool2/c-compiler.m4 +134 -0
- data/pgpool2/c-library.m4 +325 -0
- data/pgpool2/child.c +2097 -0
- data/pgpool2/config.guess +1532 -0
- data/pgpool2/config.h.in +332 -0
- data/pgpool2/config.sub +1640 -0
- data/pgpool2/configure +15752 -0
- data/pgpool2/configure.in +392 -0
- data/pgpool2/depcomp +522 -0
- data/pgpool2/doc/basebackup.sh +17 -0
- data/pgpool2/doc/pgpool-de.html +4220 -0
- data/pgpool2/doc/pgpool-en.html +5738 -0
- data/pgpool2/doc/pgpool-fr.html +4118 -0
- data/pgpool2/doc/pgpool-ja.css +198 -0
- data/pgpool2/doc/pgpool-ja.html +11279 -0
- data/pgpool2/doc/pgpool-zh_cn.html +4445 -0
- data/pgpool2/doc/pgpool.css +280 -0
- data/pgpool2/doc/pgpool_remote_start +13 -0
- data/pgpool2/doc/recovery.conf.sample +117 -0
- data/pgpool2/doc/tutorial-en.html +707 -0
- data/pgpool2/doc/tutorial-ja.html +422 -0
- data/pgpool2/doc/tutorial-memqcache-en.html +325 -0
- data/pgpool2/doc/tutorial-memqcache-ja.html +370 -0
- data/pgpool2/doc/tutorial-memqcache-zh_cn.html +322 -0
- data/pgpool2/doc/tutorial-watchdog-en.html +306 -0
- data/pgpool2/doc/tutorial-watchdog-ja.html +343 -0
- data/pgpool2/doc/tutorial-watchdog-zh_cn.html +301 -0
- data/pgpool2/doc/tutorial-zh_cn.html +537 -0
- data/pgpool2/doc/watchdog.png +0 -0
- data/pgpool2/doc/wd-en.html +236 -0
- data/pgpool2/doc/wd-en.jpg +0 -0
- data/pgpool2/doc/wd-ja.html +219 -0
- data/pgpool2/doc/wd-ja.jpg +0 -0
- data/pgpool2/doc/wd-zh_cn.html +201 -0
- data/pgpool2/doc/where_to_send_queries.odg +0 -0
- data/pgpool2/doc/where_to_send_queries.pdf +0 -0
- data/pgpool2/general.m4 +166 -0
- data/pgpool2/getopt_long.c +200 -0
- data/pgpool2/getopt_long.h +44 -0
- data/pgpool2/install-sh +251 -0
- data/pgpool2/ltmain.sh +8406 -0
- data/pgpool2/m4/libtool.m4 +7360 -0
- data/pgpool2/m4/ltoptions.m4 +368 -0
- data/pgpool2/m4/ltsugar.m4 +123 -0
- data/pgpool2/m4/ltversion.m4 +23 -0
- data/pgpool2/m4/lt~obsolete.m4 +92 -0
- data/pgpool2/main.c +2971 -0
- data/pgpool2/md5.c +444 -0
- data/pgpool2/md5.h +28 -0
- data/pgpool2/missing +360 -0
- data/pgpool2/mkinstalldirs +40 -0
- data/pgpool2/parser/Makefile.am +50 -0
- data/pgpool2/parser/Makefile.in +559 -0
- data/pgpool2/parser/copyfuncs.c +3310 -0
- data/pgpool2/parser/gram.c +39100 -0
- data/pgpool2/parser/gram.h +940 -0
- data/pgpool2/parser/gram.y +13408 -0
- data/pgpool2/parser/gramparse.h +74 -0
- data/pgpool2/parser/keywords.c +32 -0
- data/pgpool2/parser/keywords.h +39 -0
- data/pgpool2/parser/kwlist.h +425 -0
- data/pgpool2/parser/kwlookup.c +88 -0
- data/pgpool2/parser/list.c +1156 -0
- data/pgpool2/parser/makefuncs.c +518 -0
- data/pgpool2/parser/makefuncs.h +83 -0
- data/pgpool2/parser/memnodes.h +79 -0
- data/pgpool2/parser/nodes.c +29 -0
- data/pgpool2/parser/nodes.h +609 -0
- data/pgpool2/parser/outfuncs.c +5790 -0
- data/pgpool2/parser/parsenodes.h +2615 -0
- data/pgpool2/parser/parser.c +262 -0
- data/pgpool2/parser/parser.h +46 -0
- data/pgpool2/parser/pg_class.h +158 -0
- data/pgpool2/parser/pg_config_manual.h +273 -0
- data/pgpool2/parser/pg_list.h +352 -0
- data/pgpool2/parser/pg_trigger.h +147 -0
- data/pgpool2/parser/pg_wchar.h +492 -0
- data/pgpool2/parser/pool_memory.c +342 -0
- data/pgpool2/parser/pool_memory.h +77 -0
- data/pgpool2/parser/pool_parser.h +222 -0
- data/pgpool2/parser/pool_string.c +121 -0
- data/pgpool2/parser/pool_string.h +37 -0
- data/pgpool2/parser/primnodes.h +1280 -0
- data/pgpool2/parser/scan.c +4094 -0
- data/pgpool2/parser/scan.l +1451 -0
- data/pgpool2/parser/scanner.h +120 -0
- data/pgpool2/parser/scansup.c +221 -0
- data/pgpool2/parser/scansup.h +28 -0
- data/pgpool2/parser/snprintf.c +1102 -0
- data/pgpool2/parser/stringinfo.c +294 -0
- data/pgpool2/parser/stringinfo.h +178 -0
- data/pgpool2/parser/value.c +78 -0
- data/pgpool2/parser/value.h +62 -0
- data/pgpool2/parser/wchar.c +2048 -0
- data/pgpool2/pcp.conf.sample +28 -0
- data/pgpool2/pcp/Makefile.am +40 -0
- data/pgpool2/pcp/Makefile.in +771 -0
- data/pgpool2/pcp/libpcp_ext.h +250 -0
- data/pgpool2/pcp/md5.c +444 -0
- data/pgpool2/pcp/md5.h +28 -0
- data/pgpool2/pcp/pcp.c +1652 -0
- data/pgpool2/pcp/pcp.h +61 -0
- data/pgpool2/pcp/pcp_attach_node.c +172 -0
- data/pgpool2/pcp/pcp_detach_node.c +185 -0
- data/pgpool2/pcp/pcp_error.c +87 -0
- data/pgpool2/pcp/pcp_node_count.c +160 -0
- data/pgpool2/pcp/pcp_node_info.c +198 -0
- data/pgpool2/pcp/pcp_pool_status.c +166 -0
- data/pgpool2/pcp/pcp_proc_count.c +166 -0
- data/pgpool2/pcp/pcp_proc_info.c +261 -0
- data/pgpool2/pcp/pcp_promote_node.c +185 -0
- data/pgpool2/pcp/pcp_recovery_node.c +172 -0
- data/pgpool2/pcp/pcp_stop_pgpool.c +179 -0
- data/pgpool2/pcp/pcp_stream.c +385 -0
- data/pgpool2/pcp/pcp_stream.h +52 -0
- data/pgpool2/pcp/pcp_systemdb_info.c +194 -0
- data/pgpool2/pcp/pcp_watchdog_info.c +211 -0
- data/pgpool2/pcp_child.c +1493 -0
- data/pgpool2/pg_md5.c +305 -0
- data/pgpool2/pgpool.8.in +121 -0
- data/pgpool2/pgpool.conf +553 -0
- data/pgpool2/pgpool.conf.sample +666 -0
- data/pgpool2/pgpool.conf.sample-master-slave +665 -0
- data/pgpool2/pgpool.conf.sample-replication +664 -0
- data/pgpool2/pgpool.conf.sample-stream +664 -0
- data/pgpool2/pgpool.spec +264 -0
- data/pgpool2/pgpool_adm/TODO +7 -0
- data/pgpool2/pgpool_adm/pgpool_adm--1.0.sql +85 -0
- data/pgpool2/pgpool_adm/pgpool_adm.c +558 -0
- data/pgpool2/pgpool_adm/pgpool_adm.control +5 -0
- data/pgpool2/pgpool_adm/pgpool_adm.h +46 -0
- data/pgpool2/pgpool_adm/pgpool_adm.sql.in +85 -0
- data/pgpool2/pool.h +655 -0
- data/pgpool2/pool_auth.c +1390 -0
- data/pgpool2/pool_config.c +5007 -0
- data/pgpool2/pool_config.h +284 -0
- data/pgpool2/pool_config.l +3281 -0
- data/pgpool2/pool_config_md5.c +29 -0
- data/pgpool2/pool_connection_pool.c +812 -0
- data/pgpool2/pool_error.c +242 -0
- data/pgpool2/pool_globals.c +27 -0
- data/pgpool2/pool_hba.c +1723 -0
- data/pgpool2/pool_hba.conf.sample +67 -0
- data/pgpool2/pool_ip.c +567 -0
- data/pgpool2/pool_ip.h +65 -0
- data/pgpool2/pool_ipc.h +38 -0
- data/pgpool2/pool_lobj.c +242 -0
- data/pgpool2/pool_lobj.h +32 -0
- data/pgpool2/pool_memqcache.c +3818 -0
- data/pgpool2/pool_memqcache.h +268 -0
- data/pgpool2/pool_params.c +163 -0
- data/pgpool2/pool_passwd.c +249 -0
- data/pgpool2/pool_passwd.h +41 -0
- data/pgpool2/pool_path.c +193 -0
- data/pgpool2/pool_path.h +81 -0
- data/pgpool2/pool_process_context.c +247 -0
- data/pgpool2/pool_process_context.h +62 -0
- data/pgpool2/pool_process_query.c +5001 -0
- data/pgpool2/pool_process_reporting.c +1671 -0
- data/pgpool2/pool_process_reporting.h +44 -0
- data/pgpool2/pool_proto2.c +671 -0
- data/pgpool2/pool_proto_modules.c +3524 -0
- data/pgpool2/pool_proto_modules.h +185 -0
- data/pgpool2/pool_query_cache.c +1020 -0
- data/pgpool2/pool_query_context.c +1871 -0
- data/pgpool2/pool_query_context.h +105 -0
- data/pgpool2/pool_relcache.c +284 -0
- data/pgpool2/pool_relcache.h +78 -0
- data/pgpool2/pool_rewrite_outfuncs.c +9060 -0
- data/pgpool2/pool_rewrite_query.c +715 -0
- data/pgpool2/pool_rewrite_query.h +192 -0
- data/pgpool2/pool_select_walker.c +1150 -0
- data/pgpool2/pool_select_walker.h +68 -0
- data/pgpool2/pool_sema.c +161 -0
- data/pgpool2/pool_session_context.c +952 -0
- data/pgpool2/pool_session_context.h +203 -0
- data/pgpool2/pool_shmem.c +185 -0
- data/pgpool2/pool_signal.c +158 -0
- data/pgpool2/pool_signal.h +61 -0
- data/pgpool2/pool_ssl.c +339 -0
- data/pgpool2/pool_stream.c +962 -0
- data/pgpool2/pool_stream.h +61 -0
- data/pgpool2/pool_system.c +659 -0
- data/pgpool2/pool_timestamp.c +1215 -0
- data/pgpool2/pool_timestamp.h +38 -0
- data/pgpool2/pool_type.h +171 -0
- data/pgpool2/pool_worker_child.c +384 -0
- data/pgpool2/ps_status.c +404 -0
- data/pgpool2/recovery.c +435 -0
- data/pgpool2/redhat/pgpool.conf.sample.patch +52 -0
- data/pgpool2/redhat/pgpool.init +201 -0
- data/pgpool2/redhat/pgpool.sysconfig +7 -0
- data/pgpool2/redhat/rpm_installer/basebackup-replication.sh +53 -0
- data/pgpool2/redhat/rpm_installer/basebackup-stream.sh +55 -0
- data/pgpool2/redhat/rpm_installer/config_for_script +17 -0
- data/pgpool2/redhat/rpm_installer/failover.sh +64 -0
- data/pgpool2/redhat/rpm_installer/getsources.sh +141 -0
- data/pgpool2/redhat/rpm_installer/install.sh +1363 -0
- data/pgpool2/redhat/rpm_installer/pgpool_recovery_pitr +47 -0
- data/pgpool2/redhat/rpm_installer/pgpool_remote_start +15 -0
- data/pgpool2/redhat/rpm_installer/recovery.conf +4 -0
- data/pgpool2/redhat/rpm_installer/uninstall.sh +57 -0
- data/pgpool2/sample/dist_def_pgbench.sql +73 -0
- data/pgpool2/sample/pgpool.pam +3 -0
- data/pgpool2/sample/pgpool_recovery +20 -0
- data/pgpool2/sample/pgpool_recovery_pitr +19 -0
- data/pgpool2/sample/pgpool_remote_start +13 -0
- data/pgpool2/sample/replicate_def_pgbench.sql +18 -0
- data/pgpool2/sql/insert_lock.sql +15 -0
- data/pgpool2/sql/pgpool-recovery/pgpool-recovery.c +280 -0
- data/pgpool2/sql/pgpool-recovery/pgpool-recovery.sql.in +19 -0
- data/pgpool2/sql/pgpool-recovery/pgpool_recovery--1.0.sql +24 -0
- data/pgpool2/sql/pgpool-recovery/pgpool_recovery.control +5 -0
- data/pgpool2/sql/pgpool-recovery/uninstall_pgpool-recovery.sql +3 -0
- data/pgpool2/sql/pgpool-regclass/pgpool-regclass.c +206 -0
- data/pgpool2/sql/pgpool-regclass/pgpool-regclass.sql.in +4 -0
- data/pgpool2/sql/pgpool-regclass/pgpool_regclass--1.0.sql +7 -0
- data/pgpool2/sql/pgpool-regclass/pgpool_regclass.control +5 -0
- data/pgpool2/sql/pgpool-regclass/uninstall_pgpool-regclass.sql +1 -0
- data/pgpool2/sql/system_db.sql +38 -0
- data/pgpool2/strlcpy.c +85 -0
- data/pgpool2/test/C/test_extended.c +98 -0
- data/pgpool2/test/jdbc/.cvsignore +2 -0
- data/pgpool2/test/jdbc/AutoCommitTest.java +45 -0
- data/pgpool2/test/jdbc/BatchTest.java +55 -0
- data/pgpool2/test/jdbc/ColumnTest.java +60 -0
- data/pgpool2/test/jdbc/CreateTempTableTest.java +48 -0
- data/pgpool2/test/jdbc/InsertTest.java +34 -0
- data/pgpool2/test/jdbc/LockTest.java +36 -0
- data/pgpool2/test/jdbc/PgpoolTest.java +75 -0
- data/pgpool2/test/jdbc/README.euc_jp +73 -0
- data/pgpool2/test/jdbc/RunTest.java +83 -0
- data/pgpool2/test/jdbc/SelectTest.java +37 -0
- data/pgpool2/test/jdbc/UpdateTest.java +32 -0
- data/pgpool2/test/jdbc/expected/CreateTempTable +1 -0
- data/pgpool2/test/jdbc/expected/autocommit +10 -0
- data/pgpool2/test/jdbc/expected/batch +1 -0
- data/pgpool2/test/jdbc/expected/column +100 -0
- data/pgpool2/test/jdbc/expected/insert +1 -0
- data/pgpool2/test/jdbc/expected/lock +100 -0
- data/pgpool2/test/jdbc/expected/select +2 -0
- data/pgpool2/test/jdbc/expected/update +1 -0
- data/pgpool2/test/jdbc/pgpool.properties +7 -0
- data/pgpool2/test/jdbc/prepare.sql +54 -0
- data/pgpool2/test/jdbc/run.sh +6 -0
- data/pgpool2/test/parser/.cvsignore +6 -0
- data/pgpool2/test/parser/README +32 -0
- data/pgpool2/test/parser/expected/copy.out +17 -0
- data/pgpool2/test/parser/expected/create.out +64 -0
- data/pgpool2/test/parser/expected/cursor.out +37 -0
- data/pgpool2/test/parser/expected/delete.out +10 -0
- data/pgpool2/test/parser/expected/drop.out +12 -0
- data/pgpool2/test/parser/expected/insert.out +13 -0
- data/pgpool2/test/parser/expected/misc.out +28 -0
- data/pgpool2/test/parser/expected/prepare.out +4 -0
- data/pgpool2/test/parser/expected/privileges.out +31 -0
- data/pgpool2/test/parser/expected/scanner.out +30 -0
- data/pgpool2/test/parser/expected/select.out +89 -0
- data/pgpool2/test/parser/expected/transaction.out +38 -0
- data/pgpool2/test/parser/expected/update.out +11 -0
- data/pgpool2/test/parser/expected/v84.out +37 -0
- data/pgpool2/test/parser/expected/v90.out +25 -0
- data/pgpool2/test/parser/expected/var.out +22 -0
- data/pgpool2/test/parser/input/alter.sql +2 -0
- data/pgpool2/test/parser/input/copy.sql +17 -0
- data/pgpool2/test/parser/input/create.sql +64 -0
- data/pgpool2/test/parser/input/cursor.sql +37 -0
- data/pgpool2/test/parser/input/delete.sql +10 -0
- data/pgpool2/test/parser/input/drop.sql +12 -0
- data/pgpool2/test/parser/input/insert.sql +13 -0
- data/pgpool2/test/parser/input/misc.sql +28 -0
- data/pgpool2/test/parser/input/prepare.sql +4 -0
- data/pgpool2/test/parser/input/privileges.sql +31 -0
- data/pgpool2/test/parser/input/scanner.sql +34 -0
- data/pgpool2/test/parser/input/select.sql +89 -0
- data/pgpool2/test/parser/input/transaction.sql +38 -0
- data/pgpool2/test/parser/input/update.sql +11 -0
- data/pgpool2/test/parser/input/v84.sql +37 -0
- data/pgpool2/test/parser/input/v90.sql +38 -0
- data/pgpool2/test/parser/input/var.sql +22 -0
- data/pgpool2/test/parser/main.c +96 -0
- data/pgpool2/test/parser/parse_schedule +16 -0
- data/pgpool2/test/parser/pool.h +13 -0
- data/pgpool2/test/parser/run-test +62 -0
- data/pgpool2/test/pdo-test/README.euc_jp +58 -0
- data/pgpool2/test/pdo-test/SQLlist/test1.sql +3 -0
- data/pgpool2/test/pdo-test/SQLlist/test2.sql +3 -0
- data/pgpool2/test/pdo-test/collections.inc +11 -0
- data/pgpool2/test/pdo-test/def.inc +7 -0
- data/pgpool2/test/pdo-test/log.txt +0 -0
- data/pgpool2/test/pdo-test/mod/database.inc +36 -0
- data/pgpool2/test/pdo-test/mod/def.inc +0 -0
- data/pgpool2/test/pdo-test/mod/errorhandler.inc +27 -0
- data/pgpool2/test/pdo-test/pdotest.php +11 -0
- data/pgpool2/test/pdo-test/regsql.inc +56 -0
- data/pgpool2/test/pgpool_setup +898 -0
- data/pgpool2/test/regression/README +39 -0
- data/pgpool2/test/regression/clean.sh +21 -0
- data/pgpool2/test/regression/libs.sh +16 -0
- data/pgpool2/test/regression/regress.sh +166 -0
- data/pgpool2/test/regression/tests/001.load_balance/test.sh +128 -0
- data/pgpool2/test/regression/tests/002.native_replication/PgTester.java +47 -0
- data/pgpool2/test/regression/tests/002.native_replication/create.sql +6 -0
- data/pgpool2/test/regression/tests/002.native_replication/test.sh +71 -0
- data/pgpool2/test/regression/tests/003.failover/expected.r +6 -0
- data/pgpool2/test/regression/tests/003.failover/expected.s +6 -0
- data/pgpool2/test/regression/tests/003.failover/test.sh +45 -0
- data/pgpool2/test/regression/tests/004.watchdog/master.conf +12 -0
- data/pgpool2/test/regression/tests/004.watchdog/standby.conf +19 -0
- data/pgpool2/test/regression/tests/004.watchdog/test.sh +52 -0
- data/pgpool2/test/regression/tests/050.bug58/test.sh +50 -0
- data/pgpool2/test/regression/tests/051.bug60/bug.sql +12 -0
- data/pgpool2/test/regression/tests/051.bug60/database-clean.sql +6 -0
- data/pgpool2/test/regression/tests/051.bug60/database-setup.sql +28 -0
- data/pgpool2/test/regression/tests/051.bug60/test.sh +79 -0
- data/pgpool2/test/regression/tests/052.do_query/test.sh +44 -0
- data/pgpool2/test/regression/tests/053.insert_lock_hangs/test.sh +81 -0
- data/pgpool2/test/regression/tests/054.postgres_fdw/test.sh +67 -0
- data/pgpool2/test/regression/tests/055.backend_all_down/test.sh +52 -0
- data/pgpool2/test/regression/tests/056.bug63/jdbctest2.java +66 -0
- data/pgpool2/test/regression/tests/056.bug63/test.sh +47 -0
- data/pgpool2/test/regression/tests/057.bug61/test.sh +40 -0
- data/pgpool2/test/regression/tests/058.bug68/jdbctest3.java +45 -0
- data/pgpool2/test/regression/tests/058.bug68/test.sh +47 -0
- data/pgpool2/test/timestamp/expected/insert.out +16 -0
- data/pgpool2/test/timestamp/expected/misc.out +3 -0
- data/pgpool2/test/timestamp/expected/update.out +6 -0
- data/pgpool2/test/timestamp/input/insert.sql +16 -0
- data/pgpool2/test/timestamp/input/misc.sql +3 -0
- data/pgpool2/test/timestamp/input/update.sql +6 -0
- data/pgpool2/test/timestamp/main.c +129 -0
- data/pgpool2/test/timestamp/parse_schedule +3 -0
- data/pgpool2/test/timestamp/run-test +69 -0
- data/pgpool2/version.h +1 -0
- data/pgpool2/watchdog/Makefile.am +17 -0
- data/pgpool2/watchdog/Makefile.in +505 -0
- data/pgpool2/watchdog/test/stab.c +266 -0
- data/pgpool2/watchdog/test/test.c +85 -0
- data/pgpool2/watchdog/test/wd_child_t.c +87 -0
- data/pgpool2/watchdog/test/wd_lifecheck_t.c +87 -0
- data/pgpool2/watchdog/test/wd_packet_t.c +87 -0
- data/pgpool2/watchdog/test/wd_ping_t.c +20 -0
- data/pgpool2/watchdog/watchdog.c +408 -0
- data/pgpool2/watchdog/watchdog.h +209 -0
- data/pgpool2/watchdog/wd_child.c +444 -0
- data/pgpool2/watchdog/wd_ext.h +123 -0
- data/pgpool2/watchdog/wd_heartbeat.c +577 -0
- data/pgpool2/watchdog/wd_if.c +216 -0
- data/pgpool2/watchdog/wd_init.c +126 -0
- data/pgpool2/watchdog/wd_interlock.c +347 -0
- data/pgpool2/watchdog/wd_lifecheck.c +512 -0
- data/pgpool2/watchdog/wd_list.c +429 -0
- data/pgpool2/watchdog/wd_packet.c +1159 -0
- data/pgpool2/watchdog/wd_ping.c +330 -0
- data/pgpool2/ylwrap +223 -0
- data/pgsql/presto_client.py +346 -0
- data/pgsql/prestogres.py +156 -0
- data/pgsql/setup_functions.sql +21 -0
- data/pgsql/setup_language.sql +3 -0
- data/prestogres.gemspec +23 -0
- metadata +496 -0
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# ltversion.m4 -- version numbers -*- Autoconf -*-
|
|
2
|
+
#
|
|
3
|
+
# Copyright (C) 2004 Free Software Foundation, Inc.
|
|
4
|
+
# Written by Scott James Remnant, 2004
|
|
5
|
+
#
|
|
6
|
+
# This file is free software; the Free Software Foundation gives
|
|
7
|
+
# unlimited permission to copy and/or distribute it, with or without
|
|
8
|
+
# modifications, as long as this notice is preserved.
|
|
9
|
+
|
|
10
|
+
# Generated from ltversion.in.
|
|
11
|
+
|
|
12
|
+
# serial 3017 ltversion.m4
|
|
13
|
+
# This file is part of GNU Libtool
|
|
14
|
+
|
|
15
|
+
m4_define([LT_PACKAGE_VERSION], [2.2.6b])
|
|
16
|
+
m4_define([LT_PACKAGE_REVISION], [1.3017])
|
|
17
|
+
|
|
18
|
+
AC_DEFUN([LTVERSION_VERSION],
|
|
19
|
+
[macro_version='2.2.6b'
|
|
20
|
+
macro_revision='1.3017'
|
|
21
|
+
_LT_DECL(, macro_version, 0, [Which release of libtool.m4 was used?])
|
|
22
|
+
_LT_DECL(, macro_revision, 0)
|
|
23
|
+
])
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
# lt~obsolete.m4 -- aclocal satisfying obsolete definitions. -*-Autoconf-*-
|
|
2
|
+
#
|
|
3
|
+
# Copyright (C) 2004, 2005, 2007 Free Software Foundation, Inc.
|
|
4
|
+
# Written by Scott James Remnant, 2004.
|
|
5
|
+
#
|
|
6
|
+
# This file is free software; the Free Software Foundation gives
|
|
7
|
+
# unlimited permission to copy and/or distribute it, with or without
|
|
8
|
+
# modifications, as long as this notice is preserved.
|
|
9
|
+
|
|
10
|
+
# serial 4 lt~obsolete.m4
|
|
11
|
+
|
|
12
|
+
# These exist entirely to fool aclocal when bootstrapping libtool.
|
|
13
|
+
#
|
|
14
|
+
# In the past libtool.m4 has provided macros via AC_DEFUN (or AU_DEFUN)
|
|
15
|
+
# which have later been changed to m4_define as they aren't part of the
|
|
16
|
+
# exported API, or moved to Autoconf or Automake where they belong.
|
|
17
|
+
#
|
|
18
|
+
# The trouble is, aclocal is a bit thick. It'll see the old AC_DEFUN
|
|
19
|
+
# in /usr/share/aclocal/libtool.m4 and remember it, then when it sees us
|
|
20
|
+
# using a macro with the same name in our local m4/libtool.m4 it'll
|
|
21
|
+
# pull the old libtool.m4 in (it doesn't see our shiny new m4_define
|
|
22
|
+
# and doesn't know about Autoconf macros at all.)
|
|
23
|
+
#
|
|
24
|
+
# So we provide this file, which has a silly filename so it's always
|
|
25
|
+
# included after everything else. This provides aclocal with the
|
|
26
|
+
# AC_DEFUNs it wants, but when m4 processes it, it doesn't do anything
|
|
27
|
+
# because those macros already exist, or will be overwritten later.
|
|
28
|
+
# We use AC_DEFUN over AU_DEFUN for compatibility with aclocal-1.6.
|
|
29
|
+
#
|
|
30
|
+
# Anytime we withdraw an AC_DEFUN or AU_DEFUN, remember to add it here.
|
|
31
|
+
# Yes, that means every name once taken will need to remain here until
|
|
32
|
+
# we give up compatibility with versions before 1.7, at which point
|
|
33
|
+
# we need to keep only those names which we still refer to.
|
|
34
|
+
|
|
35
|
+
# This is to help aclocal find these macros, as it can't see m4_define.
|
|
36
|
+
AC_DEFUN([LTOBSOLETE_VERSION], [m4_if([1])])
|
|
37
|
+
|
|
38
|
+
m4_ifndef([AC_LIBTOOL_LINKER_OPTION], [AC_DEFUN([AC_LIBTOOL_LINKER_OPTION])])
|
|
39
|
+
m4_ifndef([AC_PROG_EGREP], [AC_DEFUN([AC_PROG_EGREP])])
|
|
40
|
+
m4_ifndef([_LT_AC_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH])])
|
|
41
|
+
m4_ifndef([_LT_AC_SHELL_INIT], [AC_DEFUN([_LT_AC_SHELL_INIT])])
|
|
42
|
+
m4_ifndef([_LT_AC_SYS_LIBPATH_AIX], [AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX])])
|
|
43
|
+
m4_ifndef([_LT_PROG_LTMAIN], [AC_DEFUN([_LT_PROG_LTMAIN])])
|
|
44
|
+
m4_ifndef([_LT_AC_TAGVAR], [AC_DEFUN([_LT_AC_TAGVAR])])
|
|
45
|
+
m4_ifndef([AC_LTDL_ENABLE_INSTALL], [AC_DEFUN([AC_LTDL_ENABLE_INSTALL])])
|
|
46
|
+
m4_ifndef([AC_LTDL_PREOPEN], [AC_DEFUN([AC_LTDL_PREOPEN])])
|
|
47
|
+
m4_ifndef([_LT_AC_SYS_COMPILER], [AC_DEFUN([_LT_AC_SYS_COMPILER])])
|
|
48
|
+
m4_ifndef([_LT_AC_LOCK], [AC_DEFUN([_LT_AC_LOCK])])
|
|
49
|
+
m4_ifndef([AC_LIBTOOL_SYS_OLD_ARCHIVE], [AC_DEFUN([AC_LIBTOOL_SYS_OLD_ARCHIVE])])
|
|
50
|
+
m4_ifndef([_LT_AC_TRY_DLOPEN_SELF], [AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF])])
|
|
51
|
+
m4_ifndef([AC_LIBTOOL_PROG_CC_C_O], [AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O])])
|
|
52
|
+
m4_ifndef([AC_LIBTOOL_SYS_HARD_LINK_LOCKS], [AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS])])
|
|
53
|
+
m4_ifndef([AC_LIBTOOL_OBJDIR], [AC_DEFUN([AC_LIBTOOL_OBJDIR])])
|
|
54
|
+
m4_ifndef([AC_LTDL_OBJDIR], [AC_DEFUN([AC_LTDL_OBJDIR])])
|
|
55
|
+
m4_ifndef([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH], [AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH])])
|
|
56
|
+
m4_ifndef([AC_LIBTOOL_SYS_LIB_STRIP], [AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP])])
|
|
57
|
+
m4_ifndef([AC_PATH_MAGIC], [AC_DEFUN([AC_PATH_MAGIC])])
|
|
58
|
+
m4_ifndef([AC_PROG_LD_GNU], [AC_DEFUN([AC_PROG_LD_GNU])])
|
|
59
|
+
m4_ifndef([AC_PROG_LD_RELOAD_FLAG], [AC_DEFUN([AC_PROG_LD_RELOAD_FLAG])])
|
|
60
|
+
m4_ifndef([AC_DEPLIBS_CHECK_METHOD], [AC_DEFUN([AC_DEPLIBS_CHECK_METHOD])])
|
|
61
|
+
m4_ifndef([AC_LIBTOOL_PROG_COMPILER_NO_RTTI], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI])])
|
|
62
|
+
m4_ifndef([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE], [AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE])])
|
|
63
|
+
m4_ifndef([AC_LIBTOOL_PROG_COMPILER_PIC], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC])])
|
|
64
|
+
m4_ifndef([AC_LIBTOOL_PROG_LD_SHLIBS], [AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS])])
|
|
65
|
+
m4_ifndef([AC_LIBTOOL_POSTDEP_PREDEP], [AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP])])
|
|
66
|
+
m4_ifndef([LT_AC_PROG_EGREP], [AC_DEFUN([LT_AC_PROG_EGREP])])
|
|
67
|
+
m4_ifndef([LT_AC_PROG_SED], [AC_DEFUN([LT_AC_PROG_SED])])
|
|
68
|
+
m4_ifndef([_LT_CC_BASENAME], [AC_DEFUN([_LT_CC_BASENAME])])
|
|
69
|
+
m4_ifndef([_LT_COMPILER_BOILERPLATE], [AC_DEFUN([_LT_COMPILER_BOILERPLATE])])
|
|
70
|
+
m4_ifndef([_LT_LINKER_BOILERPLATE], [AC_DEFUN([_LT_LINKER_BOILERPLATE])])
|
|
71
|
+
m4_ifndef([_AC_PROG_LIBTOOL], [AC_DEFUN([_AC_PROG_LIBTOOL])])
|
|
72
|
+
m4_ifndef([AC_LIBTOOL_SETUP], [AC_DEFUN([AC_LIBTOOL_SETUP])])
|
|
73
|
+
m4_ifndef([_LT_AC_CHECK_DLFCN], [AC_DEFUN([_LT_AC_CHECK_DLFCN])])
|
|
74
|
+
m4_ifndef([AC_LIBTOOL_SYS_DYNAMIC_LINKER], [AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER])])
|
|
75
|
+
m4_ifndef([_LT_AC_TAGCONFIG], [AC_DEFUN([_LT_AC_TAGCONFIG])])
|
|
76
|
+
m4_ifndef([AC_DISABLE_FAST_INSTALL], [AC_DEFUN([AC_DISABLE_FAST_INSTALL])])
|
|
77
|
+
m4_ifndef([_LT_AC_LANG_CXX], [AC_DEFUN([_LT_AC_LANG_CXX])])
|
|
78
|
+
m4_ifndef([_LT_AC_LANG_F77], [AC_DEFUN([_LT_AC_LANG_F77])])
|
|
79
|
+
m4_ifndef([_LT_AC_LANG_GCJ], [AC_DEFUN([_LT_AC_LANG_GCJ])])
|
|
80
|
+
m4_ifndef([AC_LIBTOOL_RC], [AC_DEFUN([AC_LIBTOOL_RC])])
|
|
81
|
+
m4_ifndef([AC_LIBTOOL_LANG_C_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG])])
|
|
82
|
+
m4_ifndef([_LT_AC_LANG_C_CONFIG], [AC_DEFUN([_LT_AC_LANG_C_CONFIG])])
|
|
83
|
+
m4_ifndef([AC_LIBTOOL_LANG_CXX_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG])])
|
|
84
|
+
m4_ifndef([_LT_AC_LANG_CXX_CONFIG], [AC_DEFUN([_LT_AC_LANG_CXX_CONFIG])])
|
|
85
|
+
m4_ifndef([AC_LIBTOOL_LANG_F77_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_F77_CONFIG])])
|
|
86
|
+
m4_ifndef([_LT_AC_LANG_F77_CONFIG], [AC_DEFUN([_LT_AC_LANG_F77_CONFIG])])
|
|
87
|
+
m4_ifndef([AC_LIBTOOL_LANG_GCJ_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_GCJ_CONFIG])])
|
|
88
|
+
m4_ifndef([_LT_AC_LANG_GCJ_CONFIG], [AC_DEFUN([_LT_AC_LANG_GCJ_CONFIG])])
|
|
89
|
+
m4_ifndef([AC_LIBTOOL_LANG_RC_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_RC_CONFIG])])
|
|
90
|
+
m4_ifndef([_LT_AC_LANG_RC_CONFIG], [AC_DEFUN([_LT_AC_LANG_RC_CONFIG])])
|
|
91
|
+
m4_ifndef([AC_LIBTOOL_CONFIG], [AC_DEFUN([AC_LIBTOOL_CONFIG])])
|
|
92
|
+
m4_ifndef([_LT_AC_FILE_LTDLL_C], [AC_DEFUN([_LT_AC_FILE_LTDLL_C])])
|
data/pgpool2/main.c
ADDED
|
@@ -0,0 +1,2971 @@
|
|
|
1
|
+
/* -*-pgsql-c-*- */
|
|
2
|
+
/*
|
|
3
|
+
* $Header$
|
|
4
|
+
*
|
|
5
|
+
* pgpool: a language independent connection pool server for PostgreSQL
|
|
6
|
+
* written by Tatsuo Ishii
|
|
7
|
+
*
|
|
8
|
+
* Copyright (c) 2003-2013 PgPool Global Development Group
|
|
9
|
+
*
|
|
10
|
+
* Permission to use, copy, modify, and distribute this software and
|
|
11
|
+
* its documentation for any purpose and without fee is hereby
|
|
12
|
+
* granted, provided that the above copyright notice appear in all
|
|
13
|
+
* copies and that both that copyright notice and this permission
|
|
14
|
+
* notice appear in supporting documentation, and that the name of the
|
|
15
|
+
* author not be used in advertising or publicity pertaining to
|
|
16
|
+
* distribution of the software without specific, written prior
|
|
17
|
+
* permission. The author makes no representations about the
|
|
18
|
+
* suitability of this software for any purpose. It is provided "as
|
|
19
|
+
* is" without express or implied warranty.
|
|
20
|
+
*/
|
|
21
|
+
#include "pool.h"
|
|
22
|
+
#include "pool_config.h"
|
|
23
|
+
#include "pool_process_context.h"
|
|
24
|
+
|
|
25
|
+
#include <ctype.h>
|
|
26
|
+
#include <sys/types.h>
|
|
27
|
+
#include <sys/socket.h>
|
|
28
|
+
#include <netinet/in.h>
|
|
29
|
+
#include <sys/un.h>
|
|
30
|
+
#include <netdb.h>
|
|
31
|
+
#include <arpa/inet.h>
|
|
32
|
+
#include <sys/time.h>
|
|
33
|
+
#ifdef HAVE_SYS_SELECT_H
|
|
34
|
+
#include <sys/select.h>
|
|
35
|
+
#endif
|
|
36
|
+
|
|
37
|
+
#include <sys/stat.h>
|
|
38
|
+
#include <sys/types.h>
|
|
39
|
+
#include <fcntl.h>
|
|
40
|
+
|
|
41
|
+
#include <sys/wait.h>
|
|
42
|
+
|
|
43
|
+
#include <stdio.h>
|
|
44
|
+
#include <errno.h>
|
|
45
|
+
#include <unistd.h>
|
|
46
|
+
#include <stdlib.h>
|
|
47
|
+
#include <string.h>
|
|
48
|
+
|
|
49
|
+
#include <signal.h>
|
|
50
|
+
|
|
51
|
+
#ifdef HAVE_GETOPT_H
|
|
52
|
+
#include <getopt.h>
|
|
53
|
+
#else
|
|
54
|
+
#include "getopt_long.h"
|
|
55
|
+
#endif
|
|
56
|
+
|
|
57
|
+
#include <libgen.h>
|
|
58
|
+
|
|
59
|
+
#include "version.h"
|
|
60
|
+
#include "parser/pool_memory.h"
|
|
61
|
+
#include "parser/pool_string.h"
|
|
62
|
+
#include "pool_passwd.h"
|
|
63
|
+
#include "pool_memqcache.h"
|
|
64
|
+
#include "watchdog/wd_ext.h"
|
|
65
|
+
|
|
66
|
+
/*
|
|
67
|
+
* Process pending signal actions.
|
|
68
|
+
*/
|
|
69
|
+
#define CHECK_REQUEST \
|
|
70
|
+
do { \
|
|
71
|
+
if (wakeup_request) \
|
|
72
|
+
{ \
|
|
73
|
+
wakeup_children(); \
|
|
74
|
+
wakeup_request = 0; \
|
|
75
|
+
} \
|
|
76
|
+
if (failover_request) \
|
|
77
|
+
{ \
|
|
78
|
+
failover(); \
|
|
79
|
+
failover_request = 0; \
|
|
80
|
+
} \
|
|
81
|
+
if (sigchld_request) \
|
|
82
|
+
{ \
|
|
83
|
+
reaper(); \
|
|
84
|
+
} \
|
|
85
|
+
if (reload_config_request) \
|
|
86
|
+
{ \
|
|
87
|
+
reload_config(); \
|
|
88
|
+
reload_config_request = 0; \
|
|
89
|
+
} \
|
|
90
|
+
} while (0)
|
|
91
|
+
|
|
92
|
+
#define CLEAR_ALARM \
|
|
93
|
+
do { \
|
|
94
|
+
pool_debug("health check: clearing alarm"); \
|
|
95
|
+
} while (alarm(0) > 0)
|
|
96
|
+
|
|
97
|
+
#define PGPOOLMAXLITSENQUEUELENGTH 10000
|
|
98
|
+
static void daemonize(void);
|
|
99
|
+
static int read_pid_file(void);
|
|
100
|
+
static void write_pid_file(void);
|
|
101
|
+
static int read_status_file(bool discard_status);
|
|
102
|
+
static int write_status_file(void);
|
|
103
|
+
static pid_t pcp_fork_a_child(int unix_fd, int inet_fd, char *pcp_conf_file);
|
|
104
|
+
static pid_t fork_a_child(int unix_fd, int inet_fd, int id);
|
|
105
|
+
static pid_t worker_fork_a_child(void);
|
|
106
|
+
static int create_unix_domain_socket(struct sockaddr_un un_addr_tmp);
|
|
107
|
+
static int create_inet_domain_socket(const char *hostname, const int port);
|
|
108
|
+
static void myexit(int code);
|
|
109
|
+
static void failover(void);
|
|
110
|
+
static void reaper(void);
|
|
111
|
+
static void wakeup_children(void);
|
|
112
|
+
static void reload_config(void);
|
|
113
|
+
static int pool_pause(struct timeval *timeout);
|
|
114
|
+
static void kill_all_children(int sig);
|
|
115
|
+
static int get_next_master_node(void);
|
|
116
|
+
static pid_t fork_follow_child(int old_master, int new_primary, int old_primary);
|
|
117
|
+
|
|
118
|
+
static RETSIGTYPE exit_handler(int sig);
|
|
119
|
+
static RETSIGTYPE reap_handler(int sig);
|
|
120
|
+
static RETSIGTYPE failover_handler(int sig);
|
|
121
|
+
static RETSIGTYPE reload_config_handler(int sig);
|
|
122
|
+
static RETSIGTYPE health_check_timer_handler(int sig);
|
|
123
|
+
static RETSIGTYPE wakeup_handler(int sig);
|
|
124
|
+
|
|
125
|
+
static int health_check(void);
|
|
126
|
+
static int system_db_health_check(void);
|
|
127
|
+
|
|
128
|
+
static void usage(void);
|
|
129
|
+
static void show_version(void);
|
|
130
|
+
static void stop_me(void);
|
|
131
|
+
|
|
132
|
+
static int trigger_failover_command(int node, const char *command_line,
|
|
133
|
+
int old_master, int new_master, int old_primary);
|
|
134
|
+
|
|
135
|
+
static int find_primary_node(void);
|
|
136
|
+
static int find_primary_node_repeatedly(void);
|
|
137
|
+
|
|
138
|
+
static struct sockaddr_un un_addr; /* unix domain socket path */
|
|
139
|
+
static struct sockaddr_un pcp_un_addr; /* unix domain socket path for PCP */
|
|
140
|
+
|
|
141
|
+
ProcessInfo *process_info; /* Per child info table on shmem */
|
|
142
|
+
|
|
143
|
+
/*
|
|
144
|
+
* Private copy of backend status
|
|
145
|
+
*/
|
|
146
|
+
BACKEND_STATUS private_backend_status[MAX_NUM_BACKENDS];
|
|
147
|
+
|
|
148
|
+
/*
|
|
149
|
+
* shmem connection info table
|
|
150
|
+
* this is a three dimension array. i.e.:
|
|
151
|
+
* con_info[pool_config->num_init_children][pool_config->max_pool][MAX_NUM_BACKENDS]
|
|
152
|
+
*/
|
|
153
|
+
ConnectionInfo *con_info;
|
|
154
|
+
|
|
155
|
+
static int unix_fd; /* unix domain socket fd */
|
|
156
|
+
static int inet_fd; /* inet domain socket fd */
|
|
157
|
+
|
|
158
|
+
static int follow_pid; /* pid for child process handling follow command */
|
|
159
|
+
static int pcp_pid; /* pid for child process handling PCP */
|
|
160
|
+
static int pcp_unix_fd; /* unix domain socket fd for PCP (not used) */
|
|
161
|
+
static int pcp_inet_fd; /* inet domain socket fd for PCP */
|
|
162
|
+
static char pcp_conf_file[POOLMAXPATHLEN+1]; /* path for pcp.conf */
|
|
163
|
+
static char conf_file[POOLMAXPATHLEN+1];
|
|
164
|
+
static char hba_file[POOLMAXPATHLEN+1];
|
|
165
|
+
|
|
166
|
+
static int exiting = 0; /* non 0 if I'm exiting */
|
|
167
|
+
static int switching = 0; /* non 0 if I'm fail overing or degenerating */
|
|
168
|
+
|
|
169
|
+
static int clear_cache = 0; /* non 0 if clear cache option (-c) is given */
|
|
170
|
+
static int not_detach = 0; /* non 0 if non detach option (-n) is given */
|
|
171
|
+
|
|
172
|
+
static int stop_sig = SIGTERM; /* stopping signal default value */
|
|
173
|
+
|
|
174
|
+
POOL_REQUEST_INFO *Req_info; /* request info area in shared memory */
|
|
175
|
+
volatile sig_atomic_t *InRecovery; /* non 0 if recovery is started */
|
|
176
|
+
volatile sig_atomic_t reload_config_request = 0;
|
|
177
|
+
static volatile sig_atomic_t failover_request = 0;
|
|
178
|
+
static volatile sig_atomic_t sigchld_request = 0;
|
|
179
|
+
static volatile sig_atomic_t wakeup_request = 0;
|
|
180
|
+
|
|
181
|
+
static int pipe_fds[2]; /* for delivering signals */
|
|
182
|
+
|
|
183
|
+
int my_proc_id;
|
|
184
|
+
|
|
185
|
+
static BackendStatusRecord backend_rec; /* Backend status record */
|
|
186
|
+
|
|
187
|
+
static pid_t worker_pid; /* pid of worker process */
|
|
188
|
+
|
|
189
|
+
BACKEND_STATUS* my_backend_status[MAX_NUM_BACKENDS]; /* Backend status buffer */
|
|
190
|
+
int my_master_node_id; /* Master node id buffer */
|
|
191
|
+
|
|
192
|
+
int myargc;
|
|
193
|
+
char **myargv;
|
|
194
|
+
|
|
195
|
+
/*
|
|
196
|
+
* pgpool main program
|
|
197
|
+
*/
|
|
198
|
+
int main(int argc, char **argv)
|
|
199
|
+
{
|
|
200
|
+
int opt;
|
|
201
|
+
int i;
|
|
202
|
+
int pid;
|
|
203
|
+
int size;
|
|
204
|
+
int retrycnt;
|
|
205
|
+
int sys_retrycnt;
|
|
206
|
+
int debug_level = 0;
|
|
207
|
+
int optindex;
|
|
208
|
+
bool discard_status = false;
|
|
209
|
+
bool retrying;
|
|
210
|
+
bool clear_memcache_oidmaps = false;
|
|
211
|
+
|
|
212
|
+
static struct option long_options[] = {
|
|
213
|
+
{"hba-file", required_argument, NULL, 'a'},
|
|
214
|
+
{"clear", no_argument, NULL, 'c'},
|
|
215
|
+
{"debug", no_argument, NULL, 'd'},
|
|
216
|
+
{"config-file", required_argument, NULL, 'f'},
|
|
217
|
+
{"pcp-file", required_argument, NULL, 'F'},
|
|
218
|
+
{"help", no_argument, NULL, 'h'},
|
|
219
|
+
{"mode", required_argument, NULL, 'm'},
|
|
220
|
+
{"dont-detach", no_argument, NULL, 'n'},
|
|
221
|
+
{"discard-status", no_argument, NULL, 'D'},
|
|
222
|
+
{"clear-oidmaps", no_argument, NULL, 'C'},
|
|
223
|
+
{"version", no_argument, NULL, 'v'},
|
|
224
|
+
{NULL, 0, NULL, 0}
|
|
225
|
+
};
|
|
226
|
+
|
|
227
|
+
myargc = argc;
|
|
228
|
+
myargv = argv;
|
|
229
|
+
|
|
230
|
+
snprintf(conf_file, sizeof(conf_file), "%s/%s", DEFAULT_CONFIGDIR, POOL_CONF_FILE_NAME);
|
|
231
|
+
snprintf(pcp_conf_file, sizeof(pcp_conf_file), "%s/%s", DEFAULT_CONFIGDIR, PCP_PASSWD_FILE_NAME);
|
|
232
|
+
snprintf(hba_file, sizeof(hba_file), "%s/%s", DEFAULT_CONFIGDIR, HBA_CONF_FILE_NAME);
|
|
233
|
+
|
|
234
|
+
while ((opt = getopt_long(argc, argv, "a:cdf:F:hm:nDCv", long_options, &optindex)) != -1)
|
|
235
|
+
{
|
|
236
|
+
switch (opt)
|
|
237
|
+
{
|
|
238
|
+
case 'a': /* specify hba configuration file */
|
|
239
|
+
if (!optarg)
|
|
240
|
+
{
|
|
241
|
+
usage();
|
|
242
|
+
exit(1);
|
|
243
|
+
}
|
|
244
|
+
strlcpy(hba_file, optarg, sizeof(hba_file));
|
|
245
|
+
break;
|
|
246
|
+
|
|
247
|
+
case 'c': /* clear cache option */
|
|
248
|
+
clear_cache = 1;
|
|
249
|
+
break;
|
|
250
|
+
|
|
251
|
+
case 'd': /* debug option */
|
|
252
|
+
debug_level = 1;
|
|
253
|
+
break;
|
|
254
|
+
|
|
255
|
+
case 'f': /* specify configuration file */
|
|
256
|
+
if (!optarg)
|
|
257
|
+
{
|
|
258
|
+
usage();
|
|
259
|
+
exit(1);
|
|
260
|
+
}
|
|
261
|
+
strlcpy(conf_file, optarg, sizeof(conf_file));
|
|
262
|
+
break;
|
|
263
|
+
|
|
264
|
+
case 'F': /* specify PCP password file */
|
|
265
|
+
if (!optarg)
|
|
266
|
+
{
|
|
267
|
+
usage();
|
|
268
|
+
exit(1);
|
|
269
|
+
}
|
|
270
|
+
strlcpy(pcp_conf_file, optarg, sizeof(pcp_conf_file));
|
|
271
|
+
break;
|
|
272
|
+
|
|
273
|
+
case 'h':
|
|
274
|
+
usage();
|
|
275
|
+
exit(0);
|
|
276
|
+
break;
|
|
277
|
+
|
|
278
|
+
case 'm': /* stop mode */
|
|
279
|
+
if (!optarg)
|
|
280
|
+
{
|
|
281
|
+
usage();
|
|
282
|
+
exit(1);
|
|
283
|
+
}
|
|
284
|
+
if (*optarg == 's' || !strcmp("smart", optarg))
|
|
285
|
+
stop_sig = SIGTERM; /* smart shutdown */
|
|
286
|
+
else if (*optarg == 'f' || !strcmp("fast", optarg))
|
|
287
|
+
stop_sig = SIGINT; /* fast shutdown */
|
|
288
|
+
else if (*optarg == 'i' || !strcmp("immediate", optarg))
|
|
289
|
+
stop_sig = SIGQUIT; /* immediate shutdown */
|
|
290
|
+
else
|
|
291
|
+
{
|
|
292
|
+
usage();
|
|
293
|
+
exit(1);
|
|
294
|
+
}
|
|
295
|
+
break;
|
|
296
|
+
|
|
297
|
+
case 'n': /* no detaching control ttys */
|
|
298
|
+
not_detach = 1;
|
|
299
|
+
break;
|
|
300
|
+
|
|
301
|
+
case 'D': /* discard pgpool_status */
|
|
302
|
+
discard_status = true;
|
|
303
|
+
break;
|
|
304
|
+
|
|
305
|
+
case 'C': /* discard caches in memcached */
|
|
306
|
+
clear_memcache_oidmaps = true;
|
|
307
|
+
break;
|
|
308
|
+
|
|
309
|
+
case 'v':
|
|
310
|
+
show_version();
|
|
311
|
+
exit(0);
|
|
312
|
+
|
|
313
|
+
default:
|
|
314
|
+
usage();
|
|
315
|
+
exit(1);
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
#ifdef USE_SSL
|
|
320
|
+
/* global ssl init */
|
|
321
|
+
SSL_library_init();
|
|
322
|
+
SSL_load_error_strings();
|
|
323
|
+
#endif /* USE_SSL */
|
|
324
|
+
|
|
325
|
+
mypid = getpid();
|
|
326
|
+
|
|
327
|
+
if (pool_init_config())
|
|
328
|
+
exit(1);
|
|
329
|
+
|
|
330
|
+
/*
|
|
331
|
+
* Override debug level
|
|
332
|
+
*/
|
|
333
|
+
pool_config->debug_level = debug_level;
|
|
334
|
+
|
|
335
|
+
if (pool_get_config(conf_file, INIT_CONFIG))
|
|
336
|
+
{
|
|
337
|
+
pool_error("Unable to get configuration. Exiting...");
|
|
338
|
+
exit(1);
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
/*
|
|
342
|
+
* Open syslog connection if required
|
|
343
|
+
*/
|
|
344
|
+
if (!strcmp(pool_config->log_destination, "syslog")) {
|
|
345
|
+
openlog(pool_config->syslog_ident, LOG_PID|LOG_NDELAY|LOG_NOWAIT, pool_config->syslog_facility);
|
|
346
|
+
/* set a flag to allow pool_error.c to begin writing to syslog
|
|
347
|
+
instead of stdout now that pool_get_config() is done */
|
|
348
|
+
pool_config->logsyslog = 1;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
/*
|
|
352
|
+
* Override debug level
|
|
353
|
+
*/
|
|
354
|
+
if (pool_config->debug_level == 0)
|
|
355
|
+
pool_config->debug_level = debug_level;
|
|
356
|
+
|
|
357
|
+
if (pool_config->enable_pool_hba)
|
|
358
|
+
load_hba(hba_file);
|
|
359
|
+
|
|
360
|
+
/*
|
|
361
|
+
* If a non-switch argument remains, then it should be either "reload" or "stop".
|
|
362
|
+
*/
|
|
363
|
+
if (optind == (argc - 1))
|
|
364
|
+
{
|
|
365
|
+
if (!strcmp(argv[optind], "reload"))
|
|
366
|
+
{
|
|
367
|
+
pid_t pid;
|
|
368
|
+
|
|
369
|
+
pid = read_pid_file();
|
|
370
|
+
if (pid < 0)
|
|
371
|
+
{
|
|
372
|
+
pool_error("could not read pid file");
|
|
373
|
+
pool_shmem_exit(1);
|
|
374
|
+
exit(1);
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
if (kill(pid, SIGHUP) == -1)
|
|
378
|
+
{
|
|
379
|
+
pool_error("could not reload configuration file pid: %d. reason: %s", pid, strerror(errno));
|
|
380
|
+
pool_shmem_exit(1);
|
|
381
|
+
exit(1);
|
|
382
|
+
}
|
|
383
|
+
pool_shmem_exit(0);
|
|
384
|
+
exit(0);
|
|
385
|
+
}
|
|
386
|
+
if (!strcmp(argv[optind], "stop"))
|
|
387
|
+
{
|
|
388
|
+
stop_me();
|
|
389
|
+
unlink(pool_config->pid_file_name);
|
|
390
|
+
pool_shmem_exit(0);
|
|
391
|
+
exit(0);
|
|
392
|
+
}
|
|
393
|
+
else
|
|
394
|
+
{
|
|
395
|
+
usage();
|
|
396
|
+
pool_shmem_exit(1);
|
|
397
|
+
exit(1);
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
/*
|
|
401
|
+
* else if no non-switch argument remains, then it should be a start request
|
|
402
|
+
*/
|
|
403
|
+
else if (optind == argc)
|
|
404
|
+
{
|
|
405
|
+
pid = read_pid_file();
|
|
406
|
+
if (pid > 0)
|
|
407
|
+
{
|
|
408
|
+
if (kill(pid, 0) == 0)
|
|
409
|
+
{
|
|
410
|
+
fprintf(stderr, "pid file found. is another pgpool(%d) is running?\n", pid);
|
|
411
|
+
exit(1);
|
|
412
|
+
}
|
|
413
|
+
else
|
|
414
|
+
fprintf(stderr, "pid file found but it seems bogus. Trying to start pgpool anyway...\n");
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
/*
|
|
418
|
+
* otherwise an error...
|
|
419
|
+
*/
|
|
420
|
+
else
|
|
421
|
+
{
|
|
422
|
+
usage();
|
|
423
|
+
exit(1);
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
/* check effective user id for watchdog */
|
|
427
|
+
/* watchdog must be started under the privileged user */
|
|
428
|
+
if (pool_config->use_watchdog )
|
|
429
|
+
{
|
|
430
|
+
/* check setuid bit of network interface control commands */
|
|
431
|
+
if (wd_chk_setuid() == 1)
|
|
432
|
+
{
|
|
433
|
+
/* if_up, if_down and arping command have a setuid bit */
|
|
434
|
+
pool_log("watchdog might call network commands which using setuid bit.");
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
/* set signal masks */
|
|
439
|
+
poolinitmask();
|
|
440
|
+
|
|
441
|
+
if (not_detach)
|
|
442
|
+
write_pid_file();
|
|
443
|
+
else
|
|
444
|
+
daemonize();
|
|
445
|
+
|
|
446
|
+
/*
|
|
447
|
+
* Locate pool_passwd
|
|
448
|
+
* The default file name "pool_passwd" can be changed by setting
|
|
449
|
+
* pgpool.conf's "pool_passwd" directive.
|
|
450
|
+
*/
|
|
451
|
+
if (strcmp("", pool_config->pool_passwd))
|
|
452
|
+
{
|
|
453
|
+
char pool_passwd[POOLMAXPATHLEN+1];
|
|
454
|
+
char dirnamebuf[POOLMAXPATHLEN+1];
|
|
455
|
+
char *dirp;
|
|
456
|
+
|
|
457
|
+
strlcpy(dirnamebuf, conf_file, sizeof(dirnamebuf));
|
|
458
|
+
dirp = dirname(dirnamebuf);
|
|
459
|
+
snprintf(pool_passwd, sizeof(pool_passwd), "%s/%s",
|
|
460
|
+
dirp, pool_config->pool_passwd);
|
|
461
|
+
pool_init_pool_passwd(pool_passwd);
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
if (pool_semaphore_create(MAX_NUM_SEMAPHORES))
|
|
465
|
+
{
|
|
466
|
+
pool_error("Unable to create semaphores. Exiting...");
|
|
467
|
+
pool_shmem_exit(1);
|
|
468
|
+
exit(1);
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
/*
|
|
472
|
+
* Restore previous backend status if possible
|
|
473
|
+
*/
|
|
474
|
+
read_status_file(discard_status);
|
|
475
|
+
|
|
476
|
+
/* clear cache */
|
|
477
|
+
if (clear_cache && pool_config->enable_query_cache && SYSDB_STATUS == CON_UP)
|
|
478
|
+
{
|
|
479
|
+
Interval interval[1];
|
|
480
|
+
|
|
481
|
+
interval[0].quantity = 0;
|
|
482
|
+
interval[0].unit = second;
|
|
483
|
+
|
|
484
|
+
pool_clear_cache_by_time(interval, 1);
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
/* set unix domain socket path for connections to pgpool */
|
|
488
|
+
snprintf(un_addr.sun_path, sizeof(un_addr.sun_path), "%s/.s.PGSQL.%d",
|
|
489
|
+
pool_config->socket_dir,
|
|
490
|
+
pool_config->port);
|
|
491
|
+
/* set unix domain socket path for pgpool PCP communication */
|
|
492
|
+
snprintf(pcp_un_addr.sun_path, sizeof(pcp_un_addr.sun_path), "%s/.s.PGSQL.%d",
|
|
493
|
+
pool_config->pcp_socket_dir,
|
|
494
|
+
pool_config->pcp_port);
|
|
495
|
+
|
|
496
|
+
/* set up signal handlers */
|
|
497
|
+
pool_signal(SIGPIPE, SIG_IGN);
|
|
498
|
+
|
|
499
|
+
/* create unix domain socket */
|
|
500
|
+
unix_fd = create_unix_domain_socket(un_addr);
|
|
501
|
+
|
|
502
|
+
/* create inet domain socket if any */
|
|
503
|
+
if (pool_config->listen_addresses[0])
|
|
504
|
+
{
|
|
505
|
+
inet_fd = create_inet_domain_socket(pool_config->listen_addresses, pool_config->port);
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
/*
|
|
509
|
+
* con_info is a 3 dimension array: i corresponds to pgpool child
|
|
510
|
+
* process, j corresponds to connection pool in each process and k
|
|
511
|
+
* corresponds to backends in each connection pool.
|
|
512
|
+
*
|
|
513
|
+
* XXX: Before 2010/4/12 this was a 2 dimension array: i
|
|
514
|
+
* corresponds to pgpool child process, j corresponds to
|
|
515
|
+
* connection pool in each process. Of course this was wrong.
|
|
516
|
+
*/
|
|
517
|
+
size = pool_coninfo_size();
|
|
518
|
+
con_info = pool_shared_memory_create(size);
|
|
519
|
+
if (con_info == NULL)
|
|
520
|
+
{
|
|
521
|
+
pool_error("failed to allocate connection information");
|
|
522
|
+
myexit(1);
|
|
523
|
+
}
|
|
524
|
+
memset(con_info, 0, size);
|
|
525
|
+
|
|
526
|
+
size = pool_config->num_init_children * (sizeof(ProcessInfo));
|
|
527
|
+
process_info = pool_shared_memory_create(size);
|
|
528
|
+
if (process_info == NULL)
|
|
529
|
+
{
|
|
530
|
+
pool_error("failed to allocate process_info");
|
|
531
|
+
myexit(1);
|
|
532
|
+
}
|
|
533
|
+
memset(process_info, 0, size);
|
|
534
|
+
for (i = 0; i < pool_config->num_init_children; i++)
|
|
535
|
+
{
|
|
536
|
+
process_info[i].connection_info = pool_coninfo(i,0,0);
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
/* create fail over/switch over event area */
|
|
540
|
+
Req_info = pool_shared_memory_create(sizeof(POOL_REQUEST_INFO));
|
|
541
|
+
if (Req_info == NULL)
|
|
542
|
+
{
|
|
543
|
+
pool_error("failed to allocate Req_info");
|
|
544
|
+
myexit(1);
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
/*
|
|
548
|
+
* Initialize backend status area.
|
|
549
|
+
* From now on, VALID_BACKEND macro can be used.
|
|
550
|
+
* (get_next_master_node() uses VALID_BACKEND)
|
|
551
|
+
*/
|
|
552
|
+
|
|
553
|
+
for (i=0;i<MAX_NUM_BACKENDS;i++)
|
|
554
|
+
{
|
|
555
|
+
my_backend_status[i] = &(BACKEND_INFO(i).backend_status);
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
/* initialize Req_info */
|
|
559
|
+
Req_info->kind = NODE_UP_REQUEST;
|
|
560
|
+
memset(Req_info->node_id, -1, sizeof(int) * MAX_NUM_BACKENDS);
|
|
561
|
+
Req_info->master_node_id = get_next_master_node();
|
|
562
|
+
Req_info->conn_counter = 0;
|
|
563
|
+
Req_info->switching = false;
|
|
564
|
+
|
|
565
|
+
InRecovery = pool_shared_memory_create(sizeof(int));
|
|
566
|
+
if (InRecovery == NULL)
|
|
567
|
+
{
|
|
568
|
+
pool_error("failed to allocate InRecovery");
|
|
569
|
+
myexit(1);
|
|
570
|
+
}
|
|
571
|
+
*InRecovery = RECOVERY_INIT;
|
|
572
|
+
|
|
573
|
+
/*
|
|
574
|
+
* Initialize shared memory cache
|
|
575
|
+
*/
|
|
576
|
+
if (pool_config->memory_cache_enabled)
|
|
577
|
+
{
|
|
578
|
+
if (pool_is_shmem_cache())
|
|
579
|
+
{
|
|
580
|
+
size_t size;
|
|
581
|
+
|
|
582
|
+
size = pool_shared_memory_cache_size();
|
|
583
|
+
if (size == 0)
|
|
584
|
+
{
|
|
585
|
+
pool_error("pool_shared_memory_cache_size error");
|
|
586
|
+
myexit(1);
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
if (pool_init_memory_cache(size) < 0)
|
|
590
|
+
{
|
|
591
|
+
pool_error("pool_shared_memory_cache_size error");
|
|
592
|
+
myexit(1);
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
size = pool_shared_memory_fsmm_size();
|
|
596
|
+
if (size == 0)
|
|
597
|
+
{
|
|
598
|
+
pool_error("pool_shared_memory_fsmm_size error");
|
|
599
|
+
myexit(1);
|
|
600
|
+
}
|
|
601
|
+
pool_init_fsmm(size);
|
|
602
|
+
|
|
603
|
+
pool_allocate_fsmm_clock_hand();
|
|
604
|
+
|
|
605
|
+
pool_discard_oid_maps();
|
|
606
|
+
pool_log("pool_discard_oid_maps: discarded memqcache oid maps");
|
|
607
|
+
|
|
608
|
+
pool_hash_init(pool_config->memqcache_max_num_cache);
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
#ifdef USE_MEMCACHED
|
|
612
|
+
else
|
|
613
|
+
{
|
|
614
|
+
if (clear_memcache_oidmaps)
|
|
615
|
+
{
|
|
616
|
+
pool_discard_oid_maps();
|
|
617
|
+
pool_log("pool_discard_oid_maps: discarded memqcache oid maps");
|
|
618
|
+
}
|
|
619
|
+
else
|
|
620
|
+
{
|
|
621
|
+
pool_debug("skipped discarding memqcache oid maps");
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
#endif
|
|
625
|
+
|
|
626
|
+
if (pool_init_memqcache_stats() < 0)
|
|
627
|
+
{
|
|
628
|
+
pool_error("pool_init_memqcache_stats error");
|
|
629
|
+
myexit(1);
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
/* start watchdog */
|
|
634
|
+
if (pool_config->use_watchdog )
|
|
635
|
+
{
|
|
636
|
+
if (!wd_main(1))
|
|
637
|
+
{
|
|
638
|
+
pool_error("wd_main error");
|
|
639
|
+
myexit(1);
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
/*
|
|
644
|
+
* We need to block signal here. Otherwise child might send some
|
|
645
|
+
* signals, for example SIGUSR1(fail over). Children will inherit
|
|
646
|
+
* signal blocking but they do unblock signals at the very beginning
|
|
647
|
+
* of process. So this is harmless.
|
|
648
|
+
*/
|
|
649
|
+
POOL_SETMASK(&BlockSig);
|
|
650
|
+
|
|
651
|
+
/* fork the children */
|
|
652
|
+
for (i=0;i<pool_config->num_init_children;i++)
|
|
653
|
+
{
|
|
654
|
+
process_info[i].pid = fork_a_child(unix_fd, inet_fd, i);
|
|
655
|
+
process_info[i].start_time = time(NULL);
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
/* set up signal handlers */
|
|
659
|
+
|
|
660
|
+
pool_signal(SIGTERM, exit_handler);
|
|
661
|
+
pool_signal(SIGINT, exit_handler);
|
|
662
|
+
pool_signal(SIGQUIT, exit_handler);
|
|
663
|
+
pool_signal(SIGCHLD, reap_handler);
|
|
664
|
+
pool_signal(SIGUSR1, failover_handler);
|
|
665
|
+
pool_signal(SIGUSR2, wakeup_handler);
|
|
666
|
+
pool_signal(SIGHUP, reload_config_handler);
|
|
667
|
+
|
|
668
|
+
/* create pipe for delivering event */
|
|
669
|
+
if (pipe(pipe_fds) < 0)
|
|
670
|
+
{
|
|
671
|
+
pool_error("failed to create pipe");
|
|
672
|
+
myexit(1);
|
|
673
|
+
}
|
|
674
|
+
|
|
675
|
+
pool_log("%s successfully started. version %s (%s)", PACKAGE, VERSION, PGPOOLVERSION);
|
|
676
|
+
|
|
677
|
+
/* fork a child for PCP handling */
|
|
678
|
+
pcp_unix_fd = create_unix_domain_socket(pcp_un_addr);
|
|
679
|
+
/* maybe change "*" to pool_config->pcp_listen_addresses */
|
|
680
|
+
pcp_inet_fd = create_inet_domain_socket("*", pool_config->pcp_port);
|
|
681
|
+
pcp_pid = pcp_fork_a_child(pcp_unix_fd, pcp_inet_fd, pcp_conf_file);
|
|
682
|
+
|
|
683
|
+
/* Fork worker process */
|
|
684
|
+
worker_pid = worker_fork_a_child();
|
|
685
|
+
|
|
686
|
+
retrycnt = 0; /* reset health check retry counter */
|
|
687
|
+
sys_retrycnt = 0; /* reset SystemDB health check retry counter */
|
|
688
|
+
|
|
689
|
+
/* Save primary node id */
|
|
690
|
+
Req_info->primary_node_id = find_primary_node();
|
|
691
|
+
|
|
692
|
+
/*
|
|
693
|
+
* This is the main loop
|
|
694
|
+
*/
|
|
695
|
+
|
|
696
|
+
retrying = false;
|
|
697
|
+
|
|
698
|
+
for (;;)
|
|
699
|
+
{
|
|
700
|
+
CHECK_REQUEST;
|
|
701
|
+
|
|
702
|
+
/* do we need health checking for PostgreSQL? */
|
|
703
|
+
if (pool_config->health_check_period > 0)
|
|
704
|
+
{
|
|
705
|
+
int sts;
|
|
706
|
+
int sys_sts = 0;
|
|
707
|
+
unsigned int sleep_time;
|
|
708
|
+
|
|
709
|
+
if (retrycnt == 0)
|
|
710
|
+
{
|
|
711
|
+
pool_debug("starting health checking");
|
|
712
|
+
}
|
|
713
|
+
else
|
|
714
|
+
{
|
|
715
|
+
pool_debug("retrying %d th health checking", retrycnt);
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
if (pool_config->health_check_timeout > 0)
|
|
719
|
+
{
|
|
720
|
+
/*
|
|
721
|
+
* set health checker timeout. we want to detect
|
|
722
|
+
* communication path failure much earlier before
|
|
723
|
+
* TCP/IP stack detects it.
|
|
724
|
+
*/
|
|
725
|
+
CLEAR_ALARM;
|
|
726
|
+
pool_signal(SIGALRM, health_check_timer_handler);
|
|
727
|
+
alarm(pool_config->health_check_timeout);
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
/*
|
|
731
|
+
* do actual health check. trying to connect to the backend
|
|
732
|
+
*/
|
|
733
|
+
errno = 0;
|
|
734
|
+
health_check_timer_expired = 0;
|
|
735
|
+
POOL_SETMASK(&UnBlockSig);
|
|
736
|
+
sts = health_check();
|
|
737
|
+
POOL_SETMASK(&BlockSig);
|
|
738
|
+
|
|
739
|
+
if (pool_config->parallel_mode || pool_config->enable_query_cache)
|
|
740
|
+
sys_sts = system_db_health_check();
|
|
741
|
+
|
|
742
|
+
if ((sts > 0 || sys_sts < 0) && (errno != EINTR || (errno == EINTR && health_check_timer_expired)))
|
|
743
|
+
{
|
|
744
|
+
if (sts > 0)
|
|
745
|
+
{
|
|
746
|
+
sts--;
|
|
747
|
+
|
|
748
|
+
retrycnt++;
|
|
749
|
+
pool_signal(SIGALRM, SIG_IGN); /* Cancel timer */
|
|
750
|
+
CLEAR_ALARM;
|
|
751
|
+
|
|
752
|
+
if (!pool_config->parallel_mode)
|
|
753
|
+
{
|
|
754
|
+
if (POOL_DISALLOW_TO_FAILOVER(BACKEND_INFO(sts).flag))
|
|
755
|
+
{
|
|
756
|
+
pool_log("health_check: %d failover is canceled because failover is disallowed", sts);
|
|
757
|
+
}
|
|
758
|
+
else if (retrycnt <= pool_config->health_check_max_retries)
|
|
759
|
+
{
|
|
760
|
+
/* continue to retry */
|
|
761
|
+
sleep_time = pool_config->health_check_retry_delay;
|
|
762
|
+
pool_log("health check retry sleep time: %d second(s)", sleep_time);
|
|
763
|
+
pool_sleep(sleep_time);
|
|
764
|
+
retrying = true;
|
|
765
|
+
continue;
|
|
766
|
+
}
|
|
767
|
+
else
|
|
768
|
+
{
|
|
769
|
+
/* retry count over */
|
|
770
|
+
pool_log("set %d th backend down status", sts);
|
|
771
|
+
Req_info->kind = NODE_DOWN_REQUEST;
|
|
772
|
+
Req_info->node_id[0] = sts;
|
|
773
|
+
health_check_timer_expired = 0;
|
|
774
|
+
failover();
|
|
775
|
+
/* need to distribute this info to children */
|
|
776
|
+
retrying = false;
|
|
777
|
+
}
|
|
778
|
+
}
|
|
779
|
+
else
|
|
780
|
+
{
|
|
781
|
+
if (retrycnt > NUM_BACKENDS)
|
|
782
|
+
{
|
|
783
|
+
/* retry count over */
|
|
784
|
+
pool_log("set %d th backend down status", sts);
|
|
785
|
+
Req_info->kind = NODE_DOWN_REQUEST;
|
|
786
|
+
Req_info->node_id[0] = sts;
|
|
787
|
+
health_check_timer_expired = 0;
|
|
788
|
+
failover();
|
|
789
|
+
retrycnt = 0;
|
|
790
|
+
retrying = false;
|
|
791
|
+
}
|
|
792
|
+
else
|
|
793
|
+
{
|
|
794
|
+
/* continue to retry */
|
|
795
|
+
sleep_time = pool_config->health_check_period/NUM_BACKENDS;
|
|
796
|
+
pool_debug("retry sleep time: %d seconds", sleep_time);
|
|
797
|
+
pool_sleep(sleep_time);
|
|
798
|
+
continue;
|
|
799
|
+
}
|
|
800
|
+
}
|
|
801
|
+
}
|
|
802
|
+
if (sys_sts < 0)
|
|
803
|
+
{
|
|
804
|
+
sys_retrycnt++;
|
|
805
|
+
pool_signal(SIGALRM, SIG_IGN);
|
|
806
|
+
CLEAR_ALARM;
|
|
807
|
+
|
|
808
|
+
if (sys_retrycnt > NUM_BACKENDS)
|
|
809
|
+
{
|
|
810
|
+
pool_log("set SystemDB down status");
|
|
811
|
+
SYSDB_STATUS = CON_DOWN;
|
|
812
|
+
sys_retrycnt = 0;
|
|
813
|
+
}
|
|
814
|
+
else if (sts == 0) /* goes to sleep only when SystemDB alone was down */
|
|
815
|
+
{
|
|
816
|
+
sleep_time = pool_config->health_check_period/NUM_BACKENDS;
|
|
817
|
+
pool_debug("retry sleep time: %d seconds", sleep_time);
|
|
818
|
+
pool_sleep(sleep_time);
|
|
819
|
+
continue;
|
|
820
|
+
}
|
|
821
|
+
}
|
|
822
|
+
}
|
|
823
|
+
else
|
|
824
|
+
{
|
|
825
|
+
/* success. reset retry count */
|
|
826
|
+
retrycnt = 0;
|
|
827
|
+
if (retrying)
|
|
828
|
+
{
|
|
829
|
+
pool_log("after some retrying backend returned to healthy state");
|
|
830
|
+
retrying = false;
|
|
831
|
+
}
|
|
832
|
+
}
|
|
833
|
+
|
|
834
|
+
if (pool_config->health_check_timeout > 0)
|
|
835
|
+
{
|
|
836
|
+
/* seems OK. cancel health check timer */
|
|
837
|
+
pool_signal(SIGALRM, SIG_IGN);
|
|
838
|
+
CLEAR_ALARM;
|
|
839
|
+
}
|
|
840
|
+
|
|
841
|
+
sleep_time = pool_config->health_check_period;
|
|
842
|
+
pool_sleep(sleep_time);
|
|
843
|
+
}
|
|
844
|
+
else
|
|
845
|
+
{
|
|
846
|
+
for (;;)
|
|
847
|
+
{
|
|
848
|
+
int r;
|
|
849
|
+
struct timeval t = {3, 0};
|
|
850
|
+
|
|
851
|
+
POOL_SETMASK(&UnBlockSig);
|
|
852
|
+
r = pool_pause(&t);
|
|
853
|
+
POOL_SETMASK(&BlockSig);
|
|
854
|
+
if (r > 0)
|
|
855
|
+
break;
|
|
856
|
+
}
|
|
857
|
+
}
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
pool_shmem_exit(0);
|
|
861
|
+
}
|
|
862
|
+
|
|
863
|
+
static void show_version(void)
|
|
864
|
+
{
|
|
865
|
+
fprintf(stderr, "%s version %s (%s)\n", PACKAGE, VERSION, PGPOOLVERSION);
|
|
866
|
+
}
|
|
867
|
+
|
|
868
|
+
static void usage(void)
|
|
869
|
+
{
|
|
870
|
+
fprintf(stderr, "%s version %s (%s),\n", PACKAGE, VERSION, PGPOOLVERSION);
|
|
871
|
+
fprintf(stderr, " A generic connection pool/replication/load balance server for PostgreSQL\n\n");
|
|
872
|
+
fprintf(stderr, "Usage:\n");
|
|
873
|
+
fprintf(stderr, " pgpool [ -c] [ -f CONFIG_FILE ] [ -F PCP_CONFIG_FILE ] [ -a HBA_CONFIG_FILE ]\n");
|
|
874
|
+
fprintf(stderr, " [ -n ] [ -D ] [ -d ]\n");
|
|
875
|
+
fprintf(stderr, " pgpool [ -f CONFIG_FILE ] [ -F PCP_CONFIG_FILE ] [ -a HBA_CONFIG_FILE ]\n");
|
|
876
|
+
fprintf(stderr, " [ -m SHUTDOWN-MODE ] stop\n");
|
|
877
|
+
fprintf(stderr, " pgpool [ -f CONFIG_FILE ] [ -F PCP_CONFIG_FILE ] [ -a HBA_CONFIG_FILE ] reload\n\n");
|
|
878
|
+
fprintf(stderr, "Common options:\n");
|
|
879
|
+
fprintf(stderr, " -a, --hba-file=HBA_CONFIG_FILE\n");
|
|
880
|
+
fprintf(stderr, " Sets the path to the pool_hba.conf configuration file\n");
|
|
881
|
+
fprintf(stderr, " (default: %s/%s)\n",DEFAULT_CONFIGDIR, HBA_CONF_FILE_NAME);
|
|
882
|
+
fprintf(stderr, " -f, --config-file=CONFIG_FILE\n");
|
|
883
|
+
fprintf(stderr, " Sets the path to the pgpool.conf configuration file\n");
|
|
884
|
+
fprintf(stderr, " (default: %s/%s)\n",DEFAULT_CONFIGDIR, POOL_CONF_FILE_NAME);
|
|
885
|
+
fprintf(stderr, " -F, --pcp-file=PCP_CONFIG_FILE\n");
|
|
886
|
+
fprintf(stderr, " Sets the path to the pcp.conf configuration file\n");
|
|
887
|
+
fprintf(stderr, " (default: %s/%s)\n",DEFAULT_CONFIGDIR, PCP_PASSWD_FILE_NAME);
|
|
888
|
+
fprintf(stderr, " -h, --help Prints this help\n\n");
|
|
889
|
+
fprintf(stderr, "Start options:\n");
|
|
890
|
+
fprintf(stderr, " -c, --clear Clears query cache (enable_query_cache must be on)\n");
|
|
891
|
+
fprintf(stderr, " -C, --clear-oidmaps Clears query cache oidmaps when memqcache_method is memcached\n");
|
|
892
|
+
fprintf(stderr, " (If shmem, discards whenever pgpool starts.)\n");
|
|
893
|
+
fprintf(stderr, " -n, --dont-detach Don't run in daemon mode, does not detach control tty\n");
|
|
894
|
+
fprintf(stderr, " -D, --discard-status Discard pgpool_status file and do not restore previous status\n");
|
|
895
|
+
fprintf(stderr, " -d, --debug Debug mode\n\n");
|
|
896
|
+
fprintf(stderr, "Stop options:\n");
|
|
897
|
+
fprintf(stderr, " -m, --mode=SHUTDOWN-MODE\n");
|
|
898
|
+
fprintf(stderr, " Can be \"smart\", \"fast\", or \"immediate\"\n\n");
|
|
899
|
+
fprintf(stderr, "Shutdown modes are:\n");
|
|
900
|
+
fprintf(stderr, " smart quit after all clients have disconnected\n");
|
|
901
|
+
fprintf(stderr, " fast quit directly, with proper shutdown\n");
|
|
902
|
+
fprintf(stderr, " immediate the same mode as fast\n");
|
|
903
|
+
}
|
|
904
|
+
|
|
905
|
+
/*
|
|
906
|
+
* detach control ttys
|
|
907
|
+
*/
|
|
908
|
+
static void daemonize(void)
|
|
909
|
+
{
|
|
910
|
+
int i;
|
|
911
|
+
pid_t pid;
|
|
912
|
+
int fdlimit;
|
|
913
|
+
int rc_chdir;
|
|
914
|
+
|
|
915
|
+
pid = fork();
|
|
916
|
+
if (pid == (pid_t) -1)
|
|
917
|
+
{
|
|
918
|
+
pool_error("fork() failed. reason: %s", strerror(errno));
|
|
919
|
+
pool_shmem_exit(1);
|
|
920
|
+
exit(1);
|
|
921
|
+
return; /* not reached */
|
|
922
|
+
}
|
|
923
|
+
else if (pid > 0)
|
|
924
|
+
{ /* parent */
|
|
925
|
+
pool_shmem_exit(0);
|
|
926
|
+
exit(0);
|
|
927
|
+
}
|
|
928
|
+
|
|
929
|
+
#ifdef HAVE_SETSID
|
|
930
|
+
if (setsid() < 0)
|
|
931
|
+
{
|
|
932
|
+
pool_error("setsid() failed. reason:%s", strerror(errno));
|
|
933
|
+
pool_shmem_exit(1);
|
|
934
|
+
exit(1);
|
|
935
|
+
}
|
|
936
|
+
#endif
|
|
937
|
+
|
|
938
|
+
mypid = getpid();
|
|
939
|
+
write_pid_file();
|
|
940
|
+
rc_chdir = chdir("/");
|
|
941
|
+
|
|
942
|
+
/* redirect stdin, stdout and stderr to /dev/null */
|
|
943
|
+
i = open("/dev/null", O_RDWR);
|
|
944
|
+
dup2(i, 0);
|
|
945
|
+
dup2(i, 1);
|
|
946
|
+
dup2(i, 2);
|
|
947
|
+
|
|
948
|
+
/* close syslog connection for daemonizing */
|
|
949
|
+
if (pool_config->logsyslog) {
|
|
950
|
+
closelog();
|
|
951
|
+
}
|
|
952
|
+
|
|
953
|
+
/* close other file descriptors */
|
|
954
|
+
fdlimit = sysconf(_SC_OPEN_MAX);
|
|
955
|
+
for (i = 3; i < fdlimit; i++)
|
|
956
|
+
close(i);
|
|
957
|
+
|
|
958
|
+
/* reopen syslog connection after daemonizing */
|
|
959
|
+
if (pool_config->logsyslog) {
|
|
960
|
+
openlog(pool_config->syslog_ident, LOG_PID|LOG_NDELAY|LOG_NOWAIT, pool_config->syslog_facility);
|
|
961
|
+
}
|
|
962
|
+
|
|
963
|
+
}
|
|
964
|
+
|
|
965
|
+
|
|
966
|
+
/*
|
|
967
|
+
* stop myself
|
|
968
|
+
*/
|
|
969
|
+
static void stop_me(void)
|
|
970
|
+
{
|
|
971
|
+
pid_t pid;
|
|
972
|
+
|
|
973
|
+
pid = read_pid_file();
|
|
974
|
+
if (pid < 0)
|
|
975
|
+
{
|
|
976
|
+
pool_error("could not read pid file");
|
|
977
|
+
pool_shmem_exit(1);
|
|
978
|
+
exit(1);
|
|
979
|
+
}
|
|
980
|
+
|
|
981
|
+
if (kill(pid, stop_sig) == -1)
|
|
982
|
+
{
|
|
983
|
+
pool_error("could not stop pid: %d. reason: %s", pid, strerror(errno));
|
|
984
|
+
pool_shmem_exit(1);
|
|
985
|
+
exit(1);
|
|
986
|
+
}
|
|
987
|
+
|
|
988
|
+
fprintf(stderr, "stop request sent to pgpool. waiting for termination...");
|
|
989
|
+
|
|
990
|
+
while (kill(pid, 0) == 0)
|
|
991
|
+
{
|
|
992
|
+
fprintf(stderr, ".");
|
|
993
|
+
sleep(1);
|
|
994
|
+
}
|
|
995
|
+
fprintf(stderr, "done.\n");
|
|
996
|
+
}
|
|
997
|
+
|
|
998
|
+
/*
|
|
999
|
+
* read the pid file
|
|
1000
|
+
*/
|
|
1001
|
+
static int read_pid_file(void)
|
|
1002
|
+
{
|
|
1003
|
+
int fd;
|
|
1004
|
+
int readlen;
|
|
1005
|
+
char pidbuf[128];
|
|
1006
|
+
|
|
1007
|
+
fd = open(pool_config->pid_file_name, O_RDONLY);
|
|
1008
|
+
if (fd == -1)
|
|
1009
|
+
{
|
|
1010
|
+
return -1;
|
|
1011
|
+
}
|
|
1012
|
+
if ((readlen = read(fd, pidbuf, sizeof(pidbuf))) == -1)
|
|
1013
|
+
{
|
|
1014
|
+
pool_error("could not read pid file as %s. reason: %s",
|
|
1015
|
+
pool_config->pid_file_name, strerror(errno));
|
|
1016
|
+
close(fd);
|
|
1017
|
+
return -1;
|
|
1018
|
+
}
|
|
1019
|
+
else if (readlen == 0)
|
|
1020
|
+
{
|
|
1021
|
+
pool_error("EOF detected while reading pid file as %s. reason: %s",
|
|
1022
|
+
pool_config->pid_file_name, strerror(errno));
|
|
1023
|
+
close(fd);
|
|
1024
|
+
return -1;
|
|
1025
|
+
}
|
|
1026
|
+
close(fd);
|
|
1027
|
+
return(atoi(pidbuf));
|
|
1028
|
+
}
|
|
1029
|
+
|
|
1030
|
+
/*
|
|
1031
|
+
* write the pid file
|
|
1032
|
+
*/
|
|
1033
|
+
static void write_pid_file(void)
|
|
1034
|
+
{
|
|
1035
|
+
int fd;
|
|
1036
|
+
char pidbuf[128];
|
|
1037
|
+
|
|
1038
|
+
fd = open(pool_config->pid_file_name, O_CREAT|O_WRONLY, S_IRUSR|S_IWUSR);
|
|
1039
|
+
if (fd == -1)
|
|
1040
|
+
{
|
|
1041
|
+
pool_error("could not open pid file as %s. reason: %s",
|
|
1042
|
+
pool_config->pid_file_name, strerror(errno));
|
|
1043
|
+
pool_shmem_exit(1);
|
|
1044
|
+
exit(1);
|
|
1045
|
+
}
|
|
1046
|
+
snprintf(pidbuf, sizeof(pidbuf), "%d", (int)getpid());
|
|
1047
|
+
if (write(fd, pidbuf, strlen(pidbuf)+1) == -1)
|
|
1048
|
+
{
|
|
1049
|
+
pool_error("could not write pid file as %s. reason: %s",
|
|
1050
|
+
pool_config->pid_file_name, strerror(errno));
|
|
1051
|
+
close(fd);
|
|
1052
|
+
pool_shmem_exit(1);
|
|
1053
|
+
exit(1);
|
|
1054
|
+
}
|
|
1055
|
+
if (fsync(fd) == -1)
|
|
1056
|
+
{
|
|
1057
|
+
pool_error("could not fsync pid file as %s. reason: %s",
|
|
1058
|
+
pool_config->pid_file_name, strerror(errno));
|
|
1059
|
+
close(fd);
|
|
1060
|
+
pool_shmem_exit(1);
|
|
1061
|
+
exit(1);
|
|
1062
|
+
}
|
|
1063
|
+
if (close(fd) == -1)
|
|
1064
|
+
{
|
|
1065
|
+
pool_error("could not close pid file as %s. reason: %s",
|
|
1066
|
+
pool_config->pid_file_name, strerror(errno));
|
|
1067
|
+
pool_shmem_exit(1);
|
|
1068
|
+
exit(1);
|
|
1069
|
+
}
|
|
1070
|
+
}
|
|
1071
|
+
|
|
1072
|
+
/*
|
|
1073
|
+
* Read the status file
|
|
1074
|
+
*/
|
|
1075
|
+
static int read_status_file(bool discard_status)
|
|
1076
|
+
{
|
|
1077
|
+
FILE *fd;
|
|
1078
|
+
char fnamebuf[POOLMAXPATHLEN];
|
|
1079
|
+
int i;
|
|
1080
|
+
bool someone_wakeup = false;
|
|
1081
|
+
|
|
1082
|
+
snprintf(fnamebuf, sizeof(fnamebuf), "%s/%s", pool_config->logdir, STATUS_FILE_NAME);
|
|
1083
|
+
fd = fopen(fnamebuf, "r");
|
|
1084
|
+
if (!fd)
|
|
1085
|
+
{
|
|
1086
|
+
pool_log("Backend status file %s does not exist", fnamebuf);
|
|
1087
|
+
return -1;
|
|
1088
|
+
}
|
|
1089
|
+
|
|
1090
|
+
/*
|
|
1091
|
+
* If discard_status is true, unlink pgpool_status and
|
|
1092
|
+
* do not restore previous status.
|
|
1093
|
+
*/
|
|
1094
|
+
if (discard_status)
|
|
1095
|
+
{
|
|
1096
|
+
fclose(fd);
|
|
1097
|
+
if (unlink(fnamebuf) == 0)
|
|
1098
|
+
{
|
|
1099
|
+
pool_log("Backend status file %s discarded", fnamebuf);
|
|
1100
|
+
}
|
|
1101
|
+
else
|
|
1102
|
+
{
|
|
1103
|
+
pool_error("Failed to discard backend status file %s reason:%s", fnamebuf, strerror(errno));
|
|
1104
|
+
}
|
|
1105
|
+
return 0;
|
|
1106
|
+
}
|
|
1107
|
+
|
|
1108
|
+
if (fread(&backend_rec, 1, sizeof(backend_rec), fd) != sizeof(backend_rec))
|
|
1109
|
+
{
|
|
1110
|
+
pool_error("Could not read backend status file as %s. reason: %s",
|
|
1111
|
+
fnamebuf, strerror(errno));
|
|
1112
|
+
fclose(fd);
|
|
1113
|
+
return -1;
|
|
1114
|
+
}
|
|
1115
|
+
fclose(fd);
|
|
1116
|
+
|
|
1117
|
+
for (i=0;i< pool_config->backend_desc->num_backends;i++)
|
|
1118
|
+
{
|
|
1119
|
+
if (backend_rec.status[i] == CON_DOWN)
|
|
1120
|
+
{
|
|
1121
|
+
BACKEND_INFO(i).backend_status = CON_DOWN;
|
|
1122
|
+
pool_log("read_status_file: %d th backend is set to down status", i);
|
|
1123
|
+
}
|
|
1124
|
+
else
|
|
1125
|
+
{
|
|
1126
|
+
BACKEND_INFO(i).backend_status = CON_CONNECT_WAIT;
|
|
1127
|
+
someone_wakeup = true;
|
|
1128
|
+
}
|
|
1129
|
+
}
|
|
1130
|
+
|
|
1131
|
+
/*
|
|
1132
|
+
* If no one woke up, we regard the status file bogus
|
|
1133
|
+
*/
|
|
1134
|
+
if (someone_wakeup == false)
|
|
1135
|
+
{
|
|
1136
|
+
for (i=0;i< pool_config->backend_desc->num_backends;i++)
|
|
1137
|
+
{
|
|
1138
|
+
BACKEND_INFO(i).backend_status = CON_CONNECT_WAIT;
|
|
1139
|
+
}
|
|
1140
|
+
}
|
|
1141
|
+
|
|
1142
|
+
return 0;
|
|
1143
|
+
}
|
|
1144
|
+
|
|
1145
|
+
/*
|
|
1146
|
+
* Write the pid file
|
|
1147
|
+
*/
|
|
1148
|
+
static int write_status_file(void)
|
|
1149
|
+
{
|
|
1150
|
+
FILE *fd;
|
|
1151
|
+
char fnamebuf[POOLMAXPATHLEN];
|
|
1152
|
+
int i;
|
|
1153
|
+
|
|
1154
|
+
snprintf(fnamebuf, sizeof(fnamebuf), "%s/%s", pool_config->logdir, STATUS_FILE_NAME);
|
|
1155
|
+
fd = fopen(fnamebuf, "w");
|
|
1156
|
+
if (!fd)
|
|
1157
|
+
{
|
|
1158
|
+
pool_error("Could not open status file %s", fnamebuf);
|
|
1159
|
+
return -1;
|
|
1160
|
+
}
|
|
1161
|
+
|
|
1162
|
+
memset(&backend_rec, 0, sizeof(backend_rec));
|
|
1163
|
+
|
|
1164
|
+
for (i=0;i< pool_config->backend_desc->num_backends;i++)
|
|
1165
|
+
{
|
|
1166
|
+
backend_rec.status[i] = BACKEND_INFO(i).backend_status;
|
|
1167
|
+
}
|
|
1168
|
+
|
|
1169
|
+
if (fwrite(&backend_rec, 1, sizeof(backend_rec), fd) != sizeof(backend_rec))
|
|
1170
|
+
{
|
|
1171
|
+
pool_error("Could not write backend status file as %s. reason: %s",
|
|
1172
|
+
fnamebuf, strerror(errno));
|
|
1173
|
+
fclose(fd);
|
|
1174
|
+
return -1;
|
|
1175
|
+
}
|
|
1176
|
+
fclose(fd);
|
|
1177
|
+
return 0;
|
|
1178
|
+
}
|
|
1179
|
+
|
|
1180
|
+
/*
|
|
1181
|
+
* fork a child for PCP
|
|
1182
|
+
*/
|
|
1183
|
+
pid_t pcp_fork_a_child(int unix_fd, int inet_fd, char *pcp_conf_file)
|
|
1184
|
+
{
|
|
1185
|
+
pid_t pid;
|
|
1186
|
+
|
|
1187
|
+
pid = fork();
|
|
1188
|
+
|
|
1189
|
+
if (pid == 0)
|
|
1190
|
+
{
|
|
1191
|
+
close(pipe_fds[0]);
|
|
1192
|
+
close(pipe_fds[1]);
|
|
1193
|
+
|
|
1194
|
+
myargv = save_ps_display_args(myargc, myargv);
|
|
1195
|
+
|
|
1196
|
+
/* call PCP child main */
|
|
1197
|
+
POOL_SETMASK(&UnBlockSig);
|
|
1198
|
+
health_check_timer_expired = 0;
|
|
1199
|
+
reload_config_request = 0;
|
|
1200
|
+
run_as_pcp_child = true;
|
|
1201
|
+
pcp_do_child(unix_fd, inet_fd, pcp_conf_file);
|
|
1202
|
+
}
|
|
1203
|
+
else if (pid == -1)
|
|
1204
|
+
{
|
|
1205
|
+
pool_error("fork() failed. reason: %s", strerror(errno));
|
|
1206
|
+
myexit(1);
|
|
1207
|
+
}
|
|
1208
|
+
return pid;
|
|
1209
|
+
}
|
|
1210
|
+
|
|
1211
|
+
/*
|
|
1212
|
+
* fork a child
|
|
1213
|
+
*/
|
|
1214
|
+
pid_t fork_a_child(int unix_fd, int inet_fd, int id)
|
|
1215
|
+
{
|
|
1216
|
+
pid_t pid;
|
|
1217
|
+
|
|
1218
|
+
pid = fork();
|
|
1219
|
+
|
|
1220
|
+
if (pid == 0)
|
|
1221
|
+
{
|
|
1222
|
+
/* Before we unconditionally closed pipe_fds[0] and pipe_fds[1]
|
|
1223
|
+
* here, which is apparently wrong since in the start up of
|
|
1224
|
+
* pgpool, pipe(2) is not called yet and it mistakenly closes
|
|
1225
|
+
* fd 0. Now we check the fd > 0 before close(), expecting
|
|
1226
|
+
* pipe returns fds greater than 0. Note that we cannot
|
|
1227
|
+
* unconditionally remove close(2) calls since fork_a_child()
|
|
1228
|
+
* may be called *after* pgpool starting up.
|
|
1229
|
+
*/
|
|
1230
|
+
if (pipe_fds[0] > 0)
|
|
1231
|
+
{
|
|
1232
|
+
close(pipe_fds[0]);
|
|
1233
|
+
close(pipe_fds[1]);
|
|
1234
|
+
}
|
|
1235
|
+
|
|
1236
|
+
myargv = save_ps_display_args(myargc, myargv);
|
|
1237
|
+
|
|
1238
|
+
/* call child main */
|
|
1239
|
+
POOL_SETMASK(&UnBlockSig);
|
|
1240
|
+
health_check_timer_expired = 0;
|
|
1241
|
+
reload_config_request = 0;
|
|
1242
|
+
my_proc_id = id;
|
|
1243
|
+
run_as_pcp_child = false;
|
|
1244
|
+
do_child(unix_fd, inet_fd);
|
|
1245
|
+
}
|
|
1246
|
+
else if (pid == -1)
|
|
1247
|
+
{
|
|
1248
|
+
pool_error("fork() failed. reason: %s", strerror(errno));
|
|
1249
|
+
myexit(1);
|
|
1250
|
+
}
|
|
1251
|
+
return pid;
|
|
1252
|
+
}
|
|
1253
|
+
|
|
1254
|
+
/*
|
|
1255
|
+
* fork worker child process
|
|
1256
|
+
*/
|
|
1257
|
+
pid_t worker_fork_a_child()
|
|
1258
|
+
{
|
|
1259
|
+
pid_t pid;
|
|
1260
|
+
|
|
1261
|
+
pid = fork();
|
|
1262
|
+
|
|
1263
|
+
if (pid == 0)
|
|
1264
|
+
{
|
|
1265
|
+
/* Before we unconditionally closed pipe_fds[0] and pipe_fds[1]
|
|
1266
|
+
* here, which is apparently wrong since in the start up of
|
|
1267
|
+
* pgpool, pipe(2) is not called yet and it mistakenly closes
|
|
1268
|
+
* fd 0. Now we check the fd > 0 before close(), expecting
|
|
1269
|
+
* pipe returns fds greater than 0. Note that we cannot
|
|
1270
|
+
* unconditionally remove close(2) calls since fork_a_child()
|
|
1271
|
+
* may be called *after* pgpool starting up.
|
|
1272
|
+
*/
|
|
1273
|
+
if (pipe_fds[0] > 0)
|
|
1274
|
+
{
|
|
1275
|
+
close(pipe_fds[0]);
|
|
1276
|
+
close(pipe_fds[1]);
|
|
1277
|
+
}
|
|
1278
|
+
|
|
1279
|
+
myargv = save_ps_display_args(myargc, myargv);
|
|
1280
|
+
|
|
1281
|
+
/* call child main */
|
|
1282
|
+
POOL_SETMASK(&UnBlockSig);
|
|
1283
|
+
health_check_timer_expired = 0;
|
|
1284
|
+
reload_config_request = 0;
|
|
1285
|
+
do_worker_child();
|
|
1286
|
+
}
|
|
1287
|
+
else if (pid == -1)
|
|
1288
|
+
{
|
|
1289
|
+
pool_error("fork() failed. reason: %s", strerror(errno));
|
|
1290
|
+
myexit(1);
|
|
1291
|
+
}
|
|
1292
|
+
return pid;
|
|
1293
|
+
}
|
|
1294
|
+
|
|
1295
|
+
/*
|
|
1296
|
+
* create inet domain socket
|
|
1297
|
+
*/
|
|
1298
|
+
static int create_inet_domain_socket(const char *hostname, const int port)
|
|
1299
|
+
{
|
|
1300
|
+
struct sockaddr_in addr;
|
|
1301
|
+
int fd;
|
|
1302
|
+
int status;
|
|
1303
|
+
int one = 1;
|
|
1304
|
+
int len;
|
|
1305
|
+
int backlog;
|
|
1306
|
+
|
|
1307
|
+
fd = socket(AF_INET, SOCK_STREAM, 0);
|
|
1308
|
+
if (fd == -1)
|
|
1309
|
+
{
|
|
1310
|
+
pool_error("Failed to create INET domain socket. reason: %s", strerror(errno));
|
|
1311
|
+
myexit(1);
|
|
1312
|
+
}
|
|
1313
|
+
if ((setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one,
|
|
1314
|
+
sizeof(one))) == -1)
|
|
1315
|
+
{
|
|
1316
|
+
pool_error("setsockopt() failed. reason: %s", strerror(errno));
|
|
1317
|
+
myexit(1);
|
|
1318
|
+
}
|
|
1319
|
+
|
|
1320
|
+
memset((char *) &addr, 0, sizeof(addr));
|
|
1321
|
+
addr.sin_family = AF_INET;
|
|
1322
|
+
|
|
1323
|
+
if (strcmp(hostname, "*")==0)
|
|
1324
|
+
{
|
|
1325
|
+
addr.sin_addr.s_addr = htonl(INADDR_ANY);
|
|
1326
|
+
}
|
|
1327
|
+
else
|
|
1328
|
+
{
|
|
1329
|
+
struct hostent *hostinfo;
|
|
1330
|
+
|
|
1331
|
+
hostinfo = gethostbyname(hostname);
|
|
1332
|
+
if (!hostinfo)
|
|
1333
|
+
{
|
|
1334
|
+
pool_error("could not resolve host name \"%s\": %s", hostname, hstrerror(h_errno));
|
|
1335
|
+
myexit(1);
|
|
1336
|
+
}
|
|
1337
|
+
addr.sin_addr = *(struct in_addr *) hostinfo->h_addr;
|
|
1338
|
+
}
|
|
1339
|
+
|
|
1340
|
+
addr.sin_port = htons(port);
|
|
1341
|
+
len = sizeof(struct sockaddr_in);
|
|
1342
|
+
status = bind(fd, (struct sockaddr *)&addr, len);
|
|
1343
|
+
if (status == -1)
|
|
1344
|
+
{
|
|
1345
|
+
char *host = "", *serv = "";
|
|
1346
|
+
char hostname[NI_MAXHOST], servname[NI_MAXSERV];
|
|
1347
|
+
if (getnameinfo((struct sockaddr *) &addr, len, hostname, sizeof(hostname), servname, sizeof(servname), 0) == 0) {
|
|
1348
|
+
host = hostname;
|
|
1349
|
+
serv = servname;
|
|
1350
|
+
}
|
|
1351
|
+
pool_error("bind(%s:%s) failed. reason: %s", host, serv, strerror(errno));
|
|
1352
|
+
myexit(1);
|
|
1353
|
+
}
|
|
1354
|
+
|
|
1355
|
+
backlog = pool_config->num_init_children * 2;
|
|
1356
|
+
if (backlog > PGPOOLMAXLITSENQUEUELENGTH)
|
|
1357
|
+
backlog = PGPOOLMAXLITSENQUEUELENGTH;
|
|
1358
|
+
|
|
1359
|
+
status = listen(fd, backlog);
|
|
1360
|
+
if (status < 0)
|
|
1361
|
+
{
|
|
1362
|
+
pool_error("listen() failed. reason: %s", strerror(errno));
|
|
1363
|
+
myexit(1);
|
|
1364
|
+
}
|
|
1365
|
+
return fd;
|
|
1366
|
+
}
|
|
1367
|
+
|
|
1368
|
+
/*
|
|
1369
|
+
* create UNIX domain socket
|
|
1370
|
+
*/
|
|
1371
|
+
static int create_unix_domain_socket(struct sockaddr_un un_addr_tmp)
|
|
1372
|
+
{
|
|
1373
|
+
struct sockaddr_un addr;
|
|
1374
|
+
int fd;
|
|
1375
|
+
int status;
|
|
1376
|
+
int len;
|
|
1377
|
+
|
|
1378
|
+
fd = socket(AF_UNIX, SOCK_STREAM, 0);
|
|
1379
|
+
if (fd == -1)
|
|
1380
|
+
{
|
|
1381
|
+
pool_error("Failed to create UNIX domain socket. reason: %s", strerror(errno));
|
|
1382
|
+
myexit(1);
|
|
1383
|
+
}
|
|
1384
|
+
memset((char *) &addr, 0, sizeof(addr));
|
|
1385
|
+
addr.sun_family = AF_UNIX;
|
|
1386
|
+
snprintf(addr.sun_path, sizeof(addr.sun_path), "%s", un_addr_tmp.sun_path);
|
|
1387
|
+
len = sizeof(struct sockaddr_un);
|
|
1388
|
+
status = bind(fd, (struct sockaddr *)&addr, len);
|
|
1389
|
+
if (status == -1)
|
|
1390
|
+
{
|
|
1391
|
+
pool_error("bind(%s) failed. reason: %s", addr.sun_path, strerror(errno));
|
|
1392
|
+
myexit(1);
|
|
1393
|
+
}
|
|
1394
|
+
|
|
1395
|
+
if (chmod(un_addr_tmp.sun_path, 0777) == -1)
|
|
1396
|
+
{
|
|
1397
|
+
pool_error("chmod() failed. reason: %s", strerror(errno));
|
|
1398
|
+
myexit(1);
|
|
1399
|
+
}
|
|
1400
|
+
|
|
1401
|
+
status = listen(fd, PGPOOLMAXLITSENQUEUELENGTH);
|
|
1402
|
+
if (status < 0)
|
|
1403
|
+
{
|
|
1404
|
+
pool_error("listen() failed. reason: %s", strerror(errno));
|
|
1405
|
+
myexit(1);
|
|
1406
|
+
}
|
|
1407
|
+
return fd;
|
|
1408
|
+
}
|
|
1409
|
+
|
|
1410
|
+
static void myunlink(const char* path)
|
|
1411
|
+
{
|
|
1412
|
+
if (unlink(path) == 0) return;
|
|
1413
|
+
pool_error("unlink(%s) failed: %s", path, strerror(errno));
|
|
1414
|
+
}
|
|
1415
|
+
|
|
1416
|
+
static void myexit(int code)
|
|
1417
|
+
{
|
|
1418
|
+
int i;
|
|
1419
|
+
|
|
1420
|
+
if (getpid() != mypid)
|
|
1421
|
+
return;
|
|
1422
|
+
|
|
1423
|
+
if (process_info != NULL) {
|
|
1424
|
+
POOL_SETMASK(&AuthBlockSig);
|
|
1425
|
+
exiting = 1;
|
|
1426
|
+
for (i = 0; i < pool_config->num_init_children; i++)
|
|
1427
|
+
{
|
|
1428
|
+
pid_t pid = process_info[i].pid;
|
|
1429
|
+
if (pid)
|
|
1430
|
+
{
|
|
1431
|
+
kill(pid, SIGTERM);
|
|
1432
|
+
}
|
|
1433
|
+
}
|
|
1434
|
+
|
|
1435
|
+
/* wait for all children to exit */
|
|
1436
|
+
while (wait(NULL) > 0)
|
|
1437
|
+
;
|
|
1438
|
+
if (errno != ECHILD)
|
|
1439
|
+
pool_error("wait() failed. reason:%s", strerror(errno));
|
|
1440
|
+
POOL_SETMASK(&UnBlockSig);
|
|
1441
|
+
}
|
|
1442
|
+
|
|
1443
|
+
myunlink(un_addr.sun_path);
|
|
1444
|
+
myunlink(pcp_un_addr.sun_path);
|
|
1445
|
+
myunlink(pool_config->pid_file_name);
|
|
1446
|
+
|
|
1447
|
+
write_status_file();
|
|
1448
|
+
|
|
1449
|
+
pool_shmem_exit(code);
|
|
1450
|
+
exit(code);
|
|
1451
|
+
}
|
|
1452
|
+
|
|
1453
|
+
void notice_backend_error(int node_id)
|
|
1454
|
+
{
|
|
1455
|
+
int n = node_id;
|
|
1456
|
+
|
|
1457
|
+
if (getpid() == mypid)
|
|
1458
|
+
{
|
|
1459
|
+
pool_log("notice_backend_error: called from pgpool main. ignored.");
|
|
1460
|
+
}
|
|
1461
|
+
else
|
|
1462
|
+
{
|
|
1463
|
+
degenerate_backend_set(&n, 1);
|
|
1464
|
+
}
|
|
1465
|
+
}
|
|
1466
|
+
|
|
1467
|
+
/* notice backend connection error using SIGUSR1 */
|
|
1468
|
+
void degenerate_backend_set(int *node_id_set, int count)
|
|
1469
|
+
{
|
|
1470
|
+
pid_t parent = getppid();
|
|
1471
|
+
int i;
|
|
1472
|
+
bool need_signal = false;
|
|
1473
|
+
#ifdef HAVE_SIGPROCMASK
|
|
1474
|
+
sigset_t oldmask;
|
|
1475
|
+
#else
|
|
1476
|
+
int oldmask;
|
|
1477
|
+
#endif
|
|
1478
|
+
|
|
1479
|
+
if (pool_config->parallel_mode)
|
|
1480
|
+
{
|
|
1481
|
+
return;
|
|
1482
|
+
}
|
|
1483
|
+
|
|
1484
|
+
POOL_SETMASK2(&BlockSig, &oldmask);
|
|
1485
|
+
pool_semaphore_lock(REQUEST_INFO_SEM);
|
|
1486
|
+
Req_info->kind = NODE_DOWN_REQUEST;
|
|
1487
|
+
for (i = 0; i < count; i++)
|
|
1488
|
+
{
|
|
1489
|
+
if (node_id_set[i] < 0 || node_id_set[i] >= MAX_NUM_BACKENDS ||
|
|
1490
|
+
!VALID_BACKEND(node_id_set[i]))
|
|
1491
|
+
{
|
|
1492
|
+
pool_log("degenerate_backend_set: node %d is not valid backend.", i);
|
|
1493
|
+
continue;
|
|
1494
|
+
}
|
|
1495
|
+
|
|
1496
|
+
if (POOL_DISALLOW_TO_FAILOVER(BACKEND_INFO(node_id_set[i]).flag))
|
|
1497
|
+
{
|
|
1498
|
+
pool_log("degenerate_backend_set: %d failover request from pid %d is canceled because failover is disallowed", node_id_set[i], getpid());
|
|
1499
|
+
continue;
|
|
1500
|
+
}
|
|
1501
|
+
|
|
1502
|
+
pool_log("degenerate_backend_set: %d fail over request from pid %d", node_id_set[i], getpid());
|
|
1503
|
+
Req_info->node_id[i] = node_id_set[i];
|
|
1504
|
+
need_signal = true;
|
|
1505
|
+
}
|
|
1506
|
+
|
|
1507
|
+
if (need_signal)
|
|
1508
|
+
{
|
|
1509
|
+
if (!pool_config->use_watchdog || WD_OK == wd_degenerate_backend_set(node_id_set, count))
|
|
1510
|
+
{
|
|
1511
|
+
kill(parent, SIGUSR1);
|
|
1512
|
+
}
|
|
1513
|
+
else
|
|
1514
|
+
{
|
|
1515
|
+
pool_log("degenerate_backend_set: failover request from pid %d is canceled by other pgpool", getpid());
|
|
1516
|
+
memset(Req_info->node_id, -1, sizeof(int) * MAX_NUM_BACKENDS);
|
|
1517
|
+
}
|
|
1518
|
+
}
|
|
1519
|
+
|
|
1520
|
+
pool_semaphore_unlock(REQUEST_INFO_SEM);
|
|
1521
|
+
POOL_SETMASK(&oldmask);
|
|
1522
|
+
}
|
|
1523
|
+
|
|
1524
|
+
/* send promote node request using SIGUSR1 */
|
|
1525
|
+
void promote_backend(int node_id)
|
|
1526
|
+
{
|
|
1527
|
+
pid_t parent = getppid();
|
|
1528
|
+
|
|
1529
|
+
if (!MASTER_SLAVE || strcmp(pool_config->master_slave_sub_mode, MODE_STREAMREP))
|
|
1530
|
+
{
|
|
1531
|
+
return;
|
|
1532
|
+
}
|
|
1533
|
+
|
|
1534
|
+
if (node_id < 0 || node_id >= MAX_NUM_BACKENDS || !VALID_BACKEND(node_id))
|
|
1535
|
+
{
|
|
1536
|
+
pool_error("promote_backend: node %d is not valid backend.", node_id);
|
|
1537
|
+
return;
|
|
1538
|
+
}
|
|
1539
|
+
|
|
1540
|
+
pool_semaphore_lock(REQUEST_INFO_SEM);
|
|
1541
|
+
Req_info->kind = PROMOTE_NODE_REQUEST;
|
|
1542
|
+
Req_info->node_id[0] = node_id;
|
|
1543
|
+
pool_log("promote_backend: %d promote node request from pid %d", node_id, getpid());
|
|
1544
|
+
|
|
1545
|
+
if (!pool_config->use_watchdog || WD_OK == wd_promote_backend(node_id))
|
|
1546
|
+
{
|
|
1547
|
+
kill(parent, SIGUSR1);
|
|
1548
|
+
}
|
|
1549
|
+
else
|
|
1550
|
+
{
|
|
1551
|
+
pool_log("promote_backend: promote request from pid %d is canceled by other pgpool", getpid());
|
|
1552
|
+
Req_info->node_id[0] = -1;
|
|
1553
|
+
}
|
|
1554
|
+
|
|
1555
|
+
pool_semaphore_unlock(REQUEST_INFO_SEM);
|
|
1556
|
+
}
|
|
1557
|
+
|
|
1558
|
+
/* send failback request using SIGUSR1 */
|
|
1559
|
+
void send_failback_request(int node_id)
|
|
1560
|
+
{
|
|
1561
|
+
pid_t parent = getppid();
|
|
1562
|
+
|
|
1563
|
+
pool_log("send_failback_request: fail back %d th node request from pid %d", node_id, getpid());
|
|
1564
|
+
Req_info->kind = NODE_UP_REQUEST;
|
|
1565
|
+
Req_info->node_id[0] = node_id;
|
|
1566
|
+
|
|
1567
|
+
if (node_id < 0 || node_id >= MAX_NUM_BACKENDS ||
|
|
1568
|
+
(RAW_MODE && BACKEND_INFO(node_id).backend_status != CON_DOWN && VALID_BACKEND(node_id)))
|
|
1569
|
+
{
|
|
1570
|
+
pool_error("send_failback_request: node %d is alive.", node_id);
|
|
1571
|
+
Req_info->node_id[0] = -1;
|
|
1572
|
+
return;
|
|
1573
|
+
}
|
|
1574
|
+
|
|
1575
|
+
if (pool_config->use_watchdog && WD_OK != wd_send_failback_request(node_id))
|
|
1576
|
+
{
|
|
1577
|
+
pool_log("send_failback_request: failback request from pid %d is canceled by other pgpool", getpid());
|
|
1578
|
+
Req_info->node_id[0] = -1;
|
|
1579
|
+
return;
|
|
1580
|
+
}
|
|
1581
|
+
kill(parent, SIGUSR1);
|
|
1582
|
+
}
|
|
1583
|
+
|
|
1584
|
+
static RETSIGTYPE exit_handler(int sig)
|
|
1585
|
+
{
|
|
1586
|
+
int i;
|
|
1587
|
+
|
|
1588
|
+
POOL_SETMASK(&AuthBlockSig);
|
|
1589
|
+
|
|
1590
|
+
/*
|
|
1591
|
+
* this could happen in a child process if a signal has been sent
|
|
1592
|
+
* before resetting signal handler
|
|
1593
|
+
*/
|
|
1594
|
+
if (getpid() != mypid)
|
|
1595
|
+
{
|
|
1596
|
+
pool_debug("exit_handler: I am not parent");
|
|
1597
|
+
POOL_SETMASK(&UnBlockSig);
|
|
1598
|
+
pool_shmem_exit(0);
|
|
1599
|
+
exit(0);
|
|
1600
|
+
}
|
|
1601
|
+
|
|
1602
|
+
if (sig == SIGTERM)
|
|
1603
|
+
pool_log("received smart shutdown request");
|
|
1604
|
+
else if (sig == SIGINT)
|
|
1605
|
+
pool_log("received fast shutdown request");
|
|
1606
|
+
else if (sig == SIGQUIT)
|
|
1607
|
+
pool_log("received immediate shutdown request");
|
|
1608
|
+
else
|
|
1609
|
+
{
|
|
1610
|
+
pool_error("exit_handler: unknown signal received %d", sig);
|
|
1611
|
+
POOL_SETMASK(&UnBlockSig);
|
|
1612
|
+
return;
|
|
1613
|
+
}
|
|
1614
|
+
|
|
1615
|
+
exiting = 1;
|
|
1616
|
+
|
|
1617
|
+
for (i = 0; i < pool_config->num_init_children; i++)
|
|
1618
|
+
{
|
|
1619
|
+
pid_t pid = process_info[i].pid;
|
|
1620
|
+
if (pid)
|
|
1621
|
+
{
|
|
1622
|
+
kill(pid, sig);
|
|
1623
|
+
}
|
|
1624
|
+
}
|
|
1625
|
+
|
|
1626
|
+
kill(pcp_pid, sig);
|
|
1627
|
+
kill(worker_pid, sig);
|
|
1628
|
+
|
|
1629
|
+
if (pool_config->use_watchdog)
|
|
1630
|
+
{
|
|
1631
|
+
wd_kill_watchdog(sig);
|
|
1632
|
+
}
|
|
1633
|
+
|
|
1634
|
+
POOL_SETMASK(&UnBlockSig);
|
|
1635
|
+
|
|
1636
|
+
while (wait(NULL) > 0)
|
|
1637
|
+
;
|
|
1638
|
+
|
|
1639
|
+
if (errno != ECHILD)
|
|
1640
|
+
pool_error("wait() failed. reason:%s", strerror(errno));
|
|
1641
|
+
|
|
1642
|
+
process_info = NULL;
|
|
1643
|
+
myexit(0);
|
|
1644
|
+
}
|
|
1645
|
+
|
|
1646
|
+
/*
|
|
1647
|
+
* Calculate next valid master node id.
|
|
1648
|
+
* If no valid node found, returns -1.
|
|
1649
|
+
*/
|
|
1650
|
+
static int get_next_master_node(void)
|
|
1651
|
+
{
|
|
1652
|
+
int i;
|
|
1653
|
+
|
|
1654
|
+
for (i=0;i<pool_config->backend_desc->num_backends;i++)
|
|
1655
|
+
{
|
|
1656
|
+
/*
|
|
1657
|
+
* Do not use VALID_BACKEND macro in raw mode.
|
|
1658
|
+
* VALID_BACKEND return true only if the argument is master
|
|
1659
|
+
* node id. In other words, standby nodes are false. So need
|
|
1660
|
+
* to check backend status with VALID_BACKEND_RAW.
|
|
1661
|
+
*/
|
|
1662
|
+
if (RAW_MODE)
|
|
1663
|
+
{
|
|
1664
|
+
if (VALID_BACKEND_RAW(i))
|
|
1665
|
+
break;
|
|
1666
|
+
}
|
|
1667
|
+
else
|
|
1668
|
+
{
|
|
1669
|
+
if (VALID_BACKEND(i))
|
|
1670
|
+
break;
|
|
1671
|
+
}
|
|
1672
|
+
}
|
|
1673
|
+
|
|
1674
|
+
if (i == pool_config->backend_desc->num_backends)
|
|
1675
|
+
i = -1;
|
|
1676
|
+
|
|
1677
|
+
return i;
|
|
1678
|
+
}
|
|
1679
|
+
|
|
1680
|
+
/*
|
|
1681
|
+
* handle SIGUSR1
|
|
1682
|
+
*
|
|
1683
|
+
*/
|
|
1684
|
+
static RETSIGTYPE failover_handler(int sig)
|
|
1685
|
+
{
|
|
1686
|
+
POOL_SETMASK(&BlockSig);
|
|
1687
|
+
failover_request = 1;
|
|
1688
|
+
write(pipe_fds[1], "\0", 1);
|
|
1689
|
+
POOL_SETMASK(&UnBlockSig);
|
|
1690
|
+
}
|
|
1691
|
+
|
|
1692
|
+
/*
|
|
1693
|
+
* backend connection error, failover/failback request, if possible
|
|
1694
|
+
* failover() must be called under protecting signals.
|
|
1695
|
+
*/
|
|
1696
|
+
static void failover(void)
|
|
1697
|
+
{
|
|
1698
|
+
int i;
|
|
1699
|
+
int node_id;
|
|
1700
|
+
bool by_health_check;
|
|
1701
|
+
int new_master;
|
|
1702
|
+
int new_primary;
|
|
1703
|
+
int nodes[MAX_NUM_BACKENDS];
|
|
1704
|
+
bool need_to_restart_children;
|
|
1705
|
+
int status;
|
|
1706
|
+
int sts;
|
|
1707
|
+
|
|
1708
|
+
pool_debug("failover_handler called");
|
|
1709
|
+
|
|
1710
|
+
memset(nodes, 0, sizeof(int) * MAX_NUM_BACKENDS);
|
|
1711
|
+
|
|
1712
|
+
/*
|
|
1713
|
+
* this could happen in a child process if a signal has been sent
|
|
1714
|
+
* before resetting signal handler
|
|
1715
|
+
*/
|
|
1716
|
+
if (getpid() != mypid)
|
|
1717
|
+
{
|
|
1718
|
+
pool_debug("failover_handler: I am not parent");
|
|
1719
|
+
kill(pcp_pid, SIGUSR2);
|
|
1720
|
+
return;
|
|
1721
|
+
}
|
|
1722
|
+
|
|
1723
|
+
/*
|
|
1724
|
+
* processing SIGTERM, SIGINT or SIGQUIT
|
|
1725
|
+
*/
|
|
1726
|
+
if (exiting)
|
|
1727
|
+
{
|
|
1728
|
+
pool_debug("failover_handler called while exiting");
|
|
1729
|
+
kill(pcp_pid, SIGUSR2);
|
|
1730
|
+
return;
|
|
1731
|
+
}
|
|
1732
|
+
|
|
1733
|
+
/*
|
|
1734
|
+
* processing fail over or switch over
|
|
1735
|
+
*/
|
|
1736
|
+
if (switching)
|
|
1737
|
+
{
|
|
1738
|
+
pool_debug("failover_handler called while switching");
|
|
1739
|
+
kill(pcp_pid, SIGUSR2);
|
|
1740
|
+
return;
|
|
1741
|
+
}
|
|
1742
|
+
|
|
1743
|
+
pool_semaphore_lock(REQUEST_INFO_SEM);
|
|
1744
|
+
|
|
1745
|
+
if (Req_info->kind == CLOSE_IDLE_REQUEST)
|
|
1746
|
+
{
|
|
1747
|
+
pool_semaphore_unlock(REQUEST_INFO_SEM);
|
|
1748
|
+
kill_all_children(SIGUSR1);
|
|
1749
|
+
kill(pcp_pid, SIGUSR2);
|
|
1750
|
+
return;
|
|
1751
|
+
}
|
|
1752
|
+
|
|
1753
|
+
/*
|
|
1754
|
+
* if not in replication mode/master slave mode, we treat this a restart request.
|
|
1755
|
+
* otherwise we need to check if we have already failovered.
|
|
1756
|
+
*/
|
|
1757
|
+
pool_debug("failover_handler: starting to select new master node");
|
|
1758
|
+
switching = 1;
|
|
1759
|
+
Req_info->switching = true;
|
|
1760
|
+
node_id = Req_info->node_id[0];
|
|
1761
|
+
|
|
1762
|
+
/* start of command inter-lock with watchdog */
|
|
1763
|
+
if (pool_config->use_watchdog)
|
|
1764
|
+
{
|
|
1765
|
+
by_health_check = (!failover_request && Req_info->kind==NODE_DOWN_REQUEST);
|
|
1766
|
+
wd_start_interlock(by_health_check);
|
|
1767
|
+
}
|
|
1768
|
+
|
|
1769
|
+
/* failback request? */
|
|
1770
|
+
if (Req_info->kind == NODE_UP_REQUEST)
|
|
1771
|
+
{
|
|
1772
|
+
if (node_id < 0 || node_id >= MAX_NUM_BACKENDS ||
|
|
1773
|
+
(Req_info->kind == NODE_UP_REQUEST && !(RAW_MODE &&
|
|
1774
|
+
BACKEND_INFO(node_id).backend_status == CON_DOWN) && VALID_BACKEND(node_id)) ||
|
|
1775
|
+
(Req_info->kind == NODE_DOWN_REQUEST && !VALID_BACKEND(node_id)))
|
|
1776
|
+
{
|
|
1777
|
+
pool_semaphore_unlock(REQUEST_INFO_SEM);
|
|
1778
|
+
|
|
1779
|
+
if (node_id < 0 || node_id >= MAX_NUM_BACKENDS)
|
|
1780
|
+
pool_error("failover_handler: invalid node_id %d MAX_NUM_BACKENDS: %d", node_id, MAX_NUM_BACKENDS);
|
|
1781
|
+
else
|
|
1782
|
+
pool_error("failover_handler: invalid node_id %d status:%d MAX_NUM_BACKENDS: %d", node_id,
|
|
1783
|
+
BACKEND_INFO(node_id).backend_status, MAX_NUM_BACKENDS);
|
|
1784
|
+
kill(pcp_pid, SIGUSR2);
|
|
1785
|
+
switching = 0;
|
|
1786
|
+
Req_info->switching = false;
|
|
1787
|
+
|
|
1788
|
+
/* end of command inter-lock */
|
|
1789
|
+
if (pool_config->use_watchdog)
|
|
1790
|
+
wd_leave_interlock();
|
|
1791
|
+
|
|
1792
|
+
return;
|
|
1793
|
+
}
|
|
1794
|
+
|
|
1795
|
+
pool_log("starting fail back. reconnect host %s(%d)",
|
|
1796
|
+
BACKEND_INFO(node_id).backend_hostname,
|
|
1797
|
+
BACKEND_INFO(node_id).backend_port);
|
|
1798
|
+
BACKEND_INFO(node_id).backend_status = CON_CONNECT_WAIT; /* unset down status */
|
|
1799
|
+
|
|
1800
|
+
/* wait for failback command lock or to be lock holder */
|
|
1801
|
+
if (pool_config->use_watchdog && !wd_am_I_lock_holder())
|
|
1802
|
+
{
|
|
1803
|
+
wd_wait_for_lock(WD_FAILBACK_COMMAND_LOCK);
|
|
1804
|
+
}
|
|
1805
|
+
/* execute failback command if lock holder */
|
|
1806
|
+
if (!pool_config->use_watchdog || wd_am_I_lock_holder())
|
|
1807
|
+
{
|
|
1808
|
+
trigger_failover_command(node_id, pool_config->failback_command,
|
|
1809
|
+
MASTER_NODE_ID, get_next_master_node(), PRIMARY_NODE_ID);
|
|
1810
|
+
|
|
1811
|
+
/* unlock failback command */
|
|
1812
|
+
if (pool_config->use_watchdog)
|
|
1813
|
+
wd_unlock(WD_FAILBACK_COMMAND_LOCK);
|
|
1814
|
+
}
|
|
1815
|
+
}
|
|
1816
|
+
else if (Req_info->kind == PROMOTE_NODE_REQUEST)
|
|
1817
|
+
{
|
|
1818
|
+
if (node_id != -1 && VALID_BACKEND(node_id))
|
|
1819
|
+
{
|
|
1820
|
+
pool_log("starting promotion. promote host %s(%d)",
|
|
1821
|
+
BACKEND_INFO(node_id).backend_hostname,
|
|
1822
|
+
BACKEND_INFO(node_id).backend_port);
|
|
1823
|
+
}
|
|
1824
|
+
else
|
|
1825
|
+
{
|
|
1826
|
+
pool_log("failover: no backends are promoted");
|
|
1827
|
+
pool_semaphore_unlock(REQUEST_INFO_SEM);
|
|
1828
|
+
kill(pcp_pid, SIGUSR2);
|
|
1829
|
+
switching = 0;
|
|
1830
|
+
Req_info->switching = false;
|
|
1831
|
+
|
|
1832
|
+
/* end of command inter-lock */
|
|
1833
|
+
if (pool_config->use_watchdog)
|
|
1834
|
+
wd_leave_interlock();
|
|
1835
|
+
|
|
1836
|
+
return;
|
|
1837
|
+
}
|
|
1838
|
+
}
|
|
1839
|
+
else
|
|
1840
|
+
{
|
|
1841
|
+
int cnt = 0;
|
|
1842
|
+
|
|
1843
|
+
for (i = 0; i < MAX_NUM_BACKENDS; i++)
|
|
1844
|
+
{
|
|
1845
|
+
if (Req_info->node_id[i] != -1 &&
|
|
1846
|
+
((RAW_MODE && VALID_BACKEND_RAW(Req_info->node_id[i])) ||
|
|
1847
|
+
VALID_BACKEND(Req_info->node_id[i])))
|
|
1848
|
+
{
|
|
1849
|
+
pool_log("starting degeneration. shutdown host %s(%d)",
|
|
1850
|
+
BACKEND_INFO(Req_info->node_id[i]).backend_hostname,
|
|
1851
|
+
BACKEND_INFO(Req_info->node_id[i]).backend_port);
|
|
1852
|
+
|
|
1853
|
+
BACKEND_INFO(Req_info->node_id[i]).backend_status = CON_DOWN; /* set down status */
|
|
1854
|
+
/* save down node */
|
|
1855
|
+
nodes[Req_info->node_id[i]] = 1;
|
|
1856
|
+
cnt++;
|
|
1857
|
+
}
|
|
1858
|
+
}
|
|
1859
|
+
|
|
1860
|
+
if (cnt == 0)
|
|
1861
|
+
{
|
|
1862
|
+
pool_log("failover: no backends are degenerated");
|
|
1863
|
+
pool_semaphore_unlock(REQUEST_INFO_SEM);
|
|
1864
|
+
kill(pcp_pid, SIGUSR2);
|
|
1865
|
+
switching = 0;
|
|
1866
|
+
Req_info->switching = false;
|
|
1867
|
+
|
|
1868
|
+
/* end of command inter-lock */
|
|
1869
|
+
if (pool_config->use_watchdog)
|
|
1870
|
+
wd_leave_interlock();
|
|
1871
|
+
|
|
1872
|
+
return;
|
|
1873
|
+
}
|
|
1874
|
+
}
|
|
1875
|
+
|
|
1876
|
+
new_master = get_next_master_node();
|
|
1877
|
+
|
|
1878
|
+
if (new_master < 0)
|
|
1879
|
+
{
|
|
1880
|
+
pool_error("failover_handler: no valid DB node found");
|
|
1881
|
+
}
|
|
1882
|
+
|
|
1883
|
+
/*
|
|
1884
|
+
* Before we tried to minimize restarting pgpool to protect existing
|
|
1885
|
+
* connections from clients to pgpool children. What we did here was,
|
|
1886
|
+
* if children other than master went down, we did not fail over.
|
|
1887
|
+
* This is wrong. Think about following scenario. If someone
|
|
1888
|
+
* accidentally plugs out the network cable, the TCP/IP stack keeps
|
|
1889
|
+
* retrying for long time (typically 2 hours). The only way to stop
|
|
1890
|
+
* the retry is restarting the process. Bottom line is, we need to
|
|
1891
|
+
* restart all children in any case. See pgpool-general list posting
|
|
1892
|
+
* "TCP connections are *not* closed when a backend timeout" on Jul 13
|
|
1893
|
+
* 2008 for more details.
|
|
1894
|
+
*/
|
|
1895
|
+
#ifdef NOT_USED
|
|
1896
|
+
else
|
|
1897
|
+
{
|
|
1898
|
+
if (Req_info->master_node_id == new_master && *InRecovery == RECOVERY_INIT)
|
|
1899
|
+
{
|
|
1900
|
+
pool_log("failover_handler: do not restart pgpool. same master node %d was selected", new_master);
|
|
1901
|
+
if (Req_info->kind == NODE_UP_REQUEST)
|
|
1902
|
+
{
|
|
1903
|
+
pool_log("failback done. reconnect host %s(%d)",
|
|
1904
|
+
BACKEND_INFO(node_id).backend_hostname,
|
|
1905
|
+
BACKEND_INFO(node_id).backend_port);
|
|
1906
|
+
}
|
|
1907
|
+
else
|
|
1908
|
+
{
|
|
1909
|
+
pool_log("failover done. shutdown host %s(%d)",
|
|
1910
|
+
BACKEND_INFO(node_id).backend_hostname,
|
|
1911
|
+
BACKEND_INFO(node_id).backend_port);
|
|
1912
|
+
}
|
|
1913
|
+
|
|
1914
|
+
/* exec failover_command */
|
|
1915
|
+
for (i = 0; i < pool_config->backend_desc->num_backends; i++)
|
|
1916
|
+
{
|
|
1917
|
+
if (nodes[i])
|
|
1918
|
+
trigger_failover_command(i, pool_config->failover_command);
|
|
1919
|
+
}
|
|
1920
|
+
|
|
1921
|
+
pool_semaphore_unlock(REQUEST_INFO_SEM);
|
|
1922
|
+
switching = 0;
|
|
1923
|
+
Req_info->switching = false;
|
|
1924
|
+
kill(pcp_pid, SIGUSR2);
|
|
1925
|
+
switching = 0;
|
|
1926
|
+
Req_info->switching = false;
|
|
1927
|
+
return;
|
|
1928
|
+
}
|
|
1929
|
+
}
|
|
1930
|
+
#endif
|
|
1931
|
+
|
|
1932
|
+
|
|
1933
|
+
/* On 2011/5/2 Tatsuo Ishii says: if mode is streaming replication
|
|
1934
|
+
* and request is NODE_UP_REQUEST(failback case) we don't need to
|
|
1935
|
+
* restart all children. Existing session will not use newly
|
|
1936
|
+
* attached node, but load balanced node is not changed until this
|
|
1937
|
+
* session ends, so it's harmless anyway.
|
|
1938
|
+
*/
|
|
1939
|
+
if (MASTER_SLAVE && !strcmp(pool_config->master_slave_sub_mode, MODE_STREAMREP) &&
|
|
1940
|
+
Req_info->kind == NODE_UP_REQUEST)
|
|
1941
|
+
{
|
|
1942
|
+
pool_log("Do not restart children because we are failbacking node id %d host%s port:%d and we are in streaming replication mode", node_id,
|
|
1943
|
+
BACKEND_INFO(node_id).backend_hostname,
|
|
1944
|
+
BACKEND_INFO(node_id).backend_port);
|
|
1945
|
+
|
|
1946
|
+
need_to_restart_children = false;
|
|
1947
|
+
}
|
|
1948
|
+
else
|
|
1949
|
+
{
|
|
1950
|
+
pool_log("Restart all children");
|
|
1951
|
+
|
|
1952
|
+
/* kill all children */
|
|
1953
|
+
for (i = 0; i < pool_config->num_init_children; i++)
|
|
1954
|
+
{
|
|
1955
|
+
pid_t pid = process_info[i].pid;
|
|
1956
|
+
if (pid)
|
|
1957
|
+
{
|
|
1958
|
+
kill(pid, SIGQUIT);
|
|
1959
|
+
pool_debug("failover_handler: kill %d", pid);
|
|
1960
|
+
}
|
|
1961
|
+
}
|
|
1962
|
+
|
|
1963
|
+
need_to_restart_children = true;
|
|
1964
|
+
}
|
|
1965
|
+
|
|
1966
|
+
/* wait for failover command lock or to be lock holder*/
|
|
1967
|
+
if (pool_config->use_watchdog && !wd_am_I_lock_holder())
|
|
1968
|
+
{
|
|
1969
|
+
wd_wait_for_lock(WD_FAILOVER_COMMAND_LOCK);
|
|
1970
|
+
}
|
|
1971
|
+
|
|
1972
|
+
/* execute failover command if lock holder */
|
|
1973
|
+
if (!pool_config->use_watchdog || wd_am_I_lock_holder())
|
|
1974
|
+
{
|
|
1975
|
+
/* Exec failover_command if needed */
|
|
1976
|
+
for (i = 0; i < pool_config->backend_desc->num_backends; i++)
|
|
1977
|
+
{
|
|
1978
|
+
if (nodes[i])
|
|
1979
|
+
trigger_failover_command(i, pool_config->failover_command,
|
|
1980
|
+
MASTER_NODE_ID, new_master, PRIMARY_NODE_ID);
|
|
1981
|
+
}
|
|
1982
|
+
|
|
1983
|
+
/* unlock failover command */
|
|
1984
|
+
if (pool_config->use_watchdog)
|
|
1985
|
+
wd_unlock(WD_FAILOVER_COMMAND_LOCK);
|
|
1986
|
+
}
|
|
1987
|
+
|
|
1988
|
+
|
|
1989
|
+
/* no need to wait since it will be done in reap_handler */
|
|
1990
|
+
#ifdef NOT_USED
|
|
1991
|
+
while (wait(NULL) > 0)
|
|
1992
|
+
;
|
|
1993
|
+
|
|
1994
|
+
if (errno != ECHILD)
|
|
1995
|
+
pool_error("failover_handler: wait() failed. reason:%s", strerror(errno));
|
|
1996
|
+
#endif
|
|
1997
|
+
|
|
1998
|
+
if (Req_info->kind == PROMOTE_NODE_REQUEST && VALID_BACKEND(node_id))
|
|
1999
|
+
new_primary = node_id;
|
|
2000
|
+
|
|
2001
|
+
/*
|
|
2002
|
+
* If the down node was a standby node in streaming replication
|
|
2003
|
+
* mode, we can avoid calling find_primary_node_repeatedly() and
|
|
2004
|
+
* recognize the former primary as the new primary node, which
|
|
2005
|
+
* will reduce the time to process standby down.
|
|
2006
|
+
*/
|
|
2007
|
+
else if (MASTER_SLAVE && !strcmp(pool_config->master_slave_sub_mode, MODE_STREAMREP) &&
|
|
2008
|
+
Req_info->kind == NODE_DOWN_REQUEST)
|
|
2009
|
+
{
|
|
2010
|
+
if (Req_info->primary_node_id != node_id)
|
|
2011
|
+
new_primary = Req_info->primary_node_id;
|
|
2012
|
+
else
|
|
2013
|
+
new_primary = find_primary_node_repeatedly();
|
|
2014
|
+
}
|
|
2015
|
+
else
|
|
2016
|
+
new_primary = find_primary_node_repeatedly();
|
|
2017
|
+
|
|
2018
|
+
/*
|
|
2019
|
+
* If follow_master_command is provided and in master/slave
|
|
2020
|
+
* streaming replication mode, we start degenerating all backends
|
|
2021
|
+
* as they are not replicated anymore.
|
|
2022
|
+
*/
|
|
2023
|
+
int follow_cnt = 0;
|
|
2024
|
+
if (MASTER_SLAVE && !strcmp(pool_config->master_slave_sub_mode, MODE_STREAMREP))
|
|
2025
|
+
{
|
|
2026
|
+
if (*pool_config->follow_master_command != '\0' ||
|
|
2027
|
+
Req_info->kind == PROMOTE_NODE_REQUEST)
|
|
2028
|
+
{
|
|
2029
|
+
/* only if the failover is against the current primary */
|
|
2030
|
+
if (((Req_info->kind == NODE_DOWN_REQUEST) &&
|
|
2031
|
+
(nodes[Req_info->primary_node_id])) ||
|
|
2032
|
+
((Req_info->kind == PROMOTE_NODE_REQUEST) &&
|
|
2033
|
+
(VALID_BACKEND(node_id)))) {
|
|
2034
|
+
|
|
2035
|
+
for (i = 0; i < pool_config->backend_desc->num_backends; i++)
|
|
2036
|
+
{
|
|
2037
|
+
/* do not degenerate the new primary */
|
|
2038
|
+
if ((new_primary >= 0) && (i != new_primary)) {
|
|
2039
|
+
BackendInfo *bkinfo;
|
|
2040
|
+
bkinfo = pool_get_node_info(i);
|
|
2041
|
+
pool_log("starting follow degeneration. shutdown host %s(%d)",
|
|
2042
|
+
bkinfo->backend_hostname,
|
|
2043
|
+
bkinfo->backend_port);
|
|
2044
|
+
bkinfo->backend_status = CON_DOWN; /* set down status */
|
|
2045
|
+
follow_cnt++;
|
|
2046
|
+
}
|
|
2047
|
+
}
|
|
2048
|
+
|
|
2049
|
+
if (follow_cnt == 0)
|
|
2050
|
+
{
|
|
2051
|
+
pool_log("failover: no follow backends are degenerated");
|
|
2052
|
+
}
|
|
2053
|
+
else
|
|
2054
|
+
{
|
|
2055
|
+
/* update new master node */
|
|
2056
|
+
new_master = get_next_master_node();
|
|
2057
|
+
pool_log("failover: %d follow backends have been degenerated", follow_cnt);
|
|
2058
|
+
}
|
|
2059
|
+
}
|
|
2060
|
+
}
|
|
2061
|
+
}
|
|
2062
|
+
|
|
2063
|
+
memset(Req_info->node_id, -1, sizeof(int) * MAX_NUM_BACKENDS);
|
|
2064
|
+
pool_semaphore_unlock(REQUEST_INFO_SEM);
|
|
2065
|
+
|
|
2066
|
+
/* wait for follow_master_command lock or to be lock holder */
|
|
2067
|
+
if (pool_config->use_watchdog && !wd_am_I_lock_holder())
|
|
2068
|
+
{
|
|
2069
|
+
wd_wait_for_lock(WD_FOLLOW_MASTER_COMMAND_LOCK);
|
|
2070
|
+
}
|
|
2071
|
+
|
|
2072
|
+
/* execute follow_master_command */
|
|
2073
|
+
if (!pool_config->use_watchdog || wd_am_I_lock_holder())
|
|
2074
|
+
{
|
|
2075
|
+
if ((follow_cnt > 0) && (*pool_config->follow_master_command != '\0'))
|
|
2076
|
+
{
|
|
2077
|
+
follow_pid = fork_follow_child(Req_info->master_node_id, new_primary,
|
|
2078
|
+
Req_info->primary_node_id);
|
|
2079
|
+
}
|
|
2080
|
+
|
|
2081
|
+
/* unlock follow_master_command */
|
|
2082
|
+
if (pool_config->use_watchdog)
|
|
2083
|
+
wd_unlock(WD_FOLLOW_MASTER_COMMAND_LOCK);
|
|
2084
|
+
}
|
|
2085
|
+
|
|
2086
|
+
/* end of command inter-lock */
|
|
2087
|
+
if (pool_config->use_watchdog)
|
|
2088
|
+
wd_end_interlock();
|
|
2089
|
+
|
|
2090
|
+
/* Save primary node id */
|
|
2091
|
+
Req_info->primary_node_id = new_primary;
|
|
2092
|
+
pool_log("failover: set new primary node: %d", Req_info->primary_node_id);
|
|
2093
|
+
|
|
2094
|
+
if (new_master >= 0)
|
|
2095
|
+
{
|
|
2096
|
+
Req_info->master_node_id = new_master;
|
|
2097
|
+
pool_log("failover: set new master node: %d", Req_info->master_node_id);
|
|
2098
|
+
}
|
|
2099
|
+
|
|
2100
|
+
|
|
2101
|
+
/* Fork the children if needed */
|
|
2102
|
+
if (need_to_restart_children)
|
|
2103
|
+
{
|
|
2104
|
+
for (i=0;i<pool_config->num_init_children;i++)
|
|
2105
|
+
{
|
|
2106
|
+
|
|
2107
|
+
/*
|
|
2108
|
+
* Try to kill pgpool child because previous kill signal
|
|
2109
|
+
* may not be received by pgpool child. This could happen
|
|
2110
|
+
* if multiple PostgreSQL are going down (or even starting
|
|
2111
|
+
* pgpool, without starting PostgreSQL can trigger this).
|
|
2112
|
+
* Child calls degenerate_backend() and it tries to aquire
|
|
2113
|
+
* semaphore to write a failover request. In this case the
|
|
2114
|
+
* signal mask is set as well, thus signals are never
|
|
2115
|
+
* received.
|
|
2116
|
+
*/
|
|
2117
|
+
kill(process_info[i].pid, SIGQUIT);
|
|
2118
|
+
|
|
2119
|
+
process_info[i].pid = fork_a_child(unix_fd, inet_fd, i);
|
|
2120
|
+
process_info[i].start_time = time(NULL);
|
|
2121
|
+
}
|
|
2122
|
+
}
|
|
2123
|
+
else
|
|
2124
|
+
{
|
|
2125
|
+
/* Set restart request to each child. Children will exit(1)
|
|
2126
|
+
* whenever they are idle to restart.
|
|
2127
|
+
*/
|
|
2128
|
+
for (i=0;i<pool_config->num_init_children;i++)
|
|
2129
|
+
{
|
|
2130
|
+
process_info[i].need_to_restart = 1;
|
|
2131
|
+
}
|
|
2132
|
+
}
|
|
2133
|
+
|
|
2134
|
+
/*
|
|
2135
|
+
* Send restart request to worker child.
|
|
2136
|
+
*/
|
|
2137
|
+
kill(worker_pid, SIGUSR1);
|
|
2138
|
+
|
|
2139
|
+
if (Req_info->kind == NODE_UP_REQUEST)
|
|
2140
|
+
{
|
|
2141
|
+
pool_log("failback done. reconnect host %s(%d)",
|
|
2142
|
+
BACKEND_INFO(node_id).backend_hostname,
|
|
2143
|
+
BACKEND_INFO(node_id).backend_port);
|
|
2144
|
+
}
|
|
2145
|
+
else if (Req_info->kind == PROMOTE_NODE_REQUEST)
|
|
2146
|
+
{
|
|
2147
|
+
pool_log("promotion done. promoted host %s(%d)",
|
|
2148
|
+
BACKEND_INFO(node_id).backend_hostname,
|
|
2149
|
+
BACKEND_INFO(node_id).backend_port);
|
|
2150
|
+
}
|
|
2151
|
+
else
|
|
2152
|
+
{
|
|
2153
|
+
pool_log("failover done. shutdown host %s(%d)",
|
|
2154
|
+
BACKEND_INFO(node_id).backend_hostname,
|
|
2155
|
+
BACKEND_INFO(node_id).backend_port);
|
|
2156
|
+
}
|
|
2157
|
+
|
|
2158
|
+
switching = 0;
|
|
2159
|
+
Req_info->switching = false;
|
|
2160
|
+
|
|
2161
|
+
/* kick wakeup_handler in pcp_child to notice that
|
|
2162
|
+
* failover/failback done
|
|
2163
|
+
*/
|
|
2164
|
+
kill(pcp_pid, SIGUSR2);
|
|
2165
|
+
|
|
2166
|
+
sleep(1);
|
|
2167
|
+
|
|
2168
|
+
/*
|
|
2169
|
+
* Send restart request to pcp child.
|
|
2170
|
+
*/
|
|
2171
|
+
kill(pcp_pid, SIGUSR1);
|
|
2172
|
+
for (;;)
|
|
2173
|
+
{
|
|
2174
|
+
sts = waitpid(pcp_pid, &status, 0);
|
|
2175
|
+
if (sts != -1)
|
|
2176
|
+
break;
|
|
2177
|
+
if (sts == -1)
|
|
2178
|
+
{
|
|
2179
|
+
if (errno == EINTR)
|
|
2180
|
+
continue;
|
|
2181
|
+
else
|
|
2182
|
+
{
|
|
2183
|
+
pool_error("failover: waitpid failed. reason: %s", strerror(errno));
|
|
2184
|
+
return;
|
|
2185
|
+
}
|
|
2186
|
+
}
|
|
2187
|
+
}
|
|
2188
|
+
if (WIFSIGNALED(status))
|
|
2189
|
+
pool_log("PCP child %d exits with status %d by signal %d in failover()", pcp_pid, status, WTERMSIG(status));
|
|
2190
|
+
else
|
|
2191
|
+
pool_log("PCP child %d exits with status %d in failover()", pcp_pid, status);
|
|
2192
|
+
|
|
2193
|
+
pcp_pid = pcp_fork_a_child(pcp_unix_fd, pcp_inet_fd, pcp_conf_file);
|
|
2194
|
+
pool_log("fork a new PCP child pid %d in failover()", pcp_pid);
|
|
2195
|
+
}
|
|
2196
|
+
|
|
2197
|
+
/*
|
|
2198
|
+
* health check timer handler
|
|
2199
|
+
*/
|
|
2200
|
+
static RETSIGTYPE health_check_timer_handler(int sig)
|
|
2201
|
+
{
|
|
2202
|
+
POOL_SETMASK(&BlockSig);
|
|
2203
|
+
health_check_timer_expired = 1;
|
|
2204
|
+
POOL_SETMASK(&UnBlockSig);
|
|
2205
|
+
}
|
|
2206
|
+
|
|
2207
|
+
|
|
2208
|
+
/*
|
|
2209
|
+
* Check if we can connect to the backend
|
|
2210
|
+
* returns 0 for OK. otherwise returns backend id + 1
|
|
2211
|
+
*/
|
|
2212
|
+
static int health_check(void)
|
|
2213
|
+
{
|
|
2214
|
+
POOL_CONNECTION_POOL_SLOT *slot;
|
|
2215
|
+
BackendInfo *bkinfo;
|
|
2216
|
+
static bool is_first = true;
|
|
2217
|
+
static char *dbname;
|
|
2218
|
+
int i;
|
|
2219
|
+
|
|
2220
|
+
/* Do not execute health check during recovery */
|
|
2221
|
+
if (*InRecovery)
|
|
2222
|
+
return 0;
|
|
2223
|
+
|
|
2224
|
+
Retry:
|
|
2225
|
+
/*
|
|
2226
|
+
* First we try with "postgres" database.
|
|
2227
|
+
*/
|
|
2228
|
+
if (is_first)
|
|
2229
|
+
dbname = "postgres";
|
|
2230
|
+
|
|
2231
|
+
for (i=0;i<pool_config->backend_desc->num_backends;i++)
|
|
2232
|
+
{
|
|
2233
|
+
/*
|
|
2234
|
+
* Make sure that health check timer has not been expired.
|
|
2235
|
+
* Before called health_check(), health_check_timer_expired is
|
|
2236
|
+
* set to 0. However it is possible that while processing DB
|
|
2237
|
+
* nodes health check timer expired.
|
|
2238
|
+
*/
|
|
2239
|
+
if (health_check_timer_expired)
|
|
2240
|
+
{
|
|
2241
|
+
pool_log("health_check: health check timer has been already expired before attempting to connect to %d th backend", i);
|
|
2242
|
+
return i+1;
|
|
2243
|
+
}
|
|
2244
|
+
|
|
2245
|
+
bkinfo = pool_get_node_info(i);
|
|
2246
|
+
|
|
2247
|
+
pool_debug("health_check: %d th DB node status: %d", i, bkinfo->backend_status);
|
|
2248
|
+
|
|
2249
|
+
if (bkinfo->backend_status == CON_UNUSED ||
|
|
2250
|
+
bkinfo->backend_status == CON_DOWN)
|
|
2251
|
+
continue;
|
|
2252
|
+
|
|
2253
|
+
slot = make_persistent_db_connection(bkinfo->backend_hostname,
|
|
2254
|
+
bkinfo->backend_port,
|
|
2255
|
+
dbname,
|
|
2256
|
+
pool_config->health_check_user,
|
|
2257
|
+
pool_config->health_check_password, false);
|
|
2258
|
+
|
|
2259
|
+
if (is_first)
|
|
2260
|
+
is_first = false;
|
|
2261
|
+
|
|
2262
|
+
if (!slot)
|
|
2263
|
+
{
|
|
2264
|
+
/*
|
|
2265
|
+
* Retry with template1 unless health check timer is expired.
|
|
2266
|
+
*/
|
|
2267
|
+
if (!strcmp(dbname, "postgres") && health_check_timer_expired == 0)
|
|
2268
|
+
{
|
|
2269
|
+
dbname = "template1";
|
|
2270
|
+
goto Retry;
|
|
2271
|
+
}
|
|
2272
|
+
else
|
|
2273
|
+
{
|
|
2274
|
+
pool_error("health check failed. %d th host %s at port %d is down",
|
|
2275
|
+
i,
|
|
2276
|
+
bkinfo->backend_hostname,
|
|
2277
|
+
bkinfo->backend_port);
|
|
2278
|
+
return i+1;
|
|
2279
|
+
}
|
|
2280
|
+
}
|
|
2281
|
+
else
|
|
2282
|
+
{
|
|
2283
|
+
discard_persistent_db_connection(slot);
|
|
2284
|
+
}
|
|
2285
|
+
}
|
|
2286
|
+
|
|
2287
|
+
return 0;
|
|
2288
|
+
}
|
|
2289
|
+
|
|
2290
|
+
/*
|
|
2291
|
+
* check if we can connect to the SystemDB
|
|
2292
|
+
* returns 0 for OK. otherwise returns -1
|
|
2293
|
+
*/
|
|
2294
|
+
static int
|
|
2295
|
+
system_db_health_check(void)
|
|
2296
|
+
{
|
|
2297
|
+
int fd;
|
|
2298
|
+
|
|
2299
|
+
/* V2 startup packet */
|
|
2300
|
+
typedef struct {
|
|
2301
|
+
int len; /* startup packet length */
|
|
2302
|
+
StartupPacket_v2 sp;
|
|
2303
|
+
} MySp;
|
|
2304
|
+
MySp mysp;
|
|
2305
|
+
char kind;
|
|
2306
|
+
|
|
2307
|
+
memset(&mysp, 0, sizeof(mysp));
|
|
2308
|
+
mysp.len = htonl(296);
|
|
2309
|
+
mysp.sp.protoVersion = htonl(PROTO_MAJOR_V2 << 16);
|
|
2310
|
+
strcpy(mysp.sp.database, "template1");
|
|
2311
|
+
strncpy(mysp.sp.user, SYSDB_INFO->user, sizeof(mysp.sp.user) - 1);
|
|
2312
|
+
*mysp.sp.options = '\0';
|
|
2313
|
+
*mysp.sp.unused = '\0';
|
|
2314
|
+
*mysp.sp.tty = '\0';
|
|
2315
|
+
|
|
2316
|
+
pool_debug("health_check: SystemDB status: %d", SYSDB_STATUS);
|
|
2317
|
+
|
|
2318
|
+
/* if SystemDB is already down, ignore */
|
|
2319
|
+
if (SYSDB_STATUS == CON_UNUSED || SYSDB_STATUS == CON_DOWN)
|
|
2320
|
+
return 0;
|
|
2321
|
+
|
|
2322
|
+
if (*SYSDB_INFO->hostname == '/')
|
|
2323
|
+
fd = connect_unix_domain_socket_by_port(SYSDB_INFO->port, SYSDB_INFO->hostname, FALSE);
|
|
2324
|
+
else
|
|
2325
|
+
fd = connect_inet_domain_socket_by_port(SYSDB_INFO->hostname, SYSDB_INFO->port, FALSE);
|
|
2326
|
+
|
|
2327
|
+
if (fd < 0)
|
|
2328
|
+
{
|
|
2329
|
+
pool_error("health check failed. SystemDB host %s at port %d is down",
|
|
2330
|
+
SYSDB_INFO->hostname,
|
|
2331
|
+
SYSDB_INFO->port);
|
|
2332
|
+
|
|
2333
|
+
return -1;
|
|
2334
|
+
}
|
|
2335
|
+
|
|
2336
|
+
if (write(fd, &mysp, sizeof(mysp)) < 0)
|
|
2337
|
+
{
|
|
2338
|
+
pool_error("health check failed during write. SystemDB host %s at port %d is down",
|
|
2339
|
+
SYSDB_INFO->hostname,
|
|
2340
|
+
SYSDB_INFO->port);
|
|
2341
|
+
close(fd);
|
|
2342
|
+
return -1;
|
|
2343
|
+
}
|
|
2344
|
+
|
|
2345
|
+
read(fd, &kind, 1);
|
|
2346
|
+
|
|
2347
|
+
if (write(fd, "X", 1) < 0)
|
|
2348
|
+
{
|
|
2349
|
+
pool_error("health check failed during write. SystemDB host %s at port %d is down",
|
|
2350
|
+
SYSDB_INFO->hostname,
|
|
2351
|
+
SYSDB_INFO->port);
|
|
2352
|
+
close(fd);
|
|
2353
|
+
return -1;
|
|
2354
|
+
}
|
|
2355
|
+
|
|
2356
|
+
close(fd);
|
|
2357
|
+
return 0;
|
|
2358
|
+
}
|
|
2359
|
+
|
|
2360
|
+
/*
|
|
2361
|
+
* handle SIGCHLD
|
|
2362
|
+
*/
|
|
2363
|
+
static RETSIGTYPE reap_handler(int sig)
|
|
2364
|
+
{
|
|
2365
|
+
POOL_SETMASK(&BlockSig);
|
|
2366
|
+
sigchld_request = 1;
|
|
2367
|
+
write(pipe_fds[1], "\0", 1);
|
|
2368
|
+
POOL_SETMASK(&UnBlockSig);
|
|
2369
|
+
}
|
|
2370
|
+
|
|
2371
|
+
/*
|
|
2372
|
+
* Attach zombie processes and restart child processes.
|
|
2373
|
+
* reaper() must be called protected from signals.
|
|
2374
|
+
*/
|
|
2375
|
+
static void reaper(void)
|
|
2376
|
+
{
|
|
2377
|
+
pid_t pid;
|
|
2378
|
+
int status;
|
|
2379
|
+
int i;
|
|
2380
|
+
|
|
2381
|
+
pool_debug("reap_handler called");
|
|
2382
|
+
|
|
2383
|
+
if (exiting)
|
|
2384
|
+
{
|
|
2385
|
+
pool_debug("reap_handler: exited due to exiting");
|
|
2386
|
+
return;
|
|
2387
|
+
}
|
|
2388
|
+
|
|
2389
|
+
if (switching)
|
|
2390
|
+
{
|
|
2391
|
+
pool_debug("reap_handler: exited due to switching");
|
|
2392
|
+
return;
|
|
2393
|
+
}
|
|
2394
|
+
|
|
2395
|
+
/* clear SIGCHLD request */
|
|
2396
|
+
sigchld_request = 0;
|
|
2397
|
+
|
|
2398
|
+
#ifdef HAVE_WAITPID
|
|
2399
|
+
pool_debug("reap_handler: call waitpid");
|
|
2400
|
+
while ((pid = waitpid(-1, &status, WNOHANG)) > 0)
|
|
2401
|
+
#else
|
|
2402
|
+
pool_debug("reap_handler: call wait3");
|
|
2403
|
+
while ((pid = wait3(&status, WNOHANG, NULL)) > 0)
|
|
2404
|
+
#endif
|
|
2405
|
+
{
|
|
2406
|
+
if (WIFSIGNALED(status) && WTERMSIG(status) == SIGSEGV)
|
|
2407
|
+
{
|
|
2408
|
+
/* Child terminated by segmentation fault. Report it */
|
|
2409
|
+
pool_error("Child process %d was terminated by segmentation fault", pid);
|
|
2410
|
+
}
|
|
2411
|
+
|
|
2412
|
+
/* if exiting child process was PCP handler */
|
|
2413
|
+
if (pid == pcp_pid)
|
|
2414
|
+
{
|
|
2415
|
+
if (WIFSIGNALED(status))
|
|
2416
|
+
pool_log("PCP child %d exits with status %d by signal %d", pid, status, WTERMSIG(status));
|
|
2417
|
+
else
|
|
2418
|
+
pool_log("PCP child %d exits with status %d", pid, status);
|
|
2419
|
+
|
|
2420
|
+
pcp_pid = pcp_fork_a_child(pcp_unix_fd, pcp_inet_fd, pcp_conf_file);
|
|
2421
|
+
pool_log("fork a new PCP child pid %d", pcp_pid);
|
|
2422
|
+
}
|
|
2423
|
+
|
|
2424
|
+
/* exiting process was worker process */
|
|
2425
|
+
else if (pid == worker_pid)
|
|
2426
|
+
{
|
|
2427
|
+
if (WIFSIGNALED(status))
|
|
2428
|
+
pool_log("worker child %d exits with status %d by signal %d", pid, status, WTERMSIG(status));
|
|
2429
|
+
else
|
|
2430
|
+
pool_log("worker child %d exits with status %d", pid, status);
|
|
2431
|
+
|
|
2432
|
+
if (status)
|
|
2433
|
+
worker_pid = worker_fork_a_child();
|
|
2434
|
+
|
|
2435
|
+
pool_log("fork a new worker child pid %d", worker_pid);
|
|
2436
|
+
}
|
|
2437
|
+
|
|
2438
|
+
/* exiting process was watchdog process */
|
|
2439
|
+
else if (pool_config->use_watchdog && wd_is_watchdog_pid(pid))
|
|
2440
|
+
{
|
|
2441
|
+
if (!wd_reaper_watchdog(pid, status))
|
|
2442
|
+
{
|
|
2443
|
+
pool_error("wd_reaper failed");
|
|
2444
|
+
myexit(1);
|
|
2445
|
+
}
|
|
2446
|
+
}
|
|
2447
|
+
|
|
2448
|
+
else
|
|
2449
|
+
{
|
|
2450
|
+
if (WIFSIGNALED(status))
|
|
2451
|
+
pool_debug("child %d exits with status %d by signal %d", pid, status, WTERMSIG(status));
|
|
2452
|
+
else
|
|
2453
|
+
pool_debug("child %d exits with status %d", pid, status);
|
|
2454
|
+
|
|
2455
|
+
/* look for exiting child's pid */
|
|
2456
|
+
for (i=0;i<pool_config->num_init_children;i++)
|
|
2457
|
+
{
|
|
2458
|
+
if (pid == process_info[i].pid)
|
|
2459
|
+
{
|
|
2460
|
+
/* if found, fork a new child */
|
|
2461
|
+
if (!switching && !exiting && status)
|
|
2462
|
+
{
|
|
2463
|
+
process_info[i].pid = fork_a_child(unix_fd, inet_fd, i);
|
|
2464
|
+
process_info[i].start_time = time(NULL);
|
|
2465
|
+
pool_debug("fork a new child pid %d", process_info[i].pid);
|
|
2466
|
+
break;
|
|
2467
|
+
}
|
|
2468
|
+
}
|
|
2469
|
+
}
|
|
2470
|
+
}
|
|
2471
|
+
}
|
|
2472
|
+
pool_debug("reap_handler: normally exited");
|
|
2473
|
+
}
|
|
2474
|
+
|
|
2475
|
+
/*
|
|
2476
|
+
* get node information specified by node_number
|
|
2477
|
+
*/
|
|
2478
|
+
BackendInfo *
|
|
2479
|
+
pool_get_node_info(int node_number)
|
|
2480
|
+
{
|
|
2481
|
+
if (node_number < 0 || node_number >= NUM_BACKENDS)
|
|
2482
|
+
return NULL;
|
|
2483
|
+
|
|
2484
|
+
return &BACKEND_INFO(node_number);
|
|
2485
|
+
}
|
|
2486
|
+
|
|
2487
|
+
/*
|
|
2488
|
+
* get number of nodes
|
|
2489
|
+
*/
|
|
2490
|
+
int
|
|
2491
|
+
pool_get_node_count(void)
|
|
2492
|
+
{
|
|
2493
|
+
return NUM_BACKENDS;
|
|
2494
|
+
}
|
|
2495
|
+
|
|
2496
|
+
/*
|
|
2497
|
+
* get process ids
|
|
2498
|
+
*/
|
|
2499
|
+
int *
|
|
2500
|
+
pool_get_process_list(int *array_size)
|
|
2501
|
+
{
|
|
2502
|
+
int *array;
|
|
2503
|
+
int i;
|
|
2504
|
+
|
|
2505
|
+
*array_size = pool_config->num_init_children;
|
|
2506
|
+
array = calloc(*array_size, sizeof(int));
|
|
2507
|
+
for (i = 0; i < *array_size; i++)
|
|
2508
|
+
array[i] = process_info[i].pid;
|
|
2509
|
+
|
|
2510
|
+
return array;
|
|
2511
|
+
}
|
|
2512
|
+
|
|
2513
|
+
/*
|
|
2514
|
+
* get process information specified by pid
|
|
2515
|
+
*/
|
|
2516
|
+
ProcessInfo *
|
|
2517
|
+
pool_get_process_info(pid_t pid)
|
|
2518
|
+
{
|
|
2519
|
+
int i;
|
|
2520
|
+
|
|
2521
|
+
for (i = 0; i < pool_config->num_init_children; i++)
|
|
2522
|
+
if (process_info[i].pid == pid)
|
|
2523
|
+
return &process_info[i];
|
|
2524
|
+
|
|
2525
|
+
return NULL;
|
|
2526
|
+
}
|
|
2527
|
+
|
|
2528
|
+
/*
|
|
2529
|
+
* get System DB information
|
|
2530
|
+
*/
|
|
2531
|
+
SystemDBInfo *
|
|
2532
|
+
pool_get_system_db_info(void)
|
|
2533
|
+
{
|
|
2534
|
+
if (system_db_info == NULL)
|
|
2535
|
+
return NULL;
|
|
2536
|
+
|
|
2537
|
+
return system_db_info->info;
|
|
2538
|
+
}
|
|
2539
|
+
|
|
2540
|
+
|
|
2541
|
+
/*
|
|
2542
|
+
* handle SIGUSR2
|
|
2543
|
+
* Wakeup all processes
|
|
2544
|
+
*/
|
|
2545
|
+
static void wakeup_children(void)
|
|
2546
|
+
{
|
|
2547
|
+
kill_all_children(SIGUSR2);
|
|
2548
|
+
}
|
|
2549
|
+
|
|
2550
|
+
|
|
2551
|
+
static RETSIGTYPE wakeup_handler(int sig)
|
|
2552
|
+
{
|
|
2553
|
+
POOL_SETMASK(&BlockSig);
|
|
2554
|
+
wakeup_request = 1;
|
|
2555
|
+
write(pipe_fds[1], "\0", 1);
|
|
2556
|
+
POOL_SETMASK(&UnBlockSig);
|
|
2557
|
+
}
|
|
2558
|
+
|
|
2559
|
+
/*
|
|
2560
|
+
* handle SIGHUP
|
|
2561
|
+
*
|
|
2562
|
+
*/
|
|
2563
|
+
static RETSIGTYPE reload_config_handler(int sig)
|
|
2564
|
+
{
|
|
2565
|
+
POOL_SETMASK(&BlockSig);
|
|
2566
|
+
reload_config_request = 1;
|
|
2567
|
+
write(pipe_fds[1], "\0", 1);
|
|
2568
|
+
POOL_SETMASK(&UnBlockSig);
|
|
2569
|
+
}
|
|
2570
|
+
|
|
2571
|
+
static void reload_config(void)
|
|
2572
|
+
{
|
|
2573
|
+
pool_log("reload config files.");
|
|
2574
|
+
pool_get_config(conf_file, RELOAD_CONFIG);
|
|
2575
|
+
if (pool_config->enable_pool_hba)
|
|
2576
|
+
load_hba(hba_file);
|
|
2577
|
+
if (pool_config->parallel_mode)
|
|
2578
|
+
pool_memset_system_db_info(system_db_info->info);
|
|
2579
|
+
kill_all_children(SIGHUP);
|
|
2580
|
+
|
|
2581
|
+
if (worker_pid)
|
|
2582
|
+
kill(worker_pid, SIGHUP);
|
|
2583
|
+
}
|
|
2584
|
+
|
|
2585
|
+
static void kill_all_children(int sig)
|
|
2586
|
+
{
|
|
2587
|
+
int i;
|
|
2588
|
+
|
|
2589
|
+
/* kill all children */
|
|
2590
|
+
for (i = 0; i < pool_config->num_init_children; i++)
|
|
2591
|
+
{
|
|
2592
|
+
pid_t pid = process_info[i].pid;
|
|
2593
|
+
if (pid)
|
|
2594
|
+
{
|
|
2595
|
+
kill(pid, sig);
|
|
2596
|
+
}
|
|
2597
|
+
}
|
|
2598
|
+
|
|
2599
|
+
/* make PCP process reload as well */
|
|
2600
|
+
if (sig == SIGHUP)
|
|
2601
|
+
kill(pcp_pid, sig);
|
|
2602
|
+
}
|
|
2603
|
+
|
|
2604
|
+
/*
|
|
2605
|
+
* pause in a period specified by timeout. If any data is coming
|
|
2606
|
+
* through pipe_fds[0], that means one of: failover request(SIGUSR1),
|
|
2607
|
+
* SIGCHLD received, children wake up request(SIGUSR2 used in on line
|
|
2608
|
+
* recovery processing) or config file reload request(SIGHUP) has been
|
|
2609
|
+
* occurred. In this case this function returns 1.
|
|
2610
|
+
* otherwise 0: (no signal event occurred), -1: (error)
|
|
2611
|
+
* XXX: is it OK that select(2) error is ignored here?
|
|
2612
|
+
*/
|
|
2613
|
+
static int pool_pause(struct timeval *timeout)
|
|
2614
|
+
{
|
|
2615
|
+
fd_set rfds;
|
|
2616
|
+
int n;
|
|
2617
|
+
char dummy;
|
|
2618
|
+
|
|
2619
|
+
FD_ZERO(&rfds);
|
|
2620
|
+
FD_SET(pipe_fds[0], &rfds);
|
|
2621
|
+
n = select(pipe_fds[0]+1, &rfds, NULL, NULL, timeout);
|
|
2622
|
+
if (n == 1)
|
|
2623
|
+
read(pipe_fds[0], &dummy, 1);
|
|
2624
|
+
return n;
|
|
2625
|
+
}
|
|
2626
|
+
|
|
2627
|
+
/*
|
|
2628
|
+
* sleep for seconds specified by "second". Unlike pool_pause(), this
|
|
2629
|
+
* function guarantees that it will sleep for specified seconds. This
|
|
2630
|
+
* function uses pool_pause() internally. If it informs that there is
|
|
2631
|
+
* a pending signal event, they are processed using CHECK_REQUEST
|
|
2632
|
+
* macro. Note that most of these processes are done while all signals
|
|
2633
|
+
* are blocked.
|
|
2634
|
+
*/
|
|
2635
|
+
void pool_sleep(unsigned int second)
|
|
2636
|
+
{
|
|
2637
|
+
struct timeval current_time, sleep_time;
|
|
2638
|
+
|
|
2639
|
+
gettimeofday(¤t_time, NULL);
|
|
2640
|
+
sleep_time.tv_sec = second + current_time.tv_sec;
|
|
2641
|
+
sleep_time.tv_usec = current_time.tv_usec;
|
|
2642
|
+
|
|
2643
|
+
POOL_SETMASK(&UnBlockSig);
|
|
2644
|
+
while (sleep_time.tv_sec > current_time.tv_sec)
|
|
2645
|
+
{
|
|
2646
|
+
struct timeval timeout;
|
|
2647
|
+
int r;
|
|
2648
|
+
|
|
2649
|
+
timeout.tv_sec = sleep_time.tv_sec - current_time.tv_sec;
|
|
2650
|
+
timeout.tv_usec = sleep_time.tv_usec - current_time.tv_usec;
|
|
2651
|
+
if (timeout.tv_usec < 0)
|
|
2652
|
+
{
|
|
2653
|
+
timeout.tv_sec--;
|
|
2654
|
+
timeout.tv_usec += 1000000;
|
|
2655
|
+
}
|
|
2656
|
+
|
|
2657
|
+
r = pool_pause(&timeout);
|
|
2658
|
+
POOL_SETMASK(&BlockSig);
|
|
2659
|
+
if (r > 0)
|
|
2660
|
+
CHECK_REQUEST;
|
|
2661
|
+
POOL_SETMASK(&UnBlockSig);
|
|
2662
|
+
gettimeofday(¤t_time, NULL);
|
|
2663
|
+
}
|
|
2664
|
+
POOL_SETMASK(&BlockSig);
|
|
2665
|
+
}
|
|
2666
|
+
|
|
2667
|
+
/*
|
|
2668
|
+
* get_config_file_name: return full path of pgpool.conf.
|
|
2669
|
+
*/
|
|
2670
|
+
char *get_config_file_name(void)
|
|
2671
|
+
{
|
|
2672
|
+
return conf_file;
|
|
2673
|
+
}
|
|
2674
|
+
|
|
2675
|
+
/*
|
|
2676
|
+
* get_config_file_name: return full path of pool_hba.conf.
|
|
2677
|
+
*/
|
|
2678
|
+
char *get_hba_file_name(void)
|
|
2679
|
+
{
|
|
2680
|
+
return hba_file;
|
|
2681
|
+
}
|
|
2682
|
+
|
|
2683
|
+
/*
|
|
2684
|
+
* trigger_failover_command: execute specified command at failover.
|
|
2685
|
+
* command_line is null-terminated string.
|
|
2686
|
+
*/
|
|
2687
|
+
static int trigger_failover_command(int node, const char *command_line,
|
|
2688
|
+
int old_master, int new_master, int old_primary)
|
|
2689
|
+
{
|
|
2690
|
+
int r = 0;
|
|
2691
|
+
String *exec_cmd;
|
|
2692
|
+
char port_buf[6];
|
|
2693
|
+
char buf[2];
|
|
2694
|
+
BackendInfo *info;
|
|
2695
|
+
BackendInfo *newmaster;
|
|
2696
|
+
|
|
2697
|
+
if (command_line == NULL || (strlen(command_line) == 0))
|
|
2698
|
+
return 0;
|
|
2699
|
+
|
|
2700
|
+
/* check failed nodeID */
|
|
2701
|
+
if (node < 0 || node > NUM_BACKENDS)
|
|
2702
|
+
return -1;
|
|
2703
|
+
|
|
2704
|
+
info = pool_get_node_info(node);
|
|
2705
|
+
if (!info)
|
|
2706
|
+
return -1;
|
|
2707
|
+
|
|
2708
|
+
buf[1] = '\0';
|
|
2709
|
+
pool_memory = pool_memory_create(PREPARE_BLOCK_SIZE);
|
|
2710
|
+
if (!pool_memory)
|
|
2711
|
+
{
|
|
2712
|
+
pool_error("trigger_failover_command: pool_memory_create() failed");
|
|
2713
|
+
return -1;
|
|
2714
|
+
}
|
|
2715
|
+
exec_cmd = init_string("");
|
|
2716
|
+
|
|
2717
|
+
while (*command_line)
|
|
2718
|
+
{
|
|
2719
|
+
if (*command_line == '%')
|
|
2720
|
+
{
|
|
2721
|
+
if (*(command_line + 1))
|
|
2722
|
+
{
|
|
2723
|
+
char val = *(command_line + 1);
|
|
2724
|
+
switch (val)
|
|
2725
|
+
{
|
|
2726
|
+
case 'p': /* failed node port */
|
|
2727
|
+
snprintf(port_buf, sizeof(port_buf), "%d", info->backend_port);
|
|
2728
|
+
string_append_char(exec_cmd, port_buf);
|
|
2729
|
+
break;
|
|
2730
|
+
|
|
2731
|
+
case 'D': /* failed node database directory */
|
|
2732
|
+
string_append_char(exec_cmd, info->backend_data_directory);
|
|
2733
|
+
break;
|
|
2734
|
+
|
|
2735
|
+
case 'd': /* failed node id */
|
|
2736
|
+
snprintf(port_buf, sizeof(port_buf), "%d", node);
|
|
2737
|
+
string_append_char(exec_cmd, port_buf);
|
|
2738
|
+
break;
|
|
2739
|
+
|
|
2740
|
+
case 'h': /* failed host name */
|
|
2741
|
+
string_append_char(exec_cmd, info->backend_hostname);
|
|
2742
|
+
break;
|
|
2743
|
+
|
|
2744
|
+
case 'H': /* new master host name */
|
|
2745
|
+
newmaster = pool_get_node_info(new_master);
|
|
2746
|
+
if (newmaster)
|
|
2747
|
+
string_append_char(exec_cmd, newmaster->backend_hostname);
|
|
2748
|
+
else
|
|
2749
|
+
/* no valid new master */
|
|
2750
|
+
string_append_char(exec_cmd, "");
|
|
2751
|
+
break;
|
|
2752
|
+
|
|
2753
|
+
case 'm': /* new master node id */
|
|
2754
|
+
snprintf(port_buf, sizeof(port_buf), "%d", new_master);
|
|
2755
|
+
string_append_char(exec_cmd, port_buf);
|
|
2756
|
+
break;
|
|
2757
|
+
|
|
2758
|
+
case 'r': /* new master port */
|
|
2759
|
+
newmaster = pool_get_node_info(get_next_master_node());
|
|
2760
|
+
if (newmaster)
|
|
2761
|
+
{
|
|
2762
|
+
snprintf(port_buf, sizeof(port_buf), "%d", newmaster->backend_port);
|
|
2763
|
+
string_append_char(exec_cmd, port_buf);
|
|
2764
|
+
}
|
|
2765
|
+
else
|
|
2766
|
+
/* no valid new master */
|
|
2767
|
+
string_append_char(exec_cmd, "");
|
|
2768
|
+
break;
|
|
2769
|
+
|
|
2770
|
+
case 'R': /* new master database directory */
|
|
2771
|
+
newmaster = pool_get_node_info(get_next_master_node());
|
|
2772
|
+
if (newmaster)
|
|
2773
|
+
string_append_char(exec_cmd, newmaster->backend_data_directory);
|
|
2774
|
+
else
|
|
2775
|
+
/* no valid new master */
|
|
2776
|
+
string_append_char(exec_cmd, "");
|
|
2777
|
+
break;
|
|
2778
|
+
|
|
2779
|
+
case 'M': /* old master node id */
|
|
2780
|
+
snprintf(port_buf, sizeof(port_buf), "%d", old_master);
|
|
2781
|
+
string_append_char(exec_cmd, port_buf);
|
|
2782
|
+
break;
|
|
2783
|
+
|
|
2784
|
+
case 'P': /* old primary node id */
|
|
2785
|
+
snprintf(port_buf, sizeof(port_buf), "%d", old_primary);
|
|
2786
|
+
string_append_char(exec_cmd, port_buf);
|
|
2787
|
+
break;
|
|
2788
|
+
|
|
2789
|
+
case '%': /* escape */
|
|
2790
|
+
string_append_char(exec_cmd, "%");
|
|
2791
|
+
break;
|
|
2792
|
+
|
|
2793
|
+
default: /* ignore */
|
|
2794
|
+
break;
|
|
2795
|
+
}
|
|
2796
|
+
command_line++;
|
|
2797
|
+
}
|
|
2798
|
+
} else {
|
|
2799
|
+
buf[0] = *command_line;
|
|
2800
|
+
string_append_char(exec_cmd, buf);
|
|
2801
|
+
}
|
|
2802
|
+
command_line++;
|
|
2803
|
+
}
|
|
2804
|
+
|
|
2805
|
+
if (strlen(exec_cmd->data) != 0)
|
|
2806
|
+
{
|
|
2807
|
+
pool_log("execute command: %s", exec_cmd->data);
|
|
2808
|
+
r = system(exec_cmd->data);
|
|
2809
|
+
}
|
|
2810
|
+
|
|
2811
|
+
pool_memory_delete(pool_memory, 0);
|
|
2812
|
+
pool_memory = NULL;
|
|
2813
|
+
|
|
2814
|
+
return r;
|
|
2815
|
+
}
|
|
2816
|
+
|
|
2817
|
+
/*
|
|
2818
|
+
* Find the primary node (i.e. not standby node) and returns its node
|
|
2819
|
+
* id. If no primary node is found, returns -1.
|
|
2820
|
+
*/
|
|
2821
|
+
static int find_primary_node(void)
|
|
2822
|
+
{
|
|
2823
|
+
BackendInfo *bkinfo;
|
|
2824
|
+
POOL_CONNECTION_POOL_SLOT *s;
|
|
2825
|
+
POOL_CONNECTION *con;
|
|
2826
|
+
POOL_STATUS status;
|
|
2827
|
+
POOL_SELECT_RESULT *res;
|
|
2828
|
+
bool is_standby;
|
|
2829
|
+
int i;
|
|
2830
|
+
|
|
2831
|
+
/* Streaming replication mode? */
|
|
2832
|
+
if (pool_config->master_slave_mode == 0 ||
|
|
2833
|
+
strcmp(pool_config->master_slave_sub_mode, MODE_STREAMREP))
|
|
2834
|
+
{
|
|
2835
|
+
/* No point to look for primary node if not in streaming
|
|
2836
|
+
* replication mode.
|
|
2837
|
+
*/
|
|
2838
|
+
pool_debug("find_primary_node: not in streaming replication mode");
|
|
2839
|
+
return -1;
|
|
2840
|
+
}
|
|
2841
|
+
|
|
2842
|
+
for(i=0;i<NUM_BACKENDS;i++)
|
|
2843
|
+
{
|
|
2844
|
+
if (!VALID_BACKEND(i))
|
|
2845
|
+
continue;
|
|
2846
|
+
|
|
2847
|
+
/*
|
|
2848
|
+
* Check to see if this is a standby node or not.
|
|
2849
|
+
*/
|
|
2850
|
+
is_standby = false;
|
|
2851
|
+
|
|
2852
|
+
bkinfo = pool_get_node_info(i);
|
|
2853
|
+
s = make_persistent_db_connection(bkinfo->backend_hostname,
|
|
2854
|
+
bkinfo->backend_port,
|
|
2855
|
+
"postgres",
|
|
2856
|
+
pool_config->sr_check_user,
|
|
2857
|
+
pool_config->sr_check_password, true);
|
|
2858
|
+
if (!s)
|
|
2859
|
+
{
|
|
2860
|
+
pool_error("find_primary_node: make_persistent_connection failed");
|
|
2861
|
+
return -1;
|
|
2862
|
+
}
|
|
2863
|
+
con = s->con;
|
|
2864
|
+
status = do_query(con, "SELECT pg_is_in_recovery()",
|
|
2865
|
+
&res, PROTO_MAJOR_V3);
|
|
2866
|
+
if (res->numrows <= 0)
|
|
2867
|
+
{
|
|
2868
|
+
pool_log("find_primary_node: do_query returns no rows");
|
|
2869
|
+
}
|
|
2870
|
+
if (res->data[0] == NULL)
|
|
2871
|
+
{
|
|
2872
|
+
pool_log("find_primary_node: do_query returns no data");
|
|
2873
|
+
}
|
|
2874
|
+
if (res->nullflags[0] == -1)
|
|
2875
|
+
{
|
|
2876
|
+
pool_log("find_primary_node: do_query returns NULL");
|
|
2877
|
+
}
|
|
2878
|
+
if (res->data[0] && !strcmp(res->data[0], "t"))
|
|
2879
|
+
{
|
|
2880
|
+
is_standby = true;
|
|
2881
|
+
}
|
|
2882
|
+
free_select_result(res);
|
|
2883
|
+
discard_persistent_db_connection(s);
|
|
2884
|
+
|
|
2885
|
+
/*
|
|
2886
|
+
* If this is a standby, we continue to look for primary node.
|
|
2887
|
+
*/
|
|
2888
|
+
if (is_standby)
|
|
2889
|
+
{
|
|
2890
|
+
pool_debug("find_primary_node: %d node is standby", i);
|
|
2891
|
+
}
|
|
2892
|
+
else
|
|
2893
|
+
{
|
|
2894
|
+
break;
|
|
2895
|
+
}
|
|
2896
|
+
}
|
|
2897
|
+
|
|
2898
|
+
if (i == NUM_BACKENDS)
|
|
2899
|
+
{
|
|
2900
|
+
pool_debug("find_primary_node: no primary node found");
|
|
2901
|
+
return -1;
|
|
2902
|
+
}
|
|
2903
|
+
|
|
2904
|
+
pool_log("find_primary_node: primary node id is %d", i);
|
|
2905
|
+
return i;
|
|
2906
|
+
}
|
|
2907
|
+
|
|
2908
|
+
static int find_primary_node_repeatedly(void)
|
|
2909
|
+
{
|
|
2910
|
+
int sec;
|
|
2911
|
+
int node_id = -1;
|
|
2912
|
+
|
|
2913
|
+
/* Streaming replication mode? */
|
|
2914
|
+
if (pool_config->master_slave_mode == 0 ||
|
|
2915
|
+
strcmp(pool_config->master_slave_sub_mode, MODE_STREAMREP))
|
|
2916
|
+
{
|
|
2917
|
+
/* No point to look for primary node if not in streaming
|
|
2918
|
+
* replication mode.
|
|
2919
|
+
*/
|
|
2920
|
+
pool_debug("find_primary_node: not in streaming replication mode");
|
|
2921
|
+
return -1;
|
|
2922
|
+
}
|
|
2923
|
+
|
|
2924
|
+
/*
|
|
2925
|
+
* Try to find the new primary node and keep trying for
|
|
2926
|
+
* search_primary_node_timeout seconds.
|
|
2927
|
+
* search_primary_node_timeout = 0 means never timeout and keep searching
|
|
2928
|
+
* indefinitely
|
|
2929
|
+
*/
|
|
2930
|
+
pool_log("find_primary_node_repeatedly: waiting for finding a primary node");
|
|
2931
|
+
for (sec = 0; (pool_config->search_primary_node_timeout == 0 ||
|
|
2932
|
+
sec < pool_config->search_primary_node_timeout); sec++)
|
|
2933
|
+
{
|
|
2934
|
+
node_id = find_primary_node();
|
|
2935
|
+
if (node_id != -1)
|
|
2936
|
+
break;
|
|
2937
|
+
pool_sleep(1);
|
|
2938
|
+
}
|
|
2939
|
+
return node_id;
|
|
2940
|
+
}
|
|
2941
|
+
|
|
2942
|
+
/*
|
|
2943
|
+
* fork a follow child
|
|
2944
|
+
*/
|
|
2945
|
+
pid_t fork_follow_child(int old_master, int new_primary, int old_primary)
|
|
2946
|
+
{
|
|
2947
|
+
pid_t pid;
|
|
2948
|
+
int i;
|
|
2949
|
+
|
|
2950
|
+
pid = fork();
|
|
2951
|
+
|
|
2952
|
+
if (pid == 0)
|
|
2953
|
+
{
|
|
2954
|
+
pool_log("start triggering follow command.");
|
|
2955
|
+
for (i = 0; i < pool_config->backend_desc->num_backends; i++)
|
|
2956
|
+
{
|
|
2957
|
+
BackendInfo *bkinfo;
|
|
2958
|
+
bkinfo = pool_get_node_info(i);
|
|
2959
|
+
if (bkinfo->backend_status == CON_DOWN)
|
|
2960
|
+
trigger_failover_command(i, pool_config->follow_master_command,
|
|
2961
|
+
old_master, new_primary, old_primary);
|
|
2962
|
+
}
|
|
2963
|
+
exit(0);
|
|
2964
|
+
}
|
|
2965
|
+
else if (pid == -1)
|
|
2966
|
+
{
|
|
2967
|
+
pool_error("follow fork() failed. reason: %s", strerror(errno));
|
|
2968
|
+
exit(1);
|
|
2969
|
+
}
|
|
2970
|
+
return pid;
|
|
2971
|
+
}
|