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
data/pgpool2/pool_ip.h ADDED
@@ -0,0 +1,65 @@
1
+ /* -*-pgsql-c-*- */
2
+ /*
3
+ *
4
+ * $Header$
5
+ *
6
+ * This file was imported from PostgreSQL 8.0.8 source code.
7
+ * See below for the copyright and description.
8
+ *
9
+ * pgpool: a language independent connection pool server for PostgreSQL
10
+ * written by Tatsuo Ishii
11
+ *
12
+ * Portions Copyright (c) 2003-2008 PgPool Global Development Group
13
+ * Portions Copyright (c) 2003-2005, PostgreSQL Global Development Group
14
+ *
15
+ * Permission to use, copy, modify, and distribute this software and
16
+ * its documentation for any purpose and without fee is hereby
17
+ * granted, provided that the above copyright notice appear in all
18
+ * copies and that both that copyright notice and this permission
19
+ * notice appear in supporting documentation, and that the name of the
20
+ * author not be used in advertising or publicity pertaining to
21
+ * distribution of the software without specific, written prior
22
+ * permission. The author makes no representations about the
23
+ * suitability of this software for any purpose. It is provided "as
24
+ * is" without express or implied warranty.
25
+ *
26
+ * pool_ip.h.: Definitions for IPv6-aware network access.
27
+ *
28
+ */
29
+
30
+ #ifndef POOL_IP_H
31
+ #define POOL_IP_H
32
+
33
+ #include "pool_type.h"
34
+
35
+ extern int getaddrinfo_all(const char *hostname, const char *servname,
36
+ const struct addrinfo * hintp,
37
+ struct addrinfo ** result);
38
+ extern void freeaddrinfo_all(int hint_ai_family, struct addrinfo * ai);
39
+
40
+ extern int getnameinfo_all(const struct sockaddr_storage * addr, int salen,
41
+ char *node, int nodelen,
42
+ char *service, int servicelen,
43
+ int flags);
44
+
45
+ extern int rangeSockAddr(const struct sockaddr_storage * addr,
46
+ const struct sockaddr_storage * netaddr,
47
+ const struct sockaddr_storage * netmask);
48
+
49
+ extern int SockAddr_cidr_mask(struct sockaddr_storage * mask,
50
+ char *numbits, int family);
51
+
52
+ /* imported from PostgreSQL getaddrinfo.c */
53
+ #ifndef HAVE_GAI_STRERROR
54
+ extern const char * gai_strerror(int errcode);
55
+ #endif /* HAVE_GAI_STRERROR */
56
+
57
+ #ifdef HAVE_IPV6
58
+ extern void promote_v4_to_v6_addr(struct sockaddr_storage * addr);
59
+ extern void promote_v4_to_v6_mask(struct sockaddr_storage * addr);
60
+ #endif
61
+
62
+ #define IS_AF_INET(fam) ((fam) == AF_INET)
63
+ #define IS_AF_UNIX(fam) ((fam) == AF_UNIX)
64
+
65
+ #endif /* IP_H */
@@ -0,0 +1,38 @@
1
+ /* -*-pgsql-c-*- */
2
+ /*
3
+ * $Header$
4
+ *
5
+ * pgpool: a language independent connection pool server for PostgreSQL
6
+ * written by Tatsuo Ishii
7
+ *
8
+ * Portions Copyright (c) 2003-2008, PgPool Global Development Group
9
+ * Portions Copyright (c) 2003-2004, PostgreSQL Global Development Group
10
+ *
11
+ * Permission to use, copy, modify, and distribute this software and
12
+ * its documentation for any purpose and without fee is hereby
13
+ * granted, provided that the above copyright notice appear in all
14
+ * copies and that both that copyright notice and this permission
15
+ * notice appear in supporting documentation, and that the name of the
16
+ * author not be used in advertising or publicity pertaining to
17
+ * distribution of the software without specific, written prior
18
+ * permission. The author makes no representations about the
19
+ * suitability of this software for any purpose. It is provided "as
20
+ * is" without express or implied warranty.
21
+ *
22
+ */
23
+ #ifndef IPC_H
24
+ #define IPC_H
25
+
26
+
27
+ typedef unsigned long Datum; /* XXX sizeof(long) >= sizeof(void *) */
28
+
29
+
30
+ #define IPCProtection (0600) /* access/modify by user only */
31
+
32
+
33
+ extern void shmem_exit(int code);
34
+ extern void on_shmem_exit(void (*function) (int code, Datum arg), Datum arg);
35
+ extern void on_exit_reset(void);
36
+
37
+
38
+ #endif /* IPC_H */
@@ -0,0 +1,242 @@
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-2010 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
+ * pool_lobj.c: Transparently translate lo_creat call to lo_create so
22
+ * that large objects replicated safely.
23
+ * lo_create anyway.
24
+ */
25
+ #include "config.h"
26
+ #include <stdlib.h>
27
+ #include <unistd.h>
28
+ #include <string.h>
29
+ #include <netinet/in.h>
30
+
31
+ #include "pool.h"
32
+ #include "pool_lobj.h"
33
+ #include "pool_relcache.h"
34
+ #include "pool_config.h"
35
+
36
+ /*
37
+ * Rewrite lo_creat call to lo_create call if:
38
+ * 1) it's a lo_creat function call
39
+ * 2) PostgreSQL has lo_create
40
+ * 3) In replication mode
41
+ * 4) lobj_lock_table exists and writable to everyone
42
+ *
43
+ * The argument for lo_create is created by fetching max(loid)+1 from
44
+ * pg_largeobject. To avoid race condition, we lock lobj_lock_table.
45
+ *
46
+ * Caller should call this only if protocol is V3 or higher(for
47
+ * now. There's no reason for this function not working with V2
48
+ * protocol). Return value is a rewritten packet without kind and
49
+ * length. This is allocated in a static memory. New packet length is
50
+ * set to *len.
51
+ */
52
+ char *pool_rewrite_lo_creat(char kind, char *packet, int packet_len,
53
+ POOL_CONNECTION *frontend, POOL_CONNECTION_POOL *backend, int* len)
54
+ {
55
+ #define LO_CREAT_OID_QUERY "SELECT oid FROM pg_catalog.pg_proc WHERE proname = 'lo_creat' and pronamespace = (SELECT oid FROM pg_catalog.pg_namespace WHERE nspname = 'pg_catalog')"
56
+
57
+ #define LO_CREATE_OID_QUERY "SELECT oid FROM pg_catalog.pg_proc WHERE proname = 'lo_create' and pronamespace = (SELECT oid FROM pg_catalog.pg_namespace WHERE nspname = 'pg_catalog')"
58
+
59
+ #define LO_CREATE_PACKET_LENGTH sizeof(int32)*3+sizeof(int16)*4
60
+
61
+ #define LOCK_QUERY "LOCK TABLE %s IN SHARE ROW EXCLUSIVE MODE"
62
+
63
+ #define GET_MAX_LOBJ_KEY "SELECT coalesce(max(loid)::INTEGER, 0)+1 FROM pg_catalog.pg_largeobject"
64
+
65
+ static char rewritten_packet[LO_CREATE_PACKET_LENGTH];
66
+
67
+ static POOL_RELCACHE *relcache_lo_creat;
68
+ static POOL_RELCACHE *relcache_lo_create;
69
+
70
+ int lo_creat_oid;
71
+ int lo_create_oid;
72
+ int orig_fcall_oid;
73
+ POOL_STATUS status;
74
+ char qbuf[1024];
75
+ char *p;
76
+ POOL_SELECT_RESULT *result;
77
+ int lobjid;
78
+ int32 int32val;
79
+ int16 int16val;
80
+ int16 result_format_code;
81
+
82
+ if (kind != 'F')
83
+ return NULL; /* not function call */
84
+
85
+ if (!strcmp(pool_config->lobj_lock_table,""))
86
+ return NULL; /* no lock table */
87
+
88
+ if (!REPLICATION)
89
+ return NULL; /* not in replication mode */
90
+
91
+ /*
92
+ * If relcache does not exist, create it.
93
+ */
94
+ if (!relcache_lo_creat)
95
+ {
96
+ relcache_lo_creat = pool_create_relcache(1, LO_CREAT_OID_QUERY,
97
+ int_register_func, int_unregister_func,
98
+ false);
99
+ if (relcache_lo_creat == NULL)
100
+ {
101
+ pool_error("pool_check_lo_creat: pool_create_relcache error");
102
+ return NULL;
103
+ }
104
+ }
105
+
106
+ /*
107
+ * Get lo_creat oid
108
+ */
109
+ lo_creat_oid = (int)(intptr_t)pool_search_relcache(relcache_lo_creat, backend, "pg_proc");
110
+
111
+ memmove(&orig_fcall_oid, packet, sizeof(int32));
112
+ orig_fcall_oid = ntohl(orig_fcall_oid);
113
+
114
+ pool_debug("orig_fcall_oid:% d lo_creat_oid: %d", orig_fcall_oid, lo_creat_oid);
115
+ /*
116
+ * This function call is calling lo_creat? */
117
+ if (orig_fcall_oid != lo_creat_oid)
118
+ return NULL;
119
+
120
+ /*
121
+ * If relcache does not exist, create it.
122
+ */
123
+ if (!relcache_lo_create)
124
+ {
125
+ relcache_lo_create = pool_create_relcache(1, LO_CREATE_OID_QUERY,
126
+ int_register_func, int_unregister_func,
127
+ false);
128
+ if (relcache_lo_create == NULL)
129
+ {
130
+ pool_error("pool_check_lo_creat: pool_create_relcache error");
131
+ return NULL;
132
+ }
133
+ }
134
+
135
+ /*
136
+ * Get lo_create oid
137
+ */
138
+ lo_create_oid = (int)(intptr_t)pool_search_relcache(relcache_lo_create, backend, "pg_proc");
139
+
140
+ pool_debug("pool_check_lo_creat: lo_creat_oid: %d lo_create_oid: %d",
141
+ lo_creat_oid, lo_create_oid);
142
+
143
+ /*
144
+ * Parse input packet
145
+ */
146
+ memmove(&int16val, packet+packet_len-sizeof(int16), sizeof(int16));
147
+ result_format_code = ntohs(int16val);
148
+
149
+ /* sanity check */
150
+ if (result_format_code != 0 && result_format_code != 1)
151
+ {
152
+ pool_error("pool_rewrite_lo_creat: wrong return format code: %d", int16val);
153
+ return NULL;
154
+ }
155
+
156
+ pool_debug("pool_rewrite_lo_creat: return format code: %d", int16val);
157
+
158
+ /*
159
+ * Ok, do it...
160
+ */
161
+ /* issue lock table command to lob_lock_table */
162
+ snprintf(qbuf, sizeof(qbuf), "LOCK TABLE %s IN SHARE ROW EXCLUSIVE MODE", pool_config->lobj_lock_table);
163
+ per_node_statement_log(backend, MASTER_NODE_ID, qbuf);
164
+ status = do_command(frontend, MASTER(backend), qbuf, MAJOR(backend), MASTER_CONNECTION(backend)->pid,
165
+ MASTER_CONNECTION(backend)->key, 0);
166
+ if (status == POOL_END)
167
+ {
168
+ pool_error("pool_rewrite_lo_creat: failed to execute LOCK");
169
+ return NULL;
170
+ }
171
+
172
+ /*
173
+ * If transaction state is E, do_command failed to execute command
174
+ */
175
+ if (TSTATE(backend, MASTER_NODE_ID) == 'E')
176
+ {
177
+ pool_log("pool_check_lo_creat: failed to execute: %s", qbuf);
178
+ return NULL;
179
+ }
180
+
181
+ /* get max lobj id */
182
+ per_node_statement_log(backend, MASTER_NODE_ID, GET_MAX_LOBJ_KEY);
183
+ status = do_query(MASTER(backend), GET_MAX_LOBJ_KEY, &result, MAJOR(backend));
184
+ if (status == POOL_END)
185
+ {
186
+ pool_error("pool_rewrite_lo_creat: do_query failed");
187
+ return NULL;
188
+ }
189
+
190
+ if (!result)
191
+ {
192
+ pool_log("pool_check_lo_creat: failed to execute: %s", GET_MAX_LOBJ_KEY);
193
+ return NULL;
194
+ }
195
+
196
+ lobjid = atoi(result->data[0]);
197
+ pool_debug("lobjid:%d", lobjid);
198
+ free_select_result(result);
199
+
200
+ /* sanity check */
201
+ if (lobjid <= 0)
202
+ {
203
+ pool_error("pool_rewrite_lo_creat: wrong lob id: %d", lobjid);
204
+ return NULL;
205
+ }
206
+
207
+ /*
208
+ * Create lo_create call packet
209
+ */
210
+ p = rewritten_packet;
211
+
212
+ *len = LO_CREATE_PACKET_LENGTH;
213
+
214
+ int32val = htonl(lo_create_oid);
215
+ memmove(p,&int32val, sizeof(int32)); /* lo_create oid */
216
+ p += sizeof(int32);
217
+
218
+ int16val = htons(1);
219
+ memmove(p,&int16val, sizeof(int16)); /* number of argument format code */
220
+ p += sizeof(int16);
221
+
222
+ int16val = htons(1);
223
+ memmove(p,&int16val, sizeof(int16)); /* format code */
224
+ p += sizeof(int16);
225
+
226
+ int16val = htons(1);
227
+ memmove(p,&int16val, sizeof(int16)); /* number of arguments */
228
+ p += sizeof(int16);
229
+
230
+ int32val = htonl(4);
231
+ memmove(p,&int32val, sizeof(int32)); /* argument length */
232
+ p += sizeof(int32);
233
+
234
+ int32val = htonl(lobjid);
235
+ memmove(p,&int32val, sizeof(int32)); /* argument(lobj id) */
236
+ p += sizeof(int32);
237
+
238
+ int16val = htons(result_format_code);
239
+ memmove(p,&int16val, sizeof(int16)); /* result format code */
240
+
241
+ return rewritten_packet;
242
+ }
@@ -0,0 +1,32 @@
1
+ /* -*-pgsql-c-*- */
2
+ /*
3
+ *
4
+ * $Header$
5
+ *
6
+ * pgpool: a language independent connection pool server for PostgreSQL
7
+ * written by Tatsuo Ishii
8
+ *
9
+ * Copyright (c) 2003-2010 PgPool Global Development Group
10
+ *
11
+ * Permission to use, copy, modify, and distribute this software and
12
+ * its documentation for any purpose and without fee is hereby
13
+ * granted, provided that the above copyright notice appear in all
14
+ * copies and that both that copyright notice and this permission
15
+ * notice appear in supporting documentation, and that the name of the
16
+ * author not be used in advertising or publicity pertaining to
17
+ * distribution of the software without specific, written prior
18
+ * permission. The author makes no representations about the
19
+ * suitability of this software for any purpose. It is provided "as
20
+ * is" without express or implied warranty.
21
+ *
22
+ * pool_lobj.h.: pool_lobj.c related header file
23
+ *
24
+ */
25
+
26
+ #ifndef POOL_LOBJ_H
27
+ #define POOL_LOBJ_H
28
+ #include "pool.h"
29
+
30
+ extern char *pool_rewrite_lo_creat(char kind, char *packet, int packet_len, POOL_CONNECTION *frontend, POOL_CONNECTION_POOL *backend, int* len);
31
+
32
+ #endif /* POOL_LOBJ_H */
@@ -0,0 +1,3818 @@
1
+ /* -*-pgsql-c-*- */
2
+ /*
3
+ * pgpool: a language independent connection pool server for PostgreSQL
4
+ * written by Tatsuo Ishii
5
+ *
6
+ * Copyright (c) 2003-2013 PgPool Global Development Group
7
+ *
8
+ * Permission to use, copy, modify, and distribute this software and
9
+ * its documentation for any purpose and without fee is hereby
10
+ * granted, provided that the above copyright notice appear in all
11
+ * copies and that both that copyright notice and this permission
12
+ * notice appear in supporting documentation, and that the name of the
13
+ * author not be used in advertising or publicity pertaining to
14
+ * distribution of the software without specific, written prior
15
+ * permission. The author makes no representations about the
16
+ * suitability of this software for any purpose. It is provided "as
17
+ * is" without express or implied warranty.
18
+ *
19
+ * pool_memqcache.c: query cache on shmem or memcached
20
+ *
21
+ */
22
+ #define DATABASE_TO_OID_QUERY "SELECT oid FROM pg_database WHERE datname = '%s'"
23
+
24
+ #include "pool.h"
25
+
26
+ #include <stdio.h>
27
+ #include <string.h>
28
+ #include <unistd.h>
29
+ #include <sys/file.h>
30
+ #include <sys/stat.h>
31
+ #include <sys/types.h>
32
+ #include <fcntl.h>
33
+ #include <errno.h>
34
+ #include <string.h>
35
+ #include <stdlib.h>
36
+ #include <ctype.h>
37
+ #include <arpa/inet.h>
38
+ #include <dirent.h>
39
+
40
+ #ifdef USE_MEMCACHED
41
+ #include <libmemcached/memcached.h>
42
+ #endif
43
+
44
+ #include "md5.h"
45
+ #include "pool_config.h"
46
+ #include "pool_stream.h"
47
+ #include "pool_proto_modules.h"
48
+ #include "pool_memqcache.h"
49
+ #include "parser/parsenodes.h"
50
+ #include "pool_session_context.h"
51
+ #include "pool_relcache.h"
52
+ #include "pool_select_walker.h"
53
+ #include "pool_stream.h"
54
+ #include "pool_proto_modules.h"
55
+
56
+ #ifdef USE_MEMCACHED
57
+ memcached_st *memc;
58
+ #endif
59
+
60
+ static char* encode_key(const char *s, char *buf, POOL_CONNECTION_POOL *backend);
61
+ #ifdef DEBUG
62
+ static void dump_cache_data(const char *data, size_t len);
63
+ #endif
64
+ static int pool_commit_cache(POOL_CONNECTION_POOL *backend, char *query, char *data, size_t datalen, int num_oids, int *oids);
65
+ static int pool_fetch_cache(POOL_CONNECTION_POOL *backend, const char *query, char **buf, size_t *len);
66
+ static int send_cached_messages(POOL_CONNECTION *frontend, const char *qcache, int qcachelen);
67
+ static void send_message(POOL_CONNECTION *conn, char kind, int len, const char *data);
68
+ #ifdef USE_MEMCACHED
69
+ static int delete_cache_on_memcached(const char *key);
70
+ #endif
71
+ static int pool_get_dml_table_oid(int **oid);
72
+ static int pool_get_dropdb_table_oids(int **oids, int dboid);
73
+ static void pool_discard_dml_table_oid(void);
74
+ static void pool_invalidate_query_cache(int num_table_oids, int *table_oid, bool unlink, int dboid);
75
+ static int pool_get_database_oid(void);
76
+ static void pool_add_table_oid_map(POOL_CACHEKEY *cachkey, int num_table_oids, int *table_oids);
77
+ static void pool_reset_memqcache_buffer(void);
78
+ static POOL_CACHEID *pool_add_item_shmem_cache(POOL_QUERY_HASH *query_hash, char *data, int size);
79
+ static POOL_CACHEID *pool_find_item_on_shmem_cache(POOL_QUERY_HASH *query_hash);
80
+ static char *pool_get_item_shmem_cache(POOL_QUERY_HASH *query_hash, int *size, int *sts);
81
+ static POOL_QUERY_CACHE_ARRAY * pool_add_query_cache_array(POOL_QUERY_CACHE_ARRAY *cache_array, POOL_TEMP_QUERY_CACHE *cache);
82
+ static void pool_add_temp_query_cache(POOL_TEMP_QUERY_CACHE *temp_cache, char kind, char *data, int data_len);
83
+ static void pool_add_oids_temp_query_cache(POOL_TEMP_QUERY_CACHE *temp_cache, int num_oids, int *oids);
84
+ static POOL_INTERNAL_BUFFER *pool_create_buffer(void);
85
+ static void pool_discard_buffer(POOL_INTERNAL_BUFFER *buffer);
86
+ static void pool_add_buffer(POOL_INTERNAL_BUFFER *buffer, void *data, size_t len);
87
+ static void *pool_get_buffer(POOL_INTERNAL_BUFFER *buffer, size_t *len);
88
+ static char *pool_get_buffer_pointer(POOL_INTERNAL_BUFFER *buffer);
89
+ static char *pool_get_current_cache_buffer(size_t *len);
90
+ static size_t pool_get_buffer_length(POOL_INTERNAL_BUFFER *buffer);
91
+ static void pool_check_and_discard_cache_buffer(int num_oids, int *oids);
92
+
93
+ static void pool_set_memqcache_blocks(int num_blocks);
94
+ static int pool_get_memqcache_blocks(void);
95
+ static void *pool_memory_cache_address(void);
96
+ static void pool_reset_fsmm(size_t size);
97
+ static void *pool_fsmm_address(void);
98
+ static void pool_update_fsmm(POOL_CACHE_BLOCKID blockid, size_t free_space);
99
+ static POOL_CACHE_BLOCKID pool_get_block(size_t free_space);
100
+ static POOL_CACHE_ITEM_HEADER *pool_cache_item_header(POOL_CACHEID *cacheid);
101
+ static int pool_init_cache_block(POOL_CACHE_BLOCKID blockid);
102
+ #if NOT_USED
103
+ static void pool_wipe_out_cache_block(POOL_CACHE_BLOCKID blockid);
104
+ #endif
105
+ static int pool_delete_item_shmem_cache(POOL_CACHEID *cacheid);
106
+ static char *block_address(int blockid);
107
+ static POOL_CACHE_ITEM_POINTER *item_pointer(char *block, int i);
108
+ static POOL_CACHE_ITEM_HEADER *item_header(char *block, int i);
109
+ static POOL_CACHE_BLOCKID pool_reuse_block(void);
110
+ #ifdef SHMEMCACHE_DEBUG
111
+ static void dump_shmem_cache(POOL_CACHE_BLOCKID blockid);
112
+ #endif
113
+
114
+ static int pool_hash_reset(int nelements);
115
+ static int pool_hash_insert(POOL_QUERY_HASH *key, POOL_CACHEID *cacheid, bool update);
116
+ static uint32 create_hash_key(POOL_QUERY_HASH *key);
117
+ static volatile POOL_HASH_ELEMENT *get_new_hash_element(void);
118
+ static void put_back_hash_element(volatile POOL_HASH_ELEMENT *element);
119
+ static bool is_free_hash_element(void);
120
+ static char *get_relation_without_alias(RangeVar *relation);
121
+
122
+ /*
123
+ * Connect to Memcached
124
+ */
125
+ int memcached_connect (void)
126
+ {
127
+ char *memqcache_memcached_host;
128
+ int memqcache_memcached_port;
129
+ #ifdef USE_MEMCACHED
130
+ memcached_server_st *servers;
131
+ memcached_return rc;
132
+
133
+ /* Already connected? */
134
+ if (memc)
135
+ {
136
+ return 0;
137
+ }
138
+ #endif
139
+
140
+ memqcache_memcached_host = pool_config->memqcache_memcached_host;
141
+ memqcache_memcached_port = pool_config->memqcache_memcached_port;
142
+
143
+ pool_debug("memcached_connect : memqcache_memcached_host = %s", memqcache_memcached_host);
144
+ pool_debug("memcached_connect : memqcache_memcached_port = %d", memqcache_memcached_port);
145
+
146
+ #ifdef USE_MEMCACHED
147
+ memc = memcached_create(NULL);
148
+ servers = memcached_server_list_append(NULL,
149
+ memqcache_memcached_host,
150
+ memqcache_memcached_port,
151
+ &rc);
152
+
153
+ rc = memcached_server_push(memc, servers);
154
+ if (rc != MEMCACHED_SUCCESS)
155
+ {
156
+ pool_error("memcached_connect: server_push %s\n", memcached_strerror(memc, rc));
157
+ memc = (memcached_st *)-1;
158
+ return -1;
159
+ }
160
+ memcached_server_list_free(servers);
161
+ #else
162
+ pool_error("memcached_connect: memcached support is not enabled");
163
+ return -1;
164
+ #endif
165
+ return 0;
166
+ }
167
+
168
+ /*
169
+ * Disconnect to Memcached
170
+ */
171
+ void memcached_disconnect (void)
172
+ {
173
+ #ifdef USE_MEMCACHED
174
+ if (!memc)
175
+ {
176
+ return;
177
+ }
178
+ memcached_free(memc);
179
+ #else
180
+ pool_error("memcached_disconnect: memcached support is not enabled");
181
+ #endif
182
+ }
183
+
184
+ /*
185
+ * Register buffer data for query cache on memory cache
186
+ */
187
+ void memqcache_register(char kind,
188
+ POOL_CONNECTION *frontend,
189
+ char *data,
190
+ int data_len)
191
+ {
192
+ POOL_TEMP_QUERY_CACHE *cache;
193
+
194
+ cache = pool_get_current_cache();
195
+
196
+ pool_add_temp_query_cache(cache, kind, data, data_len);
197
+ }
198
+
199
+ /*
200
+ * Commit SELECT results to cache storage.
201
+ */
202
+ static int pool_commit_cache(POOL_CONNECTION_POOL *backend, char *query, char *data, size_t datalen, int num_oids, int *oids)
203
+ {
204
+ #ifdef USE_MEMCACHED
205
+ memcached_return rc;
206
+ #endif
207
+ POOL_CACHEKEY cachekey;
208
+ char tmpkey[MAX_KEY];
209
+ time_t memqcache_expire;
210
+
211
+ /*
212
+ * get_buflen() will return -1 if query result exceeds memqcache_maxcache
213
+ */
214
+ if (datalen == -1)
215
+ {
216
+ return -1;
217
+ }
218
+
219
+ /* query disabled */
220
+ if (strlen(query) <= 0)
221
+ {
222
+ return -1;
223
+ }
224
+
225
+ pool_debug("pool_commit_cache: Query=%s", query);
226
+ #ifdef DEBUG
227
+ dump_cache_data(data, datalen);
228
+ #endif
229
+
230
+ /* encode md5key for memcached */
231
+ encode_key(query, tmpkey, backend);
232
+ pool_debug("pool_commit_cache: search key ==%s==", tmpkey);
233
+ memcpy(cachekey.hashkey, tmpkey, 32);
234
+
235
+ memqcache_expire = pool_config->memqcache_expire;
236
+ pool_debug("pool_commit_cache : memqcache_expire = %ld", memqcache_expire);
237
+
238
+ if (pool_is_shmem_cache())
239
+ {
240
+ POOL_CACHEID *cacheid;
241
+ POOL_QUERY_HASH query_hash;
242
+
243
+ memcpy(query_hash.query_hash, tmpkey, sizeof(query_hash.query_hash));
244
+
245
+ cacheid = pool_hash_search(&query_hash);
246
+
247
+ if (cacheid != NULL)
248
+ {
249
+ pool_debug("pool_commit_cache: the item already exists");
250
+ return 0;
251
+ }
252
+ else
253
+ {
254
+ cacheid = pool_add_item_shmem_cache(&query_hash, data, datalen);
255
+ if (cacheid == NULL)
256
+ {
257
+ pool_error("pool_commit_cache: pool_add_item_shmem_cache failed");
258
+ return -1;
259
+ }
260
+ else
261
+ {
262
+ pool_debug("pool_commit_cache: blockid: %d itemid: %d",
263
+ cacheid->blockid, cacheid->itemid);
264
+ }
265
+ cachekey.cacheid.blockid = cacheid->blockid;
266
+ cachekey.cacheid.itemid = cacheid->itemid;
267
+ }
268
+ }
269
+
270
+ #ifdef USE_MEMCACHED
271
+ else
272
+ {
273
+ rc = memcached_set(memc, tmpkey, 32,
274
+ data, datalen, (time_t)memqcache_expire, 0);
275
+ if (rc != MEMCACHED_SUCCESS)
276
+ {
277
+ pool_error("pool_commit_cache: memcached_set error %s", memcached_strerror(memc, rc));
278
+ return -1;
279
+ }
280
+ pool_debug("pool_commit_cache: set cache succeeded.");
281
+ }
282
+ #endif
283
+
284
+ /*
285
+ * Register cache id to oid map
286
+ */
287
+ pool_add_table_oid_map(&cachekey, num_oids, oids);
288
+
289
+ return 0;
290
+ }
291
+
292
+ /*
293
+ * Fetch from memory cache.
294
+ * 0: fetch success, 1: not found -1: error
295
+ */
296
+ static int pool_fetch_cache(POOL_CONNECTION_POOL *backend, const char *query, char **buf, size_t *len)
297
+ {
298
+ char *ptr;
299
+ char tmpkey[MAX_KEY];
300
+ int sts;
301
+ char *p;
302
+
303
+ if (strlen(query) <= 0)
304
+ {
305
+ return -1;
306
+ }
307
+
308
+ /* encode md5key for memcached */
309
+ encode_key(query, tmpkey, backend);
310
+ pool_debug("pool_fetch_cache: search key ==%s==", tmpkey);
311
+
312
+ if (pool_is_shmem_cache())
313
+ {
314
+ POOL_QUERY_HASH query_hash;
315
+ int mylen;
316
+
317
+ memcpy(query_hash.query_hash, tmpkey, sizeof(query_hash.query_hash));
318
+
319
+ ptr = pool_get_item_shmem_cache(&query_hash, &mylen, &sts);
320
+ if (ptr == NULL)
321
+ {
322
+ pool_debug("pool_fetch_cache: cache not found on shmem");
323
+ return 1;
324
+ }
325
+ *len = mylen;
326
+ }
327
+ #ifdef USE_MEMCACHED
328
+ else
329
+ {
330
+ memcached_return rc;
331
+ unsigned int flags;
332
+
333
+ ptr = memcached_get(memc, tmpkey, strlen(tmpkey), len, &flags, &rc);
334
+
335
+ if (rc != MEMCACHED_SUCCESS)
336
+ {
337
+ if (rc != MEMCACHED_NOTFOUND)
338
+ {
339
+ pool_error("pool_fetch_cache: memcached_get failed %s", memcached_strerror(memc, rc));
340
+ /*
341
+ * Turn off memory cache support to prevent future errors.
342
+ */
343
+ pool_config->memory_cache_enabled = 0;
344
+ /* Behave as if cache not found */
345
+ return 1;
346
+ }
347
+ else
348
+ {
349
+ /* Not found */
350
+ pool_debug("pool_fetch_cache: not found: query:%s key:%s", query, tmpkey);
351
+ return 1;
352
+ }
353
+ }
354
+ }
355
+ #else
356
+ else
357
+ {
358
+ pool_error("pool_fetch_cache: memcached support is not enabled");
359
+ return -1;
360
+ }
361
+ #endif
362
+
363
+ p = malloc(*len);
364
+ if (!p)
365
+ {
366
+ pool_error("pool_fetch_cache: malloc failed");
367
+ return -1;
368
+ }
369
+
370
+ memcpy(p, ptr, *len);
371
+
372
+ if (!pool_is_shmem_cache())
373
+ {
374
+ free(ptr);
375
+ }
376
+
377
+ pool_debug("pool_fetch_cache: query=%s len:%zd", query, *len);
378
+ #ifdef DEBUG
379
+ dump_cache_data(p, *len);
380
+ #endif
381
+
382
+ *buf = p;
383
+
384
+ return 0;
385
+ }
386
+
387
+ /*
388
+ * encode key.
389
+ * create cache key as md5(username + query string + database name)
390
+ */
391
+ static char* encode_key(const char *s, char *buf, POOL_CONNECTION_POOL *backend)
392
+ {
393
+ char* strkey;
394
+ int u_length;
395
+ int d_length;
396
+ int q_length;
397
+ int length;
398
+
399
+ u_length = strlen(backend->info->user);
400
+ pool_debug("encode_key: username %s", backend->info->user);
401
+
402
+ d_length = strlen(backend->info->database);
403
+ pool_debug("encode_key: database_name %s", backend->info->database);
404
+
405
+ q_length = strlen(s);
406
+ pool_debug("encode_key: query %s", s);
407
+
408
+ length = u_length + d_length + q_length + 1;
409
+
410
+ strkey = (char*)malloc(sizeof(char) * length);
411
+ if (!strkey)
412
+ {
413
+ pool_error("encode_key: malloc failed");
414
+ return NULL;
415
+ }
416
+
417
+ snprintf(strkey, length, "%s%s%s", backend->info->user, s, backend->info->database);
418
+
419
+ pool_md5_hash(strkey, strlen(strkey), buf);
420
+ pool_debug("encode_key: `%s' -> `%s'", strkey, buf);
421
+ free(strkey);
422
+ return buf;
423
+ }
424
+
425
+ #ifdef DEBUG
426
+ /*
427
+ * dump cache data
428
+ */
429
+ static void dump_cache_data(const char *data, size_t len)
430
+ {
431
+ int i;
432
+ int plen;
433
+
434
+
435
+ fprintf(stderr,"shmem: len = %zd\n", len);
436
+
437
+ while (len > 0)
438
+ {
439
+ fprintf(stderr,"shmem: kind:%c\n", *data++);
440
+ len--;
441
+ memmove(&plen, data, 4);
442
+ len -= 4;
443
+ data += 4;
444
+ plen = ntohl(plen);
445
+ fprintf(stderr,"shmem: len:%d\n", plen);
446
+ plen -= 4;
447
+
448
+ fprintf(stderr, "shmem: ");
449
+ for (i=0;i<plen;i++)
450
+ {
451
+ fprintf(stderr, "%02x ", (unsigned char)(*data++));
452
+ len--;
453
+ }
454
+ fprintf(stderr, "\n");
455
+ }
456
+ }
457
+ #endif
458
+
459
+ /*
460
+ * send cached messages
461
+ */
462
+ static int send_cached_messages(POOL_CONNECTION *frontend, const char *qcache, int qcachelen)
463
+ {
464
+ int msg = 0;
465
+ int i = 0;
466
+ int is_prepared_stmt = 0;
467
+ int len;
468
+ const char *p;
469
+
470
+ while (i < qcachelen)
471
+ {
472
+ char tmpkind;
473
+ int tmplen;
474
+
475
+ tmpkind = qcache[i];
476
+ i++;
477
+
478
+ memcpy(&tmplen, qcache+i, sizeof(tmplen));
479
+ i += sizeof(tmplen);
480
+ len = ntohl(tmplen);
481
+ p = qcache + i;
482
+ i += len - sizeof(tmplen);
483
+
484
+ /* No need to cache PARSE and BIND responses */
485
+ if (tmpkind == '1' || tmpkind == '2')
486
+ {
487
+ is_prepared_stmt = 1;
488
+ continue;
489
+ }
490
+
491
+ /*
492
+ * In the prepared statement execution, there is no need to send
493
+ * 'T' response to the frontend.
494
+ */
495
+ if (is_prepared_stmt && tmpkind == 'T')
496
+ {
497
+ continue;
498
+ }
499
+
500
+ /* send message to frontend */
501
+ pool_debug("send_cached_messages: %c len: %d", tmpkind, len);
502
+ send_message(frontend, tmpkind, len, p);
503
+
504
+ msg++;
505
+ }
506
+
507
+ return msg;
508
+ }
509
+
510
+ /*
511
+ * send message to frontend
512
+ */
513
+ static void send_message(POOL_CONNECTION *conn, char kind, int len, const char *data)
514
+ {
515
+ pool_debug("send_message: kind=%c, len=%d, data=%p", kind, len, data);
516
+
517
+ pool_write(conn, &kind, 1);
518
+
519
+ len = htonl(len);
520
+ pool_write(conn, &len, sizeof(len));
521
+
522
+ len = ntohl(len);
523
+ pool_write(conn, (void *)data, len-sizeof(len));
524
+ }
525
+
526
+ #ifdef USE_MEMCACHED
527
+ /*
528
+ * delete query cache on memcached
529
+ */
530
+ static int delete_cache_on_memcached(const char *key)
531
+ {
532
+
533
+ memcached_return rc;
534
+
535
+ pool_debug("delete_cache_on_memcached: key: %s", key);
536
+
537
+
538
+ /* delete cache data on memcached. key is md5 hash query */
539
+ rc= memcached_delete(memc, key, 32, (time_t)0);
540
+
541
+ /* delete cache data on memcached is failed */
542
+ if (rc != MEMCACHED_SUCCESS && rc != MEMCACHED_BUFFERED)
543
+ {
544
+ pool_error ("delete_cache_on_memcached: %s\n", memcached_strerror(memc, rc));
545
+ return 0;
546
+ }
547
+ return 1;
548
+
549
+ }
550
+ #endif
551
+
552
+ /*
553
+ * Fetch SELECT data from cache if possible.
554
+ */
555
+ POOL_STATUS pool_fetch_from_memory_cache(POOL_CONNECTION *frontend,
556
+ POOL_CONNECTION_POOL *backend,
557
+ char *contents, bool *foundp)
558
+ {
559
+ char *qcache;
560
+ size_t qcachelen;
561
+ int sts;
562
+ #ifdef HAVE_SIGPROCMASK
563
+ sigset_t oldmask;
564
+ #else
565
+ int oldmask;
566
+ #endif
567
+
568
+ *foundp = false;
569
+
570
+ POOL_SETMASK2(&BlockSig, &oldmask);
571
+ pool_shmem_lock();
572
+ sts = pool_fetch_cache(backend, contents, &qcache, &qcachelen);
573
+ pool_shmem_unlock();
574
+ POOL_SETMASK(&oldmask);
575
+
576
+ if (sts == 0)
577
+ {
578
+ /*
579
+ * Cache found. send each messages to frontend
580
+ */
581
+ send_cached_messages(frontend, qcache, qcachelen);
582
+ free(qcache);
583
+
584
+ /*
585
+ * If we are doing extended query, wait and discard Sync
586
+ * message from frontend. This is necessary to prevent
587
+ * receiving Sync message after Sending Ready for query.
588
+ */
589
+ if (pool_is_doing_extended_query_message())
590
+ {
591
+ char kind;
592
+ int32 len;
593
+
594
+ if (pool_flush(frontend))
595
+ return POOL_END;
596
+ if (pool_read(frontend, &kind, 1))
597
+ return POOL_END;
598
+ pool_debug("pool_fetch_from_memory_cache: expecting sync: %c", kind);
599
+ if (pool_read(frontend, &len, sizeof(len)))
600
+ return POOL_END;
601
+ }
602
+
603
+ /*
604
+ * send a "READY FOR QUERY"
605
+ */
606
+ if (MAJOR(backend) == PROTO_MAJOR_V3)
607
+ {
608
+ signed char state;
609
+
610
+ /*
611
+ * We keep previous transaction state.
612
+ */
613
+ state = MASTER(backend)->tstate;
614
+ send_message(frontend, 'Z', 5, (char *)&state);
615
+ }
616
+ else
617
+ {
618
+ pool_write(frontend, "Z", 1);
619
+ }
620
+ if (pool_flush(frontend))
621
+ {
622
+ return POOL_END;
623
+ }
624
+
625
+ *foundp = true;
626
+
627
+ if (pool_config->log_per_node_statement)
628
+ pool_log("query result fetched from cache. statement: %s", contents);
629
+
630
+ pool_debug("pool_fetch_from_memory_cache: a query result found in the query cache, %s", contents);
631
+
632
+ return POOL_CONTINUE;
633
+ }
634
+ else if (sts == -1)
635
+ {
636
+ pool_error("pool_fetch_from_memory_cache: pool_fetch_cache() failed. %s", contents);
637
+ return POOL_END;
638
+ }
639
+
640
+ /* Cache not found */
641
+ return POOL_CONTINUE;
642
+ }
643
+
644
+ /*
645
+ * Simple and rough(thus unreliable) check if the query is likely
646
+ * SELECT. Just check if the query starts with SELECT or WITH. This
647
+ * can be used before parse tree is available.
648
+ */
649
+ bool pool_is_likely_select(char *query)
650
+ {
651
+ bool do_continue = false;
652
+
653
+ if (query == NULL)
654
+ return false;
655
+
656
+ if (pool_config->ignore_leading_white_space)
657
+ {
658
+ /* Ignore leading white spaces */
659
+ while (*query && isspace(*query))
660
+ query++;
661
+ }
662
+ if (! *query) { return false; }
663
+
664
+ /*
665
+ * Get rid of head comment.
666
+ * It is sure that the query is in correct format, because the parser
667
+ * has rejected bad queries such as the one with not-ended comment.
668
+ */
669
+ while (*query)
670
+ {
671
+ /* Ignore spaces and return marks */
672
+ do_continue = false;
673
+ while (*query && isspace(*query))
674
+ {
675
+ query++;
676
+ do_continue = true;
677
+ }
678
+ if (do_continue) { continue; }
679
+
680
+ while (*query && !strncmp(query, "\n", 2))
681
+ {
682
+ query++;
683
+ do_continue = true;
684
+ }
685
+ if (do_continue)
686
+ {
687
+ query += 2;
688
+ continue;
689
+ }
690
+
691
+ /* Ignore comments like C */
692
+ if (!strncmp(query, "/*", 2))
693
+ {
694
+ while (*query && strncmp(query, "*/", 2))
695
+ query++;
696
+
697
+ query += 2;
698
+ continue;
699
+ }
700
+
701
+ /* Ignore SQL comments */
702
+ if (!strncmp(query, "--", 2))
703
+ {
704
+ while (*query && strncmp(query, "\n", 2))
705
+ query++;
706
+
707
+ query += 2;
708
+ continue;
709
+ }
710
+
711
+ if (!strncasecmp(query, "SELECT", 6) || !strncasecmp(query, "WITH", 4))
712
+ {
713
+ return true;
714
+ }
715
+
716
+ query++;
717
+ }
718
+
719
+ return false;
720
+ }
721
+
722
+ /*
723
+ * Return true if SELECT can be cached. "node" is the parse tree for
724
+ * the query and "query" is the query string.
725
+ * The query must be SELECT or WITH.
726
+ */
727
+ bool pool_is_allow_to_cache(Node *node, char *query)
728
+ {
729
+ SelectStmt *stmt;
730
+ int i = 0;
731
+ int num_oids = -1;
732
+ SelectContext ctx;
733
+
734
+ /*
735
+ * If NO QUERY CACHE comment exists, do not cache.
736
+ */
737
+ if (!strncasecmp(query, NO_QUERY_CACHE, NO_QUERY_CACHE_COMMENT_SZ))
738
+ return false;
739
+
740
+ stmt = (SelectStmt *)node;
741
+
742
+ /*
743
+ * Check black table list first.
744
+ */
745
+ if (pool_config->num_black_memqcache_table_list > 0)
746
+ {
747
+ /* Extract oids in from clause of SELECT, and check if SELECT to them could be cached. */
748
+ num_oids = pool_extract_table_oids_from_select_stmt(node, &ctx);
749
+ if (num_oids > 0)
750
+ {
751
+ for (i = 0; i < num_oids; i++)
752
+ {
753
+ pool_debug("pool_is_allow_to_cache: check table_names[%d] = %s", i, ctx.table_names[i]);
754
+ if (pool_is_table_in_black_list(ctx.table_names[i]) == true)
755
+ {
756
+ pool_debug("pool_is_allow_to_cache: false");
757
+ return false;
758
+ }
759
+ }
760
+ }
761
+ }
762
+
763
+ /* SELECT INTO or SELECT FOR SHARE or UPDATE cannot be cached */
764
+ if (pool_has_insertinto_or_locking_clause(node))
765
+ return false;
766
+
767
+ /*
768
+ * If SELECT uses non immutable functions, it's not allowed to
769
+ * cache.
770
+ */
771
+ if (pool_has_non_immutable_function_call(node))
772
+ return false;
773
+
774
+ /*
775
+ * If SELECT uses temporary tables it's not allowed to cache.
776
+ */
777
+ if (pool_config->check_temp_table && pool_has_temp_table(node))
778
+ return false;
779
+
780
+ /*
781
+ * If SELECT uses system catalogs, it's not allowed to cache.
782
+ */
783
+ if (pool_has_system_catalog(node))
784
+ return false;
785
+
786
+ /*
787
+ * If the table is in the while list, allow to cache even if it is
788
+ * VIEW or unlogged table.
789
+ */
790
+ if (pool_config->num_white_memqcache_table_list > 0)
791
+ {
792
+ if (num_oids < 0)
793
+ num_oids = pool_extract_table_oids_from_select_stmt(node, &ctx);
794
+
795
+ if (num_oids > 0)
796
+ {
797
+ for (i = 0; i < num_oids; i++)
798
+ {
799
+ char *table = ctx.table_names[i];
800
+ pool_debug("pool_is_allow_to_cache: check table_names[%d] = %s", i, table);
801
+ if (is_view(table) || is_unlogged_table(table))
802
+ {
803
+ if (pool_is_table_in_white_list(table) == false)
804
+ {
805
+ pool_debug("pool_is_allow_to_cache: false");
806
+ return false;
807
+ }
808
+ }
809
+ }
810
+ }
811
+ }
812
+ else
813
+ {
814
+ /*
815
+ * If SELECT uses views, it's not allowed to cache.
816
+ */
817
+ if (pool_has_view(node))
818
+ return false;
819
+
820
+ /*
821
+ * If SELECT uses unlogged tables, it's not allowed to cache.
822
+ */
823
+ if (pool_has_unlogged_table(node))
824
+ return false;
825
+ }
826
+ return true;
827
+ }
828
+
829
+
830
+ /*
831
+ * Return true If the SELECTed table is in back list.
832
+ */
833
+ bool pool_is_table_in_black_list(const char *table_name)
834
+ {
835
+
836
+ if (pool_config->num_black_memqcache_table_list > 0 &&
837
+ pattern_compare((char *)table_name, BLACKLIST, "black_memqcache_table_list") == 1)
838
+ {
839
+ return true;
840
+ }
841
+
842
+ return false;
843
+ }
844
+
845
+ /*
846
+ * Return true If the SELECTed table is in white list.
847
+ */
848
+ bool pool_is_table_in_white_list(const char *table_name)
849
+ {
850
+ if (pool_config->num_white_memqcache_table_list > 0 &&
851
+ pattern_compare((char *)table_name, WHITELIST, "white_memqcache_table_list") == 1)
852
+ {
853
+ return true;
854
+ }
855
+
856
+ return false;
857
+ }
858
+
859
+ /*
860
+ * Extract table oid from INSERT/UPDATE/DELETE/TRUNCATE/
861
+ * DROP TABLE/ALTER TABLE/COPY FROM statement.
862
+ * Returns number of oids.
863
+ * In case of error, returns 0(InvalidOid).
864
+ * oids buffer(oidsp) will be discarded by subsequent call.
865
+ */
866
+ int pool_extract_table_oids(Node *node, int **oidsp)
867
+ {
868
+ #define POOL_MAX_DML_OIDS 128
869
+ char *table;
870
+ static int oids[POOL_MAX_DML_OIDS];
871
+ int num_oids;
872
+ int oid;
873
+
874
+ if (node == NULL)
875
+ {
876
+ pool_error("pool_extract_table_oids: statement is NULL");
877
+ return 0;
878
+ }
879
+
880
+ num_oids = 0;
881
+ *oidsp = oids;
882
+
883
+ if (IsA(node, InsertStmt))
884
+ {
885
+ InsertStmt *stmt = (InsertStmt *)node;
886
+ table = nodeToString(stmt->relation);
887
+ }
888
+ else if (IsA(node, UpdateStmt))
889
+ {
890
+ UpdateStmt *stmt = (UpdateStmt *)node;
891
+ table = get_relation_without_alias(stmt->relation);
892
+ }
893
+ else if (IsA(node, DeleteStmt))
894
+ {
895
+ DeleteStmt *stmt = (DeleteStmt *)node;
896
+ table = get_relation_without_alias(stmt->relation);
897
+ }
898
+
899
+ #ifdef NOT_USED
900
+ /*
901
+ * We do not handle CREATE TABLE here. It is possible that
902
+ * pool_extract_table_oids() is called before CREATE TABLE gets
903
+ * executed.
904
+ */
905
+ else if (IsA(node, CreateStmt))
906
+ {
907
+ CreateStmt *stmt = (CreateStmt *)node;
908
+ table = nodeToString(stmt->relation);
909
+ }
910
+ #endif
911
+
912
+ else if (IsA(node, AlterTableStmt))
913
+ {
914
+ AlterTableStmt *stmt = (AlterTableStmt *)node;
915
+ table = nodeToString(stmt->relation);
916
+ }
917
+
918
+ else if (IsA(node, CopyStmt))
919
+ {
920
+ CopyStmt *stmt = (CopyStmt *)node;
921
+ if (stmt->is_from) /* COPY FROM? */
922
+ {
923
+ table = nodeToString(stmt->relation);
924
+ }
925
+ else
926
+ {
927
+ return 0;
928
+ }
929
+ }
930
+
931
+ else if (IsA(node, DropStmt))
932
+ {
933
+ ListCell *cell;
934
+
935
+ DropStmt *stmt = (DropStmt *)node;
936
+
937
+ if (stmt->removeType != OBJECT_TABLE)
938
+ {
939
+ return 0;
940
+ }
941
+
942
+ /* Here, stmt->objects is list of target relation info. The
943
+ * first cell of target relation info is a list (possibly)
944
+ * consists of database, schema and relation. We need to call
945
+ * makeRangeVarFromNameList() before passing to nodeToString.
946
+ * Otherwise we get weird excessively decorated relation name
947
+ * (''table_name'').
948
+ */
949
+ foreach(cell, stmt->objects)
950
+ {
951
+ if (num_oids > POOL_MAX_DML_OIDS)
952
+ {
953
+ pool_error("pool_extract_table_oids: too many oids:%d", num_oids);
954
+ return 0;
955
+ }
956
+
957
+ table = nodeToString(makeRangeVarFromNameList(lfirst(cell)));
958
+ oid = pool_table_name_to_oid(table);
959
+ if (oid > 0)
960
+ {
961
+ oids[num_oids++] = pool_table_name_to_oid(table);
962
+ pool_debug("pool_extract_table_oids: table:%s oid:%d", table, oids[num_oids-1]);
963
+ }
964
+ }
965
+ return num_oids;
966
+ }
967
+ else if (IsA(node, TruncateStmt))
968
+ {
969
+ ListCell *cell;
970
+
971
+ TruncateStmt *stmt = (TruncateStmt *)node;
972
+
973
+ foreach(cell, stmt->relations)
974
+ {
975
+ if (num_oids > POOL_MAX_DML_OIDS)
976
+ {
977
+ pool_error("pool_extract_table_oids: too many oids:%d", num_oids);
978
+ return 0;
979
+ }
980
+
981
+ table = nodeToString(lfirst(cell));
982
+ oid = pool_table_name_to_oid(table);
983
+ if (oid > 0)
984
+ {
985
+ oids[num_oids++] = pool_table_name_to_oid(table);
986
+ pool_debug("pool_extract_table_oids: table:%s oid:%d", table, oids[num_oids-1]);
987
+ }
988
+ }
989
+ return num_oids;
990
+ }
991
+ else
992
+ {
993
+ pool_debug("pool_extract_table_oids: other than INSERT/UPDATE/DELETE/TRUNCATE/DROP TABLE/ALTER TABLE statement");
994
+ return 0;
995
+ }
996
+
997
+ oid = pool_table_name_to_oid(table);
998
+ if (oid > 0)
999
+ {
1000
+ oids[num_oids++] = pool_table_name_to_oid(table);
1001
+ pool_debug("pool_extract_table_oids: table:%s oid:%d", table, oid);
1002
+ }
1003
+ return num_oids;
1004
+ }
1005
+
1006
+ /*
1007
+ * Get relation name without alias. NodeToString() calls
1008
+ * _outRangeVar(). Unfortunately _outRangeVar() returns table with
1009
+ * alias ("t1 AS foo") as a table name if table alias is used. This
1010
+ * function just trim down "AS..." part from the table name when table
1011
+ * alias is used.
1012
+ */
1013
+ static char *get_relation_without_alias(RangeVar *relation)
1014
+ {
1015
+ char *table;
1016
+ char *p;
1017
+
1018
+ if (!IsA(relation, RangeVar))
1019
+ {
1020
+ pool_error("get_relation_without_alias: not RangeVar(%d)", relation->type);
1021
+ return "";
1022
+ }
1023
+ table = nodeToString(relation);
1024
+ if (relation->alias)
1025
+ {
1026
+ p = strchr(table, ' ');
1027
+ if (!p)
1028
+ {
1029
+ pool_error("get_relation_without_alias: cannot locate space;%s", table);
1030
+ return "";
1031
+ }
1032
+ *p = '\0';
1033
+ }
1034
+ return table;
1035
+ }
1036
+
1037
+ #define POOL_OIDBUF_SIZE 1024
1038
+ static int* oidbuf;
1039
+ static int oidbufp;
1040
+ static int oidbuf_size;
1041
+
1042
+ /*
1043
+ * Add table oid to internal buffer
1044
+ */
1045
+ void pool_add_dml_table_oid(int oid)
1046
+ {
1047
+ int i;
1048
+ int* tmp;
1049
+
1050
+ if (oid == 0)
1051
+ return;
1052
+
1053
+ if (oidbufp >= oidbuf_size)
1054
+ {
1055
+ oidbuf_size += POOL_OIDBUF_SIZE;
1056
+ tmp = realloc(oidbuf, sizeof(int) * oidbuf_size);
1057
+ if (tmp == NULL)
1058
+ return;
1059
+
1060
+ oidbuf = tmp;
1061
+ }
1062
+
1063
+ for (i=0;i<oidbufp;i++)
1064
+ {
1065
+ if (oidbuf[i] == oid)
1066
+ /* Already same oid exists */
1067
+ return;
1068
+ }
1069
+ oidbuf[oidbufp++] = oid;
1070
+ }
1071
+
1072
+ /*
1073
+ * Get table oid buffer
1074
+ */
1075
+ static int pool_get_dml_table_oid(int **oid)
1076
+ {
1077
+ *oid = oidbuf;
1078
+ return oidbufp;
1079
+ }
1080
+
1081
+ static int pool_get_dropdb_table_oids(int **oids, int dboid)
1082
+ {
1083
+ int *rtn = 0;
1084
+ int oids_size = 0;
1085
+ int *tmp;
1086
+
1087
+ int num_oids = 0;
1088
+ DIR *dir;
1089
+ struct dirent *dp;
1090
+ char path[1024];
1091
+
1092
+ snprintf(path, sizeof(path), "%s/%d", pool_config->memqcache_oiddir, dboid);
1093
+ if ((dir = opendir(path)) == NULL)
1094
+ {
1095
+ pool_debug("pool_get_dropdb_table_oids: Failed to open dir: %s", path);
1096
+ return 0;
1097
+ }
1098
+
1099
+ while ((dp = readdir(dir)) != NULL)
1100
+ {
1101
+ if (strcmp(dp->d_name, ".") == 0 || strcmp(dp->d_name, "..") == 0)
1102
+ continue;
1103
+
1104
+ if (num_oids >= oids_size)
1105
+ {
1106
+ oids_size += POOL_OIDBUF_SIZE;
1107
+ tmp = realloc(rtn, sizeof(int) * oids_size);
1108
+ if (tmp == NULL)
1109
+ {
1110
+ closedir(dir);
1111
+ return 0;
1112
+ }
1113
+ rtn = tmp;
1114
+ }
1115
+
1116
+ rtn[num_oids] = atol(dp->d_name);
1117
+ num_oids++;
1118
+ }
1119
+
1120
+ closedir(dir);
1121
+ *oids = rtn;
1122
+
1123
+ return num_oids;
1124
+ }
1125
+
1126
+ /* Discard oid internal buffer */
1127
+ static void pool_discard_dml_table_oid(void)
1128
+ {
1129
+ oidbufp = 0;
1130
+ }
1131
+
1132
+ /*
1133
+ * Management modules for oid map. When caching SELECT results, we
1134
+ * record table oids to file, which has following structure.
1135
+ *
1136
+ * memqcache_oiddir -+- database_oid -+-table_oid_file1
1137
+ * |
1138
+ * +-table_oid_file2
1139
+ * |
1140
+ * +-table_oid_file3...
1141
+ *
1142
+ * table_oid_file's name is table oid, which was used by the SELECT
1143
+ * statement. The file has 1 or more cacheid(s). When SELECT result is
1144
+ * cached, the file is created and cache id is appended. Later SELECT
1145
+ * using same table oid will add to the same file. If the SELECT uses
1146
+ * multiple tables, multiple table_oid_file will be created. When
1147
+ * INSERT/UPDATE/DELETE is executed, corresponding caches must be
1148
+ * deleted(cache invalidation) (when DROP TABLE, ALTER TABLE is
1149
+ * executed, the caches must be deleted as well). When database is
1150
+ * dropped, all caches belonging to the database must be deleted.
1151
+ */
1152
+
1153
+ /*
1154
+ * Get oid of current database
1155
+ */
1156
+ static int pool_get_database_oid(void)
1157
+ {
1158
+ /*
1159
+ * Query to convert table name to oid
1160
+ */
1161
+ int oid = 0;
1162
+ static POOL_RELCACHE *relcache;
1163
+ POOL_CONNECTION_POOL *backend;
1164
+
1165
+ backend = pool_get_session_context()->backend;
1166
+
1167
+ /*
1168
+ * If relcache does not exist, create it.
1169
+ */
1170
+ if (!relcache)
1171
+ {
1172
+ relcache = pool_create_relcache(pool_config->relcache_size, DATABASE_TO_OID_QUERY,
1173
+ int_register_func, int_unregister_func,
1174
+ false);
1175
+ if (relcache == NULL)
1176
+ {
1177
+ pool_error("pool_get_database_oid: pool_create_relcache error");
1178
+ return oid;
1179
+ }
1180
+ }
1181
+
1182
+ /*
1183
+ * Search relcache.
1184
+ */
1185
+ oid = (int)(intptr_t)pool_search_relcache(relcache, backend,
1186
+ MASTER_CONNECTION(backend)->sp->database);
1187
+ return oid;
1188
+ }
1189
+
1190
+ /*
1191
+ * Get oid of current database for discarding cache files
1192
+ * after executing DROP DATABASE
1193
+ */
1194
+ int pool_get_database_oid_from_dbname(char *dbname)
1195
+ {
1196
+ int dboid = 0;
1197
+ POOL_SELECT_RESULT *res;
1198
+ POOL_STATUS status;
1199
+ char query[1024];
1200
+
1201
+ POOL_CONNECTION_POOL *backend;
1202
+ backend = pool_get_session_context()->backend;
1203
+
1204
+ snprintf(query, sizeof(query), DATABASE_TO_OID_QUERY, dbname);
1205
+ status = do_query(MASTER(backend), query, &res, MAJOR(backend));
1206
+
1207
+ if (status != POOL_CONTINUE)
1208
+ {
1209
+ pool_debug("pool_discard_oid_maps_by_db: Failed.");
1210
+ free_select_result(res);
1211
+ return 0;
1212
+ }
1213
+
1214
+ if (res->numrows != 1)
1215
+ {
1216
+ pool_debug("pool_discard_oid_maps_by_db: Failed. Received %d rows", res->numrows);
1217
+ free_select_result(res);
1218
+ return 0;
1219
+ }
1220
+
1221
+ dboid = atol(res->data[0]);
1222
+ free_select_result(res);
1223
+
1224
+ return dboid;
1225
+ }
1226
+
1227
+ /*
1228
+ * Add cache id(shmem case) or hash key(memcached case) to table oid
1229
+ * map file. Caller must hold shmem lock before calling this function
1230
+ * to avoid file extension conflict among different pgpool child
1231
+ * process.
1232
+ * As of pgpool-II 3.2, pool_handle_query_cache is responsible for that.
1233
+ * (pool_handle_query_cache -> pool_commit_cache -> pool_add_table_oid_map)
1234
+ */
1235
+ static void pool_add_table_oid_map(POOL_CACHEKEY *cachekey, int num_table_oids, int *table_oids)
1236
+ {
1237
+ char *dir;
1238
+ int dboid;
1239
+ char path[1024];
1240
+ int i;
1241
+ int len;
1242
+
1243
+ /*
1244
+ * Create memqcache_oiddir
1245
+ */
1246
+ dir = pool_config->memqcache_oiddir;
1247
+
1248
+ if (mkdir(dir, S_IREAD|S_IWRITE|S_IEXEC) == -1)
1249
+ {
1250
+ if (errno != EEXIST)
1251
+ {
1252
+ pool_error("pool_add_table_oid_map: failed to create %s. Reason:%s", dir, strerror(errno));
1253
+ return;
1254
+ }
1255
+ }
1256
+
1257
+ /*
1258
+ * Create memqcache_oiddir/database_oid
1259
+ */
1260
+ dboid = pool_get_database_oid();
1261
+
1262
+ pool_debug("pool_add_table_oid_map: dboid %d", dboid);
1263
+ if (dboid <= 0)
1264
+ {
1265
+ pool_error("pool_add_table_oid_map: could not get database oid");
1266
+ return;
1267
+ }
1268
+
1269
+ snprintf(path, sizeof(path), "%s/%d", dir, dboid);
1270
+ if (mkdir(path, S_IREAD|S_IWRITE|S_IEXEC) == -1)
1271
+ {
1272
+ if (errno != EEXIST)
1273
+ {
1274
+ pool_error("pool_add_table_oid_map: failed to create %s. reason:%s", path, strerror(errno));
1275
+ return;
1276
+ }
1277
+ }
1278
+
1279
+ if (pool_is_shmem_cache())
1280
+ {
1281
+ len = sizeof(cachekey->cacheid);
1282
+ }
1283
+ else
1284
+ {
1285
+ len = sizeof(cachekey->hashkey);
1286
+ }
1287
+
1288
+ for (i=0;i<num_table_oids;i++)
1289
+ {
1290
+ int fd;
1291
+ int oid = table_oids[i];
1292
+ int sts;
1293
+ struct flock fl;
1294
+
1295
+ /*
1296
+ * Create or open each memqcache_oiddir/database_oid/table_oid
1297
+ */
1298
+ snprintf(path, sizeof(path), "%s/%d/%d", dir, dboid, oid);
1299
+ if ((fd = open(path, O_CREAT|O_RDWR, S_IRUSR|S_IWUSR)) == -1)
1300
+ {
1301
+ pool_error("pool_add_table_oid_map: failed to create or open %s. reason:%s",
1302
+ path, strerror(errno));
1303
+ return;
1304
+ }
1305
+
1306
+ fl.l_type = F_WRLCK;
1307
+ fl.l_whence = SEEK_SET;
1308
+ fl.l_start = 0; /* Offset from l_whence */
1309
+ fl.l_len = 0; /* length, 0 = to EOF */
1310
+
1311
+ sts = fcntl(fd, F_SETLKW, &fl);
1312
+ if (sts == -1)
1313
+ {
1314
+ pool_error("pool_add_table_oid_map: failed to lock %s. reason:%s",
1315
+ path, strerror(errno));
1316
+ close(fd);
1317
+ return;
1318
+ }
1319
+
1320
+ /*
1321
+ * Below was ifdef-out because of a performance reason.
1322
+ * Looking for duplicate cache entries in a file needed
1323
+ * unacceptably high cost. So we gave up this and decided not
1324
+ * to care about duplicate entries in the file.
1325
+ */
1326
+ #ifdef NOT_USED
1327
+ for (;;)
1328
+ {
1329
+ sts = read(fd, (char *)&buf, len);
1330
+ if (sts == -1)
1331
+ {
1332
+ pool_error("pool_add_table_oid_map: failed to read %s. reason:%s",
1333
+ path, strerror(errno));
1334
+ close(fd);
1335
+ return;
1336
+ }
1337
+ else if (sts == len)
1338
+ {
1339
+ if (memcmp(cachekey, &buf, len) == 0)
1340
+ {
1341
+ /* Same key found. Skip this */
1342
+ close(fd);
1343
+ return;
1344
+ }
1345
+ continue;
1346
+ }
1347
+ /*
1348
+ * Must be EOF
1349
+ */
1350
+ if (sts != 0)
1351
+ {
1352
+ pool_error("pool_add_table_oid_map: invalid read length %d for %s", sts, path);
1353
+ close(fd);
1354
+ return;
1355
+ }
1356
+ break;
1357
+ }
1358
+ #endif
1359
+
1360
+ if (lseek(fd, 0, SEEK_END) == -1)
1361
+ {
1362
+ pool_error("pool_add_table_oid_map: failed to lseek %s. reason:%s",
1363
+ path, strerror(errno));
1364
+ close(fd);
1365
+ return;
1366
+ }
1367
+
1368
+ /*
1369
+ * Write cache_id or cache key at the end of file
1370
+ */
1371
+ sts = write(fd, (char *)cachekey, len);
1372
+ if (sts == -1 || sts != len)
1373
+ {
1374
+ pool_error("pool_add_table_oid_map: failed to write %s. reason:%s",
1375
+ path, strerror(errno));
1376
+ close(fd);
1377
+ return;
1378
+ }
1379
+ close(fd);
1380
+ }
1381
+ }
1382
+
1383
+ /*
1384
+ * Discard all oid maps at pgpool-II startup.
1385
+ * This is necessary for shmem case.
1386
+ */
1387
+ void pool_discard_oid_maps(void)
1388
+ {
1389
+ char command[1024];
1390
+
1391
+ snprintf(command, sizeof(command), "/bin/rm -fr %s/[0-9]*",
1392
+ pool_config->memqcache_oiddir);
1393
+ system(command);
1394
+ }
1395
+
1396
+ void pool_discard_oid_maps_by_db(int dboid)
1397
+ {
1398
+ char command[1024];
1399
+
1400
+ if (pool_is_shmem_cache())
1401
+ {
1402
+ snprintf(command, sizeof(command), "/bin/rm -fr %s/%d/",
1403
+ pool_config->memqcache_oiddir, dboid);
1404
+ system(command);
1405
+ pool_debug("command: %s", command);
1406
+ }
1407
+ }
1408
+
1409
+ /*
1410
+ * Reading cache id(shmem case) or hash key(memcached case) from table
1411
+ * oid map file according to table_oids and discard cache entries. If
1412
+ * unlink is true, the file will be unlinked after successful cache
1413
+ * removal.
1414
+ */
1415
+ static void pool_invalidate_query_cache(int num_table_oids, int *table_oid, bool unlinkp, int dboid)
1416
+ {
1417
+ char *dir;
1418
+ char path[1024];
1419
+ int i;
1420
+ int len;
1421
+ POOL_CACHEKEY buf;
1422
+
1423
+ /*
1424
+ * Create memqcache_oiddir
1425
+ */
1426
+ dir = pool_config->memqcache_oiddir;
1427
+ if (mkdir(dir, S_IREAD|S_IWRITE|S_IEXEC) == -1)
1428
+ {
1429
+ if (errno != EEXIST)
1430
+ {
1431
+ pool_error("pool_invalidate_query_cache: failed to create %s", dir);
1432
+ return;
1433
+ }
1434
+ }
1435
+
1436
+ /*
1437
+ * Create memqcache_oiddir/database_oid
1438
+ */
1439
+ if (dboid == 0) {
1440
+ dboid = pool_get_database_oid();
1441
+
1442
+ pool_debug("pool_invalidate_query_cache: dboid %d", dboid);
1443
+ if (dboid <= 0)
1444
+ {
1445
+ pool_error("pool_invalidate_query_cache: could not get database oid");
1446
+ return;
1447
+ }
1448
+ }
1449
+
1450
+ snprintf(path, sizeof(path), "%s/%d", dir, dboid);
1451
+ if (mkdir(path, S_IREAD|S_IWRITE|S_IEXEC) == -1)
1452
+ {
1453
+ if (errno != EEXIST)
1454
+ {
1455
+ pool_error("pool_invalidate_query_cache: failed to create %s. reason:%s", path, strerror(errno));
1456
+ return;
1457
+ }
1458
+ }
1459
+
1460
+ if (pool_is_shmem_cache())
1461
+ {
1462
+ len = sizeof(buf.cacheid);
1463
+ }
1464
+ else
1465
+ {
1466
+ len = sizeof(buf.hashkey);
1467
+ }
1468
+
1469
+ for (i=0;i<num_table_oids;i++)
1470
+ {
1471
+ int fd;
1472
+ int oid = table_oid[i];
1473
+ int sts;
1474
+ struct flock fl;
1475
+
1476
+ /*
1477
+ * Open each memqcache_oiddir/database_oid/table_oid
1478
+ */
1479
+ snprintf(path, sizeof(path), "%s/%d/%d", dir, dboid, oid);
1480
+ if ((fd = open(path, O_RDONLY)) == -1)
1481
+ {
1482
+ /* This may be normal. It is possible that no SELECT has
1483
+ * been issued since the table has been created or since
1484
+ * pgpool-II started up.
1485
+ */
1486
+ pool_debug("pool_invalidate_query_cache: failed to open %s. reason:%s",
1487
+ path, strerror(errno));
1488
+ continue;
1489
+ }
1490
+
1491
+ fl.l_type = F_RDLCK;
1492
+ fl.l_whence = SEEK_SET;
1493
+ fl.l_start = 0; /* Offset from l_whence */
1494
+ fl.l_len = 0; /* length, 0 = to EOF */
1495
+
1496
+ sts = fcntl(fd, F_SETLKW, &fl);
1497
+ if (sts == -1)
1498
+ {
1499
+ pool_error("pool_invalidate_query_cache: failed to lock %s. reason:%s",
1500
+ path, strerror(errno));
1501
+ close(fd);
1502
+ return;
1503
+ }
1504
+ for (;;)
1505
+ {
1506
+ sts = read(fd, (char *)&buf, len);
1507
+ if (sts == -1)
1508
+ {
1509
+ pool_error("pool_invalidate_query_cache: failed to read %s. reason:%s",
1510
+ path, strerror(errno));
1511
+ close(fd);
1512
+ return;
1513
+ }
1514
+ else if (sts == len)
1515
+ {
1516
+ if (pool_is_shmem_cache())
1517
+ {
1518
+ pool_debug("pool_invalidate_query_cache: deleting cacheid:%d itemid:%d",
1519
+ buf.cacheid.blockid, buf.cacheid.itemid);
1520
+ pool_delete_item_shmem_cache(&buf.cacheid);
1521
+ }
1522
+ #ifdef USE_MEMCACHED
1523
+ else
1524
+ {
1525
+ char delbuf[33];
1526
+
1527
+ memcpy(delbuf, buf.hashkey, 32);
1528
+ delbuf[32] = 0;
1529
+ pool_debug("pool_invalidate_query_cache: deleting %s", delbuf);
1530
+ delete_cache_on_memcached(delbuf);
1531
+ }
1532
+ #endif
1533
+ continue;
1534
+ }
1535
+
1536
+ /*
1537
+ * Must be EOF
1538
+ */
1539
+ if (sts != 0)
1540
+ {
1541
+ pool_error("pool_invalidate_query_cache: invalid read length %d for %s", sts, path);
1542
+ close(fd);
1543
+ return;
1544
+ }
1545
+ break;
1546
+ }
1547
+
1548
+ if (unlinkp)
1549
+ {
1550
+ unlink(path);
1551
+ }
1552
+ close(fd);
1553
+ }
1554
+ #ifdef SHMEMCACHE_DEBUG
1555
+ dump_shmem_cache(0);
1556
+ #endif
1557
+ }
1558
+
1559
+ /*
1560
+ * Reset SELECT data buffers
1561
+ */
1562
+ static void pool_reset_memqcache_buffer(void)
1563
+ {
1564
+ POOL_SESSION_CONTEXT * session_context;
1565
+
1566
+ session_context = pool_get_session_context();
1567
+
1568
+ if (session_context && session_context->query_cache_array)
1569
+ {
1570
+ POOL_TEMP_QUERY_CACHE *cache;
1571
+
1572
+ pool_debug("pool_reset_memqcache_buffer: discard: %p", session_context->query_cache_array);
1573
+
1574
+ pool_discard_query_cache_array(session_context->query_cache_array);
1575
+ session_context->query_cache_array = pool_create_query_cache_array();
1576
+
1577
+ pool_debug("pool_reset_memqcache_buffer: create: %p", session_context->query_cache_array);
1578
+
1579
+ /*
1580
+ * if the query context is still under use, we cannot discard
1581
+ * temporary cache.
1582
+ */
1583
+ if (can_query_context_destroy(session_context->query_context))
1584
+ {
1585
+ pool_debug("pool_reset_memqcache_buffer: discard temp buffer of %p (%s)",
1586
+ session_context->query_context, session_context->query_context->original_query);
1587
+ cache = pool_get_current_cache();
1588
+ pool_discard_temp_query_cache(cache);
1589
+ /*
1590
+ * Reset temp_cache pointer in the current query context
1591
+ * so that we don't double free memory.
1592
+ */
1593
+ session_context->query_context->temp_cache = NULL;
1594
+ }
1595
+ }
1596
+ pool_discard_dml_table_oid();
1597
+ pool_tmp_stats_reset_num_selects();
1598
+ }
1599
+
1600
+ /*
1601
+ * Return true if memory cache method is "shmem". The purpose of this
1602
+ * function is to cache the result of stcmp and to save a few cycle.
1603
+ */
1604
+ bool pool_is_shmem_cache(void)
1605
+ {
1606
+ static int result = -1;
1607
+
1608
+ if (result == -1)
1609
+ {
1610
+ result = strcmp(pool_config->memqcache_method, "shmem");
1611
+ }
1612
+ return (result==0)?true:false;
1613
+ }
1614
+
1615
+ /*
1616
+ * Remember memory cache number of blocks.
1617
+ */
1618
+ static int memqcache_num_blocks;
1619
+ static void pool_set_memqcache_blocks(int num_blocks)
1620
+ {
1621
+ memqcache_num_blocks = num_blocks;
1622
+ }
1623
+
1624
+ /*
1625
+ * Return memory cache number of blocks.
1626
+ */
1627
+ static int pool_get_memqcache_blocks(void)
1628
+ {
1629
+ return memqcache_num_blocks;
1630
+ }
1631
+
1632
+ /*
1633
+ * Query cache on shared memory management modules.
1634
+ */
1635
+
1636
+ /*
1637
+ * Calculate necessary shared memory size.
1638
+ */
1639
+ size_t pool_shared_memory_cache_size(void)
1640
+ {
1641
+ int num_blocks;
1642
+ size_t size;
1643
+
1644
+ if (pool_config->memqcache_maxcache > pool_config->memqcache_cache_block_size)
1645
+ {
1646
+ pool_error("pool_shared_memory_cache_size: memqcache_cache_block_size %d should be greater or equal to memqcache_maxcache %d",
1647
+ pool_config->memqcache_cache_block_size, pool_config->memqcache_maxcache);
1648
+ return 0;
1649
+ }
1650
+
1651
+ num_blocks = pool_config->memqcache_total_size/
1652
+ pool_config->memqcache_cache_block_size;
1653
+ if (num_blocks == 0)
1654
+ {
1655
+ pool_error("pool_shared_memory_cache_size: memqcache_total_size %d should be greater or equal to memqcache_cache_block_size %d",
1656
+ pool_config->memqcache_total_size, pool_config->memqcache_cache_block_size);
1657
+ return 0;
1658
+ }
1659
+
1660
+ pool_log("pool_shared_memory_cache_size: number of blocks: %d", num_blocks);
1661
+
1662
+ /* Remember # of blocks */
1663
+ pool_set_memqcache_blocks(num_blocks);
1664
+ size = pool_config->memqcache_cache_block_size * num_blocks;
1665
+ return size;
1666
+ }
1667
+
1668
+ /*
1669
+ * Acquire and initialize shared memory cache. This should be called
1670
+ * only once from pgpool main process at the process staring up time.
1671
+ */
1672
+ static void *shmem;
1673
+ int pool_init_memory_cache(size_t size)
1674
+ {
1675
+ pool_debug("pool_init_memory_cache: request size:%zd", size);
1676
+ shmem = pool_shared_memory_create(size);
1677
+ if (shmem == NULL)
1678
+ {
1679
+ pool_error("pool_init_memory_cache: failed to allocate shared memory cache. request size: %zd", size);
1680
+ return -1;
1681
+ }
1682
+ return 0;
1683
+ }
1684
+
1685
+ /*
1686
+ * Clear all the shared memory cache and reset FSMM and hash table.
1687
+ */
1688
+ void
1689
+ pool_clear_memory_cache(void)
1690
+ {
1691
+ size_t size;
1692
+ #ifdef HAVE_SIGPROCMASK
1693
+ sigset_t oldmask;
1694
+ #else
1695
+ int oldmask;
1696
+ #endif
1697
+
1698
+ POOL_SETMASK2(&BlockSig, &oldmask);
1699
+ pool_shmem_lock();
1700
+
1701
+ size = pool_shared_memory_cache_size();
1702
+ memset(shmem, 0, size);
1703
+
1704
+ size = pool_shared_memory_fsmm_size();
1705
+ pool_reset_fsmm(size);
1706
+
1707
+ pool_discard_oid_maps();
1708
+
1709
+ pool_hash_reset(pool_config->memqcache_max_num_cache);
1710
+
1711
+ pool_shmem_unlock();
1712
+ POOL_SETMASK(&oldmask);
1713
+ }
1714
+
1715
+ /*
1716
+ * Return shared memory cache address
1717
+ */
1718
+ static void *pool_memory_cache_address(void)
1719
+ {
1720
+ return shmem;
1721
+ }
1722
+
1723
+ /*
1724
+ * Initialize new block
1725
+ */
1726
+
1727
+ /*
1728
+ * Free space management map
1729
+ *
1730
+ * Free space management map (FSMM) consists of bytes. Each byte
1731
+ * corresponds to block id. For example, if you have 1GB cache and
1732
+ * block size is 8Kb, number of blocks = 131,072, thus total size of
1733
+ * FSMM is 128Kb. Each FSMM entry has value from 0 to 255. Those
1734
+ * values describes total free space in each block.
1735
+ * For example, if the value is 2, the free space can be between 64
1736
+ * bytes and 95 bytes.
1737
+ *
1738
+ * value free space(in bytes)
1739
+ * 0 0-31
1740
+ * 1 32-63
1741
+ * 2 64-95
1742
+ * 3 96-127
1743
+ * :
1744
+ * 255 8160-8192
1745
+ */
1746
+
1747
+ /*
1748
+ * Calculate necessary shared memory size for FSMM. Should be called after
1749
+ * pool_shared_memory_cache_size.
1750
+ */
1751
+ size_t pool_shared_memory_fsmm_size(void)
1752
+ {
1753
+ size_t size;
1754
+
1755
+ size = pool_get_memqcache_blocks() * sizeof(char);
1756
+ return size;
1757
+ }
1758
+
1759
+ /*
1760
+ * Acquire and initialize shared memory cache for FSMM. This should be
1761
+ * called after pool_shared_memory_cache_size only once from pgpool
1762
+ * main process at the process staring up time.
1763
+ */
1764
+ static void *fsmm;
1765
+ int pool_init_fsmm(size_t size)
1766
+ {
1767
+ int maxblock = pool_get_memqcache_blocks();
1768
+ int encode_value;
1769
+
1770
+ fsmm = pool_shared_memory_create(size);
1771
+ if (fsmm == NULL)
1772
+ {
1773
+ pool_error("pool_init_fsmm: failed to allocate shared memory cache. request size: %zd", size);
1774
+ return -1;
1775
+ }
1776
+
1777
+ encode_value = POOL_MAX_FREE_SPACE/POOL_FSMM_RATIO;
1778
+ memset(fsmm, encode_value, maxblock);
1779
+ return 0;
1780
+ }
1781
+
1782
+ /*
1783
+ * Return shared memory fsmm address
1784
+ */
1785
+ static void *pool_fsmm_address(void)
1786
+ {
1787
+ return fsmm;
1788
+ }
1789
+
1790
+ /*
1791
+ * Clock algorithm shared query cache management modules.
1792
+ */
1793
+
1794
+ /*
1795
+ * Clock hand pointing to next victim block
1796
+ */
1797
+ static int *pool_fsmm_clock_hand;
1798
+
1799
+ /*
1800
+ * Allocate and initialize clock hand on shmem
1801
+ */
1802
+ void pool_allocate_fsmm_clock_hand(void)
1803
+ {
1804
+ pool_fsmm_clock_hand = pool_shared_memory_create(sizeof(*pool_fsmm_clock_hand));
1805
+ *pool_fsmm_clock_hand = 0;
1806
+ }
1807
+
1808
+ /*
1809
+ * Reset FSMM.
1810
+ */
1811
+ static void
1812
+ pool_reset_fsmm(size_t size)
1813
+ {
1814
+ int encode_value;
1815
+
1816
+ encode_value = POOL_MAX_FREE_SPACE/POOL_FSMM_RATIO;
1817
+ memset(fsmm, encode_value, size);
1818
+
1819
+ *pool_fsmm_clock_hand = 0;
1820
+ }
1821
+
1822
+ /*
1823
+ * Find victim block using clock algorithm and make it free.
1824
+ * Returns new free block id.
1825
+ */
1826
+ static POOL_CACHE_BLOCKID pool_reuse_block(void)
1827
+ {
1828
+ int maxblock = pool_get_memqcache_blocks();
1829
+ char *block = block_address(*pool_fsmm_clock_hand);
1830
+ POOL_CACHE_BLOCK_HEADER *bh = (POOL_CACHE_BLOCK_HEADER *)block;
1831
+ POOL_CACHE_BLOCKID reused_block;
1832
+ POOL_CACHE_ITEM_POINTER *cip;
1833
+ char *p;
1834
+ int i;
1835
+
1836
+ bh->flags = 0;
1837
+ reused_block = *pool_fsmm_clock_hand;
1838
+ p = block_address(reused_block);
1839
+
1840
+ for (i=0;i<bh->num_items;i++)
1841
+ {
1842
+ cip = item_pointer(p, i);
1843
+
1844
+ if (!(POOL_ITEM_DELETED & cip->flags))
1845
+ {
1846
+ pool_hash_delete(&cip->query_hash);
1847
+ pool_debug("pool_reuse_block: blockid: %d item: %d", reused_block, i);
1848
+ }
1849
+ }
1850
+
1851
+ pool_init_cache_block(reused_block);
1852
+ pool_update_fsmm(reused_block, POOL_MAX_FREE_SPACE);
1853
+
1854
+ (*pool_fsmm_clock_hand)++;
1855
+ if (*pool_fsmm_clock_hand >= maxblock)
1856
+ *pool_fsmm_clock_hand = 0;
1857
+
1858
+ pool_log("pool_reuse_block: blockid: %d", reused_block);
1859
+
1860
+ return reused_block;
1861
+ }
1862
+
1863
+ /*
1864
+ * Get block id which has enough space
1865
+ */
1866
+ static POOL_CACHE_BLOCKID pool_get_block(size_t free_space)
1867
+ {
1868
+ int encode_value;
1869
+ unsigned char *p = pool_fsmm_address();
1870
+ int i;
1871
+ int maxblock = pool_get_memqcache_blocks();
1872
+ POOL_CACHE_BLOCK_HEADER *bh;
1873
+
1874
+ if (p == NULL)
1875
+ {
1876
+ pool_error("pool_get_block: FSMM is not initialized");
1877
+ return -1;
1878
+ }
1879
+
1880
+ if (free_space > POOL_MAX_FREE_SPACE)
1881
+ {
1882
+ pool_error("pool_get_block: invalid free space %zd", free_space);
1883
+ return -1;
1884
+ }
1885
+
1886
+ encode_value = free_space/POOL_FSMM_RATIO;
1887
+
1888
+ for (i=0;i<maxblock;i++)
1889
+ {
1890
+ if (p[i] >= encode_value)
1891
+ {
1892
+ /*
1893
+ * This block *may" have enough space.
1894
+ * We need to make sure it actually has enough space.
1895
+ */
1896
+ bh = (POOL_CACHE_BLOCK_HEADER *)block_address(i);
1897
+ if (bh->free_bytes >= free_space)
1898
+ {
1899
+ return (POOL_CACHE_BLOCKID)i;
1900
+ }
1901
+ }
1902
+ }
1903
+
1904
+ /*
1905
+ * No enough space found. Reuse victim block
1906
+ */
1907
+ return pool_reuse_block();
1908
+ }
1909
+
1910
+ /*
1911
+ * Update free space info for specified block
1912
+ */
1913
+ static void pool_update_fsmm(POOL_CACHE_BLOCKID blockid, size_t free_space)
1914
+ {
1915
+ int encode_value;
1916
+ char *p = pool_fsmm_address();
1917
+
1918
+ if (p == NULL)
1919
+ {
1920
+ pool_error("pool_set_free_space: FSMM is not initialized");
1921
+ return;
1922
+ }
1923
+
1924
+ if (blockid >= pool_get_memqcache_blocks())
1925
+ {
1926
+ pool_error("pool_set_free_space: invalid block id %d", blockid);
1927
+ return;
1928
+ }
1929
+
1930
+ if (free_space < 0 || free_space > POOL_MAX_FREE_SPACE)
1931
+ {
1932
+ pool_error("pool_set_free_space: invalid free space %zd", free_space);
1933
+ return;
1934
+ }
1935
+
1936
+ encode_value = free_space/POOL_FSMM_RATIO;
1937
+
1938
+ p[blockid] = encode_value;
1939
+
1940
+ return;
1941
+ }
1942
+
1943
+ /*
1944
+ * Add item data to shared memory cache.
1945
+ * On successful registration, returns cache id.
1946
+ * The cache id is overwritten by the subsequent call to this function.
1947
+ * On error returns NULL.
1948
+ */
1949
+ static POOL_CACHEID *pool_add_item_shmem_cache(POOL_QUERY_HASH *query_hash, char *data, int size)
1950
+ {
1951
+ static POOL_CACHEID cacheid;
1952
+ POOL_CACHE_BLOCKID blockid;
1953
+ POOL_CACHE_BLOCK_HEADER *bh;
1954
+ POOL_CACHE_ITEM_POINTER *cip;
1955
+
1956
+ POOL_CACHE_ITEM ci;
1957
+ POOL_CACHE_ITEM_POINTER cip_body;
1958
+ char *item;
1959
+
1960
+ int request_size;
1961
+ char *p;
1962
+ int i;
1963
+ char *src;
1964
+ char *dst;
1965
+ int num_deleted;
1966
+ char *dcip;
1967
+ char *dci;
1968
+ bool need_pack;
1969
+ char *work_buffer;
1970
+ int index;
1971
+
1972
+ if (query_hash == NULL)
1973
+ {
1974
+ pool_error("pool_add_item_shmem_cache: query hash is NULL");
1975
+ return NULL;
1976
+ }
1977
+
1978
+ if (data == NULL)
1979
+ {
1980
+ pool_error("pool_add_item_shmem_cache: data NULL");
1981
+ return NULL;
1982
+ }
1983
+
1984
+ if (size <= 0)
1985
+ {
1986
+ pool_error("pool_add_item_shmem_cache: invalid request size: %d", size);
1987
+ return NULL;
1988
+ }
1989
+
1990
+ /* Add overhead */
1991
+ request_size = size + sizeof(POOL_CACHE_ITEM_POINTER) + sizeof(POOL_CACHE_ITEM_HEADER);
1992
+
1993
+ /* Get cache block which has enough space */
1994
+ blockid = pool_get_block(request_size);
1995
+
1996
+ if (blockid == -1)
1997
+ {
1998
+ return NULL;
1999
+ }
2000
+
2001
+ /*
2002
+ * Initialize the block if necessary. If no live items are
2003
+ * remained, we also initialize the block. If there's contiguous
2004
+ * deleted items, we turn them into free space as well.
2005
+ */
2006
+ pool_init_cache_block(blockid);
2007
+
2008
+ /*
2009
+ * Make sure that we have at least one free hash element.
2010
+ */
2011
+ while (!is_free_hash_element())
2012
+ {
2013
+ /* If not, reuse next victim block */
2014
+ blockid = pool_reuse_block();
2015
+ pool_init_cache_block(blockid);
2016
+ }
2017
+
2018
+ /* Get block address on shmem */
2019
+ p = block_address(blockid);
2020
+ bh = (POOL_CACHE_BLOCK_HEADER *)p;
2021
+
2022
+ /*
2023
+ * Create contiguous free space. We assume that item bodies are
2024
+ * ordered from bottom to top of the block, and corresponding item
2025
+ * pointers are ordered from the youngest to the oldest in the
2026
+ * beginning of the block.
2027
+ */
2028
+
2029
+ /*
2030
+ * Optimization. If there's no deleted items, we don't need to
2031
+ * pack it to create contiguous free space.
2032
+ */
2033
+ need_pack = false;
2034
+ for (i=0;i<bh->num_items;i++)
2035
+ {
2036
+ cip = item_pointer(p, i);
2037
+
2038
+ if (POOL_ITEM_DELETED & cip->flags) /* Deleted item? */
2039
+ {
2040
+ need_pack = true;
2041
+ pool_debug("pool_add_item_shmem_cache: start creating contiguous space");
2042
+ break;
2043
+ }
2044
+ }
2045
+
2046
+ /*
2047
+ * We disable packing for now.
2048
+ * Revisit and remove following code fragment later.
2049
+ */
2050
+ need_pack = false;
2051
+
2052
+ if (need_pack)
2053
+ {
2054
+ /*
2055
+ * Pack and create contiguous free space.
2056
+ */
2057
+ dcip = calloc(1, pool_config->memqcache_cache_block_size);
2058
+ if (!dcip)
2059
+ {
2060
+ pool_error("pool_add_item_shmem_cache: calloc failed");
2061
+ return NULL;
2062
+ }
2063
+
2064
+ work_buffer = dcip;
2065
+ dci = dcip + pool_config->memqcache_cache_block_size;
2066
+ num_deleted = 0;
2067
+ index = 0;
2068
+
2069
+ for (i=0;i<bh->num_items;i++)
2070
+ {
2071
+ int total_length;
2072
+ POOL_CACHEID cid;
2073
+
2074
+ cip = item_pointer(p, i);
2075
+
2076
+ if (POOL_ITEM_DELETED & cip->flags) /* Deleted item? */
2077
+ {
2078
+ num_deleted++;
2079
+ continue;
2080
+ }
2081
+
2082
+ /* Copy item body */
2083
+ src = p + cip->offset;
2084
+ total_length = item_header(p, i)->total_length;
2085
+ dst = dci - total_length;
2086
+ cip->offset = dst - work_buffer;
2087
+ memcpy(dst, src, total_length);
2088
+
2089
+ dci -= total_length;
2090
+
2091
+ /* Copy item pointer */
2092
+ src = (char *)cip;
2093
+ dst = (char *)item_pointer(dcip, index);
2094
+ memcpy(dst, src, sizeof(POOL_CACHE_ITEM_POINTER));
2095
+
2096
+ /* Update hash index */
2097
+ cid.blockid = blockid;
2098
+ cid.itemid = index;
2099
+ pool_hash_insert(&cip->query_hash, &cid, true);
2100
+ pool_debug("pool_add_item_shmem_cache: item cid updated. old:%d %d new:%d %d",
2101
+ blockid, i, blockid, index);
2102
+
2103
+ index++;
2104
+ }
2105
+
2106
+ /* All items deleted? */
2107
+ if (num_deleted > 0 && num_deleted == bh->num_items)
2108
+ {
2109
+ pool_debug("pool_add_item_shmem_cache: all items deleted num_deleted:%d", num_deleted);
2110
+ bh->flags = 0;
2111
+ pool_init_cache_block(blockid);
2112
+ pool_update_fsmm(blockid, POOL_MAX_FREE_SPACE);
2113
+ }
2114
+ else
2115
+ {
2116
+ /* Update number of items */
2117
+ bh->num_items -= num_deleted;
2118
+
2119
+ /* Copy back the packed block except block header */
2120
+ memcpy(p+sizeof(POOL_CACHE_BLOCK_HEADER),
2121
+ work_buffer+sizeof(POOL_CACHE_BLOCK_HEADER),
2122
+ pool_config->memqcache_cache_block_size-sizeof(POOL_CACHE_BLOCK_HEADER));
2123
+ }
2124
+ free(work_buffer);
2125
+ }
2126
+
2127
+ /*
2128
+ * Make sure that we have enough free space
2129
+ */
2130
+ if (bh->free_bytes < request_size)
2131
+ {
2132
+ /* This should not happen */
2133
+ pool_error("pool_add_item_shmem_cache: not enough free space. Free space: %d required: %d block id:%d",
2134
+ bh->free_bytes, request_size, blockid);
2135
+ return NULL;
2136
+ }
2137
+
2138
+ /*
2139
+ * At this point, new item can be located at block_header->num_items
2140
+ */
2141
+
2142
+ /* Fill in cache item header */
2143
+ ci.header.timestamp = time(NULL);
2144
+ ci.header.total_length = sizeof(POOL_CACHE_ITEM_HEADER) + size;
2145
+
2146
+ /* Calculate item body address */
2147
+ if (bh->num_items == 0)
2148
+ {
2149
+ /* This is the #0 item. So address is block_bottom -
2150
+ * data_length */
2151
+ item = p + pool_config->memqcache_cache_block_size - ci.header.total_length;
2152
+
2153
+ /* Mark this block used */
2154
+ bh->flags = POOL_BLOCK_USED;
2155
+ }
2156
+ else
2157
+ {
2158
+ cip = item_pointer(p, bh->num_items-1);
2159
+ item = p + cip->offset - ci.header.total_length;
2160
+ }
2161
+
2162
+ /* Copy item header */
2163
+ memcpy(item, &ci, sizeof(POOL_CACHE_ITEM_HEADER));
2164
+ bh->free_bytes -= sizeof(POOL_CACHE_ITEM_HEADER);
2165
+
2166
+ /* Copy item body */
2167
+ memcpy(item + sizeof(POOL_CACHE_ITEM_HEADER), data, size);
2168
+ bh->free_bytes -= size;
2169
+
2170
+ /* Copy cache item pointer */
2171
+ memcpy(&cip_body.query_hash, query_hash, sizeof(POOL_QUERY_HASH));
2172
+ memset(&cip_body.next, 0, sizeof(POOL_CACHEID));
2173
+ cip_body.offset = item - p;
2174
+ cip_body.flags = POOL_ITEM_USED;
2175
+ memcpy(item_pointer(p, bh->num_items), &cip_body, sizeof(POOL_CACHE_ITEM_POINTER));
2176
+ bh->free_bytes -= sizeof(POOL_CACHE_ITEM_POINTER);
2177
+
2178
+ /* Update FSMM */
2179
+ pool_update_fsmm(blockid, bh->free_bytes);
2180
+
2181
+ cacheid.blockid = blockid;
2182
+ cacheid.itemid = bh->num_items;
2183
+ pool_debug("pool_add_item_shmem_cache: new item inserted. blockid: %d itemid:%d",
2184
+ cacheid.blockid, cacheid.itemid);
2185
+
2186
+ /* Add up number of items */
2187
+ bh->num_items++;
2188
+
2189
+ /* Update hash table */
2190
+ if (pool_hash_insert(query_hash, &cacheid, false) < 0)
2191
+ {
2192
+ pool_error("pool_add_item_shmem_cache: pool_hash_insert failed");
2193
+
2194
+ /* Since we have failed to insert hash index entry, we need to
2195
+ * undo the addition of cache entry.
2196
+ */
2197
+ pool_delete_item_shmem_cache(&cacheid);
2198
+ return NULL;
2199
+ }
2200
+
2201
+ pool_debug("pool_add_item_shmem_cache: block: %d item: %d", cacheid.blockid, cacheid.itemid);
2202
+
2203
+ #ifdef SHMEMCACHE_DEBUG
2204
+ dump_shmem_cache(blockid);
2205
+ #endif
2206
+ return &cacheid;
2207
+ }
2208
+
2209
+ /*
2210
+ * Returns item data address on shared memory cache specified by query hash.
2211
+ * Also data length is set to *size.
2212
+ * On error or data not found case returns NULL.
2213
+ * Detail is set to *sts. (0: success, 1: not found, -1: error)
2214
+ */
2215
+ static char *pool_get_item_shmem_cache(POOL_QUERY_HASH *query_hash, int *size, int *sts)
2216
+ {
2217
+ POOL_CACHEID *cacheid;
2218
+ POOL_CACHE_ITEM_HEADER *cih;
2219
+
2220
+ if (sts == NULL)
2221
+ {
2222
+ pool_error("pool_get_item_shmem_cache: sts is NULL");
2223
+ return NULL;
2224
+ }
2225
+
2226
+ *sts = -1;
2227
+
2228
+ if (query_hash == NULL)
2229
+ {
2230
+ pool_error("pool_get_item_shmem_cache: query hash is NULL");
2231
+ return NULL;
2232
+ }
2233
+
2234
+ if (size == NULL)
2235
+ {
2236
+ pool_error("pool_get_item_shmem_cache: size is NULL");
2237
+ return NULL;
2238
+ }
2239
+
2240
+ /*
2241
+ * Find cache header by using hash table
2242
+ */
2243
+ cacheid = pool_find_item_on_shmem_cache(query_hash);
2244
+ if (cacheid == NULL)
2245
+ {
2246
+ /* Not found */
2247
+ *sts = 1;
2248
+ return NULL;
2249
+ }
2250
+
2251
+ cih = pool_cache_item_header(cacheid);
2252
+
2253
+ *size = cih->total_length - sizeof(POOL_CACHE_ITEM_HEADER);
2254
+ return (char *)cih + sizeof(POOL_CACHE_ITEM_HEADER);
2255
+ }
2256
+
2257
+ /*
2258
+ * Find data on shared memory cache specified query hash.
2259
+ * On success returns cache id.
2260
+ * The cache id is overwritten by the subsequent call to this function.
2261
+ */
2262
+ static POOL_CACHEID *pool_find_item_on_shmem_cache(POOL_QUERY_HASH *query_hash)
2263
+ {
2264
+ static POOL_CACHEID cacheid;
2265
+ POOL_CACHEID *c;
2266
+ POOL_CACHE_ITEM_HEADER *cih;
2267
+ time_t now;
2268
+
2269
+ c = pool_hash_search(query_hash);
2270
+ if (!c)
2271
+ {
2272
+ return NULL;
2273
+ }
2274
+
2275
+ cih = item_header(block_address(c->blockid), c->itemid);
2276
+
2277
+ /* Check cache expiration */
2278
+ if (pool_config->memqcache_expire > 0)
2279
+ {
2280
+ now = time(NULL);
2281
+ if (now > (cih->timestamp + pool_config->memqcache_expire))
2282
+ {
2283
+ pool_debug("pool_find_item_on_shmem_cache: cache expired");
2284
+ pool_debug("pool_find_item_on_shmem_cache: now: %ld timestamp: %ld",
2285
+ now, cih->timestamp + pool_config->memqcache_expire);
2286
+ pool_delete_item_shmem_cache(c);
2287
+ return NULL;
2288
+ }
2289
+ }
2290
+
2291
+ cacheid.blockid = c->blockid;
2292
+ cacheid.itemid = c->itemid;
2293
+ return &cacheid;
2294
+ }
2295
+
2296
+ /*
2297
+ * Delete item data specified cache id from shmem.
2298
+ * On successful deletion, returns 0.
2299
+ * Other wise return -1.
2300
+ * FSMM is also updated.
2301
+ */
2302
+ static int pool_delete_item_shmem_cache(POOL_CACHEID *cacheid)
2303
+ {
2304
+ POOL_CACHE_BLOCK_HEADER *bh;
2305
+ POOL_CACHE_ITEM_POINTER *cip;
2306
+ POOL_CACHE_ITEM_HEADER *cih;
2307
+ POOL_QUERY_HASH key;
2308
+ int size;
2309
+
2310
+ pool_debug("pool_delete_item_shmem_cache: cacheid:%d itemid:%d",
2311
+ cacheid->blockid, cacheid->itemid);
2312
+
2313
+ if (cacheid->blockid >= pool_get_memqcache_blocks())
2314
+ {
2315
+ pool_error("pool_delete_item_shmem_cache: invalid block id %d",
2316
+ cacheid->blockid);
2317
+ return -1;
2318
+ }
2319
+
2320
+ bh = (POOL_CACHE_BLOCK_HEADER *)block_address(cacheid->blockid);
2321
+ if (!(bh->flags & POOL_BLOCK_USED))
2322
+ {
2323
+ pool_error("pool_delete_item_shmem_cache: block %d is not used",
2324
+ cacheid->blockid);
2325
+ return -1;
2326
+ }
2327
+
2328
+ if (cacheid->itemid < 0 || cacheid->itemid >= bh->num_items)
2329
+ {
2330
+ /*
2331
+ * This could happen if the block is reused. Since contents
2332
+ * of oid map file is not updated when the block is reused.
2333
+ */
2334
+ pool_debug("pool_delete_item_shmem_cache: invalid item id %d in block:%d",
2335
+ cacheid->itemid, cacheid->blockid);
2336
+ return -1;
2337
+ }
2338
+
2339
+ cip = item_pointer(block_address(cacheid->blockid), cacheid->itemid);
2340
+ if (!(cip->flags & POOL_ITEM_USED))
2341
+ {
2342
+ pool_error("pool_delete_item_shmem_cache: item %d was not used",
2343
+ cacheid->itemid);
2344
+ return -1;
2345
+ }
2346
+
2347
+ if (cip->flags & POOL_ITEM_DELETED)
2348
+ {
2349
+ pool_error("pool_delete_item_shmem_cache: item %d was deleted",
2350
+ cacheid->itemid);
2351
+ return -1;
2352
+ }
2353
+
2354
+ /* Save cache key */
2355
+ memcpy(&key, &cip->query_hash, sizeof(POOL_QUERY_HASH));
2356
+
2357
+ cih = pool_cache_item_header(cacheid);
2358
+ size = cih->total_length + sizeof(POOL_CACHE_ITEM_POINTER);
2359
+
2360
+ /* Delete item pointer */
2361
+ cip->flags |= POOL_ITEM_DELETED;
2362
+
2363
+ /*
2364
+ * We do NOT count down bh->num_items here. The deleted space will be recycled
2365
+ * by pool_add_item_shmem_cache(). However, if this is the last item, we can
2366
+ * recycle whole block.
2367
+ *
2368
+ * 2012/4/1: Now we do not pack data in
2369
+ * pool_add_item_shmem_cache() for performance reason. Also we
2370
+ * count down num_items if it is the last one.
2371
+ */
2372
+ if ((bh->num_items -1) == 0)
2373
+ {
2374
+ pool_debug("pool_delete_item_shmem_cache: no item remains. So initialize block");
2375
+ bh->flags = 0;
2376
+ pool_init_cache_block(cacheid->blockid);
2377
+ }
2378
+
2379
+ /* Remove hash index */
2380
+ pool_hash_delete(&key);
2381
+
2382
+ /*
2383
+ * If the deleted item is last one in the block, we add it to the free space.
2384
+ */
2385
+ if (cacheid->itemid == (bh->num_items -1))
2386
+ {
2387
+ bh->free_bytes += size;
2388
+ pool_debug("pool_delete_item_shmem_cache: after deleting %d bytes, free_bytes is %d",
2389
+ size, bh->free_bytes);
2390
+ bh->num_items--;
2391
+ }
2392
+
2393
+ /* Update FSMM */
2394
+ pool_update_fsmm(cacheid->blockid, bh->free_bytes);
2395
+
2396
+ return 0;
2397
+ }
2398
+
2399
+ /*
2400
+ * Returns item header specified by cache id.
2401
+ */
2402
+ static POOL_CACHE_ITEM_HEADER *pool_cache_item_header(POOL_CACHEID *cacheid)
2403
+ {
2404
+ POOL_CACHE_BLOCK_HEADER *bh;
2405
+
2406
+ if (cacheid->blockid >= pool_get_memqcache_blocks())
2407
+ {
2408
+ pool_error("pool_cache_item_header: invalid block id %d", cacheid->blockid);
2409
+ return NULL;
2410
+ }
2411
+
2412
+ bh = (POOL_CACHE_BLOCK_HEADER *)block_address(cacheid->blockid);
2413
+ if (cacheid->itemid < 0 || cacheid->itemid >= bh->num_items)
2414
+ {
2415
+ pool_error("pool_cache_item_header: invalid item id %d", cacheid->itemid);
2416
+ return NULL;
2417
+ }
2418
+
2419
+ return item_header((char *)bh, cacheid->itemid);
2420
+ }
2421
+
2422
+ /*
2423
+ * Initialize specified block.
2424
+ */
2425
+ static int pool_init_cache_block(POOL_CACHE_BLOCKID blockid)
2426
+ {
2427
+ char *p;
2428
+ POOL_CACHE_BLOCK_HEADER *bh;
2429
+
2430
+ if (blockid >= pool_get_memqcache_blocks())
2431
+ {
2432
+ pool_error("pool_init_cache_block: invalid block id %d", blockid);
2433
+ return -1;
2434
+ }
2435
+
2436
+ p = block_address(blockid);
2437
+ bh = (POOL_CACHE_BLOCK_HEADER *)p;
2438
+
2439
+ /* Is this block used? */
2440
+ if (!(bh->flags & POOL_BLOCK_USED))
2441
+ {
2442
+ /* Initialize empty block */
2443
+ memset(p, 0, pool_config->memqcache_cache_block_size);
2444
+ bh->free_bytes = pool_config->memqcache_cache_block_size -
2445
+ sizeof(POOL_CACHE_BLOCK_HEADER);
2446
+ }
2447
+ return 0;
2448
+ }
2449
+
2450
+ #if NOT_USED
2451
+ /*
2452
+ * Delete all items in the block.
2453
+ */
2454
+ static void pool_wipe_out_cache_block(POOL_CACHE_BLOCKID blockid)
2455
+ {
2456
+ char *p;
2457
+ POOL_CACHE_BLOCK_HEADER *bh;
2458
+ POOL_CACHE_ITEM_POINTER *cip;
2459
+ POOL_CACHEID cacheid;
2460
+ int i;
2461
+
2462
+ /* Get block address on shmem */
2463
+ p = block_address(blockid);
2464
+ bh = (POOL_CACHE_BLOCK_HEADER *)p;
2465
+ cacheid.blockid = blockid;
2466
+
2467
+ for (i=0;i<bh->num_items;i++)
2468
+ {
2469
+ cip = item_pointer(p, i);
2470
+
2471
+ if ((POOL_ITEM_DELETED & cip->flags) == 0) /* Not deleted item? */
2472
+ {
2473
+ cacheid.itemid = i;
2474
+ pool_delete_item_shmem_cache(&cacheid);
2475
+ }
2476
+ }
2477
+
2478
+ bh->flags = 0;
2479
+ pool_init_cache_block(blockid);
2480
+ pool_update_fsmm(blockid, POOL_MAX_FREE_SPACE);
2481
+ }
2482
+ #endif
2483
+
2484
+ /*
2485
+ * Acquire lock: XXX giant lock
2486
+ */
2487
+ void pool_shmem_lock(void)
2488
+ {
2489
+ if (pool_is_shmem_cache())
2490
+ {
2491
+ pool_semaphore_lock(SHM_CACHE_SEM);
2492
+ }
2493
+ }
2494
+
2495
+ /*
2496
+ * Release lock
2497
+ */
2498
+ void pool_shmem_unlock(void)
2499
+ {
2500
+ if (pool_is_shmem_cache())
2501
+ {
2502
+ pool_semaphore_unlock(SHM_CACHE_SEM);
2503
+ }
2504
+ }
2505
+
2506
+ /*
2507
+ * Returns cache block address specified by block id
2508
+ */
2509
+ static char *block_address(int blockid)
2510
+ {
2511
+ char *p;
2512
+
2513
+ p = pool_memory_cache_address() +
2514
+ blockid * pool_config->memqcache_cache_block_size;
2515
+ return p;
2516
+ }
2517
+
2518
+ /*
2519
+ * Returns i th item pointer in block address block
2520
+ */
2521
+ static POOL_CACHE_ITEM_POINTER *item_pointer(char *block, int i)
2522
+ {
2523
+ return (POOL_CACHE_ITEM_POINTER *)(block + sizeof(POOL_CACHE_BLOCK_HEADER) +
2524
+ sizeof(POOL_CACHE_ITEM_POINTER) * i);
2525
+ }
2526
+
2527
+ /*
2528
+ * Returns i th item header in block address block
2529
+ */
2530
+ static POOL_CACHE_ITEM_HEADER *item_header(char *block, int i)
2531
+ {
2532
+ POOL_CACHE_ITEM_POINTER *cip;
2533
+
2534
+ cip = item_pointer(block, i);
2535
+ return (POOL_CACHE_ITEM_HEADER *)(block + cip->offset);
2536
+ }
2537
+
2538
+ #ifdef SHMEMCACHE_DEBUG
2539
+ /*
2540
+ * Dump shmem cache block
2541
+ */
2542
+ static void dump_shmem_cache(POOL_CACHE_BLOCKID blockid)
2543
+ {
2544
+ POOL_CACHE_BLOCK_HEADER *bh;
2545
+ POOL_CACHE_ITEM_POINTER *cip;
2546
+ POOL_CACHE_ITEM_HEADER *cih;
2547
+ int i;
2548
+
2549
+ bh = (POOL_CACHE_BLOCK_HEADER *)block_address(blockid);
2550
+ fprintf(stderr, "shmem: block header(%lu bytes): flags:%x num_items:%d free_bytes:%d\n",
2551
+ sizeof(*bh), bh->flags, bh->num_items, bh->free_bytes);
2552
+ for (i=0;i<bh->num_items;i++)
2553
+ {
2554
+ cip = item_pointer((char *)bh, i);
2555
+ fprintf(stderr, "shmem: block: %d %d th item pointer(%lu bytes): offset:%d flags:%x\n",
2556
+ blockid, i, sizeof(*cip), cip->offset, cip->flags);
2557
+ cih = item_header((char *)bh, i);
2558
+ fprintf(stderr, "shmem: block: %d %d th item header(%lu bytes): timestamp:%ld length:%d\n",
2559
+ blockid, i, sizeof(*cih), cih->timestamp, cih->total_length);
2560
+ }
2561
+ }
2562
+ #endif
2563
+
2564
+ /*
2565
+ * SELECT query result array modules
2566
+ */
2567
+ POOL_QUERY_CACHE_ARRAY *pool_create_query_cache_array(void)
2568
+ {
2569
+ #define POOL_QUERY_CACHE_ARRAY_ALLOCATE_NUM 128
2570
+ #define POOL_QUERY_CACHE_ARRAY_HEADER_SIZE (sizeof(int)+sizeof(int))
2571
+
2572
+ size_t size;
2573
+ POOL_QUERY_CACHE_ARRAY *p;
2574
+
2575
+ size = POOL_QUERY_CACHE_ARRAY_HEADER_SIZE + POOL_QUERY_CACHE_ARRAY_ALLOCATE_NUM *
2576
+ sizeof(POOL_TEMP_QUERY_CACHE *);
2577
+ p = malloc(size);
2578
+ if (!p)
2579
+ {
2580
+ pool_error("pool_create_query_cache_array: malloc failed");
2581
+ return p;
2582
+ }
2583
+ p->num_caches = 0;
2584
+ p->array_size = POOL_QUERY_CACHE_ARRAY_ALLOCATE_NUM;
2585
+ return p;
2586
+ }
2587
+
2588
+ /*
2589
+ * Discard query cache array
2590
+ */
2591
+ void pool_discard_query_cache_array(POOL_QUERY_CACHE_ARRAY *cache_array)
2592
+ {
2593
+ int i;
2594
+
2595
+ if (!cache_array)
2596
+ return;
2597
+
2598
+ pool_debug("pool_discard_query_cache_array: num_caches: %d", cache_array->num_caches);
2599
+
2600
+ for (i=0;i<cache_array->num_caches;i++)
2601
+ {
2602
+ pool_debug("pool_discard_query_cache_array: i: %d cache: %p", i, cache_array->caches[i]);
2603
+ pool_discard_temp_query_cache(cache_array->caches[i]);
2604
+ }
2605
+ free(cache_array);
2606
+ }
2607
+
2608
+ /*
2609
+ * Add query cache array
2610
+ */
2611
+ static POOL_QUERY_CACHE_ARRAY * pool_add_query_cache_array(POOL_QUERY_CACHE_ARRAY *cache_array, POOL_TEMP_QUERY_CACHE *cache)
2612
+ {
2613
+ size_t size;
2614
+ POOL_QUERY_CACHE_ARRAY *cp = cache_array;
2615
+
2616
+ if (!cache_array)
2617
+ return cp;
2618
+
2619
+ pool_debug("pool_add_query_cache_array: num_caches: %d cache: %p", cache_array->num_caches, cache);
2620
+
2621
+ if (cache_array->num_caches >= cache_array->array_size)
2622
+ {
2623
+ cache_array->array_size += POOL_QUERY_CACHE_ARRAY_ALLOCATE_NUM;
2624
+ size = POOL_QUERY_CACHE_ARRAY_HEADER_SIZE + cache_array->array_size *
2625
+ sizeof(POOL_TEMP_QUERY_CACHE *);
2626
+ cache_array = realloc(cache_array, size);
2627
+ if (!cache_array)
2628
+ {
2629
+ pool_error("pool_add_query_cache_array: malloc failed");
2630
+ return cp;
2631
+ }
2632
+ }
2633
+ cache_array->caches[cache_array->num_caches++] = cache;
2634
+ return cache_array;
2635
+ }
2636
+
2637
+ /*
2638
+ * SELECT query result temporary cache modules
2639
+ */
2640
+
2641
+ /*
2642
+ * Create SELECT result temporary cache
2643
+ */
2644
+ POOL_TEMP_QUERY_CACHE *pool_create_temp_query_cache(char *query)
2645
+ {
2646
+ POOL_TEMP_QUERY_CACHE *p;
2647
+
2648
+ p = malloc(sizeof(*p));
2649
+ if (p)
2650
+ {
2651
+ p->query = strdup(query);
2652
+ if (!p->query)
2653
+ {
2654
+ pool_error("pool_create_temp_query_cache: strdup failed");
2655
+ free(p);
2656
+ return NULL;
2657
+ }
2658
+ p->buffer = pool_create_buffer();
2659
+ if (!p->buffer)
2660
+ {
2661
+ free(p->query);
2662
+ free(p);
2663
+ return NULL;
2664
+ }
2665
+ p->oids = pool_create_buffer();
2666
+ if (!p->oids)
2667
+ {
2668
+ free(p->query);
2669
+ free(p->buffer);
2670
+ free(p);
2671
+ return NULL;
2672
+ }
2673
+ p->num_oids = 0;
2674
+ p->is_exceeded = false;
2675
+ p->is_discarded = false;
2676
+ }
2677
+ return p;
2678
+ }
2679
+
2680
+ /*
2681
+ * Discard temp query cache
2682
+ */
2683
+ void pool_discard_temp_query_cache(POOL_TEMP_QUERY_CACHE *temp_cache)
2684
+ {
2685
+ if (!temp_cache)
2686
+ return;
2687
+
2688
+ if (temp_cache->query)
2689
+ free(temp_cache->query);
2690
+ if (temp_cache->buffer)
2691
+ pool_discard_buffer(temp_cache->buffer);
2692
+ if (temp_cache->oids)
2693
+ pool_discard_buffer(temp_cache->oids);
2694
+ free(temp_cache);
2695
+ }
2696
+
2697
+ /*
2698
+ * Add data to temp query cache.
2699
+ * Data must be FE/BE protocol packet.
2700
+ */
2701
+ static void pool_add_temp_query_cache(POOL_TEMP_QUERY_CACHE *temp_cache, char kind, char *data, int data_len)
2702
+ {
2703
+ POOL_INTERNAL_BUFFER *buffer;
2704
+ size_t buflen;
2705
+ int send_len;
2706
+
2707
+ if (temp_cache == NULL)
2708
+ {
2709
+ /* This could happen if cache exceeded in previous query
2710
+ * execution in the same unnamed portal.
2711
+ */
2712
+ pool_debug("pool_add_temp_query_cache: POOL_TEMP_QUERY_CACHE is NULL");
2713
+ return;
2714
+ }
2715
+
2716
+ if (temp_cache->is_exceeded)
2717
+ {
2718
+ pool_debug("pool_add_temp_query_cache: memqcache_maxcache exceeds");
2719
+ return;
2720
+ }
2721
+
2722
+ /*
2723
+ * We only store T(Table Description), D(Data row), C(Command Complete),
2724
+ * 1(ParseComplete), 2(BindComplete)
2725
+ */
2726
+ if (kind != 'T' && kind != 'D' && kind != 'C' && kind != '1' && kind != '2')
2727
+ {
2728
+ return;
2729
+ }
2730
+
2731
+ /* Check data limit */
2732
+ buffer = temp_cache->buffer;
2733
+ buflen = pool_get_buffer_length(buffer);
2734
+
2735
+ if ((buflen+data_len+sizeof(int)+1) > pool_config->memqcache_maxcache)
2736
+ {
2737
+ pool_debug("pool_add_temp_query_cache: data size exceeds memqcache_maxcache. current:%zd requested:%zd memq_maxcache:%d",
2738
+ buflen, data_len+sizeof(int)+1, pool_config->memqcache_maxcache);
2739
+ temp_cache->is_exceeded = true;
2740
+ return;
2741
+ }
2742
+
2743
+ pool_add_buffer(buffer, &kind, 1);
2744
+ send_len = htonl(data_len + sizeof(int));
2745
+ pool_add_buffer(buffer, (char *)&send_len, sizeof(int));
2746
+ pool_add_buffer(buffer, data, data_len);
2747
+
2748
+ return;
2749
+ }
2750
+
2751
+ /*
2752
+ * Add table oids used by SELECT to temp query cache.
2753
+ */
2754
+ static void pool_add_oids_temp_query_cache(POOL_TEMP_QUERY_CACHE *temp_cache, int num_oids, int *oids)
2755
+ {
2756
+ POOL_INTERNAL_BUFFER *buffer;
2757
+
2758
+ if (!temp_cache || num_oids <= 0)
2759
+ return;
2760
+
2761
+ buffer = temp_cache->oids;
2762
+ pool_add_buffer(buffer, oids, num_oids*sizeof(int));
2763
+ temp_cache->num_oids = num_oids;
2764
+ }
2765
+
2766
+ /*
2767
+ * Internal buffer management modules.
2768
+ * Usage:
2769
+ * 1) Create buffer using pool_create_buffer().
2770
+ * 2) Add data to buffer using pool_add_buffer().
2771
+ * 3) Extract (copied) data from buffer using pool_get_buffer().
2772
+ * 4) Optionally you can:
2773
+ * Obtain buffer length by using pool_get_buffer_length().
2774
+ * Obtain buffer pointer by using pool_get_buffer_pointer().
2775
+ * 5) Discard buffer using pool_discard_buffer().
2776
+ */
2777
+
2778
+ /*
2779
+ * Create and return internal buffer
2780
+ */
2781
+ static POOL_INTERNAL_BUFFER *pool_create_buffer(void)
2782
+ {
2783
+ POOL_INTERNAL_BUFFER *p;
2784
+ p = malloc(sizeof(*p));
2785
+ if (p)
2786
+ {
2787
+ memset(p, 0, sizeof(*p));
2788
+ }
2789
+ return p;
2790
+ }
2791
+
2792
+ /*
2793
+ * Discard internal buffer
2794
+ */
2795
+ static void pool_discard_buffer(POOL_INTERNAL_BUFFER *buffer)
2796
+ {
2797
+ if (buffer)
2798
+ {
2799
+ if (buffer->buf)
2800
+ free(buffer->buf);
2801
+ free(buffer);
2802
+ }
2803
+ }
2804
+
2805
+ /*
2806
+ * Add data to internal buffer
2807
+ */
2808
+ static void pool_add_buffer(POOL_INTERNAL_BUFFER *buffer, void *data, size_t len)
2809
+ {
2810
+ #define POOL_ALLOCATE_UNIT 8192
2811
+
2812
+ /* Sanity check */
2813
+ if (!buffer || !data || len == 0)
2814
+ return;
2815
+
2816
+ /* Check if we need to increase the buffer size */
2817
+ if ((buffer->buflen + len) > buffer->bufsize)
2818
+ {
2819
+ size_t allocate_size = ((buffer->buflen + len)/POOL_ALLOCATE_UNIT +1)*POOL_ALLOCATE_UNIT;
2820
+ pool_debug("pool_add_buffer: realloc old size:%zd new size:%zd",
2821
+ buffer->bufsize, allocate_size);
2822
+ buffer->bufsize = allocate_size;
2823
+ buffer->buf = (char *)realloc(buffer->buf, buffer->bufsize);
2824
+ if (!buffer->buf)
2825
+ {
2826
+ pool_error("pool_add_buffer: realloc failed(request size:%zd",
2827
+ buffer->bufsize);
2828
+ return;
2829
+ }
2830
+ }
2831
+ /* Add data to buffer */
2832
+ memcpy(buffer->buf+buffer->buflen, data, len);
2833
+ buffer->buflen += len;
2834
+
2835
+ pool_debug("pool_add_buffer: len:%zd, total:%zd bufsize:%zd",
2836
+ len, buffer->buflen, buffer->bufsize);
2837
+
2838
+ return;
2839
+ }
2840
+
2841
+ /*
2842
+ * Get data from internal buffer.
2843
+ * Data is stored in newly malloc memory.
2844
+ * Data length is returned to len.
2845
+ */
2846
+ static void *pool_get_buffer(POOL_INTERNAL_BUFFER *buffer, size_t *len)
2847
+ {
2848
+ void *p;
2849
+
2850
+ if (buffer->bufsize == 0 || buffer->buflen == 0 ||
2851
+ buffer->buf == NULL)
2852
+ {
2853
+ *len = 0;
2854
+ return NULL;
2855
+ }
2856
+
2857
+ p = malloc(buffer->buflen);
2858
+ if (!p)
2859
+ {
2860
+ pool_error("pool_get_buffer: malloc failed. Request size:%zd", buffer->buflen);
2861
+ *len = 0;
2862
+ return NULL;
2863
+ }
2864
+ memcpy(p, buffer->buf, buffer->buflen);
2865
+ *len = buffer->buflen;
2866
+ return p;
2867
+ }
2868
+
2869
+ /*
2870
+ * Get internal buffer length.
2871
+ */
2872
+ static size_t pool_get_buffer_length(POOL_INTERNAL_BUFFER *buffer)
2873
+ {
2874
+ if (buffer == NULL)
2875
+ return 0;
2876
+
2877
+ return buffer->buflen;
2878
+ }
2879
+
2880
+ /*
2881
+ * Get internal buffer pointer.
2882
+ */
2883
+ static char *pool_get_buffer_pointer(POOL_INTERNAL_BUFFER *buffer)
2884
+ {
2885
+ if (buffer == NULL)
2886
+ return NULL;
2887
+
2888
+ return buffer->buf;
2889
+ }
2890
+
2891
+ /*
2892
+ * Get query cache buffer struct of current query context
2893
+ */
2894
+ POOL_TEMP_QUERY_CACHE *pool_get_current_cache(void)
2895
+ {
2896
+ POOL_SESSION_CONTEXT *session_context;
2897
+ POOL_QUERY_CONTEXT *query_context;
2898
+ POOL_TEMP_QUERY_CACHE *p = NULL;
2899
+
2900
+ session_context = pool_get_session_context();
2901
+ if (session_context)
2902
+ {
2903
+ query_context = session_context->query_context;
2904
+ if (query_context)
2905
+ {
2906
+ p = query_context->temp_cache;
2907
+ }
2908
+ }
2909
+ return p;
2910
+ }
2911
+
2912
+ /*
2913
+ * Get query cache buffer of current query context
2914
+ */
2915
+ static char *pool_get_current_cache_buffer(size_t *len)
2916
+ {
2917
+ char *p = NULL;
2918
+ *len = 0;
2919
+ POOL_TEMP_QUERY_CACHE *cache;
2920
+
2921
+ cache = pool_get_current_cache();
2922
+ if (cache)
2923
+ {
2924
+ p = pool_get_buffer(cache->buffer, len);
2925
+ }
2926
+ return p;
2927
+ }
2928
+
2929
+ /*
2930
+ * Mark this temporary query cache buffer discarded if the SELECT
2931
+ * uses the table oid specified by oids.
2932
+ */
2933
+ static void pool_check_and_discard_cache_buffer(int num_oids, int *oids)
2934
+ {
2935
+ POOL_SESSION_CONTEXT *session_context;
2936
+ POOL_TEMP_QUERY_CACHE *cache;
2937
+ int num_caches;
2938
+ size_t len;
2939
+ int *soids;
2940
+ int i, j, k;
2941
+
2942
+ session_context = pool_get_session_context();
2943
+
2944
+ if (!session_context || !session_context->query_cache_array)
2945
+ return;
2946
+
2947
+ num_caches = session_context->query_cache_array->num_caches;
2948
+
2949
+ for (i=0;i<num_caches;i++)
2950
+ {
2951
+ cache = session_context->query_cache_array->caches[i];
2952
+ if (!cache || cache->is_discarded)
2953
+ continue;
2954
+
2955
+ soids = (int *)pool_get_buffer(cache->oids, &len);
2956
+
2957
+ for(j=0;j<cache->num_oids;j++)
2958
+ {
2959
+ if (cache->is_discarded)
2960
+ break;
2961
+
2962
+ for (k=0;k<num_oids;k++)
2963
+ {
2964
+ if (soids[j] == oids[k])
2965
+ {
2966
+ pool_debug("pool_check_and_discard_cache_buffer: discard cache for %s",
2967
+ cache->query);
2968
+ cache->is_discarded = true;
2969
+ break;
2970
+ }
2971
+ }
2972
+ }
2973
+ free(soids);
2974
+ }
2975
+ }
2976
+
2977
+ /*
2978
+ * At Ready for Query handle query cache.
2979
+ * Supposed to be called from ReadyForQuery().
2980
+ */
2981
+ void pool_handle_query_cache(POOL_CONNECTION_POOL *backend, char *query, Node *node, char state)
2982
+ {
2983
+ POOL_SESSION_CONTEXT *session_context;
2984
+ char *cache_buffer;
2985
+ size_t len;
2986
+ int num_oids;
2987
+ int *oids;
2988
+ int i;
2989
+ #ifdef HAVE_SIGPROCMASK
2990
+ sigset_t oldmask;
2991
+ #else
2992
+ int oldmask;
2993
+ #endif
2994
+
2995
+ session_context = pool_get_session_context();
2996
+
2997
+ /* Ok to cache SELECT result? */
2998
+ if (pool_is_cache_safe())
2999
+ {
3000
+ SelectContext ctx;
3001
+ POOL_MEMORY_POOL *old_context;
3002
+ old_context = pool_memory_context_switch_to(session_context->memory_context);
3003
+ num_oids = pool_extract_table_oids_from_select_stmt(node, &ctx);
3004
+ pool_memory_context_switch_to(old_context);
3005
+ oids = ctx.table_oids;;
3006
+ pool_debug("num_oids: %d oid: %d", num_oids, *oids);
3007
+
3008
+ if (state == 'I') /* Not inside a transaction? */
3009
+ {
3010
+ /*
3011
+ * Make sure that temporary cache is not exceeded.
3012
+ */
3013
+ if (!pool_is_cache_exceeded())
3014
+ {
3015
+ /*
3016
+ * If we are not inside a transaction, we can
3017
+ * immediately register to cache storage.
3018
+ */
3019
+ /* Register to memcached or shmem */
3020
+ POOL_SETMASK2(&BlockSig, &oldmask);
3021
+ pool_shmem_lock();
3022
+
3023
+ cache_buffer = pool_get_current_cache_buffer(&len);
3024
+ if (cache_buffer)
3025
+ {
3026
+ if (pool_commit_cache(backend, query, cache_buffer, len, num_oids, oids) != 0)
3027
+ {
3028
+ pool_error("ReadyForQuery: pool_commit_cache failed");
3029
+ }
3030
+ free(cache_buffer);
3031
+ }
3032
+ pool_shmem_unlock();
3033
+ POOL_SETMASK(&oldmask);
3034
+ }
3035
+
3036
+ /* Count up SELECT stats */
3037
+ pool_stats_count_up_num_selects(1);
3038
+
3039
+ /* Reset temp buffer */
3040
+ pool_reset_memqcache_buffer();
3041
+ }
3042
+ else
3043
+ {
3044
+ POOL_TEMP_QUERY_CACHE *cache = pool_get_current_cache();
3045
+
3046
+ /* In transaction. Keep to temp query cache array */
3047
+ pool_add_oids_temp_query_cache(cache, num_oids, oids);
3048
+
3049
+ /*
3050
+ * If temp cache has been overflowed, just trash the half
3051
+ * baked temp cache.
3052
+ */
3053
+ if (pool_is_cache_exceeded())
3054
+ {
3055
+ POOL_TEMP_QUERY_CACHE *cache;
3056
+
3057
+ cache = pool_get_current_cache();
3058
+ pool_discard_temp_query_cache(cache);
3059
+ /*
3060
+ * Reset temp_cache pointer in the current query context
3061
+ * so that we don't double free memory.
3062
+ */
3063
+ session_context->query_context->temp_cache = NULL;
3064
+
3065
+ }
3066
+ /*
3067
+ * Otherwise add to the temp cache array.
3068
+ */
3069
+ else
3070
+ {
3071
+ session_context->query_cache_array =
3072
+ pool_add_query_cache_array(session_context->query_cache_array, cache);
3073
+ /*
3074
+ * Reset temp_cache pointer in the current query
3075
+ * context so that we don't add the same temp cache to
3076
+ * the cache array. This is necessary such that case
3077
+ * when next query is just a "bind message", without
3078
+ * "parse message". In the case the query context is
3079
+ * reused and same cache pointer will be added to the
3080
+ * query_cache_array which we do not want.
3081
+ */
3082
+ session_context->query_context->temp_cache = NULL;
3083
+ }
3084
+
3085
+ /* Count up temporary SELECT stats */
3086
+ pool_tmp_stats_count_up_num_selects();
3087
+ }
3088
+ }
3089
+ else if (is_rollback_query(node)) /* Rollback? */
3090
+ {
3091
+ /* Discard buffered data */
3092
+ pool_reset_memqcache_buffer();
3093
+ }
3094
+ else if (is_commit_query(node)) /* Commit? */
3095
+ {
3096
+ int num_caches;
3097
+
3098
+ POOL_SETMASK2(&BlockSig, &oldmask);
3099
+ pool_shmem_lock();
3100
+
3101
+ /* Invalidate query cache */
3102
+ if (pool_config->memqcache_auto_cache_invalidation)
3103
+ {
3104
+ num_oids = pool_get_dml_table_oid(&oids);
3105
+ pool_invalidate_query_cache(num_oids, oids, true, 0);
3106
+ }
3107
+
3108
+ /*
3109
+ * If we have something in the query cache buffer, that means
3110
+ * either:
3111
+ * - We only had SELECTs in the transaction
3112
+ * - We had only SELECTs after last DML
3113
+ * Thus we can register SELECT results to cache storage.
3114
+ */
3115
+ num_caches = session_context->query_cache_array->num_caches;
3116
+ for (i=0;i<num_caches;i++)
3117
+ {
3118
+ POOL_TEMP_QUERY_CACHE *cache;
3119
+
3120
+ cache = session_context->query_cache_array->caches[i];
3121
+ if (!cache || cache->is_discarded)
3122
+ continue;
3123
+
3124
+ num_oids = cache->num_oids;
3125
+ oids = pool_get_buffer(cache->oids, &len);
3126
+ cache_buffer = pool_get_buffer(cache->buffer, &len);
3127
+
3128
+ if (pool_commit_cache(backend, cache->query, cache_buffer, len, num_oids, oids) != 0)
3129
+ {
3130
+ pool_error("ReadyForQuery: pool_commit_cache failed");
3131
+ }
3132
+ free(oids);
3133
+ free(cache_buffer);
3134
+ }
3135
+ pool_shmem_unlock();
3136
+ POOL_SETMASK(&oldmask);
3137
+
3138
+ /* Count up number of SELECT stats */
3139
+ pool_stats_count_up_num_selects(pool_tmp_stats_get_num_selects());
3140
+
3141
+ pool_reset_memqcache_buffer();
3142
+ }
3143
+ else /* Non cache safe queries */
3144
+ {
3145
+ /* Non cachable SELECT */
3146
+ if (IsA(node, SelectStmt))
3147
+ {
3148
+ if (state == 'I')
3149
+ {
3150
+ /* Count up SELECT stats */
3151
+ pool_stats_count_up_num_selects(1);
3152
+ pool_reset_memqcache_buffer();
3153
+ }
3154
+ else
3155
+ {
3156
+ /* Count up temporary SELECT stats */
3157
+ pool_tmp_stats_count_up_num_selects();
3158
+ }
3159
+ }
3160
+ /*
3161
+ * If the query is DROP DATABASE, discard both of caches in shmem/memcached and
3162
+ * oidmap in memqcache_oiddir.
3163
+ */
3164
+ else if (is_drop_database(node) && session_context->query_context->dboid != 0)
3165
+ {
3166
+ int dboid = session_context->query_context->dboid;
3167
+ num_oids = pool_get_dropdb_table_oids(&oids, dboid);
3168
+
3169
+ if (num_oids > 0 && pool_config->memqcache_auto_cache_invalidation)
3170
+ {
3171
+ pool_shmem_lock();
3172
+ pool_invalidate_query_cache(num_oids, oids, true, dboid);
3173
+ pool_discard_oid_maps_by_db(dboid);
3174
+ pool_shmem_unlock();
3175
+ pool_reset_memqcache_buffer();
3176
+
3177
+ free(oids);
3178
+ pool_debug("ReadyForQuery: deleted all cache files for the DROPped DB");
3179
+ }
3180
+ }
3181
+ else
3182
+ {
3183
+ /*
3184
+ * DML/DCL/DDL case
3185
+ */
3186
+
3187
+ /* Extract table oids from buffer */
3188
+ num_oids = pool_get_dml_table_oid(&oids);
3189
+ if (num_oids > 0 && pool_config->memqcache_auto_cache_invalidation)
3190
+ {
3191
+ /*
3192
+ * If we are not inside a transaction, we can
3193
+ * immediately invalidate query cache.
3194
+ */
3195
+ if (state == 'I')
3196
+ {
3197
+ POOL_SETMASK2(&BlockSig, &oldmask);
3198
+ pool_shmem_lock();
3199
+ pool_invalidate_query_cache(num_oids, oids, true, 0);
3200
+ pool_shmem_unlock();
3201
+ POOL_SETMASK(&oldmask);
3202
+ pool_reset_memqcache_buffer();
3203
+ }
3204
+ else
3205
+ {
3206
+ /*
3207
+ * If we are inside a transaction, we
3208
+ * cannot invalidate query cache
3209
+ * yet. However we can clear cache buffer,
3210
+ * if DML/DDL modifies the TABLE which SELECT uses.
3211
+ */
3212
+ pool_check_and_discard_cache_buffer(num_oids, oids);
3213
+ }
3214
+ }
3215
+ }
3216
+ }
3217
+ }
3218
+
3219
+ /*
3220
+ * Create and initialize query cache stats
3221
+ */
3222
+ static POOL_QUERY_CACHE_STATS *stats;
3223
+ int pool_init_memqcache_stats(void)
3224
+ {
3225
+ stats = pool_shared_memory_create(sizeof(POOL_QUERY_CACHE_STATS));
3226
+ if (stats == NULL)
3227
+ {
3228
+ pool_error("pool_init_meqcache_stats: failed to allocate shared memory stats. request size: %zd",
3229
+ sizeof(POOL_QUERY_CACHE_STATS));
3230
+ return -1;
3231
+ }
3232
+
3233
+ pool_reset_memqcache_stats();
3234
+
3235
+ return 0;
3236
+ }
3237
+
3238
+ /*
3239
+ * Returns copy of stats area. The copy is in static area and will be
3240
+ * overwritten by next call to this function.
3241
+ */
3242
+ POOL_QUERY_CACHE_STATS *pool_get_memqcache_stats(void)
3243
+ {
3244
+ static POOL_QUERY_CACHE_STATS mystats;
3245
+ #ifdef HAVE_SIGPROCMASK
3246
+ sigset_t oldmask;
3247
+ #else
3248
+ int oldmask;
3249
+ #endif
3250
+
3251
+ memset(&mystats, 0, sizeof(POOL_QUERY_CACHE_STATS));
3252
+
3253
+ if (stats)
3254
+ {
3255
+ POOL_SETMASK2(&BlockSig, &oldmask);
3256
+ pool_semaphore_lock(QUERY_CACHE_STATS_SEM);
3257
+ memcpy(&mystats, stats, sizeof(POOL_QUERY_CACHE_STATS));
3258
+ pool_semaphore_unlock(QUERY_CACHE_STATS_SEM);
3259
+ POOL_SETMASK(&oldmask);
3260
+ }
3261
+
3262
+ return &mystats;
3263
+ }
3264
+
3265
+ /*
3266
+ * Reset query cache stats. Caller must lock QUERY_CACHE_STATS_SEM if
3267
+ * necessary.
3268
+ */
3269
+ void pool_reset_memqcache_stats(void)
3270
+ {
3271
+ memset(stats, 0, sizeof(POOL_QUERY_CACHE_STATS));
3272
+ stats->start_time = time(NULL);
3273
+ }
3274
+
3275
+ /*
3276
+ * Count up number of successful SELECTs and returns the number.
3277
+ * QUERY_CACHE_STATS_SEM lock is acquired in this function.
3278
+ */
3279
+ long long int pool_stats_count_up_num_selects(long long int num)
3280
+ {
3281
+ #ifdef HAVE_SIGPROCMASK
3282
+ sigset_t oldmask;
3283
+ #else
3284
+ int oldmask;
3285
+ #endif
3286
+
3287
+ POOL_SETMASK2(&BlockSig, &oldmask);
3288
+ pool_semaphore_lock(QUERY_CACHE_STATS_SEM);
3289
+ stats->num_selects += num;
3290
+ pool_semaphore_unlock(QUERY_CACHE_STATS_SEM);
3291
+ POOL_SETMASK(&oldmask);
3292
+ return stats->num_selects;
3293
+ }
3294
+
3295
+ /*
3296
+ * Count up number of successful SELECTs in temporary area and returns
3297
+ * the number.
3298
+ */
3299
+ long long int pool_tmp_stats_count_up_num_selects(void)
3300
+ {
3301
+ POOL_SESSION_CONTEXT *session_context;
3302
+
3303
+ session_context = pool_get_session_context();
3304
+ session_context->num_selects++;
3305
+ return session_context->num_selects;
3306
+ }
3307
+
3308
+ /*
3309
+ * Return number of successful SELECTs in temporary area.
3310
+ */
3311
+ long long int pool_tmp_stats_get_num_selects(void)
3312
+ {
3313
+ POOL_SESSION_CONTEXT *session_context;
3314
+
3315
+ session_context = pool_get_session_context();
3316
+ return session_context->num_selects;
3317
+ }
3318
+
3319
+ /*
3320
+ * Reset number of successful SELECTs in temporary area.
3321
+ */
3322
+ void pool_tmp_stats_reset_num_selects(void)
3323
+ {
3324
+ POOL_SESSION_CONTEXT *session_context;
3325
+
3326
+ session_context = pool_get_session_context();
3327
+ session_context->num_selects = 0;
3328
+ }
3329
+
3330
+ /*
3331
+ * Count up number of SELECTs extracted from cache returns the number.
3332
+ * QUERY_CACHE_STATS_SEM lock is acquired in this function.
3333
+ */
3334
+ long long int pool_stats_count_up_num_cache_hits(void)
3335
+ {
3336
+ #ifdef HAVE_SIGPROCMASK
3337
+ sigset_t oldmask;
3338
+ #else
3339
+ int oldmask;
3340
+ #endif
3341
+
3342
+ POOL_SETMASK2(&BlockSig, &oldmask);
3343
+ pool_semaphore_lock(QUERY_CACHE_STATS_SEM);
3344
+ stats->num_cache_hits++;
3345
+ pool_semaphore_unlock(QUERY_CACHE_STATS_SEM);
3346
+ POOL_SETMASK(&oldmask);
3347
+ return stats->num_cache_hits;
3348
+ }
3349
+
3350
+ /*
3351
+ * On shared memory hash table implementation. We use sub part of md5
3352
+ * hash key as hash function. The experiment has shown that has_any()
3353
+ * of PostgreSQL is a little bit better than the method using part of
3354
+ * md5 hash value, but it seems adding some cpu cycles to call
3355
+ * hash_any() is not worth the trouble.
3356
+ */
3357
+
3358
+ static volatile POOL_HASH_HEADER *hash_header;
3359
+ static volatile POOL_HASH_ELEMENT *hash_elements;
3360
+ static volatile POOL_HASH_ELEMENT hash_free_body;
3361
+ static volatile POOL_HASH_ELEMENT *hash_free;
3362
+
3363
+ /*
3364
+ * Initialize hash table on shared memory "nelements" is max number of
3365
+ * hash keys. The actual number of hash key is rounded up to power of
3366
+ * 2.
3367
+ */
3368
+ #undef POOL_HASH_DEBUG
3369
+
3370
+ int pool_hash_init(int nelements)
3371
+ {
3372
+ size_t size;
3373
+ int nelements2; /* number of rounded up hash keys */
3374
+ int shift;
3375
+ uint32 mask;
3376
+ POOL_HASH_HEADER hh;
3377
+ int i;
3378
+
3379
+ if (nelements <= 0)
3380
+ {
3381
+ pool_error("pool_hash_init: invalid nelements:%d", nelements);
3382
+ return -1;
3383
+ }
3384
+
3385
+ /* Round up to power of 2 */
3386
+ shift = 32;
3387
+ nelements2 = 1;
3388
+ do
3389
+ {
3390
+ nelements2 <<= 1;
3391
+ shift--;
3392
+ } while (nelements2 < nelements);
3393
+
3394
+ mask = ~0;
3395
+ mask >>= shift;
3396
+ size = (char *)&hh.elements - (char *)&hh + sizeof(POOL_HEADER_ELEMENT)*nelements2;
3397
+ hash_header = pool_shared_memory_create(size);
3398
+ if (hash_header == NULL)
3399
+ {
3400
+ pool_error("pool_hash_init: failed to allocate shared memory cache for hash header. request size: %zd", size);
3401
+ return -1;
3402
+ }
3403
+ hash_header->nhash = nelements2;
3404
+ hash_header->mask = mask;
3405
+
3406
+ #ifdef POOL_HASH_DEBUG
3407
+ pool_log("pool_hash_init: size:%zd nelements2:%d", size, nelements2);
3408
+ #endif
3409
+
3410
+ size = sizeof(POOL_HASH_ELEMENT)*nelements2;
3411
+ hash_elements = pool_shared_memory_create(size);
3412
+ if (hash_elements == NULL)
3413
+ {
3414
+ pool_error("pool_hash_init: failed to allocate shared memory cache for free list. request size: %zd", size);
3415
+ return -1;
3416
+ }
3417
+
3418
+ #ifdef POOL_HASH_DEBUG
3419
+ pool_log("pool_hash_init: size:%zd nelements2:%d", size, nelements2);
3420
+ #endif
3421
+
3422
+ for (i=0;i<nelements2-1;i++)
3423
+ {
3424
+ hash_elements[i].next = (POOL_HASH_ELEMENT *)&hash_elements[i+1];
3425
+ }
3426
+ hash_elements[nelements2-1].next = NULL;
3427
+ hash_free = hash_elements;
3428
+
3429
+ return 0;
3430
+ }
3431
+
3432
+ /*
3433
+ * Reset hash table on shared memory "nelements" is max number of
3434
+ * hash keys. The actual number of hash key is rounded up to power of
3435
+ * 2.
3436
+ */
3437
+ static int
3438
+ pool_hash_reset(int nelements)
3439
+ {
3440
+ size_t size;
3441
+ int nelements2; /* number of rounded up hash keys */
3442
+ int shift;
3443
+ uint32 mask;
3444
+ POOL_HASH_HEADER hh;
3445
+ int i;
3446
+
3447
+ if (nelements <= 0)
3448
+ {
3449
+ pool_error("pool_hash_clear: invalid nelements:%d", nelements);
3450
+ return -1;
3451
+ }
3452
+
3453
+ /* Round up to power of 2 */
3454
+ shift = 32;
3455
+ nelements2 = 1;
3456
+ do
3457
+ {
3458
+ nelements2 <<= 1;
3459
+ shift--;
3460
+ } while (nelements2 < nelements);
3461
+
3462
+ mask = ~0;
3463
+ mask >>= shift;
3464
+
3465
+ size = (char *)&hh.elements - (char *)&hh + sizeof(POOL_HEADER_ELEMENT)*nelements2;
3466
+ memset((void *)hash_header, 0, size);
3467
+
3468
+ hash_header->nhash = nelements2;
3469
+ hash_header->mask = mask;
3470
+
3471
+ size = sizeof(POOL_HASH_ELEMENT)*nelements2;
3472
+ memset((void *)hash_elements, 0, size);
3473
+
3474
+ for (i=0;i<nelements2-1;i++)
3475
+ {
3476
+ hash_elements[i].next = (POOL_HASH_ELEMENT *)&hash_elements[i+1];
3477
+ }
3478
+ hash_elements[nelements2-1].next = NULL;
3479
+ hash_free = hash_elements;
3480
+
3481
+ return 0;
3482
+ }
3483
+
3484
+ /*
3485
+ * Search cacheid by MD5 hash key string
3486
+ * If found, returns cache id, otherwise NULL.
3487
+ */
3488
+ POOL_CACHEID *pool_hash_search(POOL_QUERY_HASH *key)
3489
+ {
3490
+ volatile POOL_HASH_ELEMENT *element;
3491
+
3492
+ uint32 hash_key = create_hash_key(key);
3493
+
3494
+ if (hash_key >= hash_header->nhash)
3495
+ {
3496
+ pool_error("pool_hash_search: invalid hash key: %uld nhash: %ld",
3497
+ hash_key, hash_header->nhash);
3498
+ return NULL;
3499
+ }
3500
+
3501
+ {
3502
+ char md5[POOL_MD5_HASHKEYLEN+1];
3503
+ memcpy(md5, key->query_hash, POOL_MD5_HASHKEYLEN);
3504
+ md5[POOL_MD5_HASHKEYLEN] = '\0';
3505
+ #ifdef POOL_HASH_DEBUG
3506
+ pool_log("pool_hash_search: hash_key:%d md5:%s", hash_key, md5);
3507
+ #endif
3508
+ }
3509
+
3510
+ element = hash_header->elements[hash_key].element;
3511
+ while (element)
3512
+ {
3513
+ {
3514
+ char md5[POOL_MD5_HASHKEYLEN+1];
3515
+ memcpy(md5, key->query_hash, POOL_MD5_HASHKEYLEN);
3516
+ md5[POOL_MD5_HASHKEYLEN] = '\0';
3517
+ #ifdef POOL_HASH_DEBUG
3518
+ pool_log("pool_hash_search: element md5:%s", md5);
3519
+ #endif
3520
+ }
3521
+
3522
+ if (memcmp((const void *)element->hashkey.query_hash,
3523
+ (const void *)key->query_hash, sizeof(key->query_hash)) == 0)
3524
+ {
3525
+ return (POOL_CACHEID *)&element->cacheid;
3526
+ }
3527
+ element = element->next;
3528
+ }
3529
+ return NULL;
3530
+ }
3531
+
3532
+ /*
3533
+ * Insert MD5 key and associated cache id into shmem hash table. If
3534
+ * "update" is true, replace cacheid associated with the MD5 key,
3535
+ * rather than throw an error.
3536
+ */
3537
+ static int pool_hash_insert(POOL_QUERY_HASH *key, POOL_CACHEID *cacheid, bool update)
3538
+ {
3539
+ POOL_HASH_ELEMENT *element;
3540
+ POOL_HASH_ELEMENT *new_element;
3541
+
3542
+ uint32 hash_key = create_hash_key(key);
3543
+
3544
+ if (hash_key >= hash_header->nhash)
3545
+ {
3546
+ pool_error("pool_hash_insert: invalid hash key: %uld nhash: %ld",
3547
+ hash_key, hash_header->nhash);
3548
+ return -1;
3549
+ }
3550
+
3551
+ {
3552
+ char md5[POOL_MD5_HASHKEYLEN+1];
3553
+ memcpy(md5, key->query_hash, POOL_MD5_HASHKEYLEN);
3554
+ md5[POOL_MD5_HASHKEYLEN] = '\0';
3555
+ #ifdef POOL_HASH_DEBUG
3556
+ pool_log("pool_hash_insert: hash_key:%d md5:%s block:%d item:%d", hash_key, md5, cacheid->blockid, cacheid->itemid);
3557
+ #endif
3558
+ }
3559
+
3560
+ /*
3561
+ * Look for hash key.
3562
+ */
3563
+ element = hash_header->elements[hash_key].element;
3564
+
3565
+ while (element)
3566
+ {
3567
+ if (memcmp((const void *)element->hashkey.query_hash,
3568
+ (const void *)key->query_hash, sizeof(key->query_hash)) == 0)
3569
+ {
3570
+ /* Hash key found. If "update" is false, just throw an error. */
3571
+ char md5[POOL_MD5_HASHKEYLEN+1];
3572
+
3573
+ if (!update)
3574
+ {
3575
+ memcpy(md5, key->query_hash, POOL_MD5_HASHKEYLEN);
3576
+ md5[POOL_MD5_HASHKEYLEN] = '\0';
3577
+ pool_error("pool_hash_insert: the key:==%s== already exists", md5);
3578
+ return -1;
3579
+ }
3580
+ else
3581
+ {
3582
+ /* Update cache id */
3583
+ memcpy((void *)&element->cacheid, cacheid, sizeof(POOL_CACHEID));
3584
+ return 0;
3585
+ }
3586
+ }
3587
+ element = element->next;
3588
+ }
3589
+
3590
+ /*
3591
+ * Ok, same key did not exist. Just insert new hash key.
3592
+ */
3593
+ new_element = (POOL_HASH_ELEMENT *)get_new_hash_element();
3594
+ if (!new_element)
3595
+ {
3596
+ pool_error("pool_hash_insert: could not get new element");
3597
+ return -1;
3598
+ }
3599
+
3600
+ element = hash_header->elements[hash_key].element;
3601
+
3602
+ hash_header->elements[hash_key].element = new_element;
3603
+ new_element->next = element;
3604
+
3605
+ memcpy((void *)new_element->hashkey.query_hash, key->query_hash, POOL_MD5_HASHKEYLEN);
3606
+ memcpy((void *)&new_element->cacheid, cacheid, sizeof(POOL_CACHEID));
3607
+
3608
+ return 0;
3609
+ }
3610
+
3611
+ /*
3612
+ * Delete MD5 key and associated cache id into shmem hash table.
3613
+ */
3614
+ int pool_hash_delete(POOL_QUERY_HASH *key)
3615
+ {
3616
+ POOL_HASH_ELEMENT *element;
3617
+ POOL_HASH_ELEMENT **delete_point;
3618
+ bool found;
3619
+
3620
+ uint32 hash_key = create_hash_key(key);
3621
+
3622
+ if (hash_key >= hash_header->nhash)
3623
+ {
3624
+ pool_error("pool_hash_delete: invalid hash key: %uld nhash: %ld",
3625
+ hash_key, hash_header->nhash);
3626
+ return -1;
3627
+ }
3628
+
3629
+ /*
3630
+ * Look for delete location
3631
+ */
3632
+ found = false;
3633
+ delete_point = (POOL_HASH_ELEMENT **)&(hash_header->elements[hash_key].element);
3634
+ element = hash_header->elements[hash_key].element;
3635
+
3636
+ while (element)
3637
+ {
3638
+ if (memcmp(element->hashkey.query_hash, key->query_hash, sizeof(key->query_hash)) == 0)
3639
+ {
3640
+ found = true;
3641
+ break;
3642
+ }
3643
+ delete_point = &element->next;
3644
+ element = element->next;
3645
+ }
3646
+
3647
+ if (!found)
3648
+ {
3649
+ char md5[POOL_MD5_HASHKEYLEN+1];
3650
+
3651
+ memcpy(md5, key->query_hash, POOL_MD5_HASHKEYLEN);
3652
+ md5[POOL_MD5_HASHKEYLEN] = '\0';
3653
+ pool_error("pool_hash_delete: the key:==%s== not found", md5);
3654
+ return -1;
3655
+ }
3656
+
3657
+ /*
3658
+ * Put back the element to free list
3659
+ */
3660
+ *delete_point = element->next;
3661
+ put_back_hash_element(element);
3662
+
3663
+ return 0;
3664
+ }
3665
+
3666
+ /*
3667
+ * Calculate 32bit binary hash key(i.e. location in hash header) from MD5
3668
+ * string. We use top most 8 characters of MD5 string for calculation.
3669
+ */
3670
+ static uint32 create_hash_key(POOL_QUERY_HASH *key)
3671
+ {
3672
+ #define POOL_HASH_NCHARS 8
3673
+
3674
+ char md5[POOL_HASH_NCHARS+1];
3675
+ uint32 mask;
3676
+
3677
+ memcpy(md5, key->query_hash, POOL_HASH_NCHARS);
3678
+ md5[POOL_HASH_NCHARS] = '\0';
3679
+ mask = strtoul(md5, NULL, 16);
3680
+ mask &= hash_header->mask;
3681
+ return mask;
3682
+ }
3683
+
3684
+ /*
3685
+ * Get new free hash element from free list.
3686
+ */
3687
+ static volatile POOL_HASH_ELEMENT *get_new_hash_element(void)
3688
+ {
3689
+ volatile POOL_HASH_ELEMENT *elm;
3690
+
3691
+ if (!hash_free->next)
3692
+ {
3693
+ /* No free element */
3694
+ return NULL;
3695
+ }
3696
+
3697
+ #ifdef POOL_HASH_DEBUG
3698
+ pool_log("get_new_hash_element: hash_free->next:%p hash_free->next->next:%p",
3699
+ hash_free->next, hash_free->next->next);
3700
+ #endif
3701
+
3702
+ elm = hash_free->next;
3703
+ hash_free->next = elm->next;
3704
+
3705
+ return elm;
3706
+ }
3707
+
3708
+ /*
3709
+ * Put back hash element to free list.
3710
+ */
3711
+ static void put_back_hash_element(volatile POOL_HASH_ELEMENT *element)
3712
+ {
3713
+ POOL_HASH_ELEMENT *elm;
3714
+
3715
+ #ifdef POOL_HASH_DEBUG
3716
+ pool_log("put_back_hash_element: hash_free->next:%p hash_free->next->next:%p",
3717
+ hash_free->next, hash_free->next->next);
3718
+ #endif
3719
+
3720
+ elm = hash_free->next;
3721
+ hash_free->next = (POOL_HASH_ELEMENT *)element;
3722
+ element->next = elm;
3723
+ }
3724
+
3725
+ /*
3726
+ * Return true if there's a free hash element.
3727
+ */
3728
+ static bool is_free_hash_element(void)
3729
+ {
3730
+ return hash_free->next != NULL;
3731
+ }
3732
+
3733
+ /*
3734
+ * Returns shared memory cache stats.
3735
+ * Subsequent call to this function will break return value
3736
+ * because its in static memory.
3737
+ * Caller must hold shmem_lock before calling this function.
3738
+ * If on memory query cache is not enabled, all stats are 0.
3739
+ */
3740
+ POOL_SHMEM_STATS *pool_get_shmem_storage_stats(void)
3741
+ {
3742
+ static POOL_SHMEM_STATS mystats;
3743
+ POOL_HASH_ELEMENT *element;
3744
+ int nblocks;
3745
+ int i;
3746
+
3747
+ memset(&mystats, 0, sizeof(POOL_SHMEM_STATS));
3748
+
3749
+ if (!pool_config-> memory_cache_enabled)
3750
+ return &mystats;
3751
+
3752
+ /*
3753
+ * Cop cache hit data
3754
+ */
3755
+ mystats.cache_stats.num_selects = stats->num_selects;
3756
+ mystats.cache_stats.num_cache_hits = stats->num_cache_hits;
3757
+
3758
+ if (strcmp(pool_config-> memqcache_method, "shmem"))
3759
+ return &mystats;
3760
+
3761
+ /* number of total hash entries */
3762
+ mystats.num_hash_entries = hash_header->nhash;
3763
+
3764
+ /* number of used hash entries */
3765
+ for (i=0;i<hash_header->nhash;i++)
3766
+ {
3767
+ element = hash_header->elements[i].element;
3768
+ while (element)
3769
+ {
3770
+ mystats.used_hash_entries++;
3771
+ element = element->next;
3772
+ }
3773
+ }
3774
+
3775
+ nblocks = pool_get_memqcache_blocks();
3776
+
3777
+ for (i=0;i<nblocks;i++)
3778
+ {
3779
+ POOL_CACHE_BLOCK_HEADER *bh;
3780
+ POOL_CACHE_ITEM_POINTER *cip;
3781
+ char *p = block_address(i);
3782
+ bh = (POOL_CACHE_BLOCK_HEADER *)p;
3783
+ int j;
3784
+
3785
+ if (bh->flags & POOL_BLOCK_USED)
3786
+ {
3787
+ for (j=0;j<bh->num_items;j++)
3788
+ {
3789
+ cip = item_pointer(p, j);
3790
+ if (POOL_ITEM_DELETED & cip->flags)
3791
+ {
3792
+ mystats.fragment_cache_entries_size += item_header(p, j)->total_length;
3793
+ }
3794
+ else
3795
+ {
3796
+ /* number of used cache entries */
3797
+ mystats.num_cache_entries++;
3798
+ /* total size of used cache entries */
3799
+ mystats.used_cache_entries_size += (item_header(p, j)->total_length + sizeof(POOL_CACHE_ITEM_POINTER));
3800
+ }
3801
+ }
3802
+ mystats.used_cache_entries_size += sizeof(POOL_CACHE_BLOCK_HEADER);
3803
+ /* total size of free(usable) cache entries */
3804
+ mystats.free_cache_entries_size += bh->free_bytes;
3805
+ }
3806
+ else
3807
+ {
3808
+ mystats.free_cache_entries_size += pool_config->memqcache_cache_block_size;
3809
+ }
3810
+ }
3811
+
3812
+ /*
3813
+ * Copy POOL_QUERY_CACHE_STATS
3814
+ */
3815
+ memcpy(&mystats.cache_stats, stats, sizeof(mystats.cache_stats));
3816
+
3817
+ return &mystats;
3818
+ }