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.
Files changed (393) hide show
  1. data/.gitignore +4 -0
  2. data/Gemfile +2 -0
  3. data/Gemfile.lock +20 -0
  4. data/LICENSE +202 -0
  5. data/NOTICE +22 -0
  6. data/README.md +217 -0
  7. data/Rakefile +13 -0
  8. data/VERSION +1 -0
  9. data/bin/prestogres +254 -0
  10. data/config/pcp.conf.sample +28 -0
  11. data/config/pgpool.conf +678 -0
  12. data/config/pool_hba.conf +84 -0
  13. data/config/pool_passwd +0 -0
  14. data/config/postgresql.conf +2 -0
  15. data/ext/.gitignore +6 -0
  16. data/ext/depend +26 -0
  17. data/ext/extconf.rb +4 -0
  18. data/ext/prestogres_config.c +12 -0
  19. data/pgpool2/.gitignore +36 -0
  20. data/pgpool2/AUTHORS +4 -0
  21. data/pgpool2/COPYING +12 -0
  22. data/pgpool2/ChangeLog +1 -0
  23. data/pgpool2/INSTALL +1 -0
  24. data/pgpool2/Makefile.am +159 -0
  25. data/pgpool2/Makefile.in +1187 -0
  26. data/pgpool2/NEWS +4960 -0
  27. data/pgpool2/README +1 -0
  28. data/pgpool2/README.euc_jp +1 -0
  29. data/pgpool2/README.online-recovery +62 -0
  30. data/pgpool2/TODO +103 -0
  31. data/pgpool2/ac_func_accept_argtypes.m4 +85 -0
  32. data/pgpool2/aclocal.m4 +1088 -0
  33. data/pgpool2/c-compiler.m4 +134 -0
  34. data/pgpool2/c-library.m4 +325 -0
  35. data/pgpool2/child.c +2097 -0
  36. data/pgpool2/config.guess +1532 -0
  37. data/pgpool2/config.h.in +332 -0
  38. data/pgpool2/config.sub +1640 -0
  39. data/pgpool2/configure +15752 -0
  40. data/pgpool2/configure.in +392 -0
  41. data/pgpool2/depcomp +522 -0
  42. data/pgpool2/doc/basebackup.sh +17 -0
  43. data/pgpool2/doc/pgpool-de.html +4220 -0
  44. data/pgpool2/doc/pgpool-en.html +5738 -0
  45. data/pgpool2/doc/pgpool-fr.html +4118 -0
  46. data/pgpool2/doc/pgpool-ja.css +198 -0
  47. data/pgpool2/doc/pgpool-ja.html +11279 -0
  48. data/pgpool2/doc/pgpool-zh_cn.html +4445 -0
  49. data/pgpool2/doc/pgpool.css +280 -0
  50. data/pgpool2/doc/pgpool_remote_start +13 -0
  51. data/pgpool2/doc/recovery.conf.sample +117 -0
  52. data/pgpool2/doc/tutorial-en.html +707 -0
  53. data/pgpool2/doc/tutorial-ja.html +422 -0
  54. data/pgpool2/doc/tutorial-memqcache-en.html +325 -0
  55. data/pgpool2/doc/tutorial-memqcache-ja.html +370 -0
  56. data/pgpool2/doc/tutorial-memqcache-zh_cn.html +322 -0
  57. data/pgpool2/doc/tutorial-watchdog-en.html +306 -0
  58. data/pgpool2/doc/tutorial-watchdog-ja.html +343 -0
  59. data/pgpool2/doc/tutorial-watchdog-zh_cn.html +301 -0
  60. data/pgpool2/doc/tutorial-zh_cn.html +537 -0
  61. data/pgpool2/doc/watchdog.png +0 -0
  62. data/pgpool2/doc/wd-en.html +236 -0
  63. data/pgpool2/doc/wd-en.jpg +0 -0
  64. data/pgpool2/doc/wd-ja.html +219 -0
  65. data/pgpool2/doc/wd-ja.jpg +0 -0
  66. data/pgpool2/doc/wd-zh_cn.html +201 -0
  67. data/pgpool2/doc/where_to_send_queries.odg +0 -0
  68. data/pgpool2/doc/where_to_send_queries.pdf +0 -0
  69. data/pgpool2/general.m4 +166 -0
  70. data/pgpool2/getopt_long.c +200 -0
  71. data/pgpool2/getopt_long.h +44 -0
  72. data/pgpool2/install-sh +251 -0
  73. data/pgpool2/ltmain.sh +8406 -0
  74. data/pgpool2/m4/libtool.m4 +7360 -0
  75. data/pgpool2/m4/ltoptions.m4 +368 -0
  76. data/pgpool2/m4/ltsugar.m4 +123 -0
  77. data/pgpool2/m4/ltversion.m4 +23 -0
  78. data/pgpool2/m4/lt~obsolete.m4 +92 -0
  79. data/pgpool2/main.c +2971 -0
  80. data/pgpool2/md5.c +444 -0
  81. data/pgpool2/md5.h +28 -0
  82. data/pgpool2/missing +360 -0
  83. data/pgpool2/mkinstalldirs +40 -0
  84. data/pgpool2/parser/Makefile.am +50 -0
  85. data/pgpool2/parser/Makefile.in +559 -0
  86. data/pgpool2/parser/copyfuncs.c +3310 -0
  87. data/pgpool2/parser/gram.c +39100 -0
  88. data/pgpool2/parser/gram.h +940 -0
  89. data/pgpool2/parser/gram.y +13408 -0
  90. data/pgpool2/parser/gramparse.h +74 -0
  91. data/pgpool2/parser/keywords.c +32 -0
  92. data/pgpool2/parser/keywords.h +39 -0
  93. data/pgpool2/parser/kwlist.h +425 -0
  94. data/pgpool2/parser/kwlookup.c +88 -0
  95. data/pgpool2/parser/list.c +1156 -0
  96. data/pgpool2/parser/makefuncs.c +518 -0
  97. data/pgpool2/parser/makefuncs.h +83 -0
  98. data/pgpool2/parser/memnodes.h +79 -0
  99. data/pgpool2/parser/nodes.c +29 -0
  100. data/pgpool2/parser/nodes.h +609 -0
  101. data/pgpool2/parser/outfuncs.c +5790 -0
  102. data/pgpool2/parser/parsenodes.h +2615 -0
  103. data/pgpool2/parser/parser.c +262 -0
  104. data/pgpool2/parser/parser.h +46 -0
  105. data/pgpool2/parser/pg_class.h +158 -0
  106. data/pgpool2/parser/pg_config_manual.h +273 -0
  107. data/pgpool2/parser/pg_list.h +352 -0
  108. data/pgpool2/parser/pg_trigger.h +147 -0
  109. data/pgpool2/parser/pg_wchar.h +492 -0
  110. data/pgpool2/parser/pool_memory.c +342 -0
  111. data/pgpool2/parser/pool_memory.h +77 -0
  112. data/pgpool2/parser/pool_parser.h +222 -0
  113. data/pgpool2/parser/pool_string.c +121 -0
  114. data/pgpool2/parser/pool_string.h +37 -0
  115. data/pgpool2/parser/primnodes.h +1280 -0
  116. data/pgpool2/parser/scan.c +4094 -0
  117. data/pgpool2/parser/scan.l +1451 -0
  118. data/pgpool2/parser/scanner.h +120 -0
  119. data/pgpool2/parser/scansup.c +221 -0
  120. data/pgpool2/parser/scansup.h +28 -0
  121. data/pgpool2/parser/snprintf.c +1102 -0
  122. data/pgpool2/parser/stringinfo.c +294 -0
  123. data/pgpool2/parser/stringinfo.h +178 -0
  124. data/pgpool2/parser/value.c +78 -0
  125. data/pgpool2/parser/value.h +62 -0
  126. data/pgpool2/parser/wchar.c +2048 -0
  127. data/pgpool2/pcp.conf.sample +28 -0
  128. data/pgpool2/pcp/Makefile.am +40 -0
  129. data/pgpool2/pcp/Makefile.in +771 -0
  130. data/pgpool2/pcp/libpcp_ext.h +250 -0
  131. data/pgpool2/pcp/md5.c +444 -0
  132. data/pgpool2/pcp/md5.h +28 -0
  133. data/pgpool2/pcp/pcp.c +1652 -0
  134. data/pgpool2/pcp/pcp.h +61 -0
  135. data/pgpool2/pcp/pcp_attach_node.c +172 -0
  136. data/pgpool2/pcp/pcp_detach_node.c +185 -0
  137. data/pgpool2/pcp/pcp_error.c +87 -0
  138. data/pgpool2/pcp/pcp_node_count.c +160 -0
  139. data/pgpool2/pcp/pcp_node_info.c +198 -0
  140. data/pgpool2/pcp/pcp_pool_status.c +166 -0
  141. data/pgpool2/pcp/pcp_proc_count.c +166 -0
  142. data/pgpool2/pcp/pcp_proc_info.c +261 -0
  143. data/pgpool2/pcp/pcp_promote_node.c +185 -0
  144. data/pgpool2/pcp/pcp_recovery_node.c +172 -0
  145. data/pgpool2/pcp/pcp_stop_pgpool.c +179 -0
  146. data/pgpool2/pcp/pcp_stream.c +385 -0
  147. data/pgpool2/pcp/pcp_stream.h +52 -0
  148. data/pgpool2/pcp/pcp_systemdb_info.c +194 -0
  149. data/pgpool2/pcp/pcp_watchdog_info.c +211 -0
  150. data/pgpool2/pcp_child.c +1493 -0
  151. data/pgpool2/pg_md5.c +305 -0
  152. data/pgpool2/pgpool.8.in +121 -0
  153. data/pgpool2/pgpool.conf +553 -0
  154. data/pgpool2/pgpool.conf.sample +666 -0
  155. data/pgpool2/pgpool.conf.sample-master-slave +665 -0
  156. data/pgpool2/pgpool.conf.sample-replication +664 -0
  157. data/pgpool2/pgpool.conf.sample-stream +664 -0
  158. data/pgpool2/pgpool.spec +264 -0
  159. data/pgpool2/pgpool_adm/TODO +7 -0
  160. data/pgpool2/pgpool_adm/pgpool_adm--1.0.sql +85 -0
  161. data/pgpool2/pgpool_adm/pgpool_adm.c +558 -0
  162. data/pgpool2/pgpool_adm/pgpool_adm.control +5 -0
  163. data/pgpool2/pgpool_adm/pgpool_adm.h +46 -0
  164. data/pgpool2/pgpool_adm/pgpool_adm.sql.in +85 -0
  165. data/pgpool2/pool.h +655 -0
  166. data/pgpool2/pool_auth.c +1390 -0
  167. data/pgpool2/pool_config.c +5007 -0
  168. data/pgpool2/pool_config.h +284 -0
  169. data/pgpool2/pool_config.l +3281 -0
  170. data/pgpool2/pool_config_md5.c +29 -0
  171. data/pgpool2/pool_connection_pool.c +812 -0
  172. data/pgpool2/pool_error.c +242 -0
  173. data/pgpool2/pool_globals.c +27 -0
  174. data/pgpool2/pool_hba.c +1723 -0
  175. data/pgpool2/pool_hba.conf.sample +67 -0
  176. data/pgpool2/pool_ip.c +567 -0
  177. data/pgpool2/pool_ip.h +65 -0
  178. data/pgpool2/pool_ipc.h +38 -0
  179. data/pgpool2/pool_lobj.c +242 -0
  180. data/pgpool2/pool_lobj.h +32 -0
  181. data/pgpool2/pool_memqcache.c +3818 -0
  182. data/pgpool2/pool_memqcache.h +268 -0
  183. data/pgpool2/pool_params.c +163 -0
  184. data/pgpool2/pool_passwd.c +249 -0
  185. data/pgpool2/pool_passwd.h +41 -0
  186. data/pgpool2/pool_path.c +193 -0
  187. data/pgpool2/pool_path.h +81 -0
  188. data/pgpool2/pool_process_context.c +247 -0
  189. data/pgpool2/pool_process_context.h +62 -0
  190. data/pgpool2/pool_process_query.c +5001 -0
  191. data/pgpool2/pool_process_reporting.c +1671 -0
  192. data/pgpool2/pool_process_reporting.h +44 -0
  193. data/pgpool2/pool_proto2.c +671 -0
  194. data/pgpool2/pool_proto_modules.c +3524 -0
  195. data/pgpool2/pool_proto_modules.h +185 -0
  196. data/pgpool2/pool_query_cache.c +1020 -0
  197. data/pgpool2/pool_query_context.c +1871 -0
  198. data/pgpool2/pool_query_context.h +105 -0
  199. data/pgpool2/pool_relcache.c +284 -0
  200. data/pgpool2/pool_relcache.h +78 -0
  201. data/pgpool2/pool_rewrite_outfuncs.c +9060 -0
  202. data/pgpool2/pool_rewrite_query.c +715 -0
  203. data/pgpool2/pool_rewrite_query.h +192 -0
  204. data/pgpool2/pool_select_walker.c +1150 -0
  205. data/pgpool2/pool_select_walker.h +68 -0
  206. data/pgpool2/pool_sema.c +161 -0
  207. data/pgpool2/pool_session_context.c +952 -0
  208. data/pgpool2/pool_session_context.h +203 -0
  209. data/pgpool2/pool_shmem.c +185 -0
  210. data/pgpool2/pool_signal.c +158 -0
  211. data/pgpool2/pool_signal.h +61 -0
  212. data/pgpool2/pool_ssl.c +339 -0
  213. data/pgpool2/pool_stream.c +962 -0
  214. data/pgpool2/pool_stream.h +61 -0
  215. data/pgpool2/pool_system.c +659 -0
  216. data/pgpool2/pool_timestamp.c +1215 -0
  217. data/pgpool2/pool_timestamp.h +38 -0
  218. data/pgpool2/pool_type.h +171 -0
  219. data/pgpool2/pool_worker_child.c +384 -0
  220. data/pgpool2/ps_status.c +404 -0
  221. data/pgpool2/recovery.c +435 -0
  222. data/pgpool2/redhat/pgpool.conf.sample.patch +52 -0
  223. data/pgpool2/redhat/pgpool.init +201 -0
  224. data/pgpool2/redhat/pgpool.sysconfig +7 -0
  225. data/pgpool2/redhat/rpm_installer/basebackup-replication.sh +53 -0
  226. data/pgpool2/redhat/rpm_installer/basebackup-stream.sh +55 -0
  227. data/pgpool2/redhat/rpm_installer/config_for_script +17 -0
  228. data/pgpool2/redhat/rpm_installer/failover.sh +64 -0
  229. data/pgpool2/redhat/rpm_installer/getsources.sh +141 -0
  230. data/pgpool2/redhat/rpm_installer/install.sh +1363 -0
  231. data/pgpool2/redhat/rpm_installer/pgpool_recovery_pitr +47 -0
  232. data/pgpool2/redhat/rpm_installer/pgpool_remote_start +15 -0
  233. data/pgpool2/redhat/rpm_installer/recovery.conf +4 -0
  234. data/pgpool2/redhat/rpm_installer/uninstall.sh +57 -0
  235. data/pgpool2/sample/dist_def_pgbench.sql +73 -0
  236. data/pgpool2/sample/pgpool.pam +3 -0
  237. data/pgpool2/sample/pgpool_recovery +20 -0
  238. data/pgpool2/sample/pgpool_recovery_pitr +19 -0
  239. data/pgpool2/sample/pgpool_remote_start +13 -0
  240. data/pgpool2/sample/replicate_def_pgbench.sql +18 -0
  241. data/pgpool2/sql/insert_lock.sql +15 -0
  242. data/pgpool2/sql/pgpool-recovery/pgpool-recovery.c +280 -0
  243. data/pgpool2/sql/pgpool-recovery/pgpool-recovery.sql.in +19 -0
  244. data/pgpool2/sql/pgpool-recovery/pgpool_recovery--1.0.sql +24 -0
  245. data/pgpool2/sql/pgpool-recovery/pgpool_recovery.control +5 -0
  246. data/pgpool2/sql/pgpool-recovery/uninstall_pgpool-recovery.sql +3 -0
  247. data/pgpool2/sql/pgpool-regclass/pgpool-regclass.c +206 -0
  248. data/pgpool2/sql/pgpool-regclass/pgpool-regclass.sql.in +4 -0
  249. data/pgpool2/sql/pgpool-regclass/pgpool_regclass--1.0.sql +7 -0
  250. data/pgpool2/sql/pgpool-regclass/pgpool_regclass.control +5 -0
  251. data/pgpool2/sql/pgpool-regclass/uninstall_pgpool-regclass.sql +1 -0
  252. data/pgpool2/sql/system_db.sql +38 -0
  253. data/pgpool2/strlcpy.c +85 -0
  254. data/pgpool2/test/C/test_extended.c +98 -0
  255. data/pgpool2/test/jdbc/.cvsignore +2 -0
  256. data/pgpool2/test/jdbc/AutoCommitTest.java +45 -0
  257. data/pgpool2/test/jdbc/BatchTest.java +55 -0
  258. data/pgpool2/test/jdbc/ColumnTest.java +60 -0
  259. data/pgpool2/test/jdbc/CreateTempTableTest.java +48 -0
  260. data/pgpool2/test/jdbc/InsertTest.java +34 -0
  261. data/pgpool2/test/jdbc/LockTest.java +36 -0
  262. data/pgpool2/test/jdbc/PgpoolTest.java +75 -0
  263. data/pgpool2/test/jdbc/README.euc_jp +73 -0
  264. data/pgpool2/test/jdbc/RunTest.java +83 -0
  265. data/pgpool2/test/jdbc/SelectTest.java +37 -0
  266. data/pgpool2/test/jdbc/UpdateTest.java +32 -0
  267. data/pgpool2/test/jdbc/expected/CreateTempTable +1 -0
  268. data/pgpool2/test/jdbc/expected/autocommit +10 -0
  269. data/pgpool2/test/jdbc/expected/batch +1 -0
  270. data/pgpool2/test/jdbc/expected/column +100 -0
  271. data/pgpool2/test/jdbc/expected/insert +1 -0
  272. data/pgpool2/test/jdbc/expected/lock +100 -0
  273. data/pgpool2/test/jdbc/expected/select +2 -0
  274. data/pgpool2/test/jdbc/expected/update +1 -0
  275. data/pgpool2/test/jdbc/pgpool.properties +7 -0
  276. data/pgpool2/test/jdbc/prepare.sql +54 -0
  277. data/pgpool2/test/jdbc/run.sh +6 -0
  278. data/pgpool2/test/parser/.cvsignore +6 -0
  279. data/pgpool2/test/parser/README +32 -0
  280. data/pgpool2/test/parser/expected/copy.out +17 -0
  281. data/pgpool2/test/parser/expected/create.out +64 -0
  282. data/pgpool2/test/parser/expected/cursor.out +37 -0
  283. data/pgpool2/test/parser/expected/delete.out +10 -0
  284. data/pgpool2/test/parser/expected/drop.out +12 -0
  285. data/pgpool2/test/parser/expected/insert.out +13 -0
  286. data/pgpool2/test/parser/expected/misc.out +28 -0
  287. data/pgpool2/test/parser/expected/prepare.out +4 -0
  288. data/pgpool2/test/parser/expected/privileges.out +31 -0
  289. data/pgpool2/test/parser/expected/scanner.out +30 -0
  290. data/pgpool2/test/parser/expected/select.out +89 -0
  291. data/pgpool2/test/parser/expected/transaction.out +38 -0
  292. data/pgpool2/test/parser/expected/update.out +11 -0
  293. data/pgpool2/test/parser/expected/v84.out +37 -0
  294. data/pgpool2/test/parser/expected/v90.out +25 -0
  295. data/pgpool2/test/parser/expected/var.out +22 -0
  296. data/pgpool2/test/parser/input/alter.sql +2 -0
  297. data/pgpool2/test/parser/input/copy.sql +17 -0
  298. data/pgpool2/test/parser/input/create.sql +64 -0
  299. data/pgpool2/test/parser/input/cursor.sql +37 -0
  300. data/pgpool2/test/parser/input/delete.sql +10 -0
  301. data/pgpool2/test/parser/input/drop.sql +12 -0
  302. data/pgpool2/test/parser/input/insert.sql +13 -0
  303. data/pgpool2/test/parser/input/misc.sql +28 -0
  304. data/pgpool2/test/parser/input/prepare.sql +4 -0
  305. data/pgpool2/test/parser/input/privileges.sql +31 -0
  306. data/pgpool2/test/parser/input/scanner.sql +34 -0
  307. data/pgpool2/test/parser/input/select.sql +89 -0
  308. data/pgpool2/test/parser/input/transaction.sql +38 -0
  309. data/pgpool2/test/parser/input/update.sql +11 -0
  310. data/pgpool2/test/parser/input/v84.sql +37 -0
  311. data/pgpool2/test/parser/input/v90.sql +38 -0
  312. data/pgpool2/test/parser/input/var.sql +22 -0
  313. data/pgpool2/test/parser/main.c +96 -0
  314. data/pgpool2/test/parser/parse_schedule +16 -0
  315. data/pgpool2/test/parser/pool.h +13 -0
  316. data/pgpool2/test/parser/run-test +62 -0
  317. data/pgpool2/test/pdo-test/README.euc_jp +58 -0
  318. data/pgpool2/test/pdo-test/SQLlist/test1.sql +3 -0
  319. data/pgpool2/test/pdo-test/SQLlist/test2.sql +3 -0
  320. data/pgpool2/test/pdo-test/collections.inc +11 -0
  321. data/pgpool2/test/pdo-test/def.inc +7 -0
  322. data/pgpool2/test/pdo-test/log.txt +0 -0
  323. data/pgpool2/test/pdo-test/mod/database.inc +36 -0
  324. data/pgpool2/test/pdo-test/mod/def.inc +0 -0
  325. data/pgpool2/test/pdo-test/mod/errorhandler.inc +27 -0
  326. data/pgpool2/test/pdo-test/pdotest.php +11 -0
  327. data/pgpool2/test/pdo-test/regsql.inc +56 -0
  328. data/pgpool2/test/pgpool_setup +898 -0
  329. data/pgpool2/test/regression/README +39 -0
  330. data/pgpool2/test/regression/clean.sh +21 -0
  331. data/pgpool2/test/regression/libs.sh +16 -0
  332. data/pgpool2/test/regression/regress.sh +166 -0
  333. data/pgpool2/test/regression/tests/001.load_balance/test.sh +128 -0
  334. data/pgpool2/test/regression/tests/002.native_replication/PgTester.java +47 -0
  335. data/pgpool2/test/regression/tests/002.native_replication/create.sql +6 -0
  336. data/pgpool2/test/regression/tests/002.native_replication/test.sh +71 -0
  337. data/pgpool2/test/regression/tests/003.failover/expected.r +6 -0
  338. data/pgpool2/test/regression/tests/003.failover/expected.s +6 -0
  339. data/pgpool2/test/regression/tests/003.failover/test.sh +45 -0
  340. data/pgpool2/test/regression/tests/004.watchdog/master.conf +12 -0
  341. data/pgpool2/test/regression/tests/004.watchdog/standby.conf +19 -0
  342. data/pgpool2/test/regression/tests/004.watchdog/test.sh +52 -0
  343. data/pgpool2/test/regression/tests/050.bug58/test.sh +50 -0
  344. data/pgpool2/test/regression/tests/051.bug60/bug.sql +12 -0
  345. data/pgpool2/test/regression/tests/051.bug60/database-clean.sql +6 -0
  346. data/pgpool2/test/regression/tests/051.bug60/database-setup.sql +28 -0
  347. data/pgpool2/test/regression/tests/051.bug60/test.sh +79 -0
  348. data/pgpool2/test/regression/tests/052.do_query/test.sh +44 -0
  349. data/pgpool2/test/regression/tests/053.insert_lock_hangs/test.sh +81 -0
  350. data/pgpool2/test/regression/tests/054.postgres_fdw/test.sh +67 -0
  351. data/pgpool2/test/regression/tests/055.backend_all_down/test.sh +52 -0
  352. data/pgpool2/test/regression/tests/056.bug63/jdbctest2.java +66 -0
  353. data/pgpool2/test/regression/tests/056.bug63/test.sh +47 -0
  354. data/pgpool2/test/regression/tests/057.bug61/test.sh +40 -0
  355. data/pgpool2/test/regression/tests/058.bug68/jdbctest3.java +45 -0
  356. data/pgpool2/test/regression/tests/058.bug68/test.sh +47 -0
  357. data/pgpool2/test/timestamp/expected/insert.out +16 -0
  358. data/pgpool2/test/timestamp/expected/misc.out +3 -0
  359. data/pgpool2/test/timestamp/expected/update.out +6 -0
  360. data/pgpool2/test/timestamp/input/insert.sql +16 -0
  361. data/pgpool2/test/timestamp/input/misc.sql +3 -0
  362. data/pgpool2/test/timestamp/input/update.sql +6 -0
  363. data/pgpool2/test/timestamp/main.c +129 -0
  364. data/pgpool2/test/timestamp/parse_schedule +3 -0
  365. data/pgpool2/test/timestamp/run-test +69 -0
  366. data/pgpool2/version.h +1 -0
  367. data/pgpool2/watchdog/Makefile.am +17 -0
  368. data/pgpool2/watchdog/Makefile.in +505 -0
  369. data/pgpool2/watchdog/test/stab.c +266 -0
  370. data/pgpool2/watchdog/test/test.c +85 -0
  371. data/pgpool2/watchdog/test/wd_child_t.c +87 -0
  372. data/pgpool2/watchdog/test/wd_lifecheck_t.c +87 -0
  373. data/pgpool2/watchdog/test/wd_packet_t.c +87 -0
  374. data/pgpool2/watchdog/test/wd_ping_t.c +20 -0
  375. data/pgpool2/watchdog/watchdog.c +408 -0
  376. data/pgpool2/watchdog/watchdog.h +209 -0
  377. data/pgpool2/watchdog/wd_child.c +444 -0
  378. data/pgpool2/watchdog/wd_ext.h +123 -0
  379. data/pgpool2/watchdog/wd_heartbeat.c +577 -0
  380. data/pgpool2/watchdog/wd_if.c +216 -0
  381. data/pgpool2/watchdog/wd_init.c +126 -0
  382. data/pgpool2/watchdog/wd_interlock.c +347 -0
  383. data/pgpool2/watchdog/wd_lifecheck.c +512 -0
  384. data/pgpool2/watchdog/wd_list.c +429 -0
  385. data/pgpool2/watchdog/wd_packet.c +1159 -0
  386. data/pgpool2/watchdog/wd_ping.c +330 -0
  387. data/pgpool2/ylwrap +223 -0
  388. data/pgsql/presto_client.py +346 -0
  389. data/pgsql/prestogres.py +156 -0
  390. data/pgsql/setup_functions.sql +21 -0
  391. data/pgsql/setup_language.sql +3 -0
  392. data/prestogres.gemspec +23 -0
  393. 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(&current_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(&current_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
+ }