prestogres 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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
+ }