prestogres 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +4 -0
- data/Gemfile +2 -0
- data/Gemfile.lock +20 -0
- data/LICENSE +202 -0
- data/NOTICE +22 -0
- data/README.md +217 -0
- data/Rakefile +13 -0
- data/VERSION +1 -0
- data/bin/prestogres +254 -0
- data/config/pcp.conf.sample +28 -0
- data/config/pgpool.conf +678 -0
- data/config/pool_hba.conf +84 -0
- data/config/pool_passwd +0 -0
- data/config/postgresql.conf +2 -0
- data/ext/.gitignore +6 -0
- data/ext/depend +26 -0
- data/ext/extconf.rb +4 -0
- data/ext/prestogres_config.c +12 -0
- data/pgpool2/.gitignore +36 -0
- data/pgpool2/AUTHORS +4 -0
- data/pgpool2/COPYING +12 -0
- data/pgpool2/ChangeLog +1 -0
- data/pgpool2/INSTALL +1 -0
- data/pgpool2/Makefile.am +159 -0
- data/pgpool2/Makefile.in +1187 -0
- data/pgpool2/NEWS +4960 -0
- data/pgpool2/README +1 -0
- data/pgpool2/README.euc_jp +1 -0
- data/pgpool2/README.online-recovery +62 -0
- data/pgpool2/TODO +103 -0
- data/pgpool2/ac_func_accept_argtypes.m4 +85 -0
- data/pgpool2/aclocal.m4 +1088 -0
- data/pgpool2/c-compiler.m4 +134 -0
- data/pgpool2/c-library.m4 +325 -0
- data/pgpool2/child.c +2097 -0
- data/pgpool2/config.guess +1532 -0
- data/pgpool2/config.h.in +332 -0
- data/pgpool2/config.sub +1640 -0
- data/pgpool2/configure +15752 -0
- data/pgpool2/configure.in +392 -0
- data/pgpool2/depcomp +522 -0
- data/pgpool2/doc/basebackup.sh +17 -0
- data/pgpool2/doc/pgpool-de.html +4220 -0
- data/pgpool2/doc/pgpool-en.html +5738 -0
- data/pgpool2/doc/pgpool-fr.html +4118 -0
- data/pgpool2/doc/pgpool-ja.css +198 -0
- data/pgpool2/doc/pgpool-ja.html +11279 -0
- data/pgpool2/doc/pgpool-zh_cn.html +4445 -0
- data/pgpool2/doc/pgpool.css +280 -0
- data/pgpool2/doc/pgpool_remote_start +13 -0
- data/pgpool2/doc/recovery.conf.sample +117 -0
- data/pgpool2/doc/tutorial-en.html +707 -0
- data/pgpool2/doc/tutorial-ja.html +422 -0
- data/pgpool2/doc/tutorial-memqcache-en.html +325 -0
- data/pgpool2/doc/tutorial-memqcache-ja.html +370 -0
- data/pgpool2/doc/tutorial-memqcache-zh_cn.html +322 -0
- data/pgpool2/doc/tutorial-watchdog-en.html +306 -0
- data/pgpool2/doc/tutorial-watchdog-ja.html +343 -0
- data/pgpool2/doc/tutorial-watchdog-zh_cn.html +301 -0
- data/pgpool2/doc/tutorial-zh_cn.html +537 -0
- data/pgpool2/doc/watchdog.png +0 -0
- data/pgpool2/doc/wd-en.html +236 -0
- data/pgpool2/doc/wd-en.jpg +0 -0
- data/pgpool2/doc/wd-ja.html +219 -0
- data/pgpool2/doc/wd-ja.jpg +0 -0
- data/pgpool2/doc/wd-zh_cn.html +201 -0
- data/pgpool2/doc/where_to_send_queries.odg +0 -0
- data/pgpool2/doc/where_to_send_queries.pdf +0 -0
- data/pgpool2/general.m4 +166 -0
- data/pgpool2/getopt_long.c +200 -0
- data/pgpool2/getopt_long.h +44 -0
- data/pgpool2/install-sh +251 -0
- data/pgpool2/ltmain.sh +8406 -0
- data/pgpool2/m4/libtool.m4 +7360 -0
- data/pgpool2/m4/ltoptions.m4 +368 -0
- data/pgpool2/m4/ltsugar.m4 +123 -0
- data/pgpool2/m4/ltversion.m4 +23 -0
- data/pgpool2/m4/lt~obsolete.m4 +92 -0
- data/pgpool2/main.c +2971 -0
- data/pgpool2/md5.c +444 -0
- data/pgpool2/md5.h +28 -0
- data/pgpool2/missing +360 -0
- data/pgpool2/mkinstalldirs +40 -0
- data/pgpool2/parser/Makefile.am +50 -0
- data/pgpool2/parser/Makefile.in +559 -0
- data/pgpool2/parser/copyfuncs.c +3310 -0
- data/pgpool2/parser/gram.c +39100 -0
- data/pgpool2/parser/gram.h +940 -0
- data/pgpool2/parser/gram.y +13408 -0
- data/pgpool2/parser/gramparse.h +74 -0
- data/pgpool2/parser/keywords.c +32 -0
- data/pgpool2/parser/keywords.h +39 -0
- data/pgpool2/parser/kwlist.h +425 -0
- data/pgpool2/parser/kwlookup.c +88 -0
- data/pgpool2/parser/list.c +1156 -0
- data/pgpool2/parser/makefuncs.c +518 -0
- data/pgpool2/parser/makefuncs.h +83 -0
- data/pgpool2/parser/memnodes.h +79 -0
- data/pgpool2/parser/nodes.c +29 -0
- data/pgpool2/parser/nodes.h +609 -0
- data/pgpool2/parser/outfuncs.c +5790 -0
- data/pgpool2/parser/parsenodes.h +2615 -0
- data/pgpool2/parser/parser.c +262 -0
- data/pgpool2/parser/parser.h +46 -0
- data/pgpool2/parser/pg_class.h +158 -0
- data/pgpool2/parser/pg_config_manual.h +273 -0
- data/pgpool2/parser/pg_list.h +352 -0
- data/pgpool2/parser/pg_trigger.h +147 -0
- data/pgpool2/parser/pg_wchar.h +492 -0
- data/pgpool2/parser/pool_memory.c +342 -0
- data/pgpool2/parser/pool_memory.h +77 -0
- data/pgpool2/parser/pool_parser.h +222 -0
- data/pgpool2/parser/pool_string.c +121 -0
- data/pgpool2/parser/pool_string.h +37 -0
- data/pgpool2/parser/primnodes.h +1280 -0
- data/pgpool2/parser/scan.c +4094 -0
- data/pgpool2/parser/scan.l +1451 -0
- data/pgpool2/parser/scanner.h +120 -0
- data/pgpool2/parser/scansup.c +221 -0
- data/pgpool2/parser/scansup.h +28 -0
- data/pgpool2/parser/snprintf.c +1102 -0
- data/pgpool2/parser/stringinfo.c +294 -0
- data/pgpool2/parser/stringinfo.h +178 -0
- data/pgpool2/parser/value.c +78 -0
- data/pgpool2/parser/value.h +62 -0
- data/pgpool2/parser/wchar.c +2048 -0
- data/pgpool2/pcp.conf.sample +28 -0
- data/pgpool2/pcp/Makefile.am +40 -0
- data/pgpool2/pcp/Makefile.in +771 -0
- data/pgpool2/pcp/libpcp_ext.h +250 -0
- data/pgpool2/pcp/md5.c +444 -0
- data/pgpool2/pcp/md5.h +28 -0
- data/pgpool2/pcp/pcp.c +1652 -0
- data/pgpool2/pcp/pcp.h +61 -0
- data/pgpool2/pcp/pcp_attach_node.c +172 -0
- data/pgpool2/pcp/pcp_detach_node.c +185 -0
- data/pgpool2/pcp/pcp_error.c +87 -0
- data/pgpool2/pcp/pcp_node_count.c +160 -0
- data/pgpool2/pcp/pcp_node_info.c +198 -0
- data/pgpool2/pcp/pcp_pool_status.c +166 -0
- data/pgpool2/pcp/pcp_proc_count.c +166 -0
- data/pgpool2/pcp/pcp_proc_info.c +261 -0
- data/pgpool2/pcp/pcp_promote_node.c +185 -0
- data/pgpool2/pcp/pcp_recovery_node.c +172 -0
- data/pgpool2/pcp/pcp_stop_pgpool.c +179 -0
- data/pgpool2/pcp/pcp_stream.c +385 -0
- data/pgpool2/pcp/pcp_stream.h +52 -0
- data/pgpool2/pcp/pcp_systemdb_info.c +194 -0
- data/pgpool2/pcp/pcp_watchdog_info.c +211 -0
- data/pgpool2/pcp_child.c +1493 -0
- data/pgpool2/pg_md5.c +305 -0
- data/pgpool2/pgpool.8.in +121 -0
- data/pgpool2/pgpool.conf +553 -0
- data/pgpool2/pgpool.conf.sample +666 -0
- data/pgpool2/pgpool.conf.sample-master-slave +665 -0
- data/pgpool2/pgpool.conf.sample-replication +664 -0
- data/pgpool2/pgpool.conf.sample-stream +664 -0
- data/pgpool2/pgpool.spec +264 -0
- data/pgpool2/pgpool_adm/TODO +7 -0
- data/pgpool2/pgpool_adm/pgpool_adm--1.0.sql +85 -0
- data/pgpool2/pgpool_adm/pgpool_adm.c +558 -0
- data/pgpool2/pgpool_adm/pgpool_adm.control +5 -0
- data/pgpool2/pgpool_adm/pgpool_adm.h +46 -0
- data/pgpool2/pgpool_adm/pgpool_adm.sql.in +85 -0
- data/pgpool2/pool.h +655 -0
- data/pgpool2/pool_auth.c +1390 -0
- data/pgpool2/pool_config.c +5007 -0
- data/pgpool2/pool_config.h +284 -0
- data/pgpool2/pool_config.l +3281 -0
- data/pgpool2/pool_config_md5.c +29 -0
- data/pgpool2/pool_connection_pool.c +812 -0
- data/pgpool2/pool_error.c +242 -0
- data/pgpool2/pool_globals.c +27 -0
- data/pgpool2/pool_hba.c +1723 -0
- data/pgpool2/pool_hba.conf.sample +67 -0
- data/pgpool2/pool_ip.c +567 -0
- data/pgpool2/pool_ip.h +65 -0
- data/pgpool2/pool_ipc.h +38 -0
- data/pgpool2/pool_lobj.c +242 -0
- data/pgpool2/pool_lobj.h +32 -0
- data/pgpool2/pool_memqcache.c +3818 -0
- data/pgpool2/pool_memqcache.h +268 -0
- data/pgpool2/pool_params.c +163 -0
- data/pgpool2/pool_passwd.c +249 -0
- data/pgpool2/pool_passwd.h +41 -0
- data/pgpool2/pool_path.c +193 -0
- data/pgpool2/pool_path.h +81 -0
- data/pgpool2/pool_process_context.c +247 -0
- data/pgpool2/pool_process_context.h +62 -0
- data/pgpool2/pool_process_query.c +5001 -0
- data/pgpool2/pool_process_reporting.c +1671 -0
- data/pgpool2/pool_process_reporting.h +44 -0
- data/pgpool2/pool_proto2.c +671 -0
- data/pgpool2/pool_proto_modules.c +3524 -0
- data/pgpool2/pool_proto_modules.h +185 -0
- data/pgpool2/pool_query_cache.c +1020 -0
- data/pgpool2/pool_query_context.c +1871 -0
- data/pgpool2/pool_query_context.h +105 -0
- data/pgpool2/pool_relcache.c +284 -0
- data/pgpool2/pool_relcache.h +78 -0
- data/pgpool2/pool_rewrite_outfuncs.c +9060 -0
- data/pgpool2/pool_rewrite_query.c +715 -0
- data/pgpool2/pool_rewrite_query.h +192 -0
- data/pgpool2/pool_select_walker.c +1150 -0
- data/pgpool2/pool_select_walker.h +68 -0
- data/pgpool2/pool_sema.c +161 -0
- data/pgpool2/pool_session_context.c +952 -0
- data/pgpool2/pool_session_context.h +203 -0
- data/pgpool2/pool_shmem.c +185 -0
- data/pgpool2/pool_signal.c +158 -0
- data/pgpool2/pool_signal.h +61 -0
- data/pgpool2/pool_ssl.c +339 -0
- data/pgpool2/pool_stream.c +962 -0
- data/pgpool2/pool_stream.h +61 -0
- data/pgpool2/pool_system.c +659 -0
- data/pgpool2/pool_timestamp.c +1215 -0
- data/pgpool2/pool_timestamp.h +38 -0
- data/pgpool2/pool_type.h +171 -0
- data/pgpool2/pool_worker_child.c +384 -0
- data/pgpool2/ps_status.c +404 -0
- data/pgpool2/recovery.c +435 -0
- data/pgpool2/redhat/pgpool.conf.sample.patch +52 -0
- data/pgpool2/redhat/pgpool.init +201 -0
- data/pgpool2/redhat/pgpool.sysconfig +7 -0
- data/pgpool2/redhat/rpm_installer/basebackup-replication.sh +53 -0
- data/pgpool2/redhat/rpm_installer/basebackup-stream.sh +55 -0
- data/pgpool2/redhat/rpm_installer/config_for_script +17 -0
- data/pgpool2/redhat/rpm_installer/failover.sh +64 -0
- data/pgpool2/redhat/rpm_installer/getsources.sh +141 -0
- data/pgpool2/redhat/rpm_installer/install.sh +1363 -0
- data/pgpool2/redhat/rpm_installer/pgpool_recovery_pitr +47 -0
- data/pgpool2/redhat/rpm_installer/pgpool_remote_start +15 -0
- data/pgpool2/redhat/rpm_installer/recovery.conf +4 -0
- data/pgpool2/redhat/rpm_installer/uninstall.sh +57 -0
- data/pgpool2/sample/dist_def_pgbench.sql +73 -0
- data/pgpool2/sample/pgpool.pam +3 -0
- data/pgpool2/sample/pgpool_recovery +20 -0
- data/pgpool2/sample/pgpool_recovery_pitr +19 -0
- data/pgpool2/sample/pgpool_remote_start +13 -0
- data/pgpool2/sample/replicate_def_pgbench.sql +18 -0
- data/pgpool2/sql/insert_lock.sql +15 -0
- data/pgpool2/sql/pgpool-recovery/pgpool-recovery.c +280 -0
- data/pgpool2/sql/pgpool-recovery/pgpool-recovery.sql.in +19 -0
- data/pgpool2/sql/pgpool-recovery/pgpool_recovery--1.0.sql +24 -0
- data/pgpool2/sql/pgpool-recovery/pgpool_recovery.control +5 -0
- data/pgpool2/sql/pgpool-recovery/uninstall_pgpool-recovery.sql +3 -0
- data/pgpool2/sql/pgpool-regclass/pgpool-regclass.c +206 -0
- data/pgpool2/sql/pgpool-regclass/pgpool-regclass.sql.in +4 -0
- data/pgpool2/sql/pgpool-regclass/pgpool_regclass--1.0.sql +7 -0
- data/pgpool2/sql/pgpool-regclass/pgpool_regclass.control +5 -0
- data/pgpool2/sql/pgpool-regclass/uninstall_pgpool-regclass.sql +1 -0
- data/pgpool2/sql/system_db.sql +38 -0
- data/pgpool2/strlcpy.c +85 -0
- data/pgpool2/test/C/test_extended.c +98 -0
- data/pgpool2/test/jdbc/.cvsignore +2 -0
- data/pgpool2/test/jdbc/AutoCommitTest.java +45 -0
- data/pgpool2/test/jdbc/BatchTest.java +55 -0
- data/pgpool2/test/jdbc/ColumnTest.java +60 -0
- data/pgpool2/test/jdbc/CreateTempTableTest.java +48 -0
- data/pgpool2/test/jdbc/InsertTest.java +34 -0
- data/pgpool2/test/jdbc/LockTest.java +36 -0
- data/pgpool2/test/jdbc/PgpoolTest.java +75 -0
- data/pgpool2/test/jdbc/README.euc_jp +73 -0
- data/pgpool2/test/jdbc/RunTest.java +83 -0
- data/pgpool2/test/jdbc/SelectTest.java +37 -0
- data/pgpool2/test/jdbc/UpdateTest.java +32 -0
- data/pgpool2/test/jdbc/expected/CreateTempTable +1 -0
- data/pgpool2/test/jdbc/expected/autocommit +10 -0
- data/pgpool2/test/jdbc/expected/batch +1 -0
- data/pgpool2/test/jdbc/expected/column +100 -0
- data/pgpool2/test/jdbc/expected/insert +1 -0
- data/pgpool2/test/jdbc/expected/lock +100 -0
- data/pgpool2/test/jdbc/expected/select +2 -0
- data/pgpool2/test/jdbc/expected/update +1 -0
- data/pgpool2/test/jdbc/pgpool.properties +7 -0
- data/pgpool2/test/jdbc/prepare.sql +54 -0
- data/pgpool2/test/jdbc/run.sh +6 -0
- data/pgpool2/test/parser/.cvsignore +6 -0
- data/pgpool2/test/parser/README +32 -0
- data/pgpool2/test/parser/expected/copy.out +17 -0
- data/pgpool2/test/parser/expected/create.out +64 -0
- data/pgpool2/test/parser/expected/cursor.out +37 -0
- data/pgpool2/test/parser/expected/delete.out +10 -0
- data/pgpool2/test/parser/expected/drop.out +12 -0
- data/pgpool2/test/parser/expected/insert.out +13 -0
- data/pgpool2/test/parser/expected/misc.out +28 -0
- data/pgpool2/test/parser/expected/prepare.out +4 -0
- data/pgpool2/test/parser/expected/privileges.out +31 -0
- data/pgpool2/test/parser/expected/scanner.out +30 -0
- data/pgpool2/test/parser/expected/select.out +89 -0
- data/pgpool2/test/parser/expected/transaction.out +38 -0
- data/pgpool2/test/parser/expected/update.out +11 -0
- data/pgpool2/test/parser/expected/v84.out +37 -0
- data/pgpool2/test/parser/expected/v90.out +25 -0
- data/pgpool2/test/parser/expected/var.out +22 -0
- data/pgpool2/test/parser/input/alter.sql +2 -0
- data/pgpool2/test/parser/input/copy.sql +17 -0
- data/pgpool2/test/parser/input/create.sql +64 -0
- data/pgpool2/test/parser/input/cursor.sql +37 -0
- data/pgpool2/test/parser/input/delete.sql +10 -0
- data/pgpool2/test/parser/input/drop.sql +12 -0
- data/pgpool2/test/parser/input/insert.sql +13 -0
- data/pgpool2/test/parser/input/misc.sql +28 -0
- data/pgpool2/test/parser/input/prepare.sql +4 -0
- data/pgpool2/test/parser/input/privileges.sql +31 -0
- data/pgpool2/test/parser/input/scanner.sql +34 -0
- data/pgpool2/test/parser/input/select.sql +89 -0
- data/pgpool2/test/parser/input/transaction.sql +38 -0
- data/pgpool2/test/parser/input/update.sql +11 -0
- data/pgpool2/test/parser/input/v84.sql +37 -0
- data/pgpool2/test/parser/input/v90.sql +38 -0
- data/pgpool2/test/parser/input/var.sql +22 -0
- data/pgpool2/test/parser/main.c +96 -0
- data/pgpool2/test/parser/parse_schedule +16 -0
- data/pgpool2/test/parser/pool.h +13 -0
- data/pgpool2/test/parser/run-test +62 -0
- data/pgpool2/test/pdo-test/README.euc_jp +58 -0
- data/pgpool2/test/pdo-test/SQLlist/test1.sql +3 -0
- data/pgpool2/test/pdo-test/SQLlist/test2.sql +3 -0
- data/pgpool2/test/pdo-test/collections.inc +11 -0
- data/pgpool2/test/pdo-test/def.inc +7 -0
- data/pgpool2/test/pdo-test/log.txt +0 -0
- data/pgpool2/test/pdo-test/mod/database.inc +36 -0
- data/pgpool2/test/pdo-test/mod/def.inc +0 -0
- data/pgpool2/test/pdo-test/mod/errorhandler.inc +27 -0
- data/pgpool2/test/pdo-test/pdotest.php +11 -0
- data/pgpool2/test/pdo-test/regsql.inc +56 -0
- data/pgpool2/test/pgpool_setup +898 -0
- data/pgpool2/test/regression/README +39 -0
- data/pgpool2/test/regression/clean.sh +21 -0
- data/pgpool2/test/regression/libs.sh +16 -0
- data/pgpool2/test/regression/regress.sh +166 -0
- data/pgpool2/test/regression/tests/001.load_balance/test.sh +128 -0
- data/pgpool2/test/regression/tests/002.native_replication/PgTester.java +47 -0
- data/pgpool2/test/regression/tests/002.native_replication/create.sql +6 -0
- data/pgpool2/test/regression/tests/002.native_replication/test.sh +71 -0
- data/pgpool2/test/regression/tests/003.failover/expected.r +6 -0
- data/pgpool2/test/regression/tests/003.failover/expected.s +6 -0
- data/pgpool2/test/regression/tests/003.failover/test.sh +45 -0
- data/pgpool2/test/regression/tests/004.watchdog/master.conf +12 -0
- data/pgpool2/test/regression/tests/004.watchdog/standby.conf +19 -0
- data/pgpool2/test/regression/tests/004.watchdog/test.sh +52 -0
- data/pgpool2/test/regression/tests/050.bug58/test.sh +50 -0
- data/pgpool2/test/regression/tests/051.bug60/bug.sql +12 -0
- data/pgpool2/test/regression/tests/051.bug60/database-clean.sql +6 -0
- data/pgpool2/test/regression/tests/051.bug60/database-setup.sql +28 -0
- data/pgpool2/test/regression/tests/051.bug60/test.sh +79 -0
- data/pgpool2/test/regression/tests/052.do_query/test.sh +44 -0
- data/pgpool2/test/regression/tests/053.insert_lock_hangs/test.sh +81 -0
- data/pgpool2/test/regression/tests/054.postgres_fdw/test.sh +67 -0
- data/pgpool2/test/regression/tests/055.backend_all_down/test.sh +52 -0
- data/pgpool2/test/regression/tests/056.bug63/jdbctest2.java +66 -0
- data/pgpool2/test/regression/tests/056.bug63/test.sh +47 -0
- data/pgpool2/test/regression/tests/057.bug61/test.sh +40 -0
- data/pgpool2/test/regression/tests/058.bug68/jdbctest3.java +45 -0
- data/pgpool2/test/regression/tests/058.bug68/test.sh +47 -0
- data/pgpool2/test/timestamp/expected/insert.out +16 -0
- data/pgpool2/test/timestamp/expected/misc.out +3 -0
- data/pgpool2/test/timestamp/expected/update.out +6 -0
- data/pgpool2/test/timestamp/input/insert.sql +16 -0
- data/pgpool2/test/timestamp/input/misc.sql +3 -0
- data/pgpool2/test/timestamp/input/update.sql +6 -0
- data/pgpool2/test/timestamp/main.c +129 -0
- data/pgpool2/test/timestamp/parse_schedule +3 -0
- data/pgpool2/test/timestamp/run-test +69 -0
- data/pgpool2/version.h +1 -0
- data/pgpool2/watchdog/Makefile.am +17 -0
- data/pgpool2/watchdog/Makefile.in +505 -0
- data/pgpool2/watchdog/test/stab.c +266 -0
- data/pgpool2/watchdog/test/test.c +85 -0
- data/pgpool2/watchdog/test/wd_child_t.c +87 -0
- data/pgpool2/watchdog/test/wd_lifecheck_t.c +87 -0
- data/pgpool2/watchdog/test/wd_packet_t.c +87 -0
- data/pgpool2/watchdog/test/wd_ping_t.c +20 -0
- data/pgpool2/watchdog/watchdog.c +408 -0
- data/pgpool2/watchdog/watchdog.h +209 -0
- data/pgpool2/watchdog/wd_child.c +444 -0
- data/pgpool2/watchdog/wd_ext.h +123 -0
- data/pgpool2/watchdog/wd_heartbeat.c +577 -0
- data/pgpool2/watchdog/wd_if.c +216 -0
- data/pgpool2/watchdog/wd_init.c +126 -0
- data/pgpool2/watchdog/wd_interlock.c +347 -0
- data/pgpool2/watchdog/wd_lifecheck.c +512 -0
- data/pgpool2/watchdog/wd_list.c +429 -0
- data/pgpool2/watchdog/wd_packet.c +1159 -0
- data/pgpool2/watchdog/wd_ping.c +330 -0
- data/pgpool2/ylwrap +223 -0
- data/pgsql/presto_client.py +346 -0
- data/pgsql/prestogres.py +156 -0
- data/pgsql/setup_functions.sql +21 -0
- data/pgsql/setup_language.sql +3 -0
- data/prestogres.gemspec +23 -0
- metadata +496 -0
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 */
|
data/pgpool2/pool_ipc.h
ADDED
|
@@ -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 */
|
data/pgpool2/pool_lobj.c
ADDED
|
@@ -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
|
+
}
|
data/pgpool2/pool_lobj.h
ADDED
|
@@ -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
|
+
}
|