prestogres 0.1.0

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